diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..3b740c5 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,27 @@ +# MCP Documentation Guidelines + +## Build Commands +- Preview changes locally: `mintlify dev` +- Deploy: Automatic after PR merge to main branch + +## Style Guidelines +- Follow existing MDX formatting and components +- Keep content clear, concise, and technically accurate +- Include practical code examples where appropriate +- Test all links and code samples before submitting +- Maintain consistent structure with existing documentation +- When documenting CLI commands, use two-line format with the prompt on a separate line: `$ claude` followed by `> /command` +- Use appropriate headings: "When to use", "Steps", and "Tips" for tutorials +- Branch naming convention: prefix with "ashwin/" (e.g., "ashwin/add-mcp-cli-docs") + +## File Organization +- Place new pages in appropriate sections (concepts, tutorials, etc.) +- Update docs.json when adding new pages +- Follow existing file naming conventions (kebab-case.mdx) +- Include proper frontmatter in MDX files + +## Documentation Standards +- Prioritize user understanding over technical completeness +- Document both basic syntax and concrete examples +- Structure command documentation with clear formatting +- For image analysis examples, use quotes: `$ claude "Analyze this image: /path/to/image.png"` \ No newline at end of file diff --git a/clients.mdx b/clients.mdx index 8f77a7c..578731b 100644 --- a/clients.mdx +++ b/clients.mdx @@ -10,17 +10,20 @@ This page provides an overview of applications that support the Model Context Pr | Client | [Resources] | [Prompts] | [Tools] | [Sampling] | Roots | Notes | |---------------------------------------------|-------------|-----------|---------|------------|--------|-----------------------------------------------------------------------------| | [Claude Desktop App][Claude] | ✅ | ✅ | ✅ | ❌ | ❌ | Full support for all MCP features | +| [Claude Code][Claude Code] | ❌ | ✅ | ✅ | ❌ | ❌ | Supports prompts and tools | | [5ire][5ire] | ❌ | ❌ | ✅ | ❌ | ❌ | Supports tools. | | [BeeAI Framework][BeeAI Framework] | ❌ | ❌ | ✅ | ❌ | ❌ | Supports tools in agentic workflows. | | [Cline][Cline] | ✅ | ❌ | ✅ | ❌ | ❌ | Supports tools and resources. | | [Continue][Continue] | ✅ | ✅ | ✅ | ❌ | ❌ | Full support for all MCP features | | [Cursor][Cursor] | ❌ | ❌ | ✅ | ❌ | ❌ | Supports tools. | | [Emacs Mcp][Mcp.el] | ❌ | ❌ | ✅ | ❌ | ❌ | Supports tools in Emacs. | +| [fast-agent][fast-agent] | ✅ | ✅ | ✅ | ✅ | ✅ | Full multimodal MCP support, with end-to-end tests | | [Firebase Genkit][Genkit] | ⚠️ | ✅ | ✅ | ❌ | ❌ | Supports resource list and lookup through tools. | | [GenAIScript][GenAIScript] | ❌ | ❌ | ✅ | ❌ | ❌ | Supports tools. | | [Goose][Goose] | ❌ | ❌ | ✅ | ❌ | ❌ | Supports tools. | | [LibreChat][LibreChat] | ❌ | ❌ | ✅ | ❌ | ❌ | Supports tools for Agents | | [mcp-agent][mcp-agent] | ❌ | ❌ | ✅ | ⚠️ | ❌ | Supports tools, server connection management, and agent workflows. | +| [oterm][oterm] | ❌ | ❌ | ✅ | ❌ | ❌ | Supports tools. | | [Roo Code][Roo Code] | ✅ | ❌ | ✅ | ❌ | ❌ | Supports tools and resources. | | [Sourcegraph Cody][Cody] | ✅ | ❌ | ❌ | ❌ | ❌ | Supports resources through OpenCTX | | [Superinterface][Superinterface] | ❌ | ❌ | ✅ | ❌ | ❌ | Supports tools | @@ -28,9 +31,14 @@ This page provides an overview of applications that support the Model Context Pr | [Windsurf Editor][Windsurf] | ❌ | ❌ | ✅ | ❌ | ❌ | Supports tools with AI Flow for collaborative development. | | [Witsy][Witsy] | ❌ | ❌ | ✅ | ❌ | ❌ | Supports tools in Witsy. | | [Zed][Zed] | ❌ | ✅ | ❌ | ❌ | ❌ | Prompts appear as slash commands | +| [SpinAI][SpinAI] | ❌ | ❌ | ✅ | ❌ | ❌ | Supports tools for Typescript AI Agents | | [OpenSumi][OpenSumi] | ❌ | ❌ | ✅ | ❌ | ❌ | Supports tools in OpenSumi | +| [Daydreams Agents][Daydreams] | ✅ | ✅ | ✅ | ❌ | ❌ | Support for drop in Servers to Daydreams agents | +| [Apify MCP Tester][Apify MCP Tester] | ❌ | ❌ | ✅ | ❌ | ❌ | Supports tools | + [Claude]: https://claude.ai/download +[Claude Code]: https://claude.ai/code [Cursor]: https://cursor.com [Zed]: https://zed.dev [Cody]: https://sourcegraph.com/cody @@ -42,14 +50,19 @@ This page provides an overview of applications that support the Model Context Pr [TheiaAI/TheiaIDE]: https://eclipsesource.com/blogs/2024/12/19/theia-ide-and-theia-ai-support-mcp/ [Superinterface]: https://superinterface.ai [5ire]: https://github.com/nanbingxyz/5ire +[Apify MCP Tester]: https://apify.com/jiri.spilka/tester-mcp-client [BeeAI Framework]: https://i-am-bee.github.io/beeai-framework +[fast-agent]: https://github.com/evalstate/fast-agent [mcp-agent]: https://github.com/lastmile-ai/mcp-agent [Mcp.el]: https://github.com/lizqwerscott/mcp.el [Roo Code]: https://roocode.com [Goose]: https://block.github.io/goose/docs/goose-architecture/#interoperability-with-extensions [Witsy]: https://github.com/nbonamy/witsy [Windsurf]: https://codeium.com/windsurf - +[Daydreams]: https://github.com/daydreamsai/daydreams +[SpinAI]: https://spinai.dev +[OpenSumi]: https://github.com/opensumi/core +[oterm]: https://github.com/ggozad/oterm [Resources]: https://modelcontextprotocol.io/docs/concepts/resources [Prompts]: https://modelcontextprotocol.io/docs/concepts/prompts [Tools]: https://modelcontextprotocol.io/docs/concepts/tools @@ -68,6 +81,13 @@ The Claude desktop application provides comprehensive support for MCP, enabling > ⓘ Note: The Claude.ai web application does not currently support MCP. MCP features are only available in the desktop application. +### Claude Code +Claude Code is an interactive agentic coding tool from Anthropic that helps you code faster through natural language commands. It supports MCP integration for prompts and tools, and also functions as an MCP server to integrate with other clients. + +**Key features:** +- Tool and prompt support for MCP servers +- Offers its own tools through an MCP server for integrating with other MCP clients + ### 5ire [5ire](https://github.com/nanbingxyz/5ire) is an open source cross-platform desktop AI assistant that supports tools through MCP servers. @@ -118,6 +138,15 @@ The Claude desktop application provides comprehensive support for MCP, enabling **Key features:** - Provides MCP tool support for Emacs. +### fast-agent +[fast-agent](https://github.com/evalstate/fast-agent) is a Python Agent framework, with simple declarative support for creating Agents and Workflows, with full multi-modal support for Anthropic and OpenAI models. + +**Key features:** +- PDF and Image support, based on MCP Native types +- Interactive front-end to develop and diagnose Agent applications, including passthrough and playback simulators +- Built in support for "Building Effective Agents" workflows. +- Deploy Agents as MCP Servers + ### Firebase Genkit [Genkit](https://github.com/firebase/genkit) is Firebase's SDK for building and integrating GenAI features into applications. The [genkitx-mcp](https://github.com/firebase/genkit/tree/main/js/plugins/mcp) plugin enables consuming MCP servers as a client or creating MCP servers from Genkit tools and prompts. @@ -162,6 +191,14 @@ Programmatically assemble prompts for LLMs using [GenAIScript](https://microsoft - Implements every pattern defined in [Building Effective Agents](https://www.anthropic.com/research/building-effective-agents). - Supports workflow pause/resume signals, such as waiting for human feedback. +### oterm +[oterm] is a terminal client for Ollama allowing users to create chats/agents. + +**Key features:** + + - Support for multiple fully customizable chat sessions with Ollama connected with tools. + - Support for MCP tools. + ### Roo Code [Roo Code](https://roocode.com) enables AI coding assistance via MCP. @@ -179,6 +216,15 @@ Programmatically assemble prompts for LLMs using [GenAIScript](https://microsoft - Uses OpenCTX as an abstraction layer - Future support planned for additional MCP features +### SpinAI +[SpinAI](https://spinai.dev) is an open-source TypeScript framework for building observable AI agents. The framework provides native MCP compatibility, allowing agents to seamlessly integrate with MCP servers and tools. + +**Key features:** +- Built-in MCP compatibility for AI agents +- Open-source TypeScript framework +- Observable agent architecture +- Native support for MCP tools integration + ### Superinterface [Superinterface](https://superinterface.ai) is AI infrastructure and a developer platform to build in-app AI assistants with support for MCP, interactive components, client-side function calling and more. @@ -235,6 +281,24 @@ Theia AI and Theia IDE's MCP integration provide users with flexibility, making - Supports MCP tools in OpenSumi - Supports built-in IDE MCP servers and custom MCP servers +### Daydreams +[Daydreams](https://github.com/daydreamsai/daydreams) is a generative agent framework for executing anything onchain + +**Key features:** +- Supports MCP Servers in config +- Exposes MCP Client + +### Apify MCP Tester + +[Apify MCP Tester](https://github.com/apify/tester-mcp-client) is an open-source client that connects to any MCP server using Server-Sent Events (SSE). +It is a standalone Apify Actor designed for testing MCP servers over SSE, with support for Authorization headers. +It uses plain JavaScript (old-school style) and is hosted on Apify, allowing you to run it without any setup. + +**Key features:** +- Connects to any MCP server via SSE. +- Works with the [Apify MCP Server](https://apify.com/apify/actors-mcp-server) to interact with one or more Apify [Actors](https://apify.com/store). +- Dynamically utilizes tools based on context and user queries (if supported by the server). + ## Adding MCP support to your application If you've added MCP support to your application, we encourage you to submit a pull request to add it to this list. MCP integration can provide your users with powerful contextual AI capabilities and make your application part of the growing MCP ecosystem. diff --git a/development/roadmap.mdx b/development/roadmap.mdx index 4e4649c..91b2827 100644 --- a/development/roadmap.mdx +++ b/development/roadmap.mdx @@ -11,7 +11,7 @@ We encourage community participation! Each section links to relevant discussions ## Remote MCP Support -Our top priority is enabling [remote MCP connections](https://github.com/modelcontextprotocol/specification/discussions/102), allowing clients to securely connect to MCP servers over the internet. Key initiatives include: +Our top priority is improving [remote MCP connections](https://github.com/modelcontextprotocol/specification/discussions/112), allowing clients to securely connect to MCP servers over the internet. Key initiatives include: - [**Authentication & Authorization**](https://github.com/modelcontextprotocol/specification/discussions/64): Adding standardized auth capabilities, particularly focused on OAuth 2.0 support. diff --git a/development/updates.mdx b/development/updates.mdx index f40e933..3389f64 100644 --- a/development/updates.mdx +++ b/development/updates.mdx @@ -3,6 +3,17 @@ title: "What's New" description: 'The latest updates and improvements to MCP' --- + + - We are exited to announce the availability of the MCP + [C# SDK](https://github.com/modelcontextprotocol/csharp-sdk/) developed by + [Peder Holdgaard Pedersen](http://github.com/PederHP) and Microsoft. This joins our growing + list of supported languages. The C# SDK is also avaialble as + [NuGet package](https://www.nuget.org/packages/ModelContextProtocol) + - Python SDK 1.5.0 was released with multiple fixes and improvements. + + + - Typescript SDK 1.7.0 was released with multiple fixes and improvements. + - We're excited to announce that the Java SDK developed by Spring AI at VMware Tanzu is now the official [Java SDK](https://github.com/modelcontextprotocol/java-sdk) for MCP. diff --git a/docs/concepts/architecture.mdx b/docs/concepts/architecture.mdx index 164628a..6d990e6 100644 --- a/docs/concepts/architecture.mdx +++ b/docs/concepts/architecture.mdx @@ -15,7 +15,7 @@ MCP follows a client-server architecture where: ```mermaid flowchart LR - subgraph " Host (e.g., Claude Desktop) " + subgraph "Host" client1[MCP Client] client2[MCP Client] end diff --git a/examples.mdx b/examples.mdx index 6edfbcc..2969bcc 100644 --- a/examples.mdx +++ b/examples.mdx @@ -51,6 +51,7 @@ These MCP servers are maintained by companies for their platforms: - **[Search1API](https://github.com/fatwang2/search1api-mcp)** - Unified API for search, crawling, and sitemaps - **[Stripe](https://github.com/stripe/agent-toolkit)** - Interact with the Stripe API - **[Tinybird](https://github.com/tinybirdco/mcp-tinybird)** - Interface with the Tinybird serverless ClickHouse platform +- **[Weaviate](https://github.com/weaviate/mcp-server-weaviate)** - Enable Agentic RAG through your Weaviate collection(s) ## Community highlights diff --git a/introduction.mdx b/introduction.mdx index b9b01d8..a858c87 100644 --- a/introduction.mdx +++ b/introduction.mdx @@ -3,7 +3,7 @@ title: Introduction description: 'Get started with the Model Context Protocol (MCP)' --- -Java SDK released! Check out [what else is new.](/development/updates) +C# SDK released! Check out [what else is new.](/development/updates) MCP is an open protocol that standardizes how applications provide context to LLMs. Think of MCP like a USB-C port for AI applications. Just as USB-C provides a standardized way to connect your devices to various peripherals and accessories, MCP provides a standardized way to connect AI models to different data sources and tools. @@ -112,6 +112,13 @@ Choose the path that best fits your needs: > Test and inspect your MCP servers with our interactive debugging tool + + + ## Explore MCP @@ -174,4 +181,4 @@ Here's how to get help or provide feedback: - For bug reports and feature requests related to the MCP specification, SDKs, or documentation (open source), please [create a GitHub issue](https://github.com/modelcontextprotocol) - For discussions or Q&A about the MCP specification, use the [specification discussions](https://github.com/modelcontextprotocol/specification/discussions) - For discussions or Q&A about other MCP open source components, use the [organization discussions](https://github.com/orgs/modelcontextprotocol/discussions) -- For bug reports, feature requests, and questions related to Claude.app and claude.ai's MCP integration, please email mcp-support@anthropic.com \ No newline at end of file +- For bug reports, feature requests, and questions related to Claude.app and claude.ai's MCP integration, please email mcp-support@anthropic.com diff --git a/quickstart/client.mdx b/quickstart/client.mdx index a751bed..281fe1e 100644 --- a/quickstart/client.mdx +++ b/quickstart/client.mdx @@ -8,7 +8,7 @@ In this tutorial, you'll learn how to build a LLM-powered chatbot client that co -[You can find the complete code for this tutorial here.](https://github.com/modelcontextprotocol/quickstart-resources/tree/main/mcp-client) +[You can find the complete code for this tutorial here.](https://github.com/modelcontextprotocol/quickstart-resources/tree/main/mcp-client-python) ## System Requirements @@ -39,7 +39,7 @@ source .venv/bin/activate uv add mcp anthropic python-dotenv # Remove boilerplate files -rm hello.py +rm main.py # Create our main file touch client.py @@ -162,7 +162,6 @@ async def process_query(self, query: str) -> str: ) # Process response and handle tool calls - tool_results = [] final_text = [] assistant_message_content = [] @@ -176,7 +175,6 @@ async def process_query(self, query: str) -> str: # Execute tool call result = await self.session.call_tool(tool_name, tool_args) - tool_results.append({"call": tool_name, "result": result}) final_text.append(f"[Calling tool {tool_name} with args {tool_args}]") assistant_message_content.append(content) @@ -316,7 +314,7 @@ uv run client.py path/to/build/index.js # node server ``` -If you're continuing the weather tutorial from the server quickstart, your command might look something like this: `python client.py .../weather/src/weather/server.py` +If you're continuing the weather tutorial from the server quickstart, your command might look something like this: `python client.py .../quickstart-resources/weather-server-python/weather.py` The client will: @@ -402,10 +400,404 @@ If you see: + + +[You can find the complete code for this tutorial here.](https://github.com/modelcontextprotocol/quickstart-resources/tree/main/mcp-client-typescript) +## System Requirements + +Before starting, ensure your system meets these requirements: +- Mac or Windows computer +- Node.js 17 or higher installed +- Latest version of `npm` installed +- Anthropic API key (Claude) + +## Setting Up Your Environment + +First, let's create and set up our project: + + +```bash MacOS/Linux +# Create project directory +mkdir mcp-client-typescript +cd mcp-client-typescript + +# Initialize npm project +npm init -y + +# Install dependencies +npm install @anthropic-ai/sdk @modelcontextprotocol/sdk dotenv + +# Install dev dependencies +npm install -D @types/node typescript + +# Create source file +touch index.ts +``` + +```powershell Windows +# Create project directory +md mcp-client-typescript +cd mcp-client-typescript + +# Initialize npm project +npm init -y + +# Install dependencies +npm install @anthropic-ai/sdk @modelcontextprotocol/sdk dotenv + +# Install dev dependencies +npm install -D @types/node typescript + +# Create source file +new-item index.ts +``` + + +Update your `package.json` to set `type: "module"` and a build script: + +```json package.json +{ + "type": "module", + "scripts": { + "build": "tsc && chmod 755 build/index.js" + } +} +``` + +Create a `tsconfig.json` in the root of your project: + +```json tsconfig.json +{ + "compilerOptions": { + "target": "ES2022", + "module": "Node16", + "moduleResolution": "Node16", + "outDir": "./build", + "rootDir": "./", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true + }, + "include": ["index.ts"], + "exclude": ["node_modules"] +} +``` + +## Setting Up Your API Key + +You'll need an Anthropic API key from the [Anthropic Console](https://console.anthropic.com/settings/keys). + +Create a `.env` file to store it: + +```bash +echo "ANTHROPIC_API_KEY=" > .env +``` + +Add `.env` to your `.gitignore`: +```bash +echo ".env" >> .gitignore +``` + + +Make sure you keep your `ANTHROPIC_API_KEY` secure! + + +## Creating the Client + +### Basic Client Structure + +First, let's set up our imports and create the basic client class in `index.ts`: + +```typescript +import { Anthropic } from "@anthropic-ai/sdk"; +import { + MessageParam, + Tool, +} from "@anthropic-ai/sdk/resources/messages/messages.mjs"; +import { Client } from "@modelcontextprotocol/sdk/client/index.js"; +import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js"; +import readline from "readline/promises"; +import dotenv from "dotenv"; + +dotenv.config(); + +const ANTHROPIC_API_KEY = process.env.ANTHROPIC_API_KEY; +if (!ANTHROPIC_API_KEY) { + throw new Error("ANTHROPIC_API_KEY is not set"); +} + +class MCPClient { + private mcp: Client; + private anthropic: Anthropic; + private transport: StdioClientTransport | null = null; + private tools: Tool[] = []; + + constructor() { + this.anthropic = new Anthropic({ + apiKey: ANTHROPIC_API_KEY, + }); + this.mcp = new Client({ name: "mcp-client-cli", version: "1.0.0" }); + } + // methods will go here +} +``` + +### Server Connection Management + +Next, we'll implement the method to connect to an MCP server: + +```typescript +async connectToServer(serverScriptPath: string) { + try { + const isJs = serverScriptPath.endsWith(".js"); + const isPy = serverScriptPath.endsWith(".py"); + if (!isJs && !isPy) { + throw new Error("Server script must be a .js or .py file"); + } + const command = isPy + ? process.platform === "win32" + ? "python" + : "python3" + : process.execPath; + + this.transport = new StdioClientTransport({ + command, + args: [serverScriptPath], + }); + this.mcp.connect(this.transport); + + const toolsResult = await this.mcp.listTools(); + this.tools = toolsResult.tools.map((tool) => { + return { + name: tool.name, + description: tool.description, + input_schema: tool.inputSchema, + }; + }); + console.log( + "Connected to server with tools:", + this.tools.map(({ name }) => name) + ); + } catch (e) { + console.log("Failed to connect to MCP server: ", e); + throw e; + } +} +``` + +### Query Processing Logic + +Now let's add the core functionality for processing queries and handling tool calls: + +```typescript +async processQuery(query: string) { + const messages: MessageParam[] = [ + { + role: "user", + content: query, + }, + ]; + + const response = await this.anthropic.messages.create({ + model: "claude-3-5-sonnet-20241022", + max_tokens: 1000, + messages, + tools: this.tools, + }); + + const finalText = []; + const toolResults = []; + + for (const content of response.content) { + if (content.type === "text") { + finalText.push(content.text); + } else if (content.type === "tool_use") { + const toolName = content.name; + const toolArgs = content.input as { [x: string]: unknown } | undefined; + + const result = await this.mcp.callTool({ + name: toolName, + arguments: toolArgs, + }); + toolResults.push(result); + finalText.push( + `[Calling tool ${toolName} with args ${JSON.stringify(toolArgs)}]` + ); + + messages.push({ + role: "user", + content: result.content as string, + }); + + const response = await this.anthropic.messages.create({ + model: "claude-3-5-sonnet-20241022", + max_tokens: 1000, + messages, + }); + + finalText.push( + response.content[0].type === "text" ? response.content[0].text : "" + ); + } + } + + return finalText.join("\n"); +} +``` + +### Interactive Chat Interface + +Now we'll add the chat loop and cleanup functionality: + +```typescript +async chatLoop() { + const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout, + }); + + try { + console.log("\nMCP Client Started!"); + console.log("Type your queries or 'quit' to exit."); + + while (true) { + const message = await rl.question("\nQuery: "); + if (message.toLowerCase() === "quit") { + break; + } + const response = await this.processQuery(message); + console.log("\n" + response); + } + } finally { + rl.close(); + } +} + +async cleanup() { + await this.mcp.close(); +} +``` + +### Main Entry Point + +Finally, we'll add the main execution logic: + +```typescript +async function main() { + if (process.argv.length < 3) { + console.log("Usage: node index.ts "); + return; + } + const mcpClient = new MCPClient(); + try { + await mcpClient.connectToServer(process.argv[2]); + await mcpClient.chatLoop(); + } finally { + await mcpClient.cleanup(); + process.exit(0); + } +} + +main(); +``` + +## Running the Client + +To run your client with any MCP server: + +```bash +# Build TypeScript +npm run build + +# Run the client +node build/index.js path/to/server.py # python server +node build/index.js path/to/build/index.js # node server +``` + + +If you're continuing the weather tutorial from the server quickstart, your command might look something like this: `node build/index.js .../quickstart-resources/weather-server-typescript/build/index.js` + + +**The client will:** +1. Connect to the specified server +2. List available tools +3. Start an interactive chat session where you can: + - Enter queries + - See tool executions + - Get responses from Claude + +## How It Works + +When you submit a query: + +1. The client gets the list of available tools from the server +2. Your query is sent to Claude along with tool descriptions +3. Claude decides which tools (if any) to use +4. The client executes any requested tool calls through the server +5. Results are sent back to Claude +6. Claude provides a natural language response +7. The response is displayed to you + +## Best practices + +1. **Error Handling** + - Use TypeScript's type system for better error detection + - Wrap tool calls in try-catch blocks + - Provide meaningful error messages + - Gracefully handle connection issues + +2. **Security** + - Store API keys securely in `.env` + - Validate server responses + - Be cautious with tool permissions + +## Troubleshooting + +### Server Path Issues +- Double-check the path to your server script is correct +- Use the absolute path if the relative path isn't working +- For Windows users, make sure to use forward slashes (/) or escaped backslashes (\\) in the path +- Verify the server file has the correct extension (.js for Node.js or .py for Python) + +Example of correct path usage: +```bash +# Relative path +node build/index.js ./server/build/index.js + +# Absolute path +node build/index.js /Users/username/projects/mcp-server/build/index.js + +# Windows path (either format works) +node build/index.js C:/projects/mcp-server/build/index.js +node build/index.js C:\\projects\\mcp-server\\build\\index.js +``` + +### Response Timing +- The first response might take up to 30 seconds to return +- This is normal and happens while: + - The server initializes + - Claude processes the query + - Tools are being executed +- Subsequent responses are typically faster +- Don't interrupt the process during this initial waiting period + +### Common Error Messages + +If you see: +- `Error: Cannot find module`: Check your build folder and ensure TypeScript compilation succeeded +- `Connection refused`: Ensure the server is running and the path is correct +- `Tool execution failed`: Verify the tool's required environment variables are set +- `ANTHROPIC_API_KEY is not set`: Check your .env file and environment variables +- `TypeError`: Ensure you're using the correct types for tool arguments + + + + -This is a quickstart demo based on Spring AI MCP auto-configuration and boot starters. +This is a quickstart demo based on Spring AI MCP auto-configuration and boot starters. To learn how to create sync and async MCP Clients manually, consult the [Java SDK Client](/sdk/java/mcp-client) documentation @@ -531,14 +923,14 @@ Key features: - Maintains conversation memory using InMemoryChatMemory - Runs as an interactive command-line application -### Build and run +### Build and run ```bash ./mvnw clean install java -jar ./target/ai-mcp-brave-chatbot-0.0.1-SNAPSHOT.jar ``` -or +or ```bash ./mvnw spring-boot:run @@ -574,6 +966,405 @@ This provides similar functionality but uses a WebFlux-based SSE transport imple + + +[You can find the complete code for this tutorial here.](https://github.com/modelcontextprotocol/kotlin-sdk/tree/main/samples/kotlin-mcp-client) + +## System Requirements + +Before starting, ensure your system meets these requirements: +- Java 17 or higher +- Anthropic API key (Claude) + +## Setting up your environment + +First, let's install `java` and `gradle` if you haven't already. +You can download `java` from [official Oracle JDK website](https://www.oracle.com/java/technologies/downloads/). +Verify your `java` installation: +```bash +java --version +``` + +Now, let's create and set up your project: + + +```bash MacOS/Linux +# Create a new directory for our project +mkdir kotlin-mcp-client +cd kotlin-mcp-client + +# Initialize a new kotlin project +gradle init +``` + +```powershell Windows +# Create a new directory for our project +md kotlin-mcp-client +cd kotlin-mcp-client +# Initialize a new kotlin project +gradle init +``` + + +After running `gradle init`, you will be presented with options for creating your project. +Select **Application** as the project type, **Kotlin** as the programming language, and **Java 17** as the Java version. + +Alternatively, you can create a Kotlin application using the [IntelliJ IDEA project wizard](https://kotlinlang.org/docs/jvm-get-started.html). + +After creating the project, add the following dependencies: + + +```kotlin build.gradle.kts +val mcpVersion = "0.3.0" +val slf4jVersion = "2.0.9" +val anthropicVersion = "0.8.0" + +dependencies { + implementation("io.modelcontextprotocol:kotlin-sdk:$mcpVersion") + implementation("org.slf4j:slf4j-nop:$slf4jVersion") + implementation("com.anthropic:anthropic-java:$anthropicVersion") +} +``` + +```groovy build.gradle +def mcpVersion = '0.3.0' +def slf4jVersion = '2.0.9' +def anthropicVersion = '0.8.0' +dependencies { + implementation "io.modelcontextprotocol:kotlin-sdk:$mcpVersion" + implementation "org.slf4j:slf4j-nop:$slf4jVersion" + implementation "com.anthropic:anthropic-java:$anthropicVersion" +} +``` + + +Also, add the following plugins to your build script: + +```kotlin build.gradle.kts +plugins { + id("com.github.johnrengelman.shadow") version "8.1.1" +} +``` + +```groovy build.gradle +plugins { + id 'com.github.johnrengelman.shadow' version '8.1.1' +} +``` + + +## Setting up your API key + +You'll need an Anthropic API key from the [Anthropic Console](https://console.anthropic.com/settings/keys). + +Set up your API key: +```bash +export ANTHROPIC_API_KEY='your-anthropic-api-key-here' +``` + + +Make sure your keep your `ANTHROPIC_API_KEY` secure! + + +## Creating the Client + +### Basic Client Structure + +First, let's create the basic client class: + +```kotlin +class MCPClient : AutoCloseable { + private val anthropic = AnthropicOkHttpClient.fromEnv() + private val mcp: Client = Client(clientInfo = Implementation(name = "mcp-client-cli", version = "1.0.0")) + private lateinit var tools: List + + // methods will go here + + override fun close() { + runBlocking { + mcp.close() + anthropic.close() + } + } +``` + +### Server connection managment + +Next, we'll implement the method to connect to an MCP server: + +```kotlin +suspend fun connectToServer(serverScriptPath: String) { + try { + val command = buildList { + when (serverScriptPath.substringAfterLast(".")) { + "js" -> add("node") + "py" -> add(if (System.getProperty("os.name").lowercase().contains("win")) "python" else "python3") + "jar" -> addAll(listOf("java", "-jar")) + else -> throw IllegalArgumentException("Server script must be a .js, .py or .jar file") + } + add(serverScriptPath) + } + + val process = ProcessBuilder(command).start() + val transport = StdioClientTransport( + input = process.inputStream.asSource().buffered(), + output = process.outputStream.asSink().buffered() + ) + + mcp.connect(transport) + + val toolsResult = mcp.listTools() + tools = toolsResult?.tools?.map { tool -> + ToolUnion.ofTool( + Tool.builder() + .name(tool.name) + .description(tool.description ?: "") + .inputSchema( + Tool.InputSchema.builder() + .type(JsonValue.from(tool.inputSchema.type)) + .properties(tool.inputSchema.properties.toJsonValue()) + .putAdditionalProperty("required", JsonValue.from(tool.inputSchema.required)) + .build() + ) + .build() + ) + } ?: emptyList() + println("Connected to server with tools: ${tools.joinToString(", ") { it.tool().get().name() }}") + } catch (e: Exception) { + println("Failed to connect to MCP server: $e") + throw e + } +} +``` + +Also create a helper function to convert from `JsonObject` to `JsonValue` for Anthropic: +```kotlin +private fun JsonObject.toJsonValue(): JsonValue { + val mapper = ObjectMapper() + val node = mapper.readTree(this.toString()) + return JsonValue.fromJsonNode(node) +} +``` + +### Query processing logic + +Now let's add the core functionality for processing queries and handling tool calls: + +```kotlin +private val messageParamsBuilder: MessageCreateParams.Builder = MessageCreateParams.builder() + .model(Model.CLAUDE_3_5_SONNET_20241022) + .maxTokens(1024) + +suspend fun processQuery(query: String): String { + val messages = mutableListOf( + MessageParam.builder() + .role(MessageParam.Role.USER) + .content(query) + .build() + ) + + val response = anthropic.messages().create( + messageParamsBuilder + .messages(messages) + .tools(tools) + .build() + ) + + val finalText = mutableListOf() + response.content().forEach { content -> + when { + content.isText() -> finalText.add(content.text().getOrNull()?.text() ?: "") + + content.isToolUse() -> { + val toolName = content.toolUse().get().name() + val toolArgs = + content.toolUse().get()._input().convert(object : TypeReference>() {}) + + val result = mcp.callTool( + name = toolName, + arguments = toolArgs ?: emptyMap() + ) + finalText.add("[Calling tool $toolName with args $toolArgs]") + + messages.add( + MessageParam.builder() + .role(MessageParam.Role.USER) + .content( + """ + "type": "tool_result", + "tool_name": $toolName, + "result": ${result?.content?.joinToString("\n") { (it as TextContent).text ?: "" }} + """.trimIndent() + ) + .build() + ) + + val aiResponse = anthropic.messages().create( + messageParamsBuilder + .messages(messages) + .build() + ) + + finalText.add(aiResponse.content().first().text().getOrNull()?.text() ?: "") + } + } + } + + return finalText.joinToString("\n", prefix = "", postfix = "") +} +``` + +### Interactive chat + +We'll add the chat loop: + +```kotlin +suspend fun chatLoop() { + println("\nMCP Client Started!") + println("Type your queries or 'quit' to exit.") + + while (true) { + print("\nQuery: ") + val message = readLine() ?: break + if (message.lowercase() == "quit") break + val response = processQuery(message) + println("\n$response") + } +} +``` + +### Main entry point + +Finally, we'll add the main execution function: + +```kotlin +fun main(args: Array) = runBlocking { + if (args.isEmpty()) throw IllegalArgumentException("Usage: java -jar /build/libs/kotlin-mcp-client-0.1.0-all.jar ") + val serverPath = args.first() + val client = MCPClient() + client.use { + client.connectToServer(serverPath) + client.chatLoop() + } +} +``` + +## Running the client + +To run your client with any MCP server: + +```bash +./gradlew build + +# Run the client +java -jar build/libs/.jar path/to/server.jar # jvm server +java -jar build/libs/.jar path/to/server.py # python server +java -jar build/libs/.jar path/to/build/index.js # node server +``` + + +If you're continuing the weather tutorial from the server quickstart, your command might look something like this: `java -jar build/libs/kotlin-mcp-client-0.1.0-all.jar .../samples/weather-stdio-server/build/libs/weather-stdio-server-0.1.0-all.jar` + + +**The client will:** +1. Connect to the specified server +2. List available tools +3. Start an interactive chat session where you can: + - Enter queries + - See tool executions + - Get responses from Claude + +## How it works + +Here's a high-level workflow schema: + +```mermaid +--- +config: + theme: neutral +--- +sequenceDiagram + actor User + participant Client + participant Claude + participant MCP_Server as MCP Server + participant Tools + + User->>Client: Send query + Client<<->>MCP_Server: Get available tools + Client->>Claude: Send query with tool descriptions + Claude-->>Client: Decide tool execution + Client->>MCP_Server: Request tool execution + MCP_Server->>Tools: Execute chosen tools + Tools-->>MCP_Server: Return results + MCP_Server-->>Client: Send results + Client->>Claude: Send tool results + Claude-->>Client: Provide final response + Client-->>User: Display response +``` + +When you submit a query: +1. The client gets the list of available tools from the server +2. Your query is sent to Claude along with tool descriptions +3. Claude decides which tools (if any) to use +4. The client executes any requested tool calls through the server +5. Results are sent back to Claude +6. Claude provides a natural language response +7. The response is displayed to you + +## Best practices + +1. **Error Handling** + - Leverage Kotlin's type system to model errors explicitly + - Wrap external tool and API calls in `try-catch` blocks when exceptions are possible + - Provide clear and meaningful error messages + - Handle network timeouts and connection issues gracefully + +2. **Security** + - Store API keys and secrets securely in `local.properties`, environment variables, or secret managers + - Validate all external responses to avoid unexpected or unsafe data usage + - Be cautious with permissions and trust boundaries when using tools + +## Troubleshooting + +### Server Path Issues +- Double-check the path to your server script is correct +- Use the absolute path if the relative path isn't working +- For Windows users, make sure to use forward slashes (/) or escaped backslashes (\\) in the path +- Make sure that the required runtime is installed (java for Java, npm for Node.js, or uv for Python) +- Verify the server file has the correct extension (.jar for Java, .js for Node.js or .py for Python) + +Example of correct path usage: +```bash +# Relative path +java -jar build/libs/client.jar ./server/build/libs/server.jar + +# Absoulute path +java -jar build/libs/client.jar /Users/username/projects/mcp-server/build/libs/server.jar + +# Windows path (either format works) +java -jar build/libs/client.jar C:/projects/mcp-server/build/libs/server.jar +java -jar build/libs/client.jar C:\\projects\\mcp-server\\build\\libs\\server.jar +``` + +### Response Timing +- The first response might take up to 30 seconds to return +- This is normal and happens while: + - The server initializes + - Claude processes the query + - Tools are being executed +- Subsequent responses are typically faster +- Don't interrupt the process during this initial waiting period + +### Common Error Messages + +If you see: +- `Connection refused`: Ensure the server is running and the path is correct +- `Tool execution failed`: Verify the tool's required environment variables are set +- `ANTHROPIC_API_KEY is not set`: Check your environment variables + + + ## Next steps @@ -596,7 +1387,7 @@ This provides similar functionality but uses a WebFlux-based SSE transport imple Learn how to use LLMs like Claude to speed up your MCP development diff --git a/quickstart/server.mdx b/quickstart/server.mdx index dfa5e29..94f86b9 100644 --- a/quickstart/server.mdx +++ b/quickstart/server.mdx @@ -7,7 +7,7 @@ In this tutorial, we'll build a simple MCP weather server and connect it to a ho ### What we'll be building -Many LLMs (including Claude) do not currently have the ability to fetch the forecast and severe weather alerts. Let's use MCP to solve that! +Many LLMs do not currently have the ability to fetch the forecast and severe weather alerts. Let's use MCP to solve that! We'll build a server that exposes two tools: `get-alerts` and `get-forecast`. Then we'll connect the server to an MCP host (in this case, Claude for Desktop): @@ -311,12 +311,12 @@ Make sure you pass in the absolute path to your server. This tells Claude for Desktop: 1. There's an MCP server named "weather" -2. To launch it by running `uv --directory /ABSOLUTE/PATH/TO/PARENT/FOLDER/weather run weather` +2. To launch it by running `uv --directory /ABSOLUTE/PATH/TO/PARENT/FOLDER/weather run weather.py` Save the file, and restart **Claude for Desktop**. - + Let's get started with building our weather server! [You can find the complete code for what we'll be building here.](https://github.com/modelcontextprotocol/quickstart-resources/tree/main/weather-server-typescript) ### Prerequisite knowledge @@ -386,7 +386,7 @@ Update your package.json to add type: "module" and a build script: "weather": "./build/index.js" }, "scripts": { - "build": "tsc && node -e \"require('fs').chmodSync('build/index.js', '755')\"", + "build": "tsc && chmod 755 build/index.js" }, "files": [ "build" @@ -433,6 +433,10 @@ const USER_AGENT = "weather-app/1.0"; const server = new McpServer({ name: "weather", version: "1.0.0", + capabilities: { + resources: {}, + tools: {}, + }, }); ``` @@ -743,7 +747,7 @@ Save the file, and restart **Claude for Desktop**. -This is a quickstart demo based on Spring AI MCP auto-configuraiton and boot starters. +This is a quickstart demo based on Spring AI MCP auto-configuration and boot starters. To learn how to create sync and async MCP Servers, manually, consult the [Java SDK Server](/sdk/java/mcp-server) documentation. @@ -1023,7 +1027,7 @@ You can re-use the existing Anthropic Destop configuration: spring.ai.mcp.client.stdio.servers-configuration=file:PATH/TO/claude_desktop_config.json ``` -When you stasrt your client applicaiton, the auto-configuration will create, automatically MCP clients from the claude_desktop_config.json. +When you start your client applicaiton, the auto-configuration will create, automatically MCP clients from the claude_desktop_config.json. For more information, see the [MCP Client Boot Starters](https://docs.spring.io/spring-ai/reference/api/mcp/mcp-server-boot-client-docs.html) reference documentation. @@ -1032,6 +1036,376 @@ For more information, see the [MCP Client Boot Starters](https://docs.spring.io/ The [starter-webflux-server](https://github.com/spring-projects/spring-ai-examples/tree/main/model-context-protocol/weather/starter-webflux-server) demonstrates how to create a MCP server using SSE transport. It showcases how to define and register MCP Tools, Resources, and Prompts, using the Spring Boot's auto-configuration capabilities. + + + +Let's get started with building our weather server! [You can find the complete code for what we'll be building here.](https://github.com/modelcontextprotocol/kotlin-sdk/tree/main/samples/weather-stdio-server) + +### Prerequisite knowledge + +This quickstart assumes you have familiarity with: +- Kotlin +- LLMs like Claude + +### System requirements + +- Java 17 or higher installed. + +### Set up your environment + +First, let's install `java` and `gradle` if you haven't already. +You can download `java` from [official Oracle JDK website](https://www.oracle.com/java/technologies/downloads/). +Verify your `java` installation: +```bash +java --version +``` + +Now, let's create and set up your project: + + +```bash MacOS/Linux +# Create a new directory for our project +mkdir weather +cd weather + +# Initialize a new kotlin project +gradle init +``` + +```powershell Windows +# Create a new directory for our project +md weather +cd weather + +# Initialize a new kotlin project +gradle init +``` + + +After running `gradle init`, you will be presented with options for creating your project. +Select **Application** as the project type, **Kotlin** as the programming language, and **Java 17** as the Java version. + +Alternatively, you can create a Kotlin application using the [IntelliJ IDEA project wizard](https://kotlinlang.org/docs/jvm-get-started.html). + +After creating the project, add the following dependencies: + +```kotlin build.gradle.kts +val mcpVersion = "0.3.0" +val slf4jVersion = "2.0.9" +val ktorVersion = "3.1.1" + +dependencies { + implementation("io.modelcontextprotocol:kotlin-sdk:$mcpVersion") + implementation("org.slf4j:slf4j-nop:$slf4jVersion") + implementation("io.ktor:ktor-client-content-negotiation:$ktorVersion") + implementation("io.ktor:ktor-serialization-kotlinx-json:$ktorVersion") +} +``` + +```groovy build.gradle +def mcpVersion = '0.3.0' +def slf4jVersion = '2.0.9' +def ktorVersion = '3.1.1' + +dependencies { + implementation "io.modelcontextprotocol:kotlin-sdk:$mcpVersion" + implementation "org.slf4j:slf4j-nop:$slf4jVersion" + implementation "io.ktor:ktor-client-content-negotiation:$ktorVersion" + implementation "io.ktor:ktor-serialization-kotlinx-json:$ktorVersion" +} +``` + + +Also, add the following plugins to your build script: + +```kotlin build.gradle.kts +plugins { + kotlin("plugin.serialization") version "your_version_of_kotlin" + id("com.github.johnrengelman.shadow") version "8.1.1" +} +``` + +```groovy build.gradle +plugins { + id 'org.jetbrains.kotlin.plugin.serialization' version 'your_version_of_kotlin' + id 'com.github.johnrengelman.shadow' version '8.1.1' +} +``` + + +Now let’s dive into building your server. + +## Building your server + +### Setting up the instance + +Add a server initialization function: + +```kotlin +// Main function to run the MCP server +fun `run mcp server`() { + // Create the MCP Server instance with a basic implementation + val server = Server( + Implementation( + name = "weather", // Tool name is "weather" + version = "1.0.0" // Version of the implementation + ), + ServerOptions( + capabilities = ServerCapabilities(tools = ServerCapabilities.Tools(listChanged = true)) + ) + ) + + // Create a transport using standard IO for server communication + val transport = StdioServerTransport( + System.`in`.asInput(), + System.out.asSink().buffered() + ) + + runBlocking { + server.connect(transport) + val done = Job() + server.onCloseCallback = { + done.complete() + } + done.join() + } +} +``` + +### Weather API helper functions + +Next, let's add functions and data classes for querying and converting responses from the National Weather Service API: + +```kotlin +// Extension function to fetch forecast information for given latitude and longitude +suspend fun HttpClient.getForecast(latitude: Double, longitude: Double): List { + val points = this.get("/points/$latitude,$longitude").body() + val forecast = this.get(points.properties.forecast).body() + return forecast.properties.periods.map { period -> + """ + ${period.name}: + Temperature: ${period.temperature} ${period.temperatureUnit} + Wind: ${period.windSpeed} ${period.windDirection} + Forecast: ${period.detailedForecast} + """.trimIndent() + } +} + +// Extension function to fetch weather alerts for a given state +suspend fun HttpClient.getAlerts(state: String): List { + val alerts = this.get("/alerts/active/area/$state").body() + return alerts.features.map { feature -> + """ + Event: ${feature.properties.event} + Area: ${feature.properties.areaDesc} + Severity: ${feature.properties.severity} + Description: ${feature.properties.description} + Instruction: ${feature.properties.instruction} + """.trimIndent() + } +} + +@Serializable +data class Points( + val properties: Properties +) { + @Serializable + data class Properties(val forecast: String) +} + +@Serializable +data class Forecast( + val properties: Properties +) { + @Serializable + data class Properties(val periods: List) + + @Serializable + data class Period( + val number: Int, val name: String, val startTime: String, val endTime: String, + val isDaytime: Boolean, val temperature: Int, val temperatureUnit: String, + val temperatureTrend: String, val probabilityOfPrecipitation: JsonObject, + val windSpeed: String, val windDirection: String, + val shortForecast: String, val detailedForecast: String, + ) +} + +@Serializable +data class Alert( + val features: List +) { + @Serializable + data class Feature( + val properties: Properties + ) + + @Serializable + data class Properties( + val event: String, val areaDesc: String, val severity: String, + val description: String, val instruction: String?, + ) +} +``` + +### Implementing tool execution + +The tool execution handler is responsible for actually executing the logic of each tool. Let's add it: + +```kotlin +// Create an HTTP client with a default request configuration and JSON content negotiation +val httpClient = HttpClient { + defaultRequest { + url("https://api.weather.gov") + headers { + append("Accept", "application/geo+json") + append("User-Agent", "WeatherApiClient/1.0") + } + contentType(ContentType.Application.Json) + } + // Install content negotiation plugin for JSON serialization/deserialization + install(ContentNegotiation) { json(Json { ignoreUnknownKeys = true }) } +} + +// Register a tool to fetch weather alerts by state +server.addTool( + name = "get_alerts", + description = """ + Get weather alerts for a US state. Input is Two-letter US state code (e.g. CA, NY) + """.trimIndent(), + inputSchema = Tool.Input( + properties = JsonObject( + mapOf( + "state" to JsonObject( + mapOf( + "type" to JsonPrimitive("string"), + "description" to JsonPrimitive("Two-letter US state code (e.g. CA, NY)") + ) + ), + ) + ), + required = listOf("state") + ) +) { request -> + val state = request.arguments["state"]?.jsonPrimitive?.content + if (state == null) { + return@addTool CallToolResult( + content = listOf(TextContent("The 'state' parameter is required.")) + ) + } + + val alerts = httpClient.getAlerts(state) + + CallToolResult(content = alerts.map { TextContent(it) }) +} + +// Register a tool to fetch weather forecast by latitude and longitude +server.addTool( + name = "get_forecast", + description = """ + Get weather forecast for a specific latitude/longitude + """.trimIndent(), + inputSchema = Tool.Input( + properties = JsonObject( + mapOf( + "latitude" to JsonObject(mapOf("type" to JsonPrimitive("number"))), + "longitude" to JsonObject(mapOf("type" to JsonPrimitive("number"))), + ) + ), + required = listOf("latitude", "longitude") + ) +) { request -> + val latitude = request.arguments["latitude"]?.jsonPrimitive?.doubleOrNull + val longitude = request.arguments["longitude"]?.jsonPrimitive?.doubleOrNull + if (latitude == null || longitude == null) { + return@addTool CallToolResult( + content = listOf(TextContent("The 'latitude' and 'longitude' parameters are required.")) + ) + } + + val forecast = httpClient.getForecast(latitude, longitude) + + CallToolResult(content = forecast.map { TextContent(it) }) +} +``` + +### Running the server + +Finally, implement the main function to run the server: + +```kotlin +fun main() = `run mcp server`() +``` + +Make sure to run `./gradlew build` to build your server. This is a very important step in getting your server to connect. + +Let's now test your server from an existing MCP host, Claude for Desktop. + +## Testing your server with Claude for Desktop + + +Claude for Desktop is not yet available on Linux. Linux users can proceed to the [Building a client](/quickstart/client) tutorial to build an MCP client that connects to the server we just built. + + +First, make sure you have Claude for Desktop installed. [You can install the latest version +here.](https://claude.ai/download) If you already have Claude for Desktop, **make sure it's updated to the latest version.** + +We'll need to configure Claude for Desktop for whichever MCP servers you want to use. +To do this, open your Claude for Desktop App configuration at `~/Library/Application Support/Claude/claude_desktop_config.json` in a text editor. +Make sure to create the file if it doesn't exist. + +For example, if you have [VS Code](https://code.visualstudio.com/) installed: + + +```bash MacOS/Linux +code ~/Library/Application\ Support/Claude/claude_desktop_config.json +``` + +```powershell Windows +code $env:AppData\Claude\claude_desktop_config.json +``` + + +You'll then add your servers in the `mcpServers` key. +The MCP UI elements will only show up in Claude for Desktop if at least one server is properly configured. + +In this case, we'll add our single weather server like so: + + +```json MacOS/Linux +{ + "mcpServers": { + "weather": { + "command": "java", + "args": [ + "-jar", + "/ABSOLUTE/PATH/TO/PARENT/FOLDER/weather/build/libs/weather-0.1.0-all.jar" + ] + } + } +} +``` + +```json Windows +{ + "mcpServers": { + "weather": { + "command": "java", + "args": [ + "-jar", + "C:\\PATH\\TO\\PARENT\\FOLDER\\weather\\build\\libs\\weather-0.1.0-all.jar" + ] + } + } +} +``` + + +This tells Claude for Desktop: +1. There's an MCP server named "weather" +2. Launch it by running `java -jar /ABSOLUTE/PATH/TO/PARENT/FOLDER/weather/build/libs/weather-0.1.0-all.jar` + +Save the file, and restart **Claude for Desktop**. + @@ -1165,7 +1539,7 @@ For more advanced troubleshooting, check out our guide on [Debugging MCP](/docs/ Learn how to use LLMs like Claude to speed up your MCP development diff --git a/sdk/java/.DS_Store b/sdk/java/.DS_Store new file mode 100644 index 0000000..5008ddf Binary files /dev/null and b/sdk/java/.DS_Store differ diff --git a/sdk/java/mcp-client.mdx b/sdk/java/mcp-client.mdx index 14ec5f6..70108bd 100644 --- a/sdk/java/mcp-client.mdx +++ b/sdk/java/mcp-client.mdx @@ -15,6 +15,11 @@ The MCP Client is a key component in the Model Context Protocol (MCP) architectu - Prompt system interactions - Optional features like roots management and sampling support + +The [Spring-AI MCP Client](https://docs.spring.io/spring-ai/reference/api/mcp/mcp-client-boot-starter-docs.html) integration extends the MCP Java SDK to +provide auto-configuration for MCP client functionality in Spring Boot applications and integrating with Spring AI’s [tool execution framework](https://docs.spring.io/spring-ai/reference/api/tools.html). + + The client provides both synchronous and asynchronous APIs for flexibility in different application contexts. @@ -182,7 +187,6 @@ The roots capability allows servers to: - Receive notifications when the roots list changes - Understand which directories and files they have access to - ### Sampling Support Sampling enables servers to request LLM interactions ("completions" or "generations") through the client: @@ -209,7 +213,6 @@ This capability allows: - Support for both text and image-based interactions - Optional inclusion of MCP server context in prompts - ## Using MCP Clients ### Tool Execution @@ -320,3 +323,4 @@ client.executePrompt("echo", Map.of( ``` + diff --git a/sdk/java/mcp-overview.mdx b/sdk/java/mcp-overview.mdx index ed1eb47..9c6a2e0 100644 --- a/sdk/java/mcp-overview.mdx +++ b/sdk/java/mcp-overview.mdx @@ -6,6 +6,12 @@ description: Introduction to the Model Context Protocol (MCP) Java SDK Java SDK for the [Model Context Protocol](https://modelcontextprotocol.org/docs/concepts/architecture) enables standardized integration between AI models and tools. + +### Breaking Changes in 0.8.0 ⚠️ +**Note:** Version 0.8.0 introduces several breaking changes including a new session-based architecture. +If you're upgrading from 0.7.0, please refer to the [Migration Guide](https://github.com/modelcontextprotocol/java-sdk/blob/main/migration-0.8.0.md) for detailed instructions. + + ## Features - MCP Client and MCP Server implementations supporting: @@ -25,6 +31,10 @@ enables standardized integration between AI models and tools. - WebMVC SSE transport for servlet-based HTTP streaming - Supports Synchronous and Asynchronous programming paradigms +[Spring AI MCP](https://docs.spring.io/spring-ai/reference/api/mcp/mcp-overview.html) extends the MCP Java SDK with Spring Boot integration, +providing both [Client](https://docs.spring.io/spring-ai/reference/api/mcp/mcp-client-boot-starter-docs.html) and [Server](https://docs.spring.io/spring-ai/reference/api/mcp/mcp-server-boot-starter-docs.html) Boot Starters. +You can bootstrap your AI Spring applications using the [Spring Initializer](https://start.spring.io/). + ## Architecture The SDK follows a layered architecture with clear separation of concerns: @@ -129,7 +139,7 @@ Add the BOM to your project: io.modelcontextprotocol.sdk mcp-bom - 0.7.0 + 0.8.0 pom import @@ -141,7 +151,7 @@ Add the BOM to your project: ```groovy dependencies { - implementation platform("io.modelcontextprotocol.sdk:mcp-bom:0.7.0") + implementation platform("io.modelcontextprotocol.sdk:mcp-bom:0.8.0") //... } ``` diff --git a/sdk/java/mcp-server.mdx b/sdk/java/mcp-server.mdx index 2323064..c51ce40 100644 --- a/sdk/java/mcp-server.mdx +++ b/sdk/java/mcp-server.mdx @@ -3,6 +3,12 @@ title: MCP Server description: Learn how to implement and configure a Model Context Protocol (MCP) server --- + +### Breaking Changes in 0.8.0 ⚠️ +**Note:** Version 0.8.0 introduces several breaking changes including a new session-based architecture. +If you're upgrading from 0.7.0, please refer to the [Migration Guide](https://github.com/modelcontextprotocol/java-sdk/blob/main/migration-0.8.0.md) for detailed instructions. + + ## Overview The MCP Server is a foundational component in the Model Context Protocol (MCP) architecture that provides tools, resources, and capabilities to clients. It implements the server-side of the protocol, responsible for: @@ -15,13 +21,18 @@ The MCP Server is a foundational component in the Model Context Protocol (MCP) a - Managing concurrent client connections - Providing structured logging and notifications + +The [Spring-AI MCP Server](https://docs.spring.io/spring-ai/reference/api/mcp/mcp-server-boot-starter-docs.html) integration extends the MCP Java SDK to +provide auto-configuration for MCP servdr functionality in Spring Boot applications. + + The server supports both synchronous and asynchronous APIs, allowing for flexible integration in different application contexts. ```java // Create a server with custom configuration -McpSyncServer syncServer = McpServer.sync(transport) +McpSyncServer syncServer = McpServer.sync(transportProvider) .serverInfo("my-server", "1.0.0") .capabilities(ServerCapabilities.builder() .resources(true) // Enable resource support @@ -31,13 +42,10 @@ McpSyncServer syncServer = McpServer.sync(transport) .build()) .build(); -// Initialize the server -syncServer.initialize(); - // Register tools, resources, and prompts -syncServer.addTool(syncToolRegistration); -syncServer.addResource(syncResourceRegistration); -syncServer.addPrompt(syncPromptRegistration); +syncServer.addTool(syncToolSpecification); +syncServer.addResource(syncResourceSpecification); +syncServer.addPrompt(syncPromptSpecification); // Send logging notifications syncServer.loggingNotification(LoggingMessageNotification.builder() @@ -54,7 +62,7 @@ syncServer.close(); ```java // Create an async server with custom configuration -McpAsyncServer asyncServer = McpServer.async(transport) +McpAsyncServer asyncServer = McpServer.async(transportProvider) .serverInfo("my-server", "1.0.0") .capabilities(ServerCapabilities.builder() .resources(true) // Enable resource support @@ -64,21 +72,16 @@ McpAsyncServer asyncServer = McpServer.async(transport) .build()) .build(); -// Initialize the server -asyncServer.initialize() - .doOnSuccess(v -> logger.info("Server initialized")) - .subscribe(); - // Register tools, resources, and prompts -asyncServer.addTool(asyncToolRegistration) +asyncServer.addTool(asyncToolSpecification) .doOnSuccess(v -> logger.info("Tool registered")) .subscribe(); -asyncServer.addResource(asyncResourceRegistration) +asyncServer.addResource(asyncResourceSpecification) .doOnSuccess(v -> logger.info("Resource registered")) .subscribe(); -asyncServer.addPrompt(asyncPromptRegistration) +asyncServer.addPrompt(asyncPromptSpecification) .doOnSuccess(v -> logger.info("Prompt registered")) .subscribe(); @@ -98,9 +101,11 @@ asyncServer.close() -## Server Transport +## Server Transport Providers -The transport layer in the MCP SDK is responsible for handling the communication between clients and servers. It provides different implementations to support various communication protocols and patterns. The SDK includes several built-in transport implementations: +The transport layer in the MCP SDK is responsible for handling the communication between clients and servers. +It provides different implementations to support various communication protocols and patterns. +The SDK includes several built-in transport provider implementations: @@ -109,7 +114,7 @@ The transport layer in the MCP SDK is responsible for handling the communication Create in-process based transport: ```java - StdioServerTransport transport = new StdioServerTransport(new ObjectMapper()); + StdioServerTransportProvider transportProvider = new StdioServerTransportProvider(new ObjectMapper()); ``` Provides bidirectional JSON-RPC message handling over standard input/output streams with non-blocking message processing, serialization/deserialization, and graceful shutdown support. @@ -132,13 +137,13 @@ The transport layer in the MCP SDK is responsible for handling the communication @Configuration class McpConfig { @Bean - WebFluxSseServerTransport webFluxSseServerTransport(ObjectMapper mapper) { - return new WebFluxSseServerTransport(mapper, "/mcp/message"); + WebFluxSseServerTransportProvider webFluxSseServerTransportProvider(ObjectMapper mapper) { + return new WebFluxSseServerTransportProvider(mapper, "/mcp/message"); } @Bean - RouterFunction mcpRouterFunction(WebFluxSseServerTransport transport) { - return transport.getRouterFunction(); + RouterFunction mcpRouterFunction(WebFluxSseServerTransportProvider transportProvider) { + return transportProvider.getRouterFunction(); } } ``` @@ -163,13 +168,13 @@ The transport layer in the MCP SDK is responsible for handling the communication @EnableWebMvc class McpConfig { @Bean - WebMvcSseServerTransport webMvcSseServerTransport(ObjectMapper mapper) { - return new WebMvcSseServerTransport(mapper, "/mcp/message"); + WebMvcSseServerTransportProvider webMvcSseServerTransportProvider(ObjectMapper mapper) { + return new WebMvcSseServerTransportProvider(mapper, "/mcp/message"); } @Bean - RouterFunction mcpRouterFunction(WebMvcSseServerTransport transport) { - return transport.getRouterFunction(); + RouterFunction mcpRouterFunction(WebMvcSseServerTransportProvider transportProvider) { + return transportProvider.getRouterFunction(); } } ``` @@ -199,13 +204,13 @@ The transport layer in the MCP SDK is responsible for handling the communication public class McpServerConfig implements WebMvcConfigurer { @Bean - public HttpServletSseServerTransport servletSseServerTransport() { - return new HttpServletSseServerTransport(new ObjectMapper(), "/mcp/message"); + public HttpServletSseServerTransportProvider servletSseServerTransportProvider() { + return new HttpServletSseServerTransportProvider(new ObjectMapper(), "/mcp/message"); } @Bean - public ServletRegistrationBean customServletBean(HttpServletSseServerTransport servlet) { - return new ServletRegistrationBean(servlet); + public ServletRegistrationBean customServletBean(HttpServletSseServerTransportProvider transportProvider) { + return new ServletRegistrationBean(transportProvider); } } ``` @@ -261,19 +266,36 @@ server.loggingNotification(LoggingMessageNotification.builder() Clients can control the minimum logging level they receive through the `mcpClient.setLoggingLevel(level)` request. Messages below the set level will be filtered out. Supported logging levels (in order of increasing severity): DEBUG (0), INFO (1), NOTICE (2), WARNING (3), ERROR (4), CRITICAL (5), ALERT (6), EMERGENCY (7) -### Tool Registration +### Tool Specification + +The Model Context Protocol allows servers to [expose tools](https://spec.modelcontextprotocol.io/specification/2024-11-05/server/tools/) that can be invoked by language models. +The Java SDK allows implementing a Tool Specifications with their handler functions. +Tools enable AI models to perform calculations, access external APIs, query databases, and manipulate files: ```java -// Sync tool registration -var syncToolRegistration = new McpServerFeatures.SyncToolRegistration( - new Tool("calculator", "Basic calculator", Map.of( - "operation", "string", - "a", "number", - "b", "number" - )), - arguments -> { +// Sync tool specification +var schema = """ + { + "type" : "object", + "id" : "urn:jsonschema:Operation", + "properties" : { + "operation" : { + "type" : "string" + }, + "a" : { + "type" : "number" + }, + "b" : { + "type" : "number" + } + } + } + """; +var syncToolSpecification = new McpServerFeatures.SyncToolSpecificaiton( + new Tool("calculator", "Basic calculator", schema), + (exchange, arguments) -> { // Tool implementation return new CallToolResult(result, false); } @@ -283,14 +305,27 @@ var syncToolRegistration = new McpServerFeatures.SyncToolRegistration( ```java -// Async tool registration -var asyncToolRegistration = new McpServerFeatures.AsyncToolRegistration( - new Tool("calculator", "Basic calculator", Map.of( - "operation", "string", - "a", "number", - "b", "number" - )), - arguments -> { +// Async tool specification +var schema = """ + { + "type" : "object", + "id" : "urn:jsonschema:Operation", + "properties" : { + "operation" : { + "type" : "string" + }, + "a" : { + "type" : "number" + }, + "b" : { + "type" : "number" + } + } + } + """; +var asyncToolSpecification = new McpServerFeatures.AsyncToolSpecificaiton( + new Tool("calculator", "Basic calculator", schema), + (exchange, arguments) -> { // Tool implementation return Mono.just(new CallToolResult(result, false)); } @@ -299,15 +334,22 @@ var asyncToolRegistration = new McpServerFeatures.AsyncToolRegistration( -### Resource Registration +The Tool specification includes a Tool definition with `name`, `description`, and `parameter schema` followed by a call handler that implements the tool's logic. +The function's first argument is `McpAsyncServerExchange` for client interaction, and the second is a map of tool arguments. + +### Resource Specification + +Specification of a resource with its handler function. +Resources provide context to AI models by exposing data such as: File contents, Database records, API responses, System information, Application state. +Example resource specification: ```java -// Sync resource registration -var syncResourceRegistration = new McpServerFeatures.SyncResourceRegistration( +// Sync resource specification +var syncResourceSpecification = new McpServerFeatures.syncResourceSpecification( new Resource("custom://resource", "name", "description", "mime-type", null), - request -> { + (exchange, request) -> { // Resource read implementation return new ReadResourceResult(contents); } @@ -317,10 +359,10 @@ var syncResourceRegistration = new McpServerFeatures.SyncResourceRegistration( ```java -// Async resource registration -var asyncResourceRegistration = new McpServerFeatures.AsyncResourceRegistration( +// Async resource specification +var asyncResourceSpecification = new McpServerFeatures.asyncResourceSpecification( new Resource("custom://resource", "name", "description", "mime-type", null), - request -> { + (exchange, request) -> { // Resource read implementation return Mono.just(new ReadResourceResult(contents)); } @@ -329,17 +371,26 @@ var asyncResourceRegistration = new McpServerFeatures.AsyncResourceRegistration( -### Prompt Registration +The resource specification compriese of resource definitions and resource read handler. +The resource definition including `name`, `description`, and `MIME type`. +The first argument of the function that handles resource read requests is an `McpAsyncServerExchange` upon which the server can +interact with the connected client. +The second arguments is a `McpSchema.ReadResourceRequest`. + +### Prompt Specification + +As part of the [Prompting capabilities](https://spec.modelcontextprotocol.io/specification/2024-11-05/server/prompts/), MCP provides a standardized way for servers to expose prompt templates to clients. +The Prompt Specification is a structured template for AI model interactions that enables consistent message formatting, parameter substitution, context injection, response formatting, and instruction templating. ```java -// Sync prompt registration -var syncPromptRegistration = new McpServerFeatures.SyncPromptRegistration( +// Sync prompt specification +var syncPromptSpecification = new McpServerFeatures.syncPromptSpecification( new Prompt("greeting", "description", List.of( new PromptArgument("name", "description", true) )), - request -> { + (exchange, request) -> { // Prompt implementation return new GetPromptResult(description, messages); } @@ -349,12 +400,12 @@ var syncPromptRegistration = new McpServerFeatures.SyncPromptRegistration( ```java -// Async prompt registration -var asyncPromptRegistration = new McpServerFeatures.AsyncPromptRegistration( +// Async prompt specification +var asyncPromptSpecification = new McpServerFeatures.asyncPromptSpecification( new Prompt("greeting", "description", List.of( new PromptArgument("name", "description", true) )), - request -> { + (exchange, request) -> { // Prompt implementation return Mono.just(new GetPromptResult(description, messages)); } @@ -363,6 +414,117 @@ var asyncPromptRegistration = new McpServerFeatures.AsyncPromptRegistration( +The prompt definition includes name (identifier for the prompt), description (purpose of the prompt), and list of arguments (parameters for templating). +The handler function processes requests and returns formatted templates. +The first argument is `McpAsyncServerExchange` for client interaction, and the second argument is a `GetPromptRequest` instance. + +### Using Sampling from a Server + +To use [Sampling capabilities](https://spec.modelcontextprotocol.io/specification/2024-11-05/client/sampling/), connect to a client that supports sampling. +No special server configuration is needed, but verify client sampling support before making requests. +Learn about [client sampling support](./mcp-client#sampling-support). + +Once connected to a compatible client, the server can request language model generations: + + + +```java +// Create a server +McpSyncServer server = McpServer.sync(transportProvider) + .serverInfo("my-server", "1.0.0") + .build(); + +// Define a tool that uses sampling +var calculatorTool = new McpServerFeatures.SyncToolSpecification( + new Tool("ai-calculator", "Performs calculations using AI", schema), + (exchange, arguments) -> { + // Check if client supports sampling + if (exchange.getClientCapabilities().sampling() == null) { + return new CallToolResult("Client does not support AI capabilities", false); + } + + // Create a sampling request + McpSchema.CreateMessageRequest request = McpSchema.CreateMessageRequest.builder() + .content(new McpSchema.TextContent("Calculate: " + arguments.get("expression"))) + .modelPreferences(McpSchema.ModelPreferences.builder() + .hints(List.of( + McpSchema.ModelHint.of("claude-3-sonnet"), + McpSchema.ModelHint.of("claude") + )) + .intelligencePriority(0.8) // Prioritize intelligence + .speedPriority(0.5) // Moderate speed importance + .build()) + .systemPrompt("You are a helpful calculator assistant. Provide only the numerical answer.") + .maxTokens(100) + .build(); + + // Request sampling from the client + McpSchema.CreateMessageResult result = exchange.createMessage(request); + + // Process the result + String answer = result.content().text(); + return new CallToolResult(answer, false); + } +); + +// Add the tool to the server +server.addTool(calculatorTool); +``` + + + +```java +// Create a server +McpAsyncServer server = McpServer.async(transportProvider) + .serverInfo("my-server", "1.0.0") + .build(); + +// Define a tool that uses sampling +var calculatorTool = new McpServerFeatures.AsyncToolSpecification( + new Tool("ai-calculator", "Performs calculations using AI", schema), + (exchange, arguments) -> { + // Check if client supports sampling + if (exchange.getClientCapabilities().sampling() == null) { + return Mono.just(new CallToolResult("Client does not support AI capabilities", false)); + } + + // Create a sampling request + McpSchema.CreateMessageRequest request = McpSchema.CreateMessageRequest.builder() + .content(new McpSchema.TextContent("Calculate: " + arguments.get("expression"))) + .modelPreferences(McpSchema.ModelPreferences.builder() + .hints(List.of( + McpSchema.ModelHint.of("claude-3-sonnet"), + McpSchema.ModelHint.of("claude") + )) + .intelligencePriority(0.8) // Prioritize intelligence + .speedPriority(0.5) // Moderate speed importance + .build()) + .systemPrompt("You are a helpful calculator assistant. Provide only the numerical answer.") + .maxTokens(100) + .build(); + + // Request sampling from the client + return exchange.createMessage(request) + .map(result -> { + // Process the result + String answer = result.content().text(); + return new CallToolResult(answer, false); + }); + } +); + +// Add the tool to the server +server.addTool(calculatorTool) + .subscribe(); +``` + + + +The `CreateMessageRequest` object allows you to specify: `Content` - the input text or image for the model, +`Model Preferences` - hints and priorities for model selection, `System Prompt` - instructions for the model's behavior and +`Max Tokens` - maximum length of the generated response. + + ## Error Handling The SDK provides comprehensive error handling through the McpError class, covering protocol compatibility, transport communication, JSON-RPC messaging, tool execution, resource management, prompt handling, timeouts, and connection issues. This unified error handling approach ensures consistent and reliable error management across both synchronous and asynchronous operations.