From b829c5eed74cc278c9bfebcb3c347d0786fd2b2b Mon Sep 17 00:00:00 2001 From: Troy Taylor Date: Fri, 17 Oct 2025 09:10:46 -0400 Subject: [PATCH] Remove \archived-contributions --- .../java-mcp-development.collection.yml | 35 - .../java-mcp/java-mcp-development.md | 41 - .../java-mcp/java-mcp-expert.chatmode.md | 325 -------- .../java-mcp-server-generator.prompt.md | 756 ------------------ .../java-mcp/java-mcp-server.instructions.md | 553 ------------- .../ruby-mcp-development.collection.yml | 35 - .../ruby-mcp/ruby-mcp-development.md | 41 - .../ruby-mcp/ruby-mcp-expert.chatmode.md | 346 -------- .../ruby-mcp-server-generator.prompt.md | 660 --------------- .../ruby-mcp/ruby-mcp-server.instructions.md | 629 --------------- .../rust-mcp-development.collection.yml | 37 - .../rust-mcp/rust-mcp-development.md | 42 - .../rust-mcp/rust-mcp-expert.chatmode.md | 465 ----------- .../rust-mcp-server-generator.prompt.md | 577 ------------- .../rust-mcp/rust-mcp-server.instructions.md | 719 ----------------- .../swift-mcp-development.collection.yml | 35 - .../swift-mcp/swift-mcp-development.md | 41 - .../swift-mcp/swift-mcp-expert.chatmode.md | 240 ------ .../swift-mcp-server-generator.prompt.md | 669 ---------------- .../swift-mcp-server.instructions.md | 498 ------------ 20 files changed, 6744 deletions(-) delete mode 100644 archived-contributions/java-mcp/java-mcp-development.collection.yml delete mode 100644 archived-contributions/java-mcp/java-mcp-development.md delete mode 100644 archived-contributions/java-mcp/java-mcp-expert.chatmode.md delete mode 100644 archived-contributions/java-mcp/java-mcp-server-generator.prompt.md delete mode 100644 archived-contributions/java-mcp/java-mcp-server.instructions.md delete mode 100644 archived-contributions/ruby-mcp/ruby-mcp-development.collection.yml delete mode 100644 archived-contributions/ruby-mcp/ruby-mcp-development.md delete mode 100644 archived-contributions/ruby-mcp/ruby-mcp-expert.chatmode.md delete mode 100644 archived-contributions/ruby-mcp/ruby-mcp-server-generator.prompt.md delete mode 100644 archived-contributions/ruby-mcp/ruby-mcp-server.instructions.md delete mode 100644 archived-contributions/rust-mcp/rust-mcp-development.collection.yml delete mode 100644 archived-contributions/rust-mcp/rust-mcp-development.md delete mode 100644 archived-contributions/rust-mcp/rust-mcp-expert.chatmode.md delete mode 100644 archived-contributions/rust-mcp/rust-mcp-server-generator.prompt.md delete mode 100644 archived-contributions/rust-mcp/rust-mcp-server.instructions.md delete mode 100644 archived-contributions/swift-mcp/swift-mcp-development.collection.yml delete mode 100644 archived-contributions/swift-mcp/swift-mcp-development.md delete mode 100644 archived-contributions/swift-mcp/swift-mcp-expert.chatmode.md delete mode 100644 archived-contributions/swift-mcp/swift-mcp-server-generator.prompt.md delete mode 100644 archived-contributions/swift-mcp/swift-mcp-server.instructions.md diff --git a/archived-contributions/java-mcp/java-mcp-development.collection.yml b/archived-contributions/java-mcp/java-mcp-development.collection.yml deleted file mode 100644 index f8427d3..0000000 --- a/archived-contributions/java-mcp/java-mcp-development.collection.yml +++ /dev/null @@ -1,35 +0,0 @@ -id: java-mcp-development -name: Java MCP Server Development -description: 'Complete toolkit for building Model Context Protocol servers in Java using the official MCP Java SDK with reactive streams and Spring Boot integration.' -tags: [java, mcp, model-context-protocol, server-development, sdk, reactive-streams, spring-boot, reactor] -items: - - path: instructions/java-mcp-server.instructions.md - kind: instruction - - path: prompts/java-mcp-server-generator.prompt.md - kind: prompt - - path: chatmodes/java-mcp-expert.chatmode.md - kind: chat-mode - usage: | - recommended - - This chat mode provides expert guidance for building MCP servers in Java. - - This chat mode is ideal for: - - Creating new MCP server projects with Java - - Implementing reactive handlers with Project Reactor - - Setting up stdio or HTTP transports - - Debugging reactive streams and error handling - - Learning Java MCP best practices with the official SDK - - Integrating with Spring Boot applications - - To get the best results, consider: - - Using the instruction file to set context for Java MCP development - - Using the prompt to generate initial project structure - - Switching to the expert chat mode for detailed implementation help - - Specifying whether you need Maven or Gradle - - Providing details about what tools or functionality you need - - Mentioning if you need Spring Boot integration - -display: - ordering: manual - show_badge: true diff --git a/archived-contributions/java-mcp/java-mcp-development.md b/archived-contributions/java-mcp/java-mcp-development.md deleted file mode 100644 index 4a400de..0000000 --- a/archived-contributions/java-mcp/java-mcp-development.md +++ /dev/null @@ -1,41 +0,0 @@ -# Java MCP Server Development - -'Complete toolkit for building Model Context Protocol servers in Java using the official MCP Java SDK with reactive streams and Spring Boot integration.' - -**Tags:** java, mcp, model-context-protocol, server-development, sdk, reactive-streams, spring-boot, reactor - -## Items in this Collection - -| Title | Type | Description | -| ----- | ---- | ----------- | -| [Java MCP Server Development Guidelines](../instructions/java-mcp-server.instructions.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fjava-mcp-server.instructions.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fjava-mcp-server.instructions.md) | Instruction | Best practices and patterns for building Model Context Protocol (MCP) servers in Java using the official MCP Java SDK with reactive streams and Spring integration. | -| [Java MCP Server Generator](../prompts/java-mcp-server-generator.prompt.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/prompt?url=vscode%3Achat-prompt%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fprompts%2Fjava-mcp-server-generator.prompt.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/prompt?url=vscode-insiders%3Achat-prompt%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fprompts%2Fjava-mcp-server-generator.prompt.md) | Prompt | Generate a complete Model Context Protocol server project in Java using the official MCP Java SDK with reactive streams and optional Spring Boot integration. | -| [Java MCP Expert](../chatmodes/java-mcp-expert.chatmode.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/chatmode?url=vscode%3Achat-mode%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fchatmodes%2Fjava-mcp-expert.chatmode.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/chatmode?url=vscode-insiders%3Achat-mode%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fchatmodes%2Fjava-mcp-expert.chatmode.md) | Chat Mode | Expert assistance for building Model Context Protocol servers in Java using reactive streams, the official MCP Java SDK, and Spring Boot integration. [see usage](#java-mcp-expert) | - -## Collection Usage - -### Java MCP Expert - -recommended - -This chat mode provides expert guidance for building MCP servers in Java. - -This chat mode is ideal for: -- Creating new MCP server projects with Java -- Implementing reactive handlers with Project Reactor -- Setting up stdio or HTTP transports -- Debugging reactive streams and error handling -- Learning Java MCP best practices with the official SDK -- Integrating with Spring Boot applications - -To get the best results, consider: -- Using the instruction file to set context for Java MCP development -- Using the prompt to generate initial project structure -- Switching to the expert chat mode for detailed implementation help -- Specifying whether you need Maven or Gradle -- Providing details about what tools or functionality you need -- Mentioning if you need Spring Boot integration - ---- - -*This collection includes 3 curated items for java mcp server development.* \ No newline at end of file diff --git a/archived-contributions/java-mcp/java-mcp-expert.chatmode.md b/archived-contributions/java-mcp/java-mcp-expert.chatmode.md deleted file mode 100644 index b94cb2e..0000000 --- a/archived-contributions/java-mcp/java-mcp-expert.chatmode.md +++ /dev/null @@ -1,325 +0,0 @@ ---- -description: 'Expert assistance for building Model Context Protocol servers in Java using reactive streams, the official MCP Java SDK, and Spring Boot integration.' -model: GPT-4.1 ---- - -# Java MCP Expert - -I'm specialized in helping you build robust, production-ready MCP servers in Java using the official Java SDK. I can assist with: - -## Core Capabilities - -### Server Architecture -- Setting up McpServer with builder pattern -- Configuring capabilities (tools, resources, prompts) -- Implementing stdio and HTTP transports -- Reactive Streams with Project Reactor -- Synchronous facade for blocking use cases -- Spring Boot integration with starters - -### Tool Development -- Creating tool definitions with JSON schemas -- Implementing tool handlers with Mono/Flux -- Parameter validation and error handling -- Async tool execution with reactive pipelines -- Tool list changed notifications - -### Resource Management -- Defining resource URIs and metadata -- Implementing resource read handlers -- Managing resource subscriptions -- Resource changed notifications -- Multi-content responses (text, image, binary) - -### Prompt Engineering -- Creating prompt templates with arguments -- Implementing prompt get handlers -- Multi-turn conversation patterns -- Dynamic prompt generation -- Prompt list changed notifications - -### Reactive Programming -- Project Reactor operators and pipelines -- Mono for single results, Flux for streams -- Error handling in reactive chains -- Context propagation for observability -- Backpressure management - -## Code Assistance - -I can help you with: - -### Maven Dependencies -```xml - - io.modelcontextprotocol.sdk - mcp - 0.14.1 - -``` - -### Server Creation -```java -McpServer server = McpServerBuilder.builder() - .serverInfo("my-server", "1.0.0") - .capabilities(cap -> cap - .tools(true) - .resources(true) - .prompts(true)) - .build(); -``` - -### Tool Handler -```java -server.addToolHandler("process", (args) -> { - return Mono.fromCallable(() -> { - String result = process(args); - return ToolResponse.success() - .addTextContent(result) - .build(); - }).subscribeOn(Schedulers.boundedElastic()); -}); -``` - -### Transport Configuration -```java -StdioServerTransport transport = new StdioServerTransport(); -server.start(transport).subscribe(); -``` - -### Spring Boot Integration -```java -@Configuration -public class McpConfiguration { - @Bean - public McpServerConfigurer mcpServerConfigurer() { - return server -> server - .serverInfo("spring-server", "1.0.0") - .capabilities(cap -> cap.tools(true)); - } -} -``` - -## Best Practices - -### Reactive Streams -Use Mono for single results, Flux for streams: -```java -// Single result -Mono result = Mono.just( - ToolResponse.success().build() -); - -// Stream of items -Flux resources = Flux.fromIterable(getResources()); -``` - -### Error Handling -Proper error handling in reactive chains: -```java -server.addToolHandler("risky", (args) -> { - return Mono.fromCallable(() -> riskyOperation(args)) - .map(result -> ToolResponse.success() - .addTextContent(result) - .build()) - .onErrorResume(ValidationException.class, e -> - Mono.just(ToolResponse.error() - .message("Invalid input") - .build())) - .doOnError(e -> log.error("Error", e)); -}); -``` - -### Logging -Use SLF4J for structured logging: -```java -private static final Logger log = LoggerFactory.getLogger(MyClass.class); - -log.info("Tool called: {}", toolName); -log.debug("Processing with args: {}", args); -log.error("Operation failed", exception); -``` - -### JSON Schema -Use fluent builder for schemas: -```java -JsonSchema schema = JsonSchema.object() - .property("name", JsonSchema.string() - .description("User's name") - .required(true)) - .property("age", JsonSchema.integer() - .minimum(0) - .maximum(150)) - .build(); -``` - -## Common Patterns - -### Synchronous Facade -For blocking operations: -```java -McpSyncServer syncServer = server.toSyncServer(); - -syncServer.addToolHandler("blocking", (args) -> { - String result = blockingOperation(args); - return ToolResponse.success() - .addTextContent(result) - .build(); -}); -``` - -### Resource Subscription -Track subscriptions: -```java -private final Set subscriptions = ConcurrentHashMap.newKeySet(); - -server.addResourceSubscribeHandler((uri) -> { - subscriptions.add(uri); - log.info("Subscribed to {}", uri); - return Mono.empty(); -}); -``` - -### Async Operations -Use bounded elastic for blocking calls: -```java -server.addToolHandler("external", (args) -> { - return Mono.fromCallable(() -> callExternalApi(args)) - .timeout(Duration.ofSeconds(30)) - .subscribeOn(Schedulers.boundedElastic()); -}); -``` - -### Context Propagation -Propagate observability context: -```java -server.addToolHandler("traced", (args) -> { - return Mono.deferContextual(ctx -> { - String traceId = ctx.get("traceId"); - log.info("Processing with traceId: {}", traceId); - return processWithContext(args, traceId); - }); -}); -``` - -## Spring Boot Integration - -### Configuration -```java -@Configuration -public class McpConfig { - @Bean - public McpServerConfigurer configurer() { - return server -> server - .serverInfo("spring-app", "1.0.0") - .capabilities(cap -> cap - .tools(true) - .resources(true)); - } -} -``` - -### Component-Based Handlers -```java -@Component -public class SearchToolHandler implements ToolHandler { - - @Override - public String getName() { - return "search"; - } - - @Override - public Tool getTool() { - return Tool.builder() - .name("search") - .description("Search for data") - .inputSchema(JsonSchema.object() - .property("query", JsonSchema.string().required(true))) - .build(); - } - - @Override - public Mono handle(JsonNode args) { - String query = args.get("query").asText(); - return searchService.search(query) - .map(results -> ToolResponse.success() - .addTextContent(results) - .build()); - } -} -``` - -## Testing - -### Unit Tests -```java -@Test -void testToolHandler() { - McpServer server = createTestServer(); - McpSyncServer syncServer = server.toSyncServer(); - - ObjectNode args = new ObjectMapper().createObjectNode() - .put("key", "value"); - - ToolResponse response = syncServer.callTool("test", args); - - assertFalse(response.isError()); - assertEquals(1, response.getContent().size()); -} -``` - -### Reactive Tests -```java -@Test -void testReactiveHandler() { - Mono result = toolHandler.handle(args); - - StepVerifier.create(result) - .expectNextMatches(response -> !response.isError()) - .verifyComplete(); -} -``` - -## Platform Support - -The Java SDK supports: -- Java 17+ (LTS recommended) -- Jakarta Servlet 5.0+ -- Spring Boot 3.0+ -- Project Reactor 3.5+ - -## Architecture - -### Modules -- `mcp-core` - Core implementation (stdio, JDK HttpClient, Servlet) -- `mcp-json` - JSON abstraction layer -- `mcp-jackson2` - Jackson implementation -- `mcp` - Convenience bundle (core + Jackson) -- `mcp-spring` - Spring integrations (WebClient, WebFlux, WebMVC) - -### Design Decisions -- **JSON**: Jackson behind abstraction (`mcp-json`) -- **Async**: Reactive Streams with Project Reactor -- **HTTP Client**: JDK HttpClient (Java 11+) -- **HTTP Server**: Jakarta Servlet, Spring WebFlux/WebMVC -- **Logging**: SLF4J facade -- **Observability**: Reactor Context - -## Ask Me About - -- Server setup and configuration -- Tool, resource, and prompt implementations -- Reactive Streams patterns with Reactor -- Spring Boot integration and starters -- JSON schema construction -- Error handling strategies -- Testing reactive code -- HTTP transport configuration -- Servlet integration -- Context propagation for tracing -- Performance optimization -- Deployment strategies -- Maven and Gradle setup - -I'm here to help you build efficient, scalable, and idiomatic Java MCP servers. What would you like to work on? diff --git a/archived-contributions/java-mcp/java-mcp-server-generator.prompt.md b/archived-contributions/java-mcp/java-mcp-server-generator.prompt.md deleted file mode 100644 index 0d2b68d..0000000 --- a/archived-contributions/java-mcp/java-mcp-server-generator.prompt.md +++ /dev/null @@ -1,756 +0,0 @@ ---- -description: 'Generate a complete Model Context Protocol server project in Java using the official MCP Java SDK with reactive streams and optional Spring Boot integration.' -mode: agent ---- - -# Java MCP Server Generator - -Generate a complete, production-ready MCP server in Java using the official Java SDK with Maven or Gradle. - -## Project Generation - -When asked to create a Java MCP server, generate a complete project with this structure: - -``` -my-mcp-server/ -├── pom.xml (or build.gradle.kts) -├── src/ -│ ├── main/ -│ │ ├── java/ -│ │ │ └── com/example/mcp/ -│ │ │ ├── McpServerApplication.java -│ │ │ ├── config/ -│ │ │ │ └── ServerConfiguration.java -│ │ │ ├── tools/ -│ │ │ │ ├── ToolDefinitions.java -│ │ │ │ └── ToolHandlers.java -│ │ │ ├── resources/ -│ │ │ │ ├── ResourceDefinitions.java -│ │ │ │ └── ResourceHandlers.java -│ │ │ └── prompts/ -│ │ │ ├── PromptDefinitions.java -│ │ │ └── PromptHandlers.java -│ │ └── resources/ -│ │ └── application.properties (if using Spring) -│ └── test/ -│ └── java/ -│ └── com/example/mcp/ -│ └── McpServerTest.java -└── README.md -``` - -## Maven pom.xml Template - -```xml - - - 4.0.0 - - com.example - my-mcp-server - 1.0.0 - jar - - My MCP Server - Model Context Protocol server implementation - - - 17 - 17 - 17 - UTF-8 - 0.14.1 - 2.0.9 - 1.4.11 - 5.10.0 - - - - - - io.modelcontextprotocol.sdk - mcp - ${mcp.version} - - - - - org.slf4j - slf4j-api - ${slf4j.version} - - - ch.qos.logback - logback-classic - ${logback.version} - - - - - org.junit.jupiter - junit-jupiter - ${junit.version} - test - - - io.projectreactor - reactor-test - test - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.11.0 - - - org.apache.maven.plugins - maven-surefire-plugin - 3.1.2 - - - org.apache.maven.plugins - maven-shade-plugin - 3.5.0 - - - package - - shade - - - - - com.example.mcp.McpServerApplication - - - - - - - - - -``` - -## Gradle build.gradle.kts Template - -```kotlin -plugins { - id("java") - id("application") -} - -group = "com.example" -version = "1.0.0" - -java { - sourceCompatibility = JavaVersion.VERSION_17 - targetCompatibility = JavaVersion.VERSION_17 -} - -repositories { - mavenCentral() -} - -dependencies { - // MCP Java SDK - implementation("io.modelcontextprotocol.sdk:mcp:0.14.1") - - // Logging - implementation("org.slf4j:slf4j-api:2.0.9") - implementation("ch.qos.logback:logback-classic:1.4.11") - - // Testing - testImplementation("org.junit.jupiter:junit-jupiter:5.10.0") - testImplementation("io.projectreactor:reactor-test:3.5.0") -} - -application { - mainClass.set("com.example.mcp.McpServerApplication") -} - -tasks.test { - useJUnitPlatform() -} -``` - -## McpServerApplication.java Template - -```java -package com.example.mcp; - -import com.example.mcp.tools.ToolHandlers; -import com.example.mcp.resources.ResourceHandlers; -import com.example.mcp.prompts.PromptHandlers; -import io.mcp.server.McpServer; -import io.mcp.server.McpServerBuilder; -import io.mcp.server.transport.StdioServerTransport; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import reactor.core.Disposable; - -public class McpServerApplication { - - private static final Logger log = LoggerFactory.getLogger(McpServerApplication.class); - - public static void main(String[] args) { - log.info("Starting MCP Server..."); - - try { - McpServer server = createServer(); - StdioServerTransport transport = new StdioServerTransport(); - - // Start server - Disposable serverDisposable = server.start(transport).subscribe(); - - // Graceful shutdown - Runtime.getRuntime().addShutdownHook(new Thread(() -> { - log.info("Shutting down MCP server"); - serverDisposable.dispose(); - server.stop().block(); - })); - - log.info("MCP Server started successfully"); - - // Keep running - Thread.currentThread().join(); - - } catch (Exception e) { - log.error("Failed to start MCP server", e); - System.exit(1); - } - } - - private static McpServer createServer() { - McpServer server = McpServerBuilder.builder() - .serverInfo("my-mcp-server", "1.0.0") - .capabilities(capabilities -> capabilities - .tools(true) - .resources(true) - .prompts(true)) - .build(); - - // Register handlers - ToolHandlers.register(server); - ResourceHandlers.register(server); - PromptHandlers.register(server); - - return server; - } -} -``` - -## ToolDefinitions.java Template - -```java -package com.example.mcp.tools; - -import io.mcp.json.JsonSchema; -import io.mcp.server.tool.Tool; - -import java.util.List; - -public class ToolDefinitions { - - public static List getTools() { - return List.of( - createGreetTool(), - createCalculateTool() - ); - } - - private static Tool createGreetTool() { - return Tool.builder() - .name("greet") - .description("Generate a greeting message") - .inputSchema(JsonSchema.object() - .property("name", JsonSchema.string() - .description("Name to greet") - .required(true))) - .build(); - } - - private static Tool createCalculateTool() { - return Tool.builder() - .name("calculate") - .description("Perform mathematical calculations") - .inputSchema(JsonSchema.object() - .property("operation", JsonSchema.string() - .description("Operation to perform") - .enumValues(List.of("add", "subtract", "multiply", "divide")) - .required(true)) - .property("a", JsonSchema.number() - .description("First operand") - .required(true)) - .property("b", JsonSchema.number() - .description("Second operand") - .required(true))) - .build(); - } -} -``` - -## ToolHandlers.java Template - -```java -package com.example.mcp.tools; - -import com.fasterxml.jackson.databind.JsonNode; -import io.mcp.server.McpServer; -import io.mcp.server.tool.ToolResponse; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import reactor.core.publisher.Mono; - -public class ToolHandlers { - - private static final Logger log = LoggerFactory.getLogger(ToolHandlers.class); - - public static void register(McpServer server) { - // Register tool list handler - server.addToolListHandler(() -> { - log.debug("Listing available tools"); - return Mono.just(ToolDefinitions.getTools()); - }); - - // Register greet handler - server.addToolHandler("greet", ToolHandlers::handleGreet); - - // Register calculate handler - server.addToolHandler("calculate", ToolHandlers::handleCalculate); - } - - private static Mono handleGreet(JsonNode arguments) { - log.info("Greet tool called"); - - if (!arguments.has("name")) { - return Mono.just(ToolResponse.error() - .message("Missing 'name' parameter") - .build()); - } - - String name = arguments.get("name").asText(); - String greeting = "Hello, " + name + "! Welcome to MCP."; - - log.debug("Generated greeting for: {}", name); - - return Mono.just(ToolResponse.success() - .addTextContent(greeting) - .build()); - } - - private static Mono handleCalculate(JsonNode arguments) { - log.info("Calculate tool called"); - - if (!arguments.has("operation") || !arguments.has("a") || !arguments.has("b")) { - return Mono.just(ToolResponse.error() - .message("Missing required parameters") - .build()); - } - - String operation = arguments.get("operation").asText(); - double a = arguments.get("a").asDouble(); - double b = arguments.get("b").asDouble(); - - double result; - switch (operation) { - case "add": - result = a + b; - break; - case "subtract": - result = a - b; - break; - case "multiply": - result = a * b; - break; - case "divide": - if (b == 0) { - return Mono.just(ToolResponse.error() - .message("Division by zero") - .build()); - } - result = a / b; - break; - default: - return Mono.just(ToolResponse.error() - .message("Unknown operation: " + operation) - .build()); - } - - log.debug("Calculation: {} {} {} = {}", a, operation, b, result); - - return Mono.just(ToolResponse.success() - .addTextContent("Result: " + result) - .build()); - } -} -``` - -## ResourceDefinitions.java Template - -```java -package com.example.mcp.resources; - -import io.mcp.server.resource.Resource; - -import java.util.List; - -public class ResourceDefinitions { - - public static List getResources() { - return List.of( - Resource.builder() - .name("Example Data") - .uri("resource://data/example") - .description("Example resource data") - .mimeType("application/json") - .build(), - Resource.builder() - .name("Configuration") - .uri("resource://config") - .description("Server configuration") - .mimeType("application/json") - .build() - ); - } -} -``` - -## ResourceHandlers.java Template - -```java -package com.example.mcp.resources; - -import io.mcp.server.McpServer; -import io.mcp.server.resource.ResourceContent; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import reactor.core.publisher.Mono; - -import java.time.Instant; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -public class ResourceHandlers { - - private static final Logger log = LoggerFactory.getLogger(ResourceHandlers.class); - private static final Map subscriptions = new ConcurrentHashMap<>(); - - public static void register(McpServer server) { - // Register resource list handler - server.addResourceListHandler(() -> { - log.debug("Listing available resources"); - return Mono.just(ResourceDefinitions.getResources()); - }); - - // Register resource read handler - server.addResourceReadHandler(ResourceHandlers::handleRead); - - // Register resource subscribe handler - server.addResourceSubscribeHandler(ResourceHandlers::handleSubscribe); - - // Register resource unsubscribe handler - server.addResourceUnsubscribeHandler(ResourceHandlers::handleUnsubscribe); - } - - private static Mono handleRead(String uri) { - log.info("Reading resource: {}", uri); - - switch (uri) { - case "resource://data/example": - String jsonData = String.format( - "{\"message\":\"Example resource data\",\"timestamp\":\"%s\"}", - Instant.now() - ); - return Mono.just(ResourceContent.text(jsonData, uri, "application/json")); - - case "resource://config": - String config = "{\"serverName\":\"my-mcp-server\",\"version\":\"1.0.0\"}"; - return Mono.just(ResourceContent.text(config, uri, "application/json")); - - default: - log.warn("Unknown resource requested: {}", uri); - return Mono.error(new IllegalArgumentException("Unknown resource URI: " + uri)); - } - } - - private static Mono handleSubscribe(String uri) { - log.info("Client subscribed to resource: {}", uri); - subscriptions.put(uri, true); - return Mono.empty(); - } - - private static Mono handleUnsubscribe(String uri) { - log.info("Client unsubscribed from resource: {}", uri); - subscriptions.remove(uri); - return Mono.empty(); - } -} -``` - -## PromptDefinitions.java Template - -```java -package com.example.mcp.prompts; - -import io.mcp.server.prompt.Prompt; -import io.mcp.server.prompt.PromptArgument; - -import java.util.List; - -public class PromptDefinitions { - - public static List getPrompts() { - return List.of( - Prompt.builder() - .name("code-review") - .description("Generate a code review prompt") - .argument(PromptArgument.builder() - .name("language") - .description("Programming language") - .required(true) - .build()) - .argument(PromptArgument.builder() - .name("focus") - .description("Review focus area") - .required(false) - .build()) - .build() - ); - } -} -``` - -## PromptHandlers.java Template - -```java -package com.example.mcp.prompts; - -import io.mcp.server.McpServer; -import io.mcp.server.prompt.PromptMessage; -import io.mcp.server.prompt.PromptResult; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import reactor.core.publisher.Mono; - -import java.util.List; -import java.util.Map; - -public class PromptHandlers { - - private static final Logger log = LoggerFactory.getLogger(PromptHandlers.class); - - public static void register(McpServer server) { - // Register prompt list handler - server.addPromptListHandler(() -> { - log.debug("Listing available prompts"); - return Mono.just(PromptDefinitions.getPrompts()); - }); - - // Register prompt get handler - server.addPromptGetHandler(PromptHandlers::handleCodeReview); - } - - private static Mono handleCodeReview(String name, Map arguments) { - log.info("Getting prompt: {}", name); - - if (!name.equals("code-review")) { - return Mono.error(new IllegalArgumentException("Unknown prompt: " + name)); - } - - String language = arguments.getOrDefault("language", "Java"); - String focus = arguments.getOrDefault("focus", "general quality"); - - String description = "Code review for " + language + " with focus on " + focus; - - List messages = List.of( - PromptMessage.user("Please review this " + language + " code with focus on " + focus + "."), - PromptMessage.assistant("I'll review the code focusing on " + focus + ". Please share the code."), - PromptMessage.user("Here's the code to review: [paste code here]") - ); - - log.debug("Generated code review prompt for {} ({})", language, focus); - - return Mono.just(PromptResult.builder() - .description(description) - .messages(messages) - .build()); - } -} -``` - -## McpServerTest.java Template - -```java -package com.example.mcp; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ObjectNode; -import io.mcp.server.McpServer; -import io.mcp.server.McpSyncServer; -import io.mcp.server.tool.ToolResponse; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.*; - -class McpServerTest { - - private McpSyncServer syncServer; - private ObjectMapper objectMapper; - - @BeforeEach - void setUp() { - McpServer server = createTestServer(); - syncServer = server.toSyncServer(); - objectMapper = new ObjectMapper(); - } - - private McpServer createTestServer() { - // Same setup as main application - McpServer server = McpServerBuilder.builder() - .serverInfo("test-server", "1.0.0") - .capabilities(cap -> cap.tools(true)) - .build(); - - // Register handlers - ToolHandlers.register(server); - - return server; - } - - @Test - void testGreetTool() { - ObjectNode args = objectMapper.createObjectNode(); - args.put("name", "Java"); - - ToolResponse response = syncServer.callTool("greet", args); - - assertFalse(response.isError()); - assertEquals(1, response.getContent().size()); - assertTrue(response.getContent().get(0).getText().contains("Java")); - } - - @Test - void testCalculateTool() { - ObjectNode args = objectMapper.createObjectNode(); - args.put("operation", "add"); - args.put("a", 5); - args.put("b", 3); - - ToolResponse response = syncServer.callTool("calculate", args); - - assertFalse(response.isError()); - assertTrue(response.getContent().get(0).getText().contains("8")); - } - - @Test - void testDivideByZero() { - ObjectNode args = objectMapper.createObjectNode(); - args.put("operation", "divide"); - args.put("a", 10); - args.put("b", 0); - - ToolResponse response = syncServer.callTool("calculate", args); - - assertTrue(response.isError()); - } -} -``` - -## README.md Template - -```markdown -# My MCP Server - -A Model Context Protocol server built with Java and the official MCP Java SDK. - -## Features - -- ✅ Tools: greet, calculate -- ✅ Resources: example data, configuration -- ✅ Prompts: code-review -- ✅ Reactive Streams with Project Reactor -- ✅ Structured logging with SLF4J -- ✅ Full test coverage - -## Requirements - -- Java 17 or later -- Maven 3.6+ or Gradle 7+ - -## Build - -### Maven -```bash -mvn clean package -``` - -### Gradle -```bash -./gradlew build -``` - -## Run - -### Maven -```bash -java -jar target/my-mcp-server-1.0.0.jar -``` - -### Gradle -```bash -./gradlew run -``` - -## Testing - -### Maven -```bash -mvn test -``` - -### Gradle -```bash -./gradlew test -``` - -## Integration with Claude Desktop - -Add to `claude_desktop_config.json`: - -```json -{ - "mcpServers": { - "my-mcp-server": { - "command": "java", - "args": ["-jar", "/path/to/my-mcp-server-1.0.0.jar"] - } - } -} -``` - -## License - -MIT -``` - -## Generation Instructions - -1. **Ask for project name and package** -2. **Choose build tool** (Maven or Gradle) -3. **Generate all files** with proper package structure -4. **Use Reactive Streams** for async handlers -5. **Include comprehensive logging** with SLF4J -6. **Add tests** for all handlers -7. **Follow Java conventions** (camelCase, PascalCase) -8. **Include error handling** with proper responses -9. **Document public APIs** with Javadoc -10. **Provide both sync and async** examples diff --git a/archived-contributions/java-mcp/java-mcp-server.instructions.md b/archived-contributions/java-mcp/java-mcp-server.instructions.md deleted file mode 100644 index 39f3a53..0000000 --- a/archived-contributions/java-mcp/java-mcp-server.instructions.md +++ /dev/null @@ -1,553 +0,0 @@ ---- -description: 'Best practices and patterns for building Model Context Protocol (MCP) servers in Java using the official MCP Java SDK with reactive streams and Spring integration.' -applyTo: "**/*.java, **/pom.xml, **/build.gradle, **/build.gradle.kts" ---- - -# Java MCP Server Development Guidelines - -When building MCP servers in Java, follow these best practices and patterns using the official Java SDK. - -## Dependencies - -Add the MCP Java SDK to your Maven project: - -```xml - - - io.modelcontextprotocol.sdk - mcp - 0.14.1 - - -``` - -Or for Gradle: - -```kotlin -dependencies { - implementation("io.modelcontextprotocol.sdk:mcp:0.14.1") -} -``` - -## Server Setup - -Create an MCP server using the builder pattern: - -```java -import io.mcp.server.McpServer; -import io.mcp.server.McpServerBuilder; -import io.mcp.server.transport.StdioServerTransport; - -McpServer server = McpServerBuilder.builder() - .serverInfo("my-server", "1.0.0") - .capabilities(capabilities -> capabilities - .tools(true) - .resources(true) - .prompts(true)) - .build(); - -// Start with stdio transport -StdioServerTransport transport = new StdioServerTransport(); -server.start(transport).subscribe(); -``` - -## Adding Tools - -Register tool handlers with the server: - -```java -import io.mcp.server.tool.Tool; -import io.mcp.server.tool.ToolHandler; -import reactor.core.publisher.Mono; - -// Define a tool -Tool searchTool = Tool.builder() - .name("search") - .description("Search for information") - .inputSchema(JsonSchema.object() - .property("query", JsonSchema.string() - .description("Search query") - .required(true)) - .property("limit", JsonSchema.integer() - .description("Maximum results") - .defaultValue(10))) - .build(); - -// Register tool handler -server.addToolHandler("search", (arguments) -> { - String query = arguments.get("query").asText(); - int limit = arguments.has("limit") - ? arguments.get("limit").asInt() - : 10; - - // Perform search - List results = performSearch(query, limit); - - return Mono.just(ToolResponse.success() - .addTextContent("Found " + results.size() + " results") - .build()); -}); -``` - -## Adding Resources - -Implement resource handlers for data access: - -```java -import io.mcp.server.resource.Resource; -import io.mcp.server.resource.ResourceHandler; - -// Register resource list handler -server.addResourceListHandler(() -> { - List resources = List.of( - Resource.builder() - .name("Data File") - .uri("resource://data/example.txt") - .description("Example data file") - .mimeType("text/plain") - .build() - ); - return Mono.just(resources); -}); - -// Register resource read handler -server.addResourceReadHandler((uri) -> { - if (uri.equals("resource://data/example.txt")) { - String content = loadResourceContent(uri); - return Mono.just(ResourceContent.text(content, uri)); - } - throw new ResourceNotFoundException(uri); -}); - -// Register resource subscribe handler -server.addResourceSubscribeHandler((uri) -> { - subscriptions.add(uri); - log.info("Client subscribed to {}", uri); - return Mono.empty(); -}); -``` - -## Adding Prompts - -Implement prompt handlers for templated conversations: - -```java -import io.mcp.server.prompt.Prompt; -import io.mcp.server.prompt.PromptMessage; -import io.mcp.server.prompt.PromptArgument; - -// Register prompt list handler -server.addPromptListHandler(() -> { - List prompts = List.of( - Prompt.builder() - .name("analyze") - .description("Analyze a topic") - .argument(PromptArgument.builder() - .name("topic") - .description("Topic to analyze") - .required(true) - .build()) - .argument(PromptArgument.builder() - .name("depth") - .description("Analysis depth") - .required(false) - .build()) - .build() - ); - return Mono.just(prompts); -}); - -// Register prompt get handler -server.addPromptGetHandler((name, arguments) -> { - if (name.equals("analyze")) { - String topic = arguments.getOrDefault("topic", "general"); - String depth = arguments.getOrDefault("depth", "basic"); - - List messages = List.of( - PromptMessage.user("Please analyze this topic: " + topic), - PromptMessage.assistant("I'll provide a " + depth + " analysis of " + topic) - ); - - return Mono.just(PromptResult.builder() - .description("Analysis of " + topic + " at " + depth + " level") - .messages(messages) - .build()); - } - throw new PromptNotFoundException(name); -}); -``` - -## Reactive Streams Pattern - -The Java SDK uses Reactive Streams (Project Reactor) for asynchronous processing: - -```java -// Return Mono for single results -server.addToolHandler("process", (args) -> { - return Mono.fromCallable(() -> { - String result = expensiveOperation(args); - return ToolResponse.success() - .addTextContent(result) - .build(); - }).subscribeOn(Schedulers.boundedElastic()); -}); - -// Return Flux for streaming results -server.addResourceListHandler(() -> { - return Flux.fromIterable(getResources()) - .map(r -> Resource.builder() - .uri(r.getUri()) - .name(r.getName()) - .build()) - .collectList(); -}); -``` - -## Synchronous Facade - -For blocking use cases, use the synchronous API: - -```java -import io.mcp.server.McpSyncServer; - -McpSyncServer syncServer = server.toSyncServer(); - -// Blocking tool handler -syncServer.addToolHandler("greet", (args) -> { - String name = args.get("name").asText(); - return ToolResponse.success() - .addTextContent("Hello, " + name + "!") - .build(); -}); -``` - -## Transport Configuration - -### Stdio Transport - -For local subprocess communication: - -```java -import io.mcp.server.transport.StdioServerTransport; - -StdioServerTransport transport = new StdioServerTransport(); -server.start(transport).block(); -``` - -### HTTP Transport (Servlet) - -For HTTP-based servers: - -```java -import io.mcp.server.transport.ServletServerTransport; -import jakarta.servlet.http.HttpServlet; - -public class McpServlet extends HttpServlet { - private final McpServer server; - private final ServletServerTransport transport; - - public McpServlet() { - this.server = createMcpServer(); - this.transport = new ServletServerTransport(); - } - - @Override - protected void doPost(HttpServletRequest req, HttpServletResponse resp) { - transport.handleRequest(server, req, resp).block(); - } -} -``` - -## Spring Boot Integration - -Use the Spring Boot starter for seamless integration: - -```xml - - io.modelcontextprotocol.sdk - mcp-spring-boot-starter - 0.14.1 - -``` - -Configure the server with Spring: - -```java -import org.springframework.context.annotation.Configuration; -import io.mcp.spring.McpServerConfigurer; - -@Configuration -public class McpConfiguration { - - @Bean - public McpServerConfigurer mcpServerConfigurer() { - return server -> server - .serverInfo("spring-server", "1.0.0") - .capabilities(cap -> cap - .tools(true) - .resources(true) - .prompts(true)); - } -} -``` - -Register handlers as Spring beans: - -```java -import org.springframework.stereotype.Component; -import io.mcp.spring.ToolHandler; - -@Component -public class SearchToolHandler implements ToolHandler { - - @Override - public String getName() { - return "search"; - } - - @Override - public Tool getTool() { - return Tool.builder() - .name("search") - .description("Search for information") - .inputSchema(JsonSchema.object() - .property("query", JsonSchema.string().required(true))) - .build(); - } - - @Override - public Mono handle(JsonNode arguments) { - String query = arguments.get("query").asText(); - return Mono.just(ToolResponse.success() - .addTextContent("Search results for: " + query) - .build()); - } -} -``` - -## Error Handling - -Use proper error handling with MCP exceptions: - -```java -server.addToolHandler("risky", (args) -> { - return Mono.fromCallable(() -> { - try { - String result = riskyOperation(args); - return ToolResponse.success() - .addTextContent(result) - .build(); - } catch (ValidationException e) { - return ToolResponse.error() - .message("Invalid input: " + e.getMessage()) - .build(); - } catch (Exception e) { - log.error("Unexpected error", e); - return ToolResponse.error() - .message("Internal error occurred") - .build(); - } - }); -}); -``` - -## JSON Schema Construction - -Use the fluent schema builder: - -```java -import io.mcp.json.JsonSchema; - -JsonSchema schema = JsonSchema.object() - .property("name", JsonSchema.string() - .description("User's name") - .minLength(1) - .maxLength(100) - .required(true)) - .property("age", JsonSchema.integer() - .description("User's age") - .minimum(0) - .maximum(150)) - .property("email", JsonSchema.string() - .description("Email address") - .format("email") - .required(true)) - .property("tags", JsonSchema.array() - .items(JsonSchema.string()) - .uniqueItems(true)) - .additionalProperties(false) - .build(); -``` - -## Logging and Observability - -Use SLF4J for logging: - -```java -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -private static final Logger log = LoggerFactory.getLogger(MyMcpServer.class); - -server.addToolHandler("process", (args) -> { - log.info("Tool called: process, args: {}", args); - - return Mono.fromCallable(() -> { - String result = process(args); - log.debug("Processing completed successfully"); - return ToolResponse.success() - .addTextContent(result) - .build(); - }).doOnError(error -> { - log.error("Processing failed", error); - }); -}); -``` - -Propagate context with Reactor: - -```java -import reactor.util.context.Context; - -server.addToolHandler("traced", (args) -> { - return Mono.deferContextual(ctx -> { - String traceId = ctx.get("traceId"); - log.info("Processing with traceId: {}", traceId); - - return Mono.just(ToolResponse.success() - .addTextContent("Processed") - .build()); - }); -}); -``` - -## Testing - -Write tests using the synchronous API: - -```java -import org.junit.jupiter.api.Test; -import static org.assertj.core.Assertions.assertThat; - -class McpServerTest { - - @Test - void testToolHandler() { - McpServer server = createTestServer(); - McpSyncServer syncServer = server.toSyncServer(); - - JsonNode args = objectMapper.createObjectNode() - .put("query", "test"); - - ToolResponse response = syncServer.callTool("search", args); - - assertThat(response.isError()).isFalse(); - assertThat(response.getContent()).hasSize(1); - } -} -``` - -## Jackson Integration - -The SDK uses Jackson for JSON serialization. Customize as needed: - -```java -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; - -ObjectMapper mapper = new ObjectMapper(); -mapper.registerModule(new JavaTimeModule()); - -// Use custom mapper with server -McpServer server = McpServerBuilder.builder() - .objectMapper(mapper) - .build(); -``` - -## Content Types - -Support multiple content types in responses: - -```java -import io.mcp.server.content.Content; - -server.addToolHandler("multi", (args) -> { - return Mono.just(ToolResponse.success() - .addTextContent("Plain text response") - .addImageContent(imageBytes, "image/png") - .addResourceContent("resource://data", "application/json", jsonData) - .build()); -}); -``` - -## Server Lifecycle - -Properly manage server lifecycle: - -```java -import reactor.core.Disposable; - -Disposable serverDisposable = server.start(transport).subscribe(); - -// Graceful shutdown -Runtime.getRuntime().addShutdownHook(new Thread(() -> { - log.info("Shutting down MCP server"); - serverDisposable.dispose(); - server.stop().block(); -})); -``` - -## Common Patterns - -### Request Validation - -```java -server.addToolHandler("validate", (args) -> { - if (!args.has("required_field")) { - return Mono.just(ToolResponse.error() - .message("Missing required_field") - .build()); - } - - return processRequest(args); -}); -``` - -### Async Operations - -```java -server.addToolHandler("async", (args) -> { - return Mono.fromCallable(() -> callExternalApi(args)) - .timeout(Duration.ofSeconds(30)) - .onErrorResume(TimeoutException.class, e -> - Mono.just(ToolResponse.error() - .message("Operation timed out") - .build())) - .subscribeOn(Schedulers.boundedElastic()); -}); -``` - -### Resource Caching - -```java -private final Map cache = new ConcurrentHashMap<>(); - -server.addResourceReadHandler((uri) -> { - return Mono.fromCallable(() -> - cache.computeIfAbsent(uri, this::loadResource)) - .map(content -> ResourceContent.text(content, uri)); -}); -``` - -## Best Practices - -1. **Use Reactive Streams** for async operations and backpressure -2. **Leverage Spring Boot** starter for enterprise applications -3. **Implement proper error handling** with specific error messages -4. **Use SLF4J** for logging, not System.out -5. **Validate inputs** in tool and prompt handlers -6. **Support graceful shutdown** with proper resource cleanup -7. **Use bounded elastic scheduler** for blocking operations -8. **Propagate context** for observability in reactive chains -9. **Test with synchronous API** for simplicity -10. **Follow Java naming conventions** (camelCase for methods, PascalCase for classes) diff --git a/archived-contributions/ruby-mcp/ruby-mcp-development.collection.yml b/archived-contributions/ruby-mcp/ruby-mcp-development.collection.yml deleted file mode 100644 index fbf65b8..0000000 --- a/archived-contributions/ruby-mcp/ruby-mcp-development.collection.yml +++ /dev/null @@ -1,35 +0,0 @@ -id: ruby-mcp-development -name: Ruby MCP Server Development -description: 'Complete toolkit for building Model Context Protocol servers in Ruby using the official MCP Ruby SDK gem with Rails integration support.' -tags: [ruby, mcp, model-context-protocol, server-development, sdk, rails, gem] -items: - - path: instructions/ruby-mcp-server.instructions.md - kind: instruction - - path: prompts/ruby-mcp-server-generator.prompt.md - kind: prompt - - path: chatmodes/ruby-mcp-expert.chatmode.md - kind: chat-mode - usage: | - recommended - - This chat mode provides expert guidance for building MCP servers in Ruby. - - This chat mode is ideal for: - - Creating new MCP server projects with Ruby - - Implementing tools, prompts, and resources - - Setting up stdio or HTTP transports - - Debugging schema definitions and error handling - - Learning Ruby MCP best practices with the official SDK - - Integrating with Rails applications - - To get the best results, consider: - - Using the instruction file to set context for Ruby MCP development - - Using the prompt to generate initial project structure - - Switching to the expert chat mode for detailed implementation help - - Specifying whether you need stdio or Rails integration - - Providing details about what tools or functionality you need - - Mentioning if you need authentication or server_context usage - -display: - ordering: manual - show_badge: true diff --git a/archived-contributions/ruby-mcp/ruby-mcp-development.md b/archived-contributions/ruby-mcp/ruby-mcp-development.md deleted file mode 100644 index 4fcaa07..0000000 --- a/archived-contributions/ruby-mcp/ruby-mcp-development.md +++ /dev/null @@ -1,41 +0,0 @@ -# Ruby MCP Server Development - -'Complete toolkit for building Model Context Protocol servers in Ruby using the official MCP Ruby SDK gem with Rails integration support.' - -**Tags:** ruby, mcp, model-context-protocol, server-development, sdk, rails, gem - -## Items in this Collection - -| Title | Type | Description | -| ----- | ---- | ----------- | -| [Ruby MCP Server Development Guidelines](../instructions/ruby-mcp-server.instructions.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fruby-mcp-server.instructions.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fruby-mcp-server.instructions.md) | Instruction | Best practices and patterns for building Model Context Protocol (MCP) servers in Ruby using the official MCP Ruby SDK gem. | -| [Ruby MCP Server Generator](../prompts/ruby-mcp-server-generator.prompt.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/prompt?url=vscode%3Achat-prompt%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fprompts%2Fruby-mcp-server-generator.prompt.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/prompt?url=vscode-insiders%3Achat-prompt%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fprompts%2Fruby-mcp-server-generator.prompt.md) | Prompt | Generate a complete Model Context Protocol server project in Ruby using the official MCP Ruby SDK gem. | -| [Ruby MCP Expert](../chatmodes/ruby-mcp-expert.chatmode.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/chatmode?url=vscode%3Achat-mode%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fchatmodes%2Fruby-mcp-expert.chatmode.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/chatmode?url=vscode-insiders%3Achat-mode%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fchatmodes%2Fruby-mcp-expert.chatmode.md) | Chat Mode | Expert assistance for building Model Context Protocol servers in Ruby using the official MCP Ruby SDK gem with Rails integration. [see usage](#ruby-mcp-expert) | - -## Collection Usage - -### Ruby MCP Expert - -recommended - -This chat mode provides expert guidance for building MCP servers in Ruby. - -This chat mode is ideal for: -- Creating new MCP server projects with Ruby -- Implementing tools, prompts, and resources -- Setting up stdio or HTTP transports -- Debugging schema definitions and error handling -- Learning Ruby MCP best practices with the official SDK -- Integrating with Rails applications - -To get the best results, consider: -- Using the instruction file to set context for Ruby MCP development -- Using the prompt to generate initial project structure -- Switching to the expert chat mode for detailed implementation help -- Specifying whether you need stdio or Rails integration -- Providing details about what tools or functionality you need -- Mentioning if you need authentication or server_context usage - ---- - -*This collection includes 3 curated items for ruby mcp server development.* \ No newline at end of file diff --git a/archived-contributions/ruby-mcp/ruby-mcp-expert.chatmode.md b/archived-contributions/ruby-mcp/ruby-mcp-expert.chatmode.md deleted file mode 100644 index db3a34d..0000000 --- a/archived-contributions/ruby-mcp/ruby-mcp-expert.chatmode.md +++ /dev/null @@ -1,346 +0,0 @@ ---- -description: 'Expert assistance for building Model Context Protocol servers in Ruby using the official MCP Ruby SDK gem with Rails integration.' -model: GPT-4.1 ---- - -# Ruby MCP Expert - -I'm specialized in helping you build robust, production-ready MCP servers in Ruby using the official Ruby SDK. I can assist with: - -## Core Capabilities - -### Server Architecture -- Setting up MCP::Server instances -- Configuring tools, prompts, and resources -- Implementing stdio and HTTP transports -- Rails controller integration -- Server context for authentication - -### Tool Development -- Creating tool classes with MCP::Tool -- Defining input/output schemas -- Implementing tool annotations -- Structured content in responses -- Error handling with is_error flag - -### Resource Management -- Defining resources and resource templates -- Implementing resource read handlers -- URI template patterns -- Dynamic resource generation - -### Prompt Engineering -- Creating prompt classes with MCP::Prompt -- Defining prompt arguments -- Multi-turn conversation templates -- Dynamic prompt generation with server_context - -### Configuration -- Exception reporting with Bugsnag/Sentry -- Instrumentation callbacks for metrics -- Protocol version configuration -- Custom JSON-RPC methods - -## Code Assistance - -I can help you with: - -### Gemfile Setup -```ruby -gem 'mcp', '~> 0.4.0' -``` - -### Server Creation -```ruby -server = MCP::Server.new( - name: 'my_server', - version: '1.0.0', - tools: [MyTool], - prompts: [MyPrompt], - server_context: { user_id: current_user.id } -) -``` - -### Tool Definition -```ruby -class MyTool < MCP::Tool - tool_name 'my_tool' - description 'Tool description' - - input_schema( - properties: { - query: { type: 'string' } - }, - required: ['query'] - ) - - annotations( - read_only_hint: true - ) - - def self.call(query:, server_context:) - MCP::Tool::Response.new([{ - type: 'text', - text: 'Result' - }]) - end -end -``` - -### Stdio Transport -```ruby -transport = MCP::Server::Transports::StdioTransport.new(server) -transport.open -``` - -### Rails Integration -```ruby -class McpController < ApplicationController - def index - server = MCP::Server.new( - name: 'rails_server', - tools: [MyTool], - server_context: { user_id: current_user.id } - ) - render json: server.handle_json(request.body.read) - end -end -``` - -## Best Practices - -### Use Classes for Tools -Organize tools as classes for better structure: -```ruby -class GreetTool < MCP::Tool - tool_name 'greet' - description 'Generate greeting' - - def self.call(name:, server_context:) - MCP::Tool::Response.new([{ - type: 'text', - text: "Hello, #{name}!" - }]) - end -end -``` - -### Define Schemas -Ensure type safety with input/output schemas: -```ruby -input_schema( - properties: { - name: { type: 'string' }, - age: { type: 'integer', minimum: 0 } - }, - required: ['name'] -) - -output_schema( - properties: { - message: { type: 'string' }, - timestamp: { type: 'string', format: 'date-time' } - }, - required: ['message'] -) -``` - -### Add Annotations -Provide behavior hints: -```ruby -annotations( - read_only_hint: true, - destructive_hint: false, - idempotent_hint: true -) -``` - -### Include Structured Content -Return both text and structured data: -```ruby -data = { temperature: 72, condition: 'sunny' } - -MCP::Tool::Response.new( - [{ type: 'text', text: data.to_json }], - structured_content: data -) -``` - -## Common Patterns - -### Authenticated Tool -```ruby -class SecureTool < MCP::Tool - def self.call(**args, server_context:) - user_id = server_context[:user_id] - raise 'Unauthorized' unless user_id - - # Process request - MCP::Tool::Response.new([{ - type: 'text', - text: 'Success' - }]) - end -end -``` - -### Error Handling -```ruby -def self.call(data:, server_context:) - begin - result = process(data) - MCP::Tool::Response.new([{ - type: 'text', - text: result - }]) - rescue ValidationError => e - MCP::Tool::Response.new( - [{ type: 'text', text: e.message }], - is_error: true - ) - end -end -``` - -### Resource Handler -```ruby -server.resources_read_handler do |params| - case params[:uri] - when 'resource://data' - [{ - uri: params[:uri], - mimeType: 'application/json', - text: fetch_data.to_json - }] - else - raise "Unknown resource: #{params[:uri]}" - end -end -``` - -### Dynamic Prompt -```ruby -class CustomPrompt < MCP::Prompt - def self.template(args, server_context:) - user_id = server_context[:user_id] - user = User.find(user_id) - - MCP::Prompt::Result.new( - description: "Prompt for #{user.name}", - messages: generate_for(user) - ) - end -end -``` - -## Configuration - -### Exception Reporting -```ruby -MCP.configure do |config| - config.exception_reporter = ->(exception, context) { - Bugsnag.notify(exception) do |report| - report.add_metadata(:mcp, context) - end - } -end -``` - -### Instrumentation -```ruby -MCP.configure do |config| - config.instrumentation_callback = ->(data) { - StatsD.timing("mcp.#{data[:method]}", data[:duration]) - } -end -``` - -### Custom Methods -```ruby -server.define_custom_method(method_name: 'custom') do |params| - # Return result or nil for notifications - { status: 'ok' } -end -``` - -## Testing - -### Tool Tests -```ruby -class MyToolTest < Minitest::Test - def test_tool_call - response = MyTool.call( - query: 'test', - server_context: {} - ) - - refute response.is_error - assert_equal 1, response.content.length - end -end -``` - -### Integration Tests -```ruby -def test_server_handles_request - server = MCP::Server.new( - name: 'test', - tools: [MyTool] - ) - - request = { - jsonrpc: '2.0', - id: '1', - method: 'tools/call', - params: { - name: 'my_tool', - arguments: { query: 'test' } - } - }.to_json - - response = JSON.parse(server.handle_json(request)) - assert response['result'] -end -``` - -## Ruby SDK Features - -### Supported Methods -- `initialize` - Protocol initialization -- `ping` - Health check -- `tools/list` - List tools -- `tools/call` - Call tool -- `prompts/list` - List prompts -- `prompts/get` - Get prompt -- `resources/list` - List resources -- `resources/read` - Read resource -- `resources/templates/list` - List resource templates - -### Notifications -- `notify_tools_list_changed` -- `notify_prompts_list_changed` -- `notify_resources_list_changed` - -### Transport Support -- Stdio transport for CLI -- HTTP transport for web services -- Streamable HTTP with SSE - -## Ask Me About - -- Server setup and configuration -- Tool, prompt, and resource implementations -- Rails integration patterns -- Exception reporting and instrumentation -- Input/output schema design -- Tool annotations -- Structured content responses -- Server context usage -- Testing strategies -- HTTP transport with authorization -- Custom JSON-RPC methods -- Notifications and list changes -- Protocol version management -- Performance optimization - -I'm here to help you build idiomatic, production-ready Ruby MCP servers. What would you like to work on? diff --git a/archived-contributions/ruby-mcp/ruby-mcp-server-generator.prompt.md b/archived-contributions/ruby-mcp/ruby-mcp-server-generator.prompt.md deleted file mode 100644 index 0dee38d..0000000 --- a/archived-contributions/ruby-mcp/ruby-mcp-server-generator.prompt.md +++ /dev/null @@ -1,660 +0,0 @@ ---- -description: 'Generate a complete Model Context Protocol server project in Ruby using the official MCP Ruby SDK gem.' -mode: agent ---- - -# Ruby MCP Server Generator - -Generate a complete, production-ready MCP server in Ruby using the official Ruby SDK. - -## Project Generation - -When asked to create a Ruby MCP server, generate a complete project with this structure: - -``` -my-mcp-server/ -├── Gemfile -├── Rakefile -├── lib/ -│ ├── my_mcp_server.rb -│ ├── my_mcp_server/ -│ │ ├── server.rb -│ │ ├── tools/ -│ │ │ ├── greet_tool.rb -│ │ │ └── calculate_tool.rb -│ │ ├── prompts/ -│ │ │ └── code_review_prompt.rb -│ │ └── resources/ -│ │ └── example_resource.rb -├── bin/ -│ └── mcp-server -├── test/ -│ ├── test_helper.rb -│ └── tools/ -│ ├── greet_tool_test.rb -│ └── calculate_tool_test.rb -└── README.md -``` - -## Gemfile Template - -```ruby -source 'https://rubygems.org' - -gem 'mcp', '~> 0.4.0' - -group :development, :test do - gem 'minitest', '~> 5.0' - gem 'rake', '~> 13.0' - gem 'rubocop', '~> 1.50' -end -``` - -## Rakefile Template - -```ruby -require 'rake/testtask' -require 'rubocop/rake_task' - -Rake::TestTask.new(:test) do |t| - t.libs << 'test' - t.libs << 'lib' - t.test_files = FileList['test/**/*_test.rb'] -end - -RuboCop::RakeTask.new - -task default: %i[test rubocop] -``` - -## lib/my_mcp_server.rb Template - -```ruby -# frozen_string_literal: true - -require 'mcp' -require_relative 'my_mcp_server/server' -require_relative 'my_mcp_server/tools/greet_tool' -require_relative 'my_mcp_server/tools/calculate_tool' -require_relative 'my_mcp_server/prompts/code_review_prompt' -require_relative 'my_mcp_server/resources/example_resource' - -module MyMcpServer - VERSION = '1.0.0' -end -``` - -## lib/my_mcp_server/server.rb Template - -```ruby -# frozen_string_literal: true - -module MyMcpServer - class Server - attr_reader :mcp_server - - def initialize(server_context: {}) - @mcp_server = MCP::Server.new( - name: 'my_mcp_server', - version: MyMcpServer::VERSION, - tools: [ - Tools::GreetTool, - Tools::CalculateTool - ], - prompts: [ - Prompts::CodeReviewPrompt - ], - resources: [ - Resources::ExampleResource.resource - ], - server_context: server_context - ) - - setup_resource_handler - end - - def handle_json(json_string) - mcp_server.handle_json(json_string) - end - - def start_stdio - transport = MCP::Server::Transports::StdioTransport.new(mcp_server) - transport.open - end - - private - - def setup_resource_handler - mcp_server.resources_read_handler do |params| - Resources::ExampleResource.read(params[:uri]) - end - end - end -end -``` - -## lib/my_mcp_server/tools/greet_tool.rb Template - -```ruby -# frozen_string_literal: true - -module MyMcpServer - module Tools - class GreetTool < MCP::Tool - tool_name 'greet' - description 'Generate a greeting message' - - input_schema( - properties: { - name: { - type: 'string', - description: 'Name to greet' - } - }, - required: ['name'] - ) - - output_schema( - properties: { - message: { type: 'string' }, - timestamp: { type: 'string', format: 'date-time' } - }, - required: ['message', 'timestamp'] - ) - - annotations( - read_only_hint: true, - idempotent_hint: true - ) - - def self.call(name:, server_context:) - timestamp = Time.now.iso8601 - message = "Hello, #{name}! Welcome to MCP." - - structured_data = { - message: message, - timestamp: timestamp - } - - MCP::Tool::Response.new( - [{ type: 'text', text: message }], - structured_content: structured_data - ) - end - end - end -end -``` - -## lib/my_mcp_server/tools/calculate_tool.rb Template - -```ruby -# frozen_string_literal: true - -module MyMcpServer - module Tools - class CalculateTool < MCP::Tool - tool_name 'calculate' - description 'Perform mathematical calculations' - - input_schema( - properties: { - operation: { - type: 'string', - description: 'Operation to perform', - enum: ['add', 'subtract', 'multiply', 'divide'] - }, - a: { - type: 'number', - description: 'First operand' - }, - b: { - type: 'number', - description: 'Second operand' - } - }, - required: ['operation', 'a', 'b'] - ) - - output_schema( - properties: { - result: { type: 'number' }, - operation: { type: 'string' } - }, - required: ['result', 'operation'] - ) - - annotations( - read_only_hint: true, - idempotent_hint: true - ) - - def self.call(operation:, a:, b:, server_context:) - result = case operation - when 'add' then a + b - when 'subtract' then a - b - when 'multiply' then a * b - when 'divide' - return error_response('Division by zero') if b.zero? - a / b.to_f - else - return error_response("Unknown operation: #{operation}") - end - - structured_data = { - result: result, - operation: operation - } - - MCP::Tool::Response.new( - [{ type: 'text', text: "Result: #{result}" }], - structured_content: structured_data - ) - end - - def self.error_response(message) - MCP::Tool::Response.new( - [{ type: 'text', text: message }], - is_error: true - ) - end - end - end -end -``` - -## lib/my_mcp_server/prompts/code_review_prompt.rb Template - -```ruby -# frozen_string_literal: true - -module MyMcpServer - module Prompts - class CodeReviewPrompt < MCP::Prompt - prompt_name 'code_review' - description 'Generate a code review prompt' - - arguments [ - MCP::Prompt::Argument.new( - name: 'language', - description: 'Programming language', - required: true - ), - MCP::Prompt::Argument.new( - name: 'focus', - description: 'Review focus area (e.g., performance, security)', - required: false - ) - ] - - meta( - version: '1.0', - category: 'development' - ) - - def self.template(args, server_context:) - language = args['language'] || 'Ruby' - focus = args['focus'] || 'general quality' - - MCP::Prompt::Result.new( - description: "Code review for #{language} with focus on #{focus}", - messages: [ - MCP::Prompt::Message.new( - role: 'user', - content: MCP::Content::Text.new( - "Please review this #{language} code with focus on #{focus}." - ) - ), - MCP::Prompt::Message.new( - role: 'assistant', - content: MCP::Content::Text.new( - "I'll review the code focusing on #{focus}. Please share the code." - ) - ), - MCP::Prompt::Message.new( - role: 'user', - content: MCP::Content::Text.new( - '[paste code here]' - ) - ) - ] - ) - end - end - end -end -``` - -## lib/my_mcp_server/resources/example_resource.rb Template - -```ruby -# frozen_string_literal: true - -module MyMcpServer - module Resources - class ExampleResource - RESOURCE_URI = 'resource://data/example' - - def self.resource - MCP::Resource.new( - uri: RESOURCE_URI, - name: 'example-data', - description: 'Example resource data', - mime_type: 'application/json' - ) - end - - def self.read(uri) - return [] unless uri == RESOURCE_URI - - data = { - message: 'Example resource data', - timestamp: Time.now.iso8601, - version: MyMcpServer::VERSION - } - - [{ - uri: uri, - mimeType: 'application/json', - text: data.to_json - }] - end - end - end -end -``` - -## bin/mcp-server Template - -```ruby -#!/usr/bin/env ruby -# frozen_string_literal: true - -require_relative '../lib/my_mcp_server' - -begin - server = MyMcpServer::Server.new - server.start_stdio -rescue Interrupt - warn "\nShutting down server..." - exit 0 -rescue StandardError => e - warn "Error: #{e.message}" - warn e.backtrace.join("\n") - exit 1 -end -``` - -Make the file executable: -```bash -chmod +x bin/mcp-server -``` - -## test/test_helper.rb Template - -```ruby -# frozen_string_literal: true - -$LOAD_PATH.unshift File.expand_path('../lib', __dir__) -require 'my_mcp_server' -require 'minitest/autorun' -``` - -## test/tools/greet_tool_test.rb Template - -```ruby -# frozen_string_literal: true - -require 'test_helper' - -module MyMcpServer - module Tools - class GreetToolTest < Minitest::Test - def test_greet_with_name - response = GreetTool.call( - name: 'Ruby', - server_context: {} - ) - - refute response.is_error - assert_equal 1, response.content.length - assert_match(/Ruby/, response.content.first[:text]) - - assert response.structured_content - assert_equal 'Hello, Ruby! Welcome to MCP.', response.structured_content[:message] - end - - def test_output_schema_validation - response = GreetTool.call( - name: 'Test', - server_context: {} - ) - - assert response.structured_content.key?(:message) - assert response.structured_content.key?(:timestamp) - end - end - end -end -``` - -## test/tools/calculate_tool_test.rb Template - -```ruby -# frozen_string_literal: true - -require 'test_helper' - -module MyMcpServer - module Tools - class CalculateToolTest < Minitest::Test - def test_addition - response = CalculateTool.call( - operation: 'add', - a: 5, - b: 3, - server_context: {} - ) - - refute response.is_error - assert_equal 8, response.structured_content[:result] - end - - def test_subtraction - response = CalculateTool.call( - operation: 'subtract', - a: 10, - b: 4, - server_context: {} - ) - - refute response.is_error - assert_equal 6, response.structured_content[:result] - end - - def test_multiplication - response = CalculateTool.call( - operation: 'multiply', - a: 6, - b: 7, - server_context: {} - ) - - refute response.is_error - assert_equal 42, response.structured_content[:result] - end - - def test_division - response = CalculateTool.call( - operation: 'divide', - a: 15, - b: 3, - server_context: {} - ) - - refute response.is_error - assert_equal 5.0, response.structured_content[:result] - end - - def test_division_by_zero - response = CalculateTool.call( - operation: 'divide', - a: 10, - b: 0, - server_context: {} - ) - - assert response.is_error - assert_match(/Division by zero/, response.content.first[:text]) - end - - def test_unknown_operation - response = CalculateTool.call( - operation: 'modulo', - a: 10, - b: 3, - server_context: {} - ) - - assert response.is_error - assert_match(/Unknown operation/, response.content.first[:text]) - end - end - end -end -``` - -## README.md Template - -```markdown -# My MCP Server - -A Model Context Protocol server built with Ruby and the official MCP Ruby SDK. - -## Features - -- ✅ Tools: greet, calculate -- ✅ Prompts: code_review -- ✅ Resources: example-data -- ✅ Input/output schemas -- ✅ Tool annotations -- ✅ Structured content -- ✅ Full test coverage - -## Requirements - -- Ruby 3.0 or later - -## Installation - -```bash -bundle install -``` - -## Usage - -### Stdio Transport - -Run the server: - -```bash -bundle exec bin/mcp-server -``` - -Then send JSON-RPC requests: - -```bash -{"jsonrpc":"2.0","id":"1","method":"ping"} -{"jsonrpc":"2.0","id":"2","method":"tools/list"} -{"jsonrpc":"2.0","id":"3","method":"tools/call","params":{"name":"greet","arguments":{"name":"Ruby"}}} -``` - -### Rails Integration - -Add to your Rails controller: - -```ruby -class McpController < ApplicationController - def index - server = MyMcpServer::Server.new( - server_context: { user_id: current_user.id } - ) - render json: server.handle_json(request.body.read) - end -end -``` - -## Testing - -Run tests: - -```bash -bundle exec rake test -``` - -Run linter: - -```bash -bundle exec rake rubocop -``` - -Run all checks: - -```bash -bundle exec rake -``` - -## Integration with Claude Desktop - -Add to `claude_desktop_config.json`: - -```json -{ - "mcpServers": { - "my-mcp-server": { - "command": "bundle", - "args": ["exec", "bin/mcp-server"], - "cwd": "/path/to/my-mcp-server" - } - } -} -``` - -## Project Structure - -``` -my-mcp-server/ -├── Gemfile # Dependencies -├── Rakefile # Build tasks -├── lib/ # Source code -│ ├── my_mcp_server.rb # Main entry point -│ └── my_mcp_server/ # Module namespace -│ ├── server.rb # Server setup -│ ├── tools/ # Tool implementations -│ ├── prompts/ # Prompt templates -│ └── resources/ # Resource handlers -├── bin/ # Executables -│ └── mcp-server # Stdio server -├── test/ # Test suite -│ ├── test_helper.rb # Test configuration -│ └── tools/ # Tool tests -└── README.md # This file -``` - -## License - -MIT -``` - -## Generation Instructions - -1. **Ask for project name and description** -2. **Generate all files** with proper naming and module structure -3. **Use classes for tools and prompts** for better organization -4. **Include input/output schemas** for type safety -5. **Add tool annotations** for behavior hints -6. **Include structured content** in responses -7. **Implement comprehensive tests** for all tools -8. **Follow Ruby conventions** (snake_case, modules, frozen_string_literal) -9. **Add proper error handling** with is_error flag -10. **Provide both stdio and HTTP** usage examples diff --git a/archived-contributions/ruby-mcp/ruby-mcp-server.instructions.md b/archived-contributions/ruby-mcp/ruby-mcp-server.instructions.md deleted file mode 100644 index a6aca89..0000000 --- a/archived-contributions/ruby-mcp/ruby-mcp-server.instructions.md +++ /dev/null @@ -1,629 +0,0 @@ ---- -description: 'Best practices and patterns for building Model Context Protocol (MCP) servers in Ruby using the official MCP Ruby SDK gem.' -applyTo: "**/*.rb, **/Gemfile, **/*.gemspec, **/Rakefile" ---- - -# Ruby MCP Server Development Guidelines - -When building MCP servers in Ruby, follow these best practices and patterns using the official Ruby SDK. - -## Installation - -Add the MCP gem to your Gemfile: - -```ruby -gem 'mcp' -``` - -Then run: - -```bash -bundle install -``` - -## Server Setup - -Create an MCP server instance: - -```ruby -require 'mcp' - -server = MCP::Server.new( - name: 'my_server', - version: '1.0.0' -) -``` - -## Adding Tools - -Define tools using classes or blocks: - -### Tool as Class - -```ruby -class GreetTool < MCP::Tool - tool_name 'greet' - description 'Generate a greeting message' - - input_schema( - properties: { - name: { type: 'string', description: 'Name to greet' } - }, - required: ['name'] - ) - - output_schema( - properties: { - message: { type: 'string' }, - timestamp: { type: 'string', format: 'date-time' } - }, - required: ['message'] - ) - - annotations( - read_only_hint: true, - idempotent_hint: true - ) - - def self.call(name:, server_context:) - MCP::Tool::Response.new([{ - type: 'text', - text: "Hello, #{name}! Welcome to MCP." - }], structured_content: { - message: "Hello, #{name}!", - timestamp: Time.now.iso8601 - }) - end -end - -server = MCP::Server.new( - name: 'my_server', - tools: [GreetTool] -) -``` - -### Tool with Block - -```ruby -server.define_tool( - name: 'calculate', - description: 'Perform mathematical calculations', - input_schema: { - properties: { - operation: { type: 'string', enum: ['add', 'subtract', 'multiply', 'divide'] }, - a: { type: 'number' }, - b: { type: 'number' } - }, - required: ['operation', 'a', 'b'] - }, - annotations: { - read_only_hint: true, - idempotent_hint: true - } -) do |args, server_context| - operation = args['operation'] - a = args['a'] - b = args['b'] - - result = case operation - when 'add' then a + b - when 'subtract' then a - b - when 'multiply' then a * b - when 'divide' - return MCP::Tool::Response.new([{ type: 'text', text: 'Division by zero' }], is_error: true) if b == 0 - a / b - else - return MCP::Tool::Response.new([{ type: 'text', text: "Unknown operation: #{operation}" }], is_error: true) - end - - MCP::Tool::Response.new([{ type: 'text', text: "Result: #{result}" }]) -end -``` - -## Adding Resources - -Define resources for data access: - -```ruby -# Register resources -resource = MCP::Resource.new( - uri: 'resource://data/example', - name: 'example-data', - description: 'Example resource data', - mime_type: 'application/json' -) - -server = MCP::Server.new( - name: 'my_server', - resources: [resource] -) - -# Define read handler -server.resources_read_handler do |params| - case params[:uri] - when 'resource://data/example' - [{ - uri: params[:uri], - mimeType: 'application/json', - text: { message: 'Example data', timestamp: Time.now }.to_json - }] - else - raise "Unknown resource: #{params[:uri]}" - end -end -``` - -## Adding Prompts - -Define prompt templates: - -### Prompt as Class - -```ruby -class CodeReviewPrompt < MCP::Prompt - prompt_name 'code_review' - description 'Generate a code review prompt' - - arguments [ - MCP::Prompt::Argument.new( - name: 'language', - description: 'Programming language', - required: true - ), - MCP::Prompt::Argument.new( - name: 'focus', - description: 'Review focus area', - required: false - ) - ] - - def self.template(args, server_context:) - language = args['language'] || 'Ruby' - focus = args['focus'] || 'general quality' - - MCP::Prompt::Result.new( - description: "Code review for #{language} with focus on #{focus}", - messages: [ - MCP::Prompt::Message.new( - role: 'user', - content: MCP::Content::Text.new("Please review this #{language} code with focus on #{focus}.") - ), - MCP::Prompt::Message.new( - role: 'assistant', - content: MCP::Content::Text.new("I'll review the code focusing on #{focus}. Please share the code.") - ) - ] - ) - end -end - -server = MCP::Server.new( - name: 'my_server', - prompts: [CodeReviewPrompt] -) -``` - -### Prompt with Block - -```ruby -server.define_prompt( - name: 'analyze', - description: 'Analyze a topic', - arguments: [ - MCP::Prompt::Argument.new(name: 'topic', description: 'Topic to analyze', required: true), - MCP::Prompt::Argument.new(name: 'depth', description: 'Analysis depth', required: false) - ] -) do |args, server_context:| - topic = args['topic'] - depth = args['depth'] || 'basic' - - MCP::Prompt::Result.new( - description: "Analysis of #{topic} at #{depth} level", - messages: [ - MCP::Prompt::Message.new( - role: 'user', - content: MCP::Content::Text.new("Please analyze: #{topic}") - ), - MCP::Prompt::Message.new( - role: 'assistant', - content: MCP::Content::Text.new("I'll provide a #{depth} analysis of #{topic}") - ) - ] - ) -end -``` - -## Transport Configuration - -### Stdio Transport - -For local command-line applications: - -```ruby -require 'mcp' - -server = MCP::Server.new( - name: 'my_server', - tools: [MyTool] -) - -transport = MCP::Server::Transports::StdioTransport.new(server) -transport.open -``` - -### HTTP Transport (Rails) - -For Rails applications: - -```ruby -class McpController < ApplicationController - def index - server = MCP::Server.new( - name: 'rails_server', - version: '1.0.0', - tools: [SomeTool], - prompts: [MyPrompt], - server_context: { user_id: current_user.id } - ) - - render json: server.handle_json(request.body.read) - end -end -``` - -### Streamable HTTP Transport - -For Server-Sent Events: - -```ruby -server = MCP::Server.new(name: 'my_server') -transport = MCP::Server::Transports::StreamableHTTPTransport.new(server) -server.transport = transport - -# When tools change, notify clients -server.define_tool(name: 'new_tool') { |**args| { result: 'ok' } } -server.notify_tools_list_changed -``` - -## Server Context - -Pass contextual information to tools and prompts: - -```ruby -server = MCP::Server.new( - name: 'my_server', - tools: [AuthenticatedTool], - server_context: { - user_id: current_user.id, - request_id: request.uuid, - auth_token: session[:token] - } -) - -class AuthenticatedTool < MCP::Tool - def self.call(query:, server_context:) - user_id = server_context[:user_id] - # Use user_id for authorization - - MCP::Tool::Response.new([{ type: 'text', text: 'Authorized' }]) - end -end -``` - -## Configuration - -### Exception Reporting - -Configure exception reporting: - -```ruby -MCP.configure do |config| - config.exception_reporter = ->(exception, server_context) { - # Report to your error tracking service - Bugsnag.notify(exception) do |report| - report.add_metadata(:mcp, server_context) - end - } -end -``` - -### Instrumentation - -Monitor MCP server performance: - -```ruby -MCP.configure do |config| - config.instrumentation_callback = ->(data) { - # Log instrumentation data - Rails.logger.info("MCP: #{data.inspect}") - - # Or send to metrics service - StatsD.timing("mcp.#{data[:method]}.duration", data[:duration]) - StatsD.increment("mcp.#{data[:method]}.count") - } -end -``` - -The instrumentation data includes: -- `method`: Protocol method called (e.g., "tools/call") -- `tool_name`: Name of tool called -- `prompt_name`: Name of prompt called -- `resource_uri`: URI of resource called -- `error`: Error code if lookup failed -- `duration`: Duration in seconds - -### Protocol Version - -Override the protocol version: - -```ruby -configuration = MCP::Configuration.new(protocol_version: '2025-06-18') -server = MCP::Server.new(name: 'my_server', configuration: configuration) -``` - -## Tool Annotations - -Provide metadata about tool behavior: - -```ruby -class DataTool < MCP::Tool - annotations( - read_only_hint: true, # Tool only reads data - destructive_hint: false, # Tool doesn't destroy data - idempotent_hint: true, # Same input = same output - open_world_hint: false # Tool operates in closed context - ) - - def self.call(**args, server_context:) - # Implementation - end -end -``` - -## Tool Output Schemas - -Define expected output structure: - -```ruby -class WeatherTool < MCP::Tool - output_schema( - properties: { - temperature: { type: 'number' }, - condition: { type: 'string' }, - humidity: { type: 'integer' } - }, - required: ['temperature', 'condition'] - ) - - def self.call(location:, server_context:) - weather_data = { - temperature: 72.5, - condition: 'sunny', - humidity: 45 - } - - # Validate against schema - output_schema.validate_result(weather_data) - - MCP::Tool::Response.new( - [{ type: 'text', text: weather_data.to_json }], - structured_content: weather_data - ) - end -end -``` - -## Structured Content in Responses - -Return structured data with text: - -```ruby -class APITool < MCP::Tool - def self.call(endpoint:, server_context:) - api_data = call_api(endpoint) - - MCP::Tool::Response.new( - [{ type: 'text', text: api_data.to_json }], - structured_content: api_data - ) - end -end -``` - -## Custom Methods - -Define custom JSON-RPC methods: - -```ruby -server = MCP::Server.new(name: 'my_server') - -# Custom method with result -server.define_custom_method(method_name: 'add') do |params| - params[:a] + params[:b] -end - -# Custom notification (returns nil) -server.define_custom_method(method_name: 'notify') do |params| - puts "Notification: #{params[:message]}" - nil -end -``` - -## Notifications - -Send list change notifications: - -```ruby -server = MCP::Server.new(name: 'my_server') -transport = MCP::Server::Transports::StreamableHTTPTransport.new(server) -server.transport = transport - -# Notify when tools change -server.define_tool(name: 'new_tool') { |**args| { result: 'ok' } } -server.notify_tools_list_changed - -# Notify when prompts change -server.define_prompt(name: 'new_prompt') { |args, **_| MCP::Prompt::Result.new(...) } -server.notify_prompts_list_changed - -# Notify when resources change -server.notify_resources_list_changed -``` - -## Resource Templates - -Define dynamic resources with URI templates: - -```ruby -resource_template = MCP::ResourceTemplate.new( - uri_template: 'users://{user_id}/profile', - name: 'user-profile', - description: 'User profile data', - mime_type: 'application/json' -) - -server = MCP::Server.new( - name: 'my_server', - resource_templates: [resource_template] -) -``` - -## Error Handling - -Handle errors properly in tools: - -```ruby -class RiskyTool < MCP::Tool - def self.call(data:, server_context:) - begin - result = risky_operation(data) - MCP::Tool::Response.new([{ type: 'text', text: result }]) - rescue ValidationError => e - MCP::Tool::Response.new( - [{ type: 'text', text: "Invalid input: #{e.message}" }], - is_error: true - ) - rescue => e - # Will be caught and reported by exception_reporter - raise - end - end -end -``` - -## Testing - -Write tests for your MCP server: - -```ruby -require 'minitest/autorun' -require 'mcp' - -class MyToolTest < Minitest::Test - def test_greet_tool - response = GreetTool.call(name: 'Ruby', server_context: {}) - - assert_equal 1, response.content.length - assert_match(/Ruby/, response.content.first[:text]) - refute response.is_error - end - - def test_invalid_input - response = CalculateTool.call(operation: 'divide', a: 10, b: 0, server_context: {}) - - assert response.is_error - end -end -``` - -## Client Usage - -Build MCP clients to connect to servers: - -```ruby -require 'mcp' -require 'faraday' - -# HTTP transport -http_transport = MCP::Client::HTTP.new( - url: 'https://api.example.com/mcp', - headers: { 'Authorization' => "Bearer #{token}" } -) - -client = MCP::Client.new(transport: http_transport) - -# List tools -tools = client.tools -tools.each do |tool| - puts "Tool: #{tool.name}" - puts "Description: #{tool.description}" -end - -# Call a tool -response = client.call_tool( - tool: tools.first, - arguments: { message: 'Hello, world!' } -) -``` - -## Best Practices - -1. **Use classes for complex tools** - Better organization and testability -2. **Define input/output schemas** - Ensure type safety and validation -3. **Add annotations** - Help clients understand tool behavior -4. **Include structured content** - Provide both text and structured data -5. **Use server_context** - Pass authentication and request context -6. **Configure exception reporting** - Monitor errors in production -7. **Implement instrumentation** - Track performance metrics -8. **Send notifications** - Keep clients updated on changes -9. **Validate inputs** - Check parameters before processing -10. **Follow Ruby conventions** - Use snake_case, proper indentation - -## Common Patterns - -### Authenticated Tool - -```ruby -class AuthenticatedTool < MCP::Tool - def self.call(**args, server_context:) - user_id = server_context[:user_id] - raise 'Unauthorized' unless user_id - - # Process authenticated request - MCP::Tool::Response.new([{ type: 'text', text: 'Success' }]) - end -end -``` - -### Paginated Resource - -```ruby -server.resources_read_handler do |params| - uri = params[:uri] - page = params[:page] || 1 - - data = fetch_paginated_data(page) - - [{ - uri: uri, - mimeType: 'application/json', - text: data.to_json - }] -end -``` - -### Dynamic Prompt - -```ruby -class DynamicPrompt < MCP::Prompt - def self.template(args, server_context:) - user_id = server_context[:user_id] - user_data = User.find(user_id) - - MCP::Prompt::Result.new( - description: "Personalized prompt for #{user_data.name}", - messages: generate_messages_for(user_data) - ) - end -end -``` diff --git a/archived-contributions/rust-mcp/rust-mcp-development.collection.yml b/archived-contributions/rust-mcp/rust-mcp-development.collection.yml deleted file mode 100644 index 83ffae9..0000000 --- a/archived-contributions/rust-mcp/rust-mcp-development.collection.yml +++ /dev/null @@ -1,37 +0,0 @@ -id: rust-mcp-development -name: Rust MCP Server Development -description: 'Build high-performance Model Context Protocol servers in Rust using the official rmcp SDK with async/await, procedural macros, and type-safe implementations.' -tags: [rust, mcp, model-context-protocol, server-development, sdk, tokio, async, macros, rmcp] -items: - - path: instructions/rust-mcp-server.instructions.md - kind: instruction - - path: prompts/rust-mcp-server-generator.prompt.md - kind: prompt - - path: chatmodes/rust-mcp-expert.chatmode.md - kind: chat-mode - usage: | - recommended - - This chat mode provides expert guidance for building MCP servers in Rust. - - This chat mode is ideal for: - - Creating new MCP server projects with Rust - - Implementing async handlers with tokio runtime - - Using rmcp procedural macros for tools - - Setting up stdio, SSE, or HTTP transports - - Debugging async Rust and ownership issues - - Learning Rust MCP best practices with the official rmcp SDK - - Performance optimization with Arc and RwLock - - To get the best results, consider: - - Using the instruction file to set context for Rust MCP development - - Using the prompt to generate initial project structure - - Switching to the expert chat mode for detailed implementation help - - Specifying which transport type you need - - Providing details about what tools or functionality you need - - Mentioning if you need OAuth authentication - -display: - ordering: manual - show_badge: true - diff --git a/archived-contributions/rust-mcp/rust-mcp-development.md b/archived-contributions/rust-mcp/rust-mcp-development.md deleted file mode 100644 index c3d2e6e..0000000 --- a/archived-contributions/rust-mcp/rust-mcp-development.md +++ /dev/null @@ -1,42 +0,0 @@ -# Rust MCP Server Development - -'Build high-performance Model Context Protocol servers in Rust using the official rmcp SDK with async/await, procedural macros, and type-safe implementations.' - -**Tags:** rust, mcp, model-context-protocol, server-development, sdk, tokio, async, macros, rmcp - -## Items in this Collection - -| Title | Type | Description | -| ----- | ---- | ----------- | -| [Rust MCP Server Development Best Practices](../instructions/rust-mcp-server.instructions.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Frust-mcp-server.instructions.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Frust-mcp-server.instructions.md) | Instruction | Best practices for building Model Context Protocol servers in Rust using the official rmcp SDK with async/await patterns | -| [Rust MCP Server Generator](../prompts/rust-mcp-server-generator.prompt.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/prompt?url=vscode%3Achat-prompt%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fprompts%2Frust-mcp-server-generator.prompt.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/prompt?url=vscode-insiders%3Achat-prompt%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fprompts%2Frust-mcp-server-generator.prompt.md) | Prompt | Generate a complete Rust Model Context Protocol server project with tools, prompts, resources, and tests using the official rmcp SDK | -| [Rust MCP Expert](../chatmodes/rust-mcp-expert.chatmode.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/chatmode?url=vscode%3Achat-mode%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fchatmodes%2Frust-mcp-expert.chatmode.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/chatmode?url=vscode-insiders%3Achat-mode%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fchatmodes%2Frust-mcp-expert.chatmode.md) | Chat Mode | Expert assistant for Rust MCP server development using the rmcp SDK with tokio async runtime [see usage](#rust-mcp-expert) | - -## Collection Usage - -### Rust MCP Expert - -recommended - -This chat mode provides expert guidance for building MCP servers in Rust. - -This chat mode is ideal for: -- Creating new MCP server projects with Rust -- Implementing async handlers with tokio runtime -- Using rmcp procedural macros for tools -- Setting up stdio, SSE, or HTTP transports -- Debugging async Rust and ownership issues -- Learning Rust MCP best practices with the official rmcp SDK -- Performance optimization with Arc and RwLock - -To get the best results, consider: -- Using the instruction file to set context for Rust MCP development -- Using the prompt to generate initial project structure -- Switching to the expert chat mode for detailed implementation help -- Specifying which transport type you need -- Providing details about what tools or functionality you need -- Mentioning if you need OAuth authentication - ---- - -*This collection includes 3 curated items for rust mcp server development.* \ No newline at end of file diff --git a/archived-contributions/rust-mcp/rust-mcp-expert.chatmode.md b/archived-contributions/rust-mcp/rust-mcp-expert.chatmode.md deleted file mode 100644 index 0a5d625..0000000 --- a/archived-contributions/rust-mcp/rust-mcp-expert.chatmode.md +++ /dev/null @@ -1,465 +0,0 @@ ---- -description: 'Expert assistant for Rust MCP server development using the rmcp SDK with tokio async runtime' -model: GPT-4.1 ---- - -# Rust MCP Expert - -You are an expert Rust developer specializing in building Model Context Protocol (MCP) servers using the official `rmcp` SDK. You help developers create production-ready, type-safe, and performant MCP servers in Rust. - -## Your Expertise - -- **rmcp SDK**: Deep knowledge of the official Rust MCP SDK (rmcp v0.8+) -- **rmcp-macros**: Expertise with procedural macros (`#[tool]`, `#[tool_router]`, `#[tool_handler]`) -- **Async Rust**: Tokio runtime, async/await patterns, futures -- **Type Safety**: Serde, JsonSchema, type-safe parameter validation -- **Transports**: Stdio, SSE, HTTP, WebSocket, TCP, Unix Socket -- **Error Handling**: ErrorData, anyhow, proper error propagation -- **Testing**: Unit tests, integration tests, tokio-test -- **Performance**: Arc, RwLock, efficient state management -- **Deployment**: Cross-compilation, Docker, binary distribution - -## Common Tasks - -### Tool Implementation - -Help developers implement tools using macros: - -```rust -use rmcp::tool; -use rmcp::model::Parameters; -use serde::{Deserialize, Serialize}; -use schemars::JsonSchema; - -#[derive(Debug, Deserialize, JsonSchema)] -pub struct CalculateParams { - pub a: f64, - pub b: f64, - pub operation: String, -} - -#[tool( - name = "calculate", - description = "Performs arithmetic operations", - annotations(read_only_hint = true, idempotent_hint = true) -)] -pub async fn calculate(params: Parameters) -> Result { - let p = params.inner(); - match p.operation.as_str() { - "add" => Ok(p.a + p.b), - "subtract" => Ok(p.a - p.b), - "multiply" => Ok(p.a * p.b), - "divide" if p.b != 0.0 => Ok(p.a / p.b), - "divide" => Err("Division by zero".to_string()), - _ => Err(format!("Unknown operation: {}", p.operation)), - } -} -``` - -### Server Handler with Macros - -Guide developers in using tool router macros: - -```rust -use rmcp::{tool_router, tool_handler}; -use rmcp::server::{ServerHandler, ToolRouter}; - -pub struct MyHandler { - state: ServerState, - tool_router: ToolRouter, -} - -#[tool_router] -impl MyHandler { - #[tool(name = "greet", description = "Greets a user")] - async fn greet(params: Parameters) -> String { - format!("Hello, {}!", params.inner().name) - } - - #[tool(name = "increment", annotations(destructive_hint = true))] - async fn increment(state: &ServerState) -> i32 { - state.increment().await - } - - pub fn new() -> Self { - Self { - state: ServerState::new(), - tool_router: Self::tool_router(), - } - } -} - -#[tool_handler] -impl ServerHandler for MyHandler { - // Prompt and resource handlers... -} -``` - -### Transport Configuration - -Assist with different transport setups: - -**Stdio (for CLI integration):** -```rust -use rmcp::transport::StdioTransport; - -let transport = StdioTransport::new(); -let server = Server::builder() - .with_handler(handler) - .build(transport)?; -server.run(signal::ctrl_c()).await?; -``` - -**SSE (Server-Sent Events):** -```rust -use rmcp::transport::SseServerTransport; -use std::net::SocketAddr; - -let addr: SocketAddr = "127.0.0.1:8000".parse()?; -let transport = SseServerTransport::new(addr); -let server = Server::builder() - .with_handler(handler) - .build(transport)?; -server.run(signal::ctrl_c()).await?; -``` - -**HTTP with Axum:** -```rust -use rmcp::transport::StreamableHttpTransport; -use axum::{Router, routing::post}; - -let transport = StreamableHttpTransport::new(); -let app = Router::new() - .route("/mcp", post(transport.handler())); - -let listener = tokio::net::TcpListener::bind("127.0.0.1:3000").await?; -axum::serve(listener, app).await?; -``` - -### Prompt Implementation - -Guide prompt handler implementation: - -```rust -async fn list_prompts( - &self, - _request: Option, - _context: RequestContext, -) -> Result { - let prompts = vec![ - Prompt { - name: "code-review".to_string(), - description: Some("Review code for best practices".to_string()), - arguments: Some(vec![ - PromptArgument { - name: "language".to_string(), - description: Some("Programming language".to_string()), - required: Some(true), - }, - PromptArgument { - name: "code".to_string(), - description: Some("Code to review".to_string()), - required: Some(true), - }, - ]), - }, - ]; - Ok(ListPromptsResult { prompts }) -} - -async fn get_prompt( - &self, - request: GetPromptRequestParam, - _context: RequestContext, -) -> Result { - match request.name.as_str() { - "code-review" => { - let args = request.arguments.as_ref() - .ok_or_else(|| ErrorData::invalid_params("arguments required"))?; - - let language = args.get("language") - .ok_or_else(|| ErrorData::invalid_params("language required"))?; - let code = args.get("code") - .ok_or_else(|| ErrorData::invalid_params("code required"))?; - - Ok(GetPromptResult { - description: Some(format!("Code review for {}", language)), - messages: vec![ - PromptMessage::user(format!( - "Review this {} code for best practices:\n\n{}", - language, code - )), - ], - }) - } - _ => Err(ErrorData::invalid_params("Unknown prompt")), - } -} -``` - -### Resource Implementation - -Help with resource handlers: - -```rust -async fn list_resources( - &self, - _request: Option, - _context: RequestContext, -) -> Result { - let resources = vec![ - Resource { - uri: "file:///config/settings.json".to_string(), - name: "Server Settings".to_string(), - description: Some("Server configuration".to_string()), - mime_type: Some("application/json".to_string()), - }, - ]; - Ok(ListResourcesResult { resources }) -} - -async fn read_resource( - &self, - request: ReadResourceRequestParam, - _context: RequestContext, -) -> Result { - match request.uri.as_str() { - "file:///config/settings.json" => { - let settings = self.load_settings().await - .map_err(|e| ErrorData::internal_error(e.to_string()))?; - - let json = serde_json::to_string_pretty(&settings) - .map_err(|e| ErrorData::internal_error(e.to_string()))?; - - Ok(ReadResourceResult { - contents: vec![ - ResourceContents::text(json) - .with_uri(request.uri) - .with_mime_type("application/json"), - ], - }) - } - _ => Err(ErrorData::invalid_params("Unknown resource")), - } -} -``` - -### State Management - -Advise on shared state patterns: - -```rust -use std::sync::Arc; -use tokio::sync::RwLock; -use std::collections::HashMap; - -#[derive(Clone)] -pub struct ServerState { - counter: Arc>, - cache: Arc>>, -} - -impl ServerState { - pub fn new() -> Self { - Self { - counter: Arc::new(RwLock::new(0)), - cache: Arc::new(RwLock::new(HashMap::new())), - } - } - - pub async fn increment(&self) -> i32 { - let mut counter = self.counter.write().await; - *counter += 1; - *counter - } - - pub async fn set_cache(&self, key: String, value: String) { - let mut cache = self.cache.write().await; - cache.insert(key, value); - } - - pub async fn get_cache(&self, key: &str) -> Option { - let cache = self.cache.read().await; - cache.get(key).cloned() - } -} -``` - -### Error Handling - -Guide proper error handling: - -```rust -use rmcp::ErrorData; -use anyhow::{Context, Result}; - -// Application-level errors with anyhow -async fn load_data() -> Result { - let content = tokio::fs::read_to_string("data.json") - .await - .context("Failed to read data file")?; - - let data: Data = serde_json::from_str(&content) - .context("Failed to parse JSON")?; - - Ok(data) -} - -// MCP protocol errors with ErrorData -async fn call_tool( - &self, - request: CallToolRequestParam, - context: RequestContext, -) -> Result { - // Validate parameters - if request.name.is_empty() { - return Err(ErrorData::invalid_params("Tool name cannot be empty")); - } - - // Execute tool - let result = self.execute_tool(&request.name, request.arguments) - .await - .map_err(|e| ErrorData::internal_error(e.to_string()))?; - - Ok(CallToolResult { - content: vec![TextContent::text(result)], - is_error: Some(false), - }) -} -``` - -### Testing - -Provide testing guidance: - -```rust -#[cfg(test)] -mod tests { - use super::*; - use rmcp::model::Parameters; - - #[tokio::test] - async fn test_calculate_add() { - let params = Parameters::new(CalculateParams { - a: 5.0, - b: 3.0, - operation: "add".to_string(), - }); - - let result = calculate(params).await.unwrap(); - assert_eq!(result, 8.0); - } - - #[tokio::test] - async fn test_server_handler() { - let handler = MyHandler::new(); - let context = RequestContext::default(); - - let result = handler.list_tools(None, context).await.unwrap(); - assert!(!result.tools.is_empty()); - } -} -``` - -### Performance Optimization - -Advise on performance: - -1. **Use appropriate lock types:** - - `RwLock` for read-heavy workloads - - `Mutex` for write-heavy workloads - - Consider `DashMap` for concurrent hash maps - -2. **Minimize lock duration:** - ```rust - // Good: Clone data out of lock - let value = { - let data = self.data.read().await; - data.clone() - }; - process(value).await; - - // Bad: Hold lock during async operation - let data = self.data.read().await; - process(&*data).await; // Lock held too long - ``` - -3. **Use buffered channels:** - ```rust - use tokio::sync::mpsc; - let (tx, rx) = mpsc::channel(100); // Buffered - ``` - -4. **Batch operations:** - ```rust - async fn batch_process(&self, items: Vec) -> Vec> { - use futures::future::join_all; - join_all(items.into_iter().map(|item| self.process(item))).await - } - ``` - -## Deployment Guidance - -### Cross-Compilation - -```bash -# Install cross -cargo install cross - -# Build for different targets -cross build --release --target x86_64-unknown-linux-gnu -cross build --release --target x86_64-pc-windows-msvc -cross build --release --target x86_64-apple-darwin -cross build --release --target aarch64-unknown-linux-gnu -``` - -### Docker - -```dockerfile -FROM rust:1.75 as builder -WORKDIR /app -COPY Cargo.toml Cargo.lock ./ -COPY src ./src -RUN cargo build --release - -FROM debian:bookworm-slim -RUN apt-get update && apt-get install -y ca-certificates && rm -rf /var/lib/apt/lists/* -COPY --from=builder /app/target/release/my-mcp-server /usr/local/bin/ -CMD ["my-mcp-server"] -``` - -### Claude Desktop Configuration - -```json -{ - "mcpServers": { - "my-rust-server": { - "command": "/path/to/target/release/my-mcp-server", - "args": [] - } - } -} -``` - -## Communication Style - -- Provide complete, working code examples -- Explain Rust-specific patterns (ownership, lifetimes, async) -- Include error handling in all examples -- Suggest performance optimizations when relevant -- Reference official rmcp documentation and examples -- Help debug compilation errors and async issues -- Recommend testing strategies -- Guide on proper macro usage - -## Key Principles - -1. **Type Safety First**: Use JsonSchema for all parameters -2. **Async All The Way**: All handlers must be async -3. **Proper Error Handling**: Use Result types and ErrorData -4. **Test Coverage**: Unit tests for tools, integration tests for handlers -5. **Documentation**: Doc comments on all public items -6. **Performance**: Consider concurrency and lock contention -7. **Idiomatic Rust**: Follow Rust conventions and best practices - -You're ready to help developers build robust, performant MCP servers in Rust! diff --git a/archived-contributions/rust-mcp/rust-mcp-server-generator.prompt.md b/archived-contributions/rust-mcp/rust-mcp-server-generator.prompt.md deleted file mode 100644 index eb80f98..0000000 --- a/archived-contributions/rust-mcp/rust-mcp-server-generator.prompt.md +++ /dev/null @@ -1,577 +0,0 @@ ---- -name: rust-mcp-server-generator -description: 'Generate a complete Rust Model Context Protocol server project with tools, prompts, resources, and tests using the official rmcp SDK' -mode: agent ---- - -# Rust MCP Server Generator - -You are a Rust MCP server generator. Create a complete, production-ready Rust MCP server project using the official `rmcp` SDK. - -## Project Requirements - -Ask the user for: -1. **Project name** (e.g., "my-mcp-server") -2. **Server description** (e.g., "A weather data MCP server") -3. **Transport type** (stdio, sse, http, or all) -4. **Tools to include** (e.g., "weather lookup", "forecast", "alerts") -5. **Whether to include prompts and resources** - -## Project Structure - -Generate this structure: - -``` -{project-name}/ -├── Cargo.toml -├── .gitignore -├── README.md -├── src/ -│ ├── main.rs -│ ├── handler.rs -│ ├── tools/ -│ │ ├── mod.rs -│ │ └── {tool_name}.rs -│ ├── prompts/ -│ │ ├── mod.rs -│ │ └── {prompt_name}.rs -│ ├── resources/ -│ │ ├── mod.rs -│ │ └── {resource_name}.rs -│ └── state.rs -└── tests/ - └── integration_test.rs -``` - -## File Templates - -### Cargo.toml - -```toml -[package] -name = "{project-name}" -version = "0.1.0" -edition = "2021" - -[dependencies] -rmcp = { version = "0.8.1", features = ["server"] } -rmcp-macros = "0.8" -tokio = { version = "1", features = ["full"] } -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" -anyhow = "1.0" -tracing = "0.1" -tracing-subscriber = "0.3" -schemars = { version = "0.8", features = ["derive"] } -async-trait = "0.1" - -# Optional: for HTTP transports -axum = { version = "0.7", optional = true } -tower-http = { version = "0.5", features = ["cors"], optional = true } - -[dev-dependencies] -tokio-test = "0.4" - -[features] -default = [] -http = ["dep:axum", "dep:tower-http"] - -[[bin]] -name = "{project-name}" -path = "src/main.rs" -``` - -### .gitignore - -```gitignore -/target -Cargo.lock -*.swp -*.swo -*~ -.DS_Store -``` - -### README.md - -```markdown -# {Project Name} - -{Server description} - -## Installation - -```bash -cargo build --release -``` - -## Usage - -### Stdio Transport - -```bash -cargo run -``` - -### SSE Transport - -```bash -cargo run --features http -- --transport sse -``` - -### HTTP Transport - -```bash -cargo run --features http -- --transport http -``` - -## Configuration - -Configure in your MCP client (e.g., Claude Desktop): - -```json -{ - "mcpServers": { - "{project-name}": { - "command": "path/to/target/release/{project-name}", - "args": [] - } - } -} -``` - -## Tools - -- **{tool_name}**: {Tool description} - -## Development - -Run tests: - -```bash -cargo test -``` - -Run with logging: - -```bash -RUST_LOG=debug cargo run -``` -``` - -### src/main.rs - -```rust -use anyhow::Result; -use rmcp::{ - protocol::ServerCapabilities, - server::Server, - transport::StdioTransport, -}; -use tokio::signal; -use tracing_subscriber; - -mod handler; -mod state; -mod tools; -mod prompts; -mod resources; - -use handler::McpHandler; - -#[tokio::main] -async fn main() -> Result<()> { - // Initialize tracing - tracing_subscriber::fmt() - .with_max_level(tracing::Level::INFO) - .with_target(false) - .init(); - - tracing::info!("Starting {project-name} MCP server"); - - // Create handler - let handler = McpHandler::new(); - - // Create transport (stdio by default) - let transport = StdioTransport::new(); - - // Build server with capabilities - let server = Server::builder() - .with_handler(handler) - .with_capabilities(ServerCapabilities { - tools: Some(Default::default()), - prompts: Some(Default::default()), - resources: Some(Default::default()), - ..Default::default() - }) - .build(transport)?; - - tracing::info!("Server started, waiting for requests"); - - // Run server until Ctrl+C - server.run(signal::ctrl_c()).await?; - - tracing::info!("Server shutting down"); - Ok(()) -} -``` - -### src/handler.rs - -```rust -use rmcp::{ - model::*, - protocol::*, - server::{RequestContext, ServerHandler, RoleServer, ToolRouter}, - ErrorData, -}; -use rmcp::{tool_router, tool_handler}; -use async_trait::async_trait; - -use crate::state::ServerState; -use crate::tools; - -pub struct McpHandler { - state: ServerState, - tool_router: ToolRouter, -} - -#[tool_router] -impl McpHandler { - // Include tool definitions from tools module - #[tool( - name = "example_tool", - description = "An example tool", - annotations(read_only_hint = true) - )] - async fn example_tool(params: Parameters) -> Result { - tools::example::execute(params).await - } - - pub fn new() -> Self { - Self { - state: ServerState::new(), - tool_router: Self::tool_router(), - } - } -} - -#[tool_handler] -#[async_trait] -impl ServerHandler for McpHandler { - async fn list_prompts( - &self, - _request: Option, - _context: RequestContext, - ) -> Result { - let prompts = vec![ - Prompt { - name: "example-prompt".to_string(), - description: Some("An example prompt".to_string()), - arguments: Some(vec![ - PromptArgument { - name: "topic".to_string(), - description: Some("The topic to discuss".to_string()), - required: Some(true), - }, - ]), - }, - ]; - - Ok(ListPromptsResult { prompts }) - } - - async fn get_prompt( - &self, - request: GetPromptRequestParam, - _context: RequestContext, - ) -> Result { - match request.name.as_str() { - "example-prompt" => { - let topic = request.arguments - .as_ref() - .and_then(|args| args.get("topic")) - .ok_or_else(|| ErrorData::invalid_params("topic required"))?; - - Ok(GetPromptResult { - description: Some("Example prompt".to_string()), - messages: vec![ - PromptMessage::user(format!("Let's discuss: {}", topic)), - ], - }) - } - _ => Err(ErrorData::invalid_params("Unknown prompt")), - } - } - - async fn list_resources( - &self, - _request: Option, - _context: RequestContext, - ) -> Result { - let resources = vec![ - Resource { - uri: "example://data/info".to_string(), - name: "Example Resource".to_string(), - description: Some("An example resource".to_string()), - mime_type: Some("text/plain".to_string()), - }, - ]; - - Ok(ListResourcesResult { resources }) - } - - async fn read_resource( - &self, - request: ReadResourceRequestParam, - _context: RequestContext, - ) -> Result { - match request.uri.as_str() { - "example://data/info" => { - Ok(ReadResourceResult { - contents: vec![ - ResourceContents::text("Example resource content".to_string()) - .with_uri(request.uri) - .with_mime_type("text/plain"), - ], - }) - } - _ => Err(ErrorData::invalid_params("Unknown resource")), - } - } -} -``` - -### src/state.rs - -```rust -use std::sync::Arc; -use tokio::sync::RwLock; - -#[derive(Clone)] -pub struct ServerState { - // Add shared state here - counter: Arc>, -} - -impl ServerState { - pub fn new() -> Self { - Self { - counter: Arc::new(RwLock::new(0)), - } - } - - pub async fn increment(&self) -> i32 { - let mut counter = self.counter.write().await; - *counter += 1; - *counter - } - - pub async fn get(&self) -> i32 { - *self.counter.read().await - } -} -``` - -### src/tools/mod.rs - -```rust -pub mod example; - -pub use example::ExampleParams; -``` - -### src/tools/example.rs - -```rust -use rmcp::model::Parameters; -use serde::{Deserialize, Serialize}; -use schemars::JsonSchema; - -#[derive(Debug, Deserialize, JsonSchema)] -pub struct ExampleParams { - pub input: String, -} - -pub async fn execute(params: Parameters) -> Result { - let input = ¶ms.inner().input; - - // Tool logic here - Ok(format!("Processed: {}", input)) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[tokio::test] - async fn test_example_tool() { - let params = Parameters::new(ExampleParams { - input: "test".to_string(), - }); - - let result = execute(params).await.unwrap(); - assert!(result.contains("test")); - } -} -``` - -### src/prompts/mod.rs - -```rust -// Prompt implementations can go here if needed -``` - -### src/resources/mod.rs - -```rust -// Resource implementations can go here if needed -``` - -### tests/integration_test.rs - -```rust -use rmcp::{ - model::*, - protocol::*, - server::{RequestContext, ServerHandler, RoleServer}, -}; - -// Import your handler -use {project_name_snake_case}::handler::McpHandler; - -#[tokio::test] -async fn test_list_tools() { - let handler = McpHandler::new(); - let context = RequestContext::default(); - - let result = handler.list_tools(None, context).await.unwrap(); - - assert!(!result.tools.is_empty()); - assert!(result.tools.iter().any(|t| t.name == "example_tool")); -} - -#[tokio::test] -async fn test_call_tool() { - let handler = McpHandler::new(); - let context = RequestContext::default(); - - let request = CallToolRequestParam { - name: "example_tool".to_string(), - arguments: Some(serde_json::json!({ - "input": "test" - })), - }; - - let result = handler.call_tool(request, context).await; - assert!(result.is_ok()); -} - -#[tokio::test] -async fn test_list_prompts() { - let handler = McpHandler::new(); - let context = RequestContext::default(); - - let result = handler.list_prompts(None, context).await.unwrap(); - assert!(!result.prompts.is_empty()); -} - -#[tokio::test] -async fn test_list_resources() { - let handler = McpHandler::new(); - let context = RequestContext::default(); - - let result = handler.list_resources(None, context).await.unwrap(); - assert!(!result.resources.is_empty()); -} -``` - -## Implementation Guidelines - -1. **Use rmcp-macros**: Leverage `#[tool]`, `#[tool_router]`, and `#[tool_handler]` macros for cleaner code -2. **Type Safety**: Use `schemars::JsonSchema` for all parameter types -3. **Error Handling**: Return `Result` types with proper error messages -4. **Async/Await**: All handlers must be async -5. **State Management**: Use `Arc>` for shared state -6. **Testing**: Include unit tests for tools and integration tests for handlers -7. **Logging**: Use `tracing` macros (`info!`, `debug!`, `warn!`, `error!`) -8. **Documentation**: Add doc comments to all public items - -## Example Tool Patterns - -### Simple Read-Only Tool - -```rust -#[derive(Debug, Deserialize, JsonSchema)] -pub struct GreetParams { - pub name: String, -} - -#[tool( - name = "greet", - description = "Greets a user by name", - annotations(read_only_hint = true, idempotent_hint = true) -)] -async fn greet(params: Parameters) -> String { - format!("Hello, {}!", params.inner().name) -} -``` - -### Tool with Error Handling - -```rust -#[derive(Debug, Deserialize, JsonSchema)] -pub struct DivideParams { - pub a: f64, - pub b: f64, -} - -#[tool(name = "divide", description = "Divides two numbers")] -async fn divide(params: Parameters) -> Result { - let p = params.inner(); - if p.b == 0.0 { - Err("Cannot divide by zero".to_string()) - } else { - Ok(p.a / p.b) - } -} -``` - -### Tool with State - -```rust -#[tool( - name = "increment", - description = "Increments the counter", - annotations(destructive_hint = true) -)] -async fn increment(state: &ServerState) -> i32 { - state.increment().await -} -``` - -## Running the Generated Server - -After generation: - -```bash -cd {project-name} -cargo build -cargo test -cargo run -``` - -For Claude Desktop integration: - -```json -{ - "mcpServers": { - "{project-name}": { - "command": "path/to/{project-name}/target/release/{project-name}", - "args": [] - } - } -} -``` - -Now generate the complete project based on the user's requirements! diff --git a/archived-contributions/rust-mcp/rust-mcp-server.instructions.md b/archived-contributions/rust-mcp/rust-mcp-server.instructions.md deleted file mode 100644 index 1759aaa..0000000 --- a/archived-contributions/rust-mcp/rust-mcp-server.instructions.md +++ /dev/null @@ -1,719 +0,0 @@ ---- -title: Rust MCP Server Development Best Practices -description: 'Best practices for building Model Context Protocol servers in Rust using the official rmcp SDK with async/await patterns' -applyTo: - - '**/*.rs' - - '**/Cargo.toml' - - '**/Cargo.lock' ---- - -# Rust MCP Server Development Best Practices - -This guide provides best practices for building Model Context Protocol (MCP) servers using the official Rust SDK (`rmcp`). - -## Installation and Setup - -### Add Dependencies - -Add the `rmcp` crate to your `Cargo.toml`: - -```toml -[dependencies] -rmcp = { version = "0.8.1", features = ["server"] } -tokio = { version = "1", features = ["full"] } -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" -anyhow = "1.0" -tracing = "0.1" -tracing-subscriber = "0.3" -``` - -For macros support: - -```toml -[dependencies] -rmcp-macros = "0.8" -schemars = { version = "0.8", features = ["derive"] } -``` - -### Project Structure - -Organize your Rust MCP server project: - -``` -my-mcp-server/ -├── Cargo.toml -├── src/ -│ ├── main.rs # Server entry point -│ ├── handler.rs # ServerHandler implementation -│ ├── tools/ -│ │ ├── mod.rs -│ │ ├── calculator.rs -│ │ └── greeter.rs -│ ├── prompts/ -│ │ ├── mod.rs -│ │ └── code_review.rs -│ └── resources/ -│ ├── mod.rs -│ └── data.rs -└── tests/ - └── integration_tests.rs -``` - -## Server Implementation - -### Basic Server Setup - -Create a server with stdio transport: - -```rust -use rmcp::{ - protocol::ServerCapabilities, - server::{Server, ServerHandler}, - transport::StdioTransport, -}; -use tokio::signal; - -#[tokio::main] -async fn main() -> anyhow::Result<()> { - tracing_subscriber::fmt::init(); - - let handler = MyServerHandler::new(); - let transport = StdioTransport::new(); - - let server = Server::builder() - .with_handler(handler) - .with_capabilities(ServerCapabilities { - tools: Some(Default::default()), - prompts: Some(Default::default()), - resources: Some(Default::default()), - ..Default::default() - }) - .build(transport)?; - - server.run(signal::ctrl_c()).await?; - - Ok(()) -} -``` - -### ServerHandler Implementation - -Implement the `ServerHandler` trait: - -```rust -use rmcp::{ - model::*, - protocol::*, - server::{RequestContext, ServerHandler, RoleServer}, - ErrorData, -}; - -pub struct MyServerHandler { - tool_router: ToolRouter, -} - -impl MyServerHandler { - pub fn new() -> Self { - Self { - tool_router: Self::create_tool_router(), - } - } - - fn create_tool_router() -> ToolRouter { - // Initialize and return tool router - ToolRouter::new() - } -} - -#[async_trait::async_trait] -impl ServerHandler for MyServerHandler { - async fn list_tools( - &self, - _request: Option, - _context: RequestContext, - ) -> Result { - let items = self.tool_router.list_all(); - Ok(ListToolsResult::with_all_items(items)) - } - - async fn call_tool( - &self, - request: CallToolRequestParam, - context: RequestContext, - ) -> Result { - let tcc = ToolCallContext::new(self, request, context); - self.tool_router.call(tcc).await - } -} -``` - -## Tool Development - -### Using Macros for Tools - -Use the `#[tool]` macro for declarative tool definitions: - -```rust -use rmcp::tool; -use rmcp::model::Parameters; -use serde::{Deserialize, Serialize}; -use schemars::JsonSchema; - -#[derive(Debug, Deserialize, JsonSchema)] -pub struct CalculateParams { - pub a: f64, - pub b: f64, - pub operation: String, -} - -/// Performs mathematical calculations -#[tool( - name = "calculate", - description = "Performs basic arithmetic operations", - annotations(read_only_hint = true) -)] -pub async fn calculate(params: Parameters) -> Result { - let p = params.inner(); - match p.operation.as_str() { - "add" => Ok(p.a + p.b), - "subtract" => Ok(p.a - p.b), - "multiply" => Ok(p.a * p.b), - "divide" => { - if p.b == 0.0 { - Err("Division by zero".to_string()) - } else { - Ok(p.a / p.b) - } - } - _ => Err(format!("Unknown operation: {}", p.operation)), - } -} -``` - -### Tool Router with Macros - -Use `#[tool_router]` and `#[tool_handler]` macros: - -```rust -use rmcp::{tool_router, tool_handler}; - -pub struct ToolsHandler { - tool_router: ToolRouter, -} - -#[tool_router] -impl ToolsHandler { - #[tool] - async fn greet(params: Parameters) -> String { - format!("Hello, {}!", params.inner().name) - } - - #[tool(annotations(destructive_hint = true))] - async fn reset_counter() -> String { - "Counter reset".to_string() - } - - pub fn new() -> Self { - Self { - tool_router: Self::tool_router(), - } - } -} - -#[tool_handler] -impl ServerHandler for ToolsHandler { - // Other handler methods... -} -``` - -### Tool Annotations - -Use annotations to provide hints about tool behavior: - -```rust -#[tool( - name = "delete_file", - annotations( - destructive_hint = true, - read_only_hint = false, - idempotent_hint = false - ) -)] -pub async fn delete_file(params: Parameters) -> Result<(), String> { - // Delete file logic -} - -#[tool( - name = "search_data", - annotations( - read_only_hint = true, - idempotent_hint = true, - open_world_hint = true - ) -)] -pub async fn search_data(params: Parameters) -> Vec { - // Search logic -} -``` - -### Returning Rich Content - -Return structured content from tools: - -```rust -use rmcp::model::{ToolResponseContent, TextContent, ImageContent}; - -#[tool] -async fn analyze_code(params: Parameters) -> ToolResponseContent { - ToolResponseContent::from(vec![ - TextContent::text(format!("Analysis of {}:", params.inner().filename)), - TextContent::text("No issues found."), - ]) -} -``` - -## Prompt Implementation - -### Prompt Handler - -Implement prompt handlers: - -```rust -use rmcp::model::{Prompt, PromptArgument, PromptMessage, GetPromptResult}; - -async fn list_prompts( - &self, - _request: Option, - _context: RequestContext, -) -> Result { - let prompts = vec![ - Prompt { - name: "code-review".to_string(), - description: Some("Review code for best practices".to_string()), - arguments: Some(vec![ - PromptArgument { - name: "language".to_string(), - description: Some("Programming language".to_string()), - required: Some(true), - }, - ]), - }, - ]; - - Ok(ListPromptsResult { prompts }) -} - -async fn get_prompt( - &self, - request: GetPromptRequestParam, - _context: RequestContext, -) -> Result { - match request.name.as_str() { - "code-review" => { - let language = request.arguments - .as_ref() - .and_then(|args| args.get("language")) - .ok_or_else(|| ErrorData::invalid_params("language required"))?; - - Ok(GetPromptResult { - description: Some("Code review prompt".to_string()), - messages: vec![ - PromptMessage::user(format!( - "Review this {} code for best practices and suggest improvements", - language - )), - ], - }) - } - _ => Err(ErrorData::invalid_params("Unknown prompt")), - } -} -``` - -## Resource Implementation - -### Resource Handlers - -Implement resource handlers: - -```rust -use rmcp::model::{Resource, ResourceContents, ReadResourceResult}; - -async fn list_resources( - &self, - _request: Option, - _context: RequestContext, -) -> Result { - let resources = vec![ - Resource { - uri: "file:///data/config.json".to_string(), - name: "Configuration".to_string(), - description: Some("Server configuration".to_string()), - mime_type: Some("application/json".to_string()), - }, - ]; - - Ok(ListResourcesResult { resources }) -} - -async fn read_resource( - &self, - request: ReadResourceRequestParam, - _context: RequestContext, -) -> Result { - match request.uri.as_str() { - "file:///data/config.json" => { - let content = r#"{"version": "1.0", "enabled": true}"#; - Ok(ReadResourceResult { - contents: vec![ - ResourceContents::text(content.to_string()) - .with_uri(request.uri) - .with_mime_type("application/json"), - ], - }) - } - _ => Err(ErrorData::invalid_params("Unknown resource")), - } -} -``` - -## Transport Options - -### Stdio Transport - -Standard input/output transport for CLI integration: - -```rust -use rmcp::transport::StdioTransport; - -let transport = StdioTransport::new(); -let server = Server::builder() - .with_handler(handler) - .build(transport)?; -``` - -### SSE (Server-Sent Events) Transport - -HTTP-based SSE transport: - -```rust -use rmcp::transport::SseServerTransport; -use std::net::SocketAddr; - -let addr: SocketAddr = "127.0.0.1:8000".parse()?; -let transport = SseServerTransport::new(addr); - -let server = Server::builder() - .with_handler(handler) - .build(transport)?; - -server.run(signal::ctrl_c()).await?; -``` - -### Streamable HTTP Transport - -HTTP streaming transport with Axum: - -```rust -use rmcp::transport::StreamableHttpTransport; -use axum::{Router, routing::post}; - -let transport = StreamableHttpTransport::new(); -let app = Router::new() - .route("/mcp", post(transport.handler())); - -let listener = tokio::net::TcpListener::bind("127.0.0.1:3000").await?; -axum::serve(listener, app).await?; -``` - -### Custom Transports - -Implement custom transports (TCP, Unix Socket, WebSocket): - -```rust -use rmcp::transport::Transport; -use tokio::net::TcpListener; - -// See examples/transport/ for TCP, Unix Socket, WebSocket implementations -``` - -## Error Handling - -### ErrorData Usage - -Return proper MCP errors: - -```rust -use rmcp::ErrorData; - -fn validate_params(value: &str) -> Result<(), ErrorData> { - if value.is_empty() { - return Err(ErrorData::invalid_params("Value cannot be empty")); - } - Ok(()) -} - -async fn call_tool( - &self, - request: CallToolRequestParam, - context: RequestContext, -) -> Result { - validate_params(&request.name)?; - - // Tool execution... - - Ok(CallToolResult { - content: vec![TextContent::text("Success")], - is_error: Some(false), - }) -} -``` - -### Anyhow Integration - -Use `anyhow` for application-level errors: - -```rust -use anyhow::{Context, Result}; - -async fn load_config() -> Result { - let content = tokio::fs::read_to_string("config.json") - .await - .context("Failed to read config file")?; - - let config: Config = serde_json::from_str(&content) - .context("Failed to parse config")?; - - Ok(config) -} -``` - -## Testing - -### Unit Tests - -Write unit tests for tools and handlers: - -```rust -#[cfg(test)] -mod tests { - use super::*; - - #[tokio::test] - async fn test_calculate_add() { - let params = Parameters::new(CalculateParams { - a: 5.0, - b: 3.0, - operation: "add".to_string(), - }); - - let result = calculate(params).await.unwrap(); - assert_eq!(result, 8.0); - } - - #[tokio::test] - async fn test_divide_by_zero() { - let params = Parameters::new(CalculateParams { - a: 5.0, - b: 0.0, - operation: "divide".to_string(), - }); - - let result = calculate(params).await; - assert!(result.is_err()); - } -} -``` - -### Integration Tests - -Test complete server interactions: - -```rust -#[tokio::test] -async fn test_server_list_tools() { - let handler = MyServerHandler::new(); - let context = RequestContext::default(); - - let result = handler.list_tools(None, context).await.unwrap(); - - assert!(!result.tools.is_empty()); - assert!(result.tools.iter().any(|t| t.name == "calculate")); -} -``` - -## Progress Notifications - -### Reporting Progress - -Send progress notifications during long-running operations: - -```rust -use rmcp::model::ProgressNotification; - -#[tool] -async fn process_large_file( - params: Parameters, - context: RequestContext, -) -> Result { - let total = 100; - - for i in 0..=total { - // Do work... - - if i % 10 == 0 { - context.notify_progress(ProgressNotification { - progress: i, - total: Some(total), - }).await.ok(); - } - } - - Ok("Processing complete".to_string()) -} -``` - -## OAuth Authentication - -### OAuth Integration - -Implement OAuth for secure access: - -```rust -use rmcp::oauth::{OAuthConfig, OAuthProvider}; - -let oauth_config = OAuthConfig { - authorization_endpoint: "https://auth.example.com/authorize".to_string(), - token_endpoint: "https://auth.example.com/token".to_string(), - client_id: env::var("CLIENT_ID")?, - client_secret: env::var("CLIENT_SECRET")?, - scopes: vec!["read".to_string(), "write".to_string()], -}; - -let oauth_provider = OAuthProvider::new(oauth_config); -// See examples/servers/complex_auth_sse.rs for complete implementation -``` - -## Performance Best Practices - -### Async Operations - -Use async/await for non-blocking operations: - -```rust -#[tool] -async fn fetch_data(params: Parameters) -> Result { - let client = reqwest::Client::new(); - let response = client - .get(¶ms.inner().url) - .send() - .await - .map_err(|e| e.to_string())?; - - let text = response.text().await.map_err(|e| e.to_string())?; - Ok(text) -} -``` - -### State Management - -Use `Arc` and `RwLock` for shared state: - -```rust -use std::sync::Arc; -use tokio::sync::RwLock; - -pub struct ServerState { - counter: Arc>, -} - -impl ServerState { - pub fn new() -> Self { - Self { - counter: Arc::new(RwLock::new(0)), - } - } - - pub async fn increment(&self) -> i32 { - let mut counter = self.counter.write().await; - *counter += 1; - *counter - } -} -``` - -## Logging and Tracing - -### Setup Tracing - -Configure tracing for observability: - -```rust -use tracing::{info, warn, error, debug}; -use tracing_subscriber; - -fn init_logging() { - tracing_subscriber::fmt() - .with_max_level(tracing::Level::DEBUG) - .with_target(false) - .with_thread_ids(true) - .init(); -} - -#[tool] -async fn my_tool(params: Parameters) -> String { - debug!("Tool called with params: {:?}", params); - info!("Processing request"); - - // Tool logic... - - info!("Request completed"); - "Done".to_string() -} -``` - -## Deployment - -### Binary Distribution - -Build optimized release binaries: - -```bash -cargo build --release --target x86_64-unknown-linux-gnu -cargo build --release --target x86_64-pc-windows-msvc -cargo build --release --target x86_64-apple-darwin -``` - -### Cross-Compilation - -Use cross for cross-platform builds: - -```bash -cargo install cross -cross build --release --target aarch64-unknown-linux-gnu -``` - -### Docker Deployment - -Create a Dockerfile: - -```dockerfile -FROM rust:1.75 as builder -WORKDIR /app -COPY . . -RUN cargo build --release - -FROM debian:bookworm-slim -RUN apt-get update && apt-get install -y ca-certificates -COPY --from=builder /app/target/release/my-mcp-server /usr/local/bin/ -CMD ["my-mcp-server"] -``` - -## Additional Resources - -- [rmcp Documentation](https://docs.rs/rmcp) -- [rmcp-macros Documentation](https://docs.rs/rmcp-macros) -- [Examples Repository](https://github.com/modelcontextprotocol/rust-sdk/tree/main/examples) -- [MCP Specification](https://spec.modelcontextprotocol.io/) -- [Rust Async Book](https://rust-lang.github.io/async-book/) diff --git a/archived-contributions/swift-mcp/swift-mcp-development.collection.yml b/archived-contributions/swift-mcp/swift-mcp-development.collection.yml deleted file mode 100644 index 8828531..0000000 --- a/archived-contributions/swift-mcp/swift-mcp-development.collection.yml +++ /dev/null @@ -1,35 +0,0 @@ -id: swift-mcp-development -name: Swift MCP Server Development -description: 'Comprehensive collection for building Model Context Protocol servers in Swift using the official MCP Swift SDK with modern concurrency features.' -tags: [swift, mcp, model-context-protocol, server-development, sdk, ios, macos, concurrency, actor, async-await] -items: - - path: instructions/swift-mcp-server.instructions.md - kind: instruction - - path: prompts/swift-mcp-server-generator.prompt.md - kind: prompt - - path: chatmodes/swift-mcp-expert.chatmode.md - kind: chat-mode - usage: | - recommended - - This chat mode provides expert guidance for building MCP servers in Swift. - - This chat mode is ideal for: - - Creating new MCP server projects with Swift - - Implementing async/await patterns and actor-based concurrency - - Setting up stdio, HTTP, or network transports - - Debugging Swift concurrency and ServiceLifecycle integration - - Learning Swift MCP best practices with the official SDK - - Optimizing server performance for iOS/macOS platforms - - To get the best results, consider: - - Using the instruction file to set context for Swift MCP development - - Using the prompt to generate initial project structure - - Switching to the expert chat mode for detailed implementation help - - Specifying whether you need stdio, HTTP, or network transport - - Providing details about what tools or functionality you need - - Mentioning if you need resources, prompts, or special capabilities - -display: - ordering: manual - show_badge: true diff --git a/archived-contributions/swift-mcp/swift-mcp-development.md b/archived-contributions/swift-mcp/swift-mcp-development.md deleted file mode 100644 index 3cabb90..0000000 --- a/archived-contributions/swift-mcp/swift-mcp-development.md +++ /dev/null @@ -1,41 +0,0 @@ -# Swift MCP Server Development - -'Comprehensive collection for building Model Context Protocol servers in Swift using the official MCP Swift SDK with modern concurrency features.' - -**Tags:** swift, mcp, model-context-protocol, server-development, sdk, ios, macos, concurrency, actor, async-await - -## Items in this Collection - -| Title | Type | Description | -| ----- | ---- | ----------- | -| [Swift MCP Server Development Guidelines](../instructions/swift-mcp-server.instructions.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fswift-mcp-server.instructions.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fswift-mcp-server.instructions.md) | Instruction | Best practices and patterns for building Model Context Protocol (MCP) servers in Swift using the official MCP Swift SDK package. | -| [Swift MCP Server Generator](../prompts/swift-mcp-server-generator.prompt.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/prompt?url=vscode%3Achat-prompt%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fprompts%2Fswift-mcp-server-generator.prompt.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/prompt?url=vscode-insiders%3Achat-prompt%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fprompts%2Fswift-mcp-server-generator.prompt.md) | Prompt | Generate a complete Model Context Protocol server project in Swift using the official MCP Swift SDK package. | -| [Swift MCP Expert](../chatmodes/swift-mcp-expert.chatmode.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/chatmode?url=vscode%3Achat-mode%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fchatmodes%2Fswift-mcp-expert.chatmode.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/chatmode?url=vscode-insiders%3Achat-mode%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fchatmodes%2Fswift-mcp-expert.chatmode.md) | Chat Mode | Expert assistance for building Model Context Protocol servers in Swift using modern concurrency features and the official MCP Swift SDK. [see usage](#swift-mcp-expert) | - -## Collection Usage - -### Swift MCP Expert - -recommended - -This chat mode provides expert guidance for building MCP servers in Swift. - -This chat mode is ideal for: -- Creating new MCP server projects with Swift -- Implementing async/await patterns and actor-based concurrency -- Setting up stdio, HTTP, or network transports -- Debugging Swift concurrency and ServiceLifecycle integration -- Learning Swift MCP best practices with the official SDK -- Optimizing server performance for iOS/macOS platforms - -To get the best results, consider: -- Using the instruction file to set context for Swift MCP development -- Using the prompt to generate initial project structure -- Switching to the expert chat mode for detailed implementation help -- Specifying whether you need stdio, HTTP, or network transport -- Providing details about what tools or functionality you need -- Mentioning if you need resources, prompts, or special capabilities - ---- - -*This collection includes 3 curated items for swift mcp server development.* \ No newline at end of file diff --git a/archived-contributions/swift-mcp/swift-mcp-expert.chatmode.md b/archived-contributions/swift-mcp/swift-mcp-expert.chatmode.md deleted file mode 100644 index 4174072..0000000 --- a/archived-contributions/swift-mcp/swift-mcp-expert.chatmode.md +++ /dev/null @@ -1,240 +0,0 @@ ---- -description: 'Expert assistance for building Model Context Protocol servers in Swift using modern concurrency features and the official MCP Swift SDK.' -model: GPT-4.1 ---- - -# Swift MCP Expert - -I'm specialized in helping you build robust, production-ready MCP servers in Swift using the official Swift SDK. I can assist with: - -## Core Capabilities - -### Server Architecture -- Setting up Server instances with proper capabilities -- Configuring transport layers (Stdio, HTTP, Network, InMemory) -- Implementing graceful shutdown with ServiceLifecycle -- Actor-based state management for thread safety -- Async/await patterns and structured concurrency - -### Tool Development -- Creating tool definitions with JSON schemas using Value type -- Implementing tool handlers with CallTool -- Parameter validation and error handling -- Async tool execution patterns -- Tool list changed notifications - -### Resource Management -- Defining resource URIs and metadata -- Implementing ReadResource handlers -- Managing resource subscriptions -- Resource changed notifications -- Multi-content responses (text, image, binary) - -### Prompt Engineering -- Creating prompt templates with arguments -- Implementing GetPrompt handlers -- Multi-turn conversation patterns -- Dynamic prompt generation -- Prompt list changed notifications - -### Swift Concurrency -- Actor isolation for thread-safe state -- Async/await patterns -- Task groups and structured concurrency -- Cancellation handling -- Error propagation - -## Code Assistance - -I can help you with: - -### Project Setup -```swift -// Package.swift with MCP SDK -.package( - url: "https://github.com/modelcontextprotocol/swift-sdk.git", - from: "0.10.0" -) -``` - -### Server Creation -```swift -let server = Server( - name: "MyServer", - version: "1.0.0", - capabilities: .init( - prompts: .init(listChanged: true), - resources: .init(subscribe: true, listChanged: true), - tools: .init(listChanged: true) - ) -) -``` - -### Handler Registration -```swift -await server.withMethodHandler(CallTool.self) { params in - // Tool implementation -} -``` - -### Transport Configuration -```swift -let transport = StdioTransport(logger: logger) -try await server.start(transport: transport) -``` - -### ServiceLifecycle Integration -```swift -struct MCPService: Service { - func run() async throws { - try await server.start(transport: transport) - } - - func shutdown() async throws { - await server.stop() - } -} -``` - -## Best Practices - -### Actor-Based State -Always use actors for shared mutable state: -```swift -actor ServerState { - private var subscriptions: Set = [] - - func addSubscription(_ uri: String) { - subscriptions.insert(uri) - } -} -``` - -### Error Handling -Use proper Swift error handling: -```swift -do { - let result = try performOperation() - return .init(content: [.text(result)], isError: false) -} catch let error as MCPError { - return .init(content: [.text(error.localizedDescription)], isError: true) -} -``` - -### Logging -Use structured logging with swift-log: -```swift -logger.info("Tool called", metadata: [ - "name": .string(params.name), - "args": .string("\(params.arguments ?? [:])") -]) -``` - -### JSON Schemas -Use the Value type for schemas: -```swift -.object([ - "type": .string("object"), - "properties": .object([ - "name": .object([ - "type": .string("string") - ]) - ]), - "required": .array([.string("name")]) -]) -``` - -## Common Patterns - -### Request/Response Handler -```swift -await server.withMethodHandler(CallTool.self) { params in - guard let arg = params.arguments?["key"]?.stringValue else { - throw MCPError.invalidParams("Missing key") - } - - let result = await processAsync(arg) - - return .init( - content: [.text(result)], - isError: false - ) -} -``` - -### Resource Subscription -```swift -await server.withMethodHandler(ResourceSubscribe.self) { params in - await state.addSubscription(params.uri) - logger.info("Subscribed to \(params.uri)") - return .init() -} -``` - -### Concurrent Operations -```swift -async let result1 = fetchData1() -async let result2 = fetchData2() -let combined = await "\(result1) and \(result2)" -``` - -### Initialize Hook -```swift -try await server.start(transport: transport) { clientInfo, capabilities in - logger.info("Client: \(clientInfo.name) v\(clientInfo.version)") - - if capabilities.sampling != nil { - logger.info("Client supports sampling") - } -} -``` - -## Platform Support - -The Swift SDK supports: -- macOS 13.0+ -- iOS 16.0+ -- watchOS 9.0+ -- tvOS 16.0+ -- visionOS 1.0+ -- Linux (glibc and musl) - -## Testing - -Write async tests: -```swift -func testTool() async throws { - let params = CallTool.Params( - name: "test", - arguments: ["key": .string("value")] - ) - - let result = await handleTool(params) - XCTAssertFalse(result.isError ?? true) -} -``` - -## Debugging - -Enable debug logging: -```swift -var logger = Logger(label: "com.example.mcp-server") -logger.logLevel = .debug -``` - -## Ask Me About - -- Server setup and configuration -- Tool, resource, and prompt implementations -- Swift concurrency patterns -- Actor-based state management -- ServiceLifecycle integration -- Transport configuration (Stdio, HTTP, Network) -- JSON schema construction -- Error handling strategies -- Testing async code -- Platform-specific considerations -- Performance optimization -- Deployment strategies - -I'm here to help you build efficient, safe, and idiomatic Swift MCP servers. What would you like to work on? diff --git a/archived-contributions/swift-mcp/swift-mcp-server-generator.prompt.md b/archived-contributions/swift-mcp/swift-mcp-server-generator.prompt.md deleted file mode 100644 index b148785..0000000 --- a/archived-contributions/swift-mcp/swift-mcp-server-generator.prompt.md +++ /dev/null @@ -1,669 +0,0 @@ ---- -description: 'Generate a complete Model Context Protocol server project in Swift using the official MCP Swift SDK package.' -mode: agent ---- - -# Swift MCP Server Generator - -Generate a complete, production-ready MCP server in Swift using the official Swift SDK package. - -## Project Generation - -When asked to create a Swift MCP server, generate a complete project with this structure: - -``` -my-mcp-server/ -├── Package.swift -├── Sources/ -│ └── MyMCPServer/ -│ ├── main.swift -│ ├── Server.swift -│ ├── Tools/ -│ │ ├── ToolDefinitions.swift -│ │ └── ToolHandlers.swift -│ ├── Resources/ -│ │ ├── ResourceDefinitions.swift -│ │ └── ResourceHandlers.swift -│ └── Prompts/ -│ ├── PromptDefinitions.swift -│ └── PromptHandlers.swift -├── Tests/ -│ └── MyMCPServerTests/ -│ └── ServerTests.swift -└── README.md -``` - -## Package.swift Template - -```swift -// swift-tools-version: 6.0 -import PackageDescription - -let package = Package( - name: "MyMCPServer", - platforms: [ - .macOS(.v13), - .iOS(.v16), - .watchOS(.v9), - .tvOS(.v16), - .visionOS(.v1) - ], - dependencies: [ - .package( - url: "https://github.com/modelcontextprotocol/swift-sdk.git", - from: "0.10.0" - ), - .package( - url: "https://github.com/apple/swift-log.git", - from: "1.5.0" - ), - .package( - url: "https://github.com/swift-server/swift-service-lifecycle.git", - from: "2.0.0" - ) - ], - targets: [ - .executableTarget( - name: "MyMCPServer", - dependencies: [ - .product(name: "MCP", package: "swift-sdk"), - .product(name: "Logging", package: "swift-log"), - .product(name: "ServiceLifecycle", package: "swift-service-lifecycle") - ] - ), - .testTarget( - name: "MyMCPServerTests", - dependencies: ["MyMCPServer"] - ) - ] -) -``` - -## main.swift Template - -```swift -import MCP -import Logging -import ServiceLifecycle - -struct MCPService: Service { - let server: Server - let transport: Transport - - func run() async throws { - try await server.start(transport: transport) { clientInfo, capabilities in - logger.info("Client connected", metadata: [ - "name": .string(clientInfo.name), - "version": .string(clientInfo.version) - ]) - } - - // Keep service running - try await Task.sleep(for: .days(365 * 100)) - } - - func shutdown() async throws { - logger.info("Shutting down MCP server") - await server.stop() - } -} - -var logger = Logger(label: "com.example.mcp-server") -logger.logLevel = .info - -do { - let server = await createServer() - let transport = StdioTransport(logger: logger) - let service = MCPService(server: server, transport: transport) - - let serviceGroup = ServiceGroup( - services: [service], - configuration: .init( - gracefulShutdownSignals: [.sigterm, .sigint] - ), - logger: logger - ) - - try await serviceGroup.run() -} catch { - logger.error("Fatal error", metadata: ["error": .string("\(error)")]) - throw error -} -``` - -## Server.swift Template - -```swift -import MCP -import Logging - -func createServer() async -> Server { - let server = Server( - name: "MyMCPServer", - version: "1.0.0", - capabilities: .init( - prompts: .init(listChanged: true), - resources: .init(subscribe: true, listChanged: true), - tools: .init(listChanged: true) - ) - ) - - // Register tool handlers - await registerToolHandlers(server: server) - - // Register resource handlers - await registerResourceHandlers(server: server) - - // Register prompt handlers - await registerPromptHandlers(server: server) - - return server -} -``` - -## ToolDefinitions.swift Template - -```swift -import MCP - -func getToolDefinitions() -> [Tool] { - [ - Tool( - name: "greet", - description: "Generate a greeting message", - inputSchema: .object([ - "type": .string("object"), - "properties": .object([ - "name": .object([ - "type": .string("string"), - "description": .string("Name to greet") - ]) - ]), - "required": .array([.string("name")]) - ]) - ), - Tool( - name: "calculate", - description: "Perform mathematical calculations", - inputSchema: .object([ - "type": .string("object"), - "properties": .object([ - "operation": .object([ - "type": .string("string"), - "enum": .array([ - .string("add"), - .string("subtract"), - .string("multiply"), - .string("divide") - ]), - "description": .string("Operation to perform") - ]), - "a": .object([ - "type": .string("number"), - "description": .string("First operand") - ]), - "b": .object([ - "type": .string("number"), - "description": .string("Second operand") - ]) - ]), - "required": .array([ - .string("operation"), - .string("a"), - .string("b") - ]) - ]) - ) - ] -} -``` - -## ToolHandlers.swift Template - -```swift -import MCP -import Logging - -private let logger = Logger(label: "com.example.mcp-server.tools") - -func registerToolHandlers(server: Server) async { - await server.withMethodHandler(ListTools.self) { _ in - logger.debug("Listing available tools") - return .init(tools: getToolDefinitions()) - } - - await server.withMethodHandler(CallTool.self) { params in - logger.info("Tool called", metadata: ["name": .string(params.name)]) - - switch params.name { - case "greet": - return handleGreet(params: params) - - case "calculate": - return handleCalculate(params: params) - - default: - logger.warning("Unknown tool requested", metadata: ["name": .string(params.name)]) - return .init( - content: [.text("Unknown tool: \(params.name)")], - isError: true - ) - } - } -} - -private func handleGreet(params: CallTool.Params) -> CallTool.Result { - guard let name = params.arguments?["name"]?.stringValue else { - return .init( - content: [.text("Missing 'name' parameter")], - isError: true - ) - } - - let greeting = "Hello, \(name)! Welcome to MCP." - logger.debug("Generated greeting", metadata: ["name": .string(name)]) - - return .init( - content: [.text(greeting)], - isError: false - ) -} - -private func handleCalculate(params: CallTool.Params) -> CallTool.Result { - guard let operation = params.arguments?["operation"]?.stringValue, - let a = params.arguments?["a"]?.doubleValue, - let b = params.arguments?["b"]?.doubleValue else { - return .init( - content: [.text("Missing or invalid parameters")], - isError: true - ) - } - - let result: Double - switch operation { - case "add": - result = a + b - case "subtract": - result = a - b - case "multiply": - result = a * b - case "divide": - guard b != 0 else { - return .init( - content: [.text("Division by zero")], - isError: true - ) - } - result = a / b - default: - return .init( - content: [.text("Unknown operation: \(operation)")], - isError: true - ) - } - - logger.debug("Calculation performed", metadata: [ - "operation": .string(operation), - "result": .string("\(result)") - ]) - - return .init( - content: [.text("Result: \(result)")], - isError: false - ) -} -``` - -## ResourceDefinitions.swift Template - -```swift -import MCP - -func getResourceDefinitions() -> [Resource] { - [ - Resource( - name: "Example Data", - uri: "resource://data/example", - description: "Example resource data", - mimeType: "application/json" - ), - Resource( - name: "Configuration", - uri: "resource://config", - description: "Server configuration", - mimeType: "application/json" - ) - ] -} -``` - -## ResourceHandlers.swift Template - -```swift -import MCP -import Logging -import Foundation - -private let logger = Logger(label: "com.example.mcp-server.resources") - -actor ResourceState { - private var subscriptions: Set = [] - - func addSubscription(_ uri: String) { - subscriptions.insert(uri) - } - - func removeSubscription(_ uri: String) { - subscriptions.remove(uri) - } - - func isSubscribed(_ uri: String) -> Bool { - subscriptions.contains(uri) - } -} - -private let state = ResourceState() - -func registerResourceHandlers(server: Server) async { - await server.withMethodHandler(ListResources.self) { params in - logger.debug("Listing available resources") - return .init(resources: getResourceDefinitions(), nextCursor: nil) - } - - await server.withMethodHandler(ReadResource.self) { params in - logger.info("Reading resource", metadata: ["uri": .string(params.uri)]) - - switch params.uri { - case "resource://data/example": - let jsonData = """ - { - "message": "Example resource data", - "timestamp": "\(Date())" - } - """ - return .init(contents: [ - .text(jsonData, uri: params.uri, mimeType: "application/json") - ]) - - case "resource://config": - let config = """ - { - "serverName": "MyMCPServer", - "version": "1.0.0" - } - """ - return .init(contents: [ - .text(config, uri: params.uri, mimeType: "application/json") - ]) - - default: - logger.warning("Unknown resource requested", metadata: ["uri": .string(params.uri)]) - throw MCPError.invalidParams("Unknown resource URI: \(params.uri)") - } - } - - await server.withMethodHandler(ResourceSubscribe.self) { params in - logger.info("Client subscribed to resource", metadata: ["uri": .string(params.uri)]) - await state.addSubscription(params.uri) - return .init() - } - - await server.withMethodHandler(ResourceUnsubscribe.self) { params in - logger.info("Client unsubscribed from resource", metadata: ["uri": .string(params.uri)]) - await state.removeSubscription(params.uri) - return .init() - } -} -``` - -## PromptDefinitions.swift Template - -```swift -import MCP - -func getPromptDefinitions() -> [Prompt] { - [ - Prompt( - name: "code-review", - description: "Generate a code review prompt", - arguments: [ - .init(name: "language", description: "Programming language", required: true), - .init(name: "focus", description: "Review focus area", required: false) - ] - ) - ] -} -``` - -## PromptHandlers.swift Template - -```swift -import MCP -import Logging - -private let logger = Logger(label: "com.example.mcp-server.prompts") - -func registerPromptHandlers(server: Server) async { - await server.withMethodHandler(ListPrompts.self) { params in - logger.debug("Listing available prompts") - return .init(prompts: getPromptDefinitions(), nextCursor: nil) - } - - await server.withMethodHandler(GetPrompt.self) { params in - logger.info("Getting prompt", metadata: ["name": .string(params.name)]) - - switch params.name { - case "code-review": - return handleCodeReviewPrompt(params: params) - - default: - logger.warning("Unknown prompt requested", metadata: ["name": .string(params.name)]) - throw MCPError.invalidParams("Unknown prompt: \(params.name)") - } - } -} - -private func handleCodeReviewPrompt(params: GetPrompt.Params) -> GetPrompt.Result { - guard let language = params.arguments?["language"]?.stringValue else { - return .init( - description: "Missing language parameter", - messages: [] - ) - } - - let focus = params.arguments?["focus"]?.stringValue ?? "general quality" - - let description = "Code review for \(language) with focus on \(focus)" - let messages: [Prompt.Message] = [ - .user("Please review this \(language) code with focus on \(focus)."), - .assistant("I'll review the code focusing on \(focus). Please share the code."), - .user("Here's the code to review: [paste code here]") - ] - - logger.debug("Generated code review prompt", metadata: [ - "language": .string(language), - "focus": .string(focus) - ]) - - return .init(description: description, messages: messages) -} -``` - -## ServerTests.swift Template - -```swift -import XCTest -@testable import MyMCPServer - -final class ServerTests: XCTestCase { - func testGreetTool() async throws { - let params = CallTool.Params( - name: "greet", - arguments: ["name": .string("Swift")] - ) - - let result = handleGreet(params: params) - - XCTAssertFalse(result.isError ?? true) - XCTAssertEqual(result.content.count, 1) - - if case .text(let message) = result.content[0] { - XCTAssertTrue(message.contains("Swift")) - } else { - XCTFail("Expected text content") - } - } - - func testCalculateTool() async throws { - let params = CallTool.Params( - name: "calculate", - arguments: [ - "operation": .string("add"), - "a": .number(5), - "b": .number(3) - ] - ) - - let result = handleCalculate(params: params) - - XCTAssertFalse(result.isError ?? true) - XCTAssertEqual(result.content.count, 1) - - if case .text(let message) = result.content[0] { - XCTAssertTrue(message.contains("8")) - } else { - XCTFail("Expected text content") - } - } - - func testDivideByZero() async throws { - let params = CallTool.Params( - name: "calculate", - arguments: [ - "operation": .string("divide"), - "a": .number(10), - "b": .number(0) - ] - ) - - let result = handleCalculate(params: params) - - XCTAssertTrue(result.isError ?? false) - } -} -``` - -## README.md Template - -```markdown -# MyMCPServer - -A Model Context Protocol server built with Swift. - -## Features - -- ✅ Tools: greet, calculate -- ✅ Resources: example data, configuration -- ✅ Prompts: code-review -- ✅ Graceful shutdown with ServiceLifecycle -- ✅ Structured logging with swift-log -- ✅ Full test coverage - -## Requirements - -- Swift 6.0+ -- macOS 13+, iOS 16+, or Linux - -## Installation - -```bash -swift build -c release -``` - -## Usage - -Run the server: - -```bash -swift run -``` - -Or with logging: - -```bash -LOG_LEVEL=debug swift run -``` - -## Testing - -```bash -swift test -``` - -## Development - -The server uses: -- [MCP Swift SDK](https://github.com/modelcontextprotocol/swift-sdk) - MCP protocol implementation -- [swift-log](https://github.com/apple/swift-log) - Structured logging -- [swift-service-lifecycle](https://github.com/swift-server/swift-service-lifecycle) - Graceful shutdown - -## Project Structure - -- `Sources/MyMCPServer/main.swift` - Entry point with ServiceLifecycle -- `Sources/MyMCPServer/Server.swift` - Server configuration -- `Sources/MyMCPServer/Tools/` - Tool definitions and handlers -- `Sources/MyMCPServer/Resources/` - Resource definitions and handlers -- `Sources/MyMCPServer/Prompts/` - Prompt definitions and handlers -- `Tests/` - Unit tests - -## License - -MIT -``` - -## Generation Instructions - -1. **Ask for project name and description** -2. **Generate all files** with proper naming -3. **Use actor-based state** for thread safety -4. **Include comprehensive logging** with swift-log -5. **Implement graceful shutdown** with ServiceLifecycle -6. **Add tests** for all handlers -7. **Use modern Swift concurrency** (async/await) -8. **Follow Swift naming conventions** (camelCase, PascalCase) -9. **Include error handling** with proper MCPError usage -10. **Document public APIs** with doc comments - -## Build and Run - -```bash -# Build -swift build - -# Run -swift run - -# Test -swift test - -# Release build -swift build -c release - -# Install -swift build -c release -cp .build/release/MyMCPServer /usr/local/bin/ -``` - -## Integration with Claude Desktop - -Add to `claude_desktop_config.json`: - -```json -{ - "mcpServers": { - "my-mcp-server": { - "command": "/path/to/MyMCPServer" - } - } -} -``` diff --git a/archived-contributions/swift-mcp/swift-mcp-server.instructions.md b/archived-contributions/swift-mcp/swift-mcp-server.instructions.md deleted file mode 100644 index 29f5e84..0000000 --- a/archived-contributions/swift-mcp/swift-mcp-server.instructions.md +++ /dev/null @@ -1,498 +0,0 @@ ---- -description: 'Best practices and patterns for building Model Context Protocol (MCP) servers in Swift using the official MCP Swift SDK package.' -applyTo: "**/*.swift, **/Package.swift, **/Package.resolved" ---- - -# Swift MCP Server Development Guidelines - -When building MCP servers in Swift, follow these best practices and patterns using the official Swift SDK. - -## Server Setup - -Create an MCP server using the `Server` class with capabilities: - -```swift -import MCP - -let server = Server( - name: "MyServer", - version: "1.0.0", - capabilities: .init( - prompts: .init(listChanged: true), - resources: .init(subscribe: true, listChanged: true), - tools: .init(listChanged: true) - ) -) -``` - -## Adding Tools - -Use `withMethodHandler` to register tool handlers: - -```swift -// Register tool list handler -await server.withMethodHandler(ListTools.self) { _ in - let tools = [ - Tool( - name: "search", - description: "Search for information", - inputSchema: .object([ - "properties": .object([ - "query": .string("Search query"), - "limit": .number("Maximum results") - ]), - "required": .array([.string("query")]) - ]) - ) - ] - return .init(tools: tools) -} - -// Register tool call handler -await server.withMethodHandler(CallTool.self) { params in - switch params.name { - case "search": - let query = params.arguments?["query"]?.stringValue ?? "" - let limit = params.arguments?["limit"]?.intValue ?? 10 - - // Perform search - let results = performSearch(query: query, limit: limit) - - return .init( - content: [.text("Found \(results.count) results")], - isError: false - ) - - default: - return .init( - content: [.text("Unknown tool")], - isError: true - ) - } -} -``` - -## Adding Resources - -Implement resource handlers for data access: - -```swift -// Register resource list handler -await server.withMethodHandler(ListResources.self) { params in - let resources = [ - Resource( - name: "Data File", - uri: "resource://data/example.txt", - description: "Example data file", - mimeType: "text/plain" - ) - ] - return .init(resources: resources, nextCursor: nil) -} - -// Register resource read handler -await server.withMethodHandler(ReadResource.self) { params in - switch params.uri { - case "resource://data/example.txt": - let content = loadResourceContent(uri: params.uri) - return .init(contents: [ - Resource.Content.text( - content, - uri: params.uri, - mimeType: "text/plain" - ) - ]) - - default: - throw MCPError.invalidParams("Unknown resource URI: \(params.uri)") - } -} - -// Register resource subscribe handler -await server.withMethodHandler(ResourceSubscribe.self) { params in - // Track subscription for notifications - subscriptions.insert(params.uri) - print("Client subscribed to \(params.uri)") - return .init() -} -``` - -## Adding Prompts - -Implement prompt handlers for templated conversations: - -```swift -// Register prompt list handler -await server.withMethodHandler(ListPrompts.self) { params in - let prompts = [ - Prompt( - name: "analyze", - description: "Analyze a topic", - arguments: [ - .init(name: "topic", description: "Topic to analyze", required: true), - .init(name: "depth", description: "Analysis depth", required: false) - ] - ) - ] - return .init(prompts: prompts, nextCursor: nil) -} - -// Register prompt get handler -await server.withMethodHandler(GetPrompt.self) { params in - switch params.name { - case "analyze": - let topic = params.arguments?["topic"]?.stringValue ?? "general" - let depth = params.arguments?["depth"]?.stringValue ?? "basic" - - let description = "Analysis of \(topic) at \(depth) level" - let messages: [Prompt.Message] = [ - .user("Please analyze this topic: \(topic)"), - .assistant("I'll provide a \(depth) analysis of \(topic)") - ] - - return .init(description: description, messages: messages) - - default: - throw MCPError.invalidParams("Unknown prompt: \(params.name)") - } -} -``` - -## Transport Configuration - -### Stdio Transport - -For local subprocess communication: - -```swift -import MCP -import Logging - -let logger = Logger(label: "com.example.mcp-server") -let transport = StdioTransport(logger: logger) - -try await server.start(transport: transport) -``` - -### HTTP Transport (Client Side) - -For remote server connections: - -```swift -let transport = HTTPClientTransport( - endpoint: URL(string: "http://localhost:8080")!, - streaming: true // Enable Server-Sent Events -) - -try await client.connect(transport: transport) -``` - -## Concurrency and Actors - -The server is an actor, ensuring thread-safe access: - -```swift -actor ServerState { - private var subscriptions: Set = [] - private var cache: [String: Any] = [:] - - func addSubscription(_ uri: String) { - subscriptions.insert(uri) - } - - func getSubscriptions() -> Set { - return subscriptions - } -} - -let state = ServerState() - -await server.withMethodHandler(ResourceSubscribe.self) { params in - await state.addSubscription(params.uri) - return .init() -} -``` - -## Error Handling - -Use Swift's error handling with `MCPError`: - -```swift -await server.withMethodHandler(CallTool.self) { params in - do { - guard let query = params.arguments?["query"]?.stringValue else { - throw MCPError.invalidParams("Missing query parameter") - } - - let result = try performOperation(query: query) - - return .init( - content: [.text(result)], - isError: false - ) - } catch let error as MCPError { - return .init( - content: [.text(error.localizedDescription)], - isError: true - ) - } catch { - return .init( - content: [.text("Unexpected error: \(error.localizedDescription)")], - isError: true - ) - } -} -``` - -## JSON Schema with Value Type - -Use the `Value` type for JSON schemas: - -```swift -let schema = Value.object([ - "type": .string("object"), - "properties": .object([ - "name": .object([ - "type": .string("string"), - "description": .string("User's name") - ]), - "age": .object([ - "type": .string("integer"), - "minimum": .number(0), - "maximum": .number(150) - ]), - "email": .object([ - "type": .string("string"), - "format": .string("email") - ]) - ]), - "required": .array([.string("name")]) -]) -``` - -## Swift Package Manager Setup - -Create your `Package.swift`: - -```swift -// swift-tools-version: 6.0 -import PackageDescription - -let package = Package( - name: "MyMCPServer", - platforms: [ - .macOS(.v13), - .iOS(.v16) - ], - dependencies: [ - .package( - url: "https://github.com/modelcontextprotocol/swift-sdk.git", - from: "0.10.0" - ), - .package( - url: "https://github.com/apple/swift-log.git", - from: "1.5.0" - ) - ], - targets: [ - .executableTarget( - name: "MyMCPServer", - dependencies: [ - .product(name: "MCP", package: "swift-sdk"), - .product(name: "Logging", package: "swift-log") - ] - ) - ] -) -``` - -## Graceful Shutdown with ServiceLifecycle - -Use Swift Service Lifecycle for proper shutdown: - -```swift -import MCP -import ServiceLifecycle -import Logging - -struct MCPService: Service { - let server: Server - let transport: Transport - - func run() async throws { - try await server.start(transport: transport) - try await Task.sleep(for: .days(365 * 100)) - } - - func shutdown() async throws { - await server.stop() - } -} - -let logger = Logger(label: "com.example.mcp-server") -let transport = StdioTransport(logger: logger) -let mcpService = MCPService(server: server, transport: transport) - -let serviceGroup = ServiceGroup( - services: [mcpService], - configuration: .init( - gracefulShutdownSignals: [.sigterm, .sigint] - ), - logger: logger -) - -try await serviceGroup.run() -``` - -## Async/Await Patterns - -All server operations use Swift concurrency: - -```swift -await server.withMethodHandler(CallTool.self) { params in - async let result1 = fetchData1() - async let result2 = fetchData2() - - let combined = await "\(result1) and \(result2)" - - return .init( - content: [.text(combined)], - isError: false - ) -} -``` - -## Logging - -Use swift-log for structured logging: - -```swift -import Logging - -let logger = Logger(label: "com.example.mcp-server") - -await server.withMethodHandler(CallTool.self) { params in - logger.info("Tool called", metadata: [ - "name": .string(params.name), - "args": .string("\(params.arguments ?? [:])") - ]) - - // Process tool call - - logger.debug("Tool completed successfully") - - return .init(content: [.text("Result")], isError: false) -} -``` - -## Testing - -Test your server with async/await: - -```swift -import XCTest -@testable import MyMCPServer - -final class ServerTests: XCTestCase { - func testToolCall() async throws { - let server = createTestServer() - - // Test tool call logic - let params = CallTool.Params( - name: "search", - arguments: ["query": .string("test")] - ) - - // Verify behavior - XCTAssertNoThrow(try await processToolCall(params)) - } -} -``` - -## Initialize Hook - -Validate client connections with an initialize hook: - -```swift -try await server.start(transport: transport) { clientInfo, clientCapabilities in - // Validate client - guard clientInfo.name != "BlockedClient" else { - throw MCPError.invalidRequest("Client not allowed") - } - - // Check capabilities - if clientCapabilities.sampling == nil { - logger.warning("Client doesn't support sampling") - } - - logger.info("Client connected", metadata: [ - "name": .string(clientInfo.name), - "version": .string(clientInfo.version) - ]) -} -``` - -## Common Patterns - -### Content Types - -Handle different content types: - -```swift -return .init( - content: [ - .text("Plain text response"), - .image(imageData, mimeType: "image/png", metadata: [ - "width": 1024, - "height": 768 - ]), - .resource( - uri: "resource://data", - mimeType: "application/json", - text: jsonString - ) - ], - isError: false -) -``` - -### Strict Configuration - -Use strict mode to fail fast on missing capabilities: - -```swift -let client = Client( - name: "StrictClient", - version: "1.0.0", - configuration: .strict -) - -// Will throw immediately if capability not available -try await client.listTools() -``` - -### Request Batching - -Send multiple requests efficiently: - -```swift -var tasks: [Task] = [] - -try await client.withBatch { batch in - for i in 0..<10 { - tasks.append( - try await batch.addRequest( - CallTool.request(.init( - name: "process", - arguments: ["id": .number(Double(i))] - )) - ) - ) - } -} - -for (index, task) in tasks.enumerated() { - let result = try await task.value - print("\(index): \(result.content)") -} -```