├── .gitignore ├── README.md ├── build-and-register.sh ├── docs ├── claude-code │ ├── cc-overview.md │ ├── cc-troubleshooting.md │ └── cc-tutorials.md └── mcp │ ├── github-modelcontextprotocol-java-sdk-README.md │ ├── github-modelcontextprotocol-kotlin-sdk-README.md │ ├── github-modelcontextprotocol-python-sdk-README.md │ ├── github-modelcontextprotocol-typescript-sdk-README.md │ ├── modelcontextprotocol-servers-README.md │ ├── modelcontextprotocol.io-clients.md │ ├── modelcontextprotocol.io-development-contributing.md │ ├── modelcontextprotocol.io-development-roadmap.md │ ├── modelcontextprotocol.io-development-updates.md │ ├── modelcontextprotocol.io-docs-concepts-architecture.md │ ├── modelcontextprotocol.io-docs-concepts-prompts.md │ ├── modelcontextprotocol.io-docs-concepts-resources.md │ ├── modelcontextprotocol.io-docs-concepts-roots.md │ ├── modelcontextprotocol.io-docs-concepts-sampling.md │ ├── modelcontextprotocol.io-docs-concepts-tools.md │ ├── modelcontextprotocol.io-docs-concepts-transports.md │ ├── modelcontextprotocol.io-docs-tools-debugging.md │ ├── modelcontextprotocol.io-docs-tools-inspector.md │ ├── modelcontextprotocol.io-examples.md │ ├── modelcontextprotocol.io-introduction.md │ ├── modelcontextprotocol.io-llms.txt │ ├── modelcontextprotocol.io-quickstart-client.md │ ├── modelcontextprotocol.io-quickstart-server.md │ ├── modelcontextprotocol.io-quickstart-user.md │ ├── modelcontextprotocol.io-sdk-java-mcp-client.md │ ├── modelcontextprotocol.io-sdk-java-mcp-overview.md │ ├── modelcontextprotocol.io-sdk-java-mcp-server.md │ └── modelcontextprotocol.io-tutorials-building-mcp-with-llms.md ├── examples └── example-usage.md ├── package-lock.json ├── package.json ├── scripts ├── build-and-register.sh └── register-with-claude.sh ├── src ├── common │ ├── errors.ts │ ├── logger.ts │ └── version.ts ├── index.ts ├── operations │ ├── docker.ts │ └── mcp-client.ts ├── test-runner.ts └── types │ └── schemas.ts ├── test ├── basic-test-suite.json ├── claude-chat-test-suite.json ├── docker-mcp-test-suite.json └── docker-production-test.json └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Python-generated files 2 | __pycache__/ 3 | *.py[oc] 4 | build/ 5 | dist/ 6 | wheels/ 7 | *.egg-info 8 | 9 | # Virtual environments 10 | .venv 11 | 12 | # Node-generated files 13 | dist/ 14 | node_modules/ 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MCP Test Client 2 | 3 | An MCP middleware that acts as both a server (to Claude) and a client (to servers under test) for testing MCP servers during development. 4 | 5 | ## Architecture 6 | 7 | The MCP Test Client has a dual role: 8 | - It's a **server** registered with Claude that exposes tools for testing 9 | - It's a **client** that connects to and tests other MCP servers 10 | 11 | ``` 12 | ┌─────────────┐ ┌───────────────────┐ ┌────────────────┐ 13 | │ │ Tools │ │ Client │ │ 14 | │ Claude │─────────>│ MCP Test Client │─────────>│ Server Under │ 15 | │ │ │ │ │ Test │ 16 | └─────────────┘ └───────────────────┘ └────────────────┘ 17 | ``` 18 | 19 | This architecture lets you test MCP servers without registering them directly with Claude. 20 | 21 | ## Features 22 | 23 | - Deploy MCP servers to test environments 24 | - Call individual tools with custom arguments 25 | - Run automated test suites 26 | - View server logs 27 | - Test servers before formal registration with Claude 28 | 29 | ## Implementation 30 | 31 | The MCP Test Client is implemented with: 32 | 33 | - **Process Management**: Spawns and manages MCP server processes 34 | - **MCP SDK Client**: Uses the official MCP SDK to communicate with servers 35 | - **Custom Transport**: Implements a custom transport for stdio communication 36 | - **Test Execution**: Runs tests and validates responses 37 | - **CLI Interface**: Provides an interactive testing interface 38 | 39 | The current implementation is Phase 1 of the design plan, with future enhancements planned for Phases 2 and 3. 40 | 41 | ## Installation 42 | 43 | ```bash 44 | # Install dependencies 45 | npm install 46 | 47 | # Build the TypeScript project 48 | npm run build 49 | ``` 50 | 51 | ## Usage 52 | 53 | ### As an MCP Server 54 | 55 | The MCP Test Client is registered with Claude via the `claude-mcp-local` script. You can use the following tools: 56 | 57 | 1. Deploy a server: 58 | ```typescript 59 | mcp__mcp-test__mcp_test_deploy_server({ 60 | name: "my-server", 61 | source_path: "/path/to/server", 62 | env_vars: { 63 | "API_KEY": "${API_KEY}" 64 | } 65 | }) 66 | ``` 67 | 68 | 2. Call a tool on a deployed server: 69 | ```typescript 70 | mcp__mcp-test__mcp_test_call_tool({ 71 | server_name: "my-server", 72 | tool_name: "tool_name", 73 | arguments: { 74 | // Tool-specific arguments 75 | } 76 | }) 77 | ``` 78 | 79 | 3. Run tests against a server: 80 | ```typescript 81 | mcp__mcp-test__mcp_test_run_tests({ 82 | server_name: "my-server" 83 | }) 84 | ``` 85 | 86 | 4. View server logs: 87 | ```typescript 88 | mcp__mcp-test__mcp_test_get_logs({ 89 | server_name: "my-server", 90 | lines: 100 91 | }) 92 | ``` 93 | 94 | 5. List deployed servers: 95 | ```typescript 96 | mcp__mcp-test__mcp_test_list_servers({}) 97 | ``` 98 | 99 | 6. Stop a server: 100 | ```typescript 101 | mcp__mcp-test__mcp_test_stop_server({ 102 | server_name: "my-server" 103 | }) 104 | ``` 105 | 106 | ### As a CLI Tool 107 | 108 | Run the CLI interface for testing: 109 | 110 | ```bash 111 | # Use npm script 112 | npm run test 113 | 114 | # Or run directly 115 | node dist/test-runner.js 116 | ``` 117 | 118 | This provides an interactive menu for deploying, testing, and managing MCP servers. 119 | 120 | ## Development Workflow 121 | 122 | The MCP Test Client supports this workflow: 123 | 124 | 1. Develop an MCP server in the playground directory 125 | 2. Deploy it to the test environment with MCP Test Client 126 | 3. Test functionality, call individual tools, and debug issues 127 | 4. Fix and iterate until the server works correctly 128 | 5. Migrate the server to mcp-servers/ when ready 129 | 6. Register with Claude through claude-mcp-local 130 | 131 | ## Future Enhancements 132 | 133 | Planned enhancements include: 134 | 135 | - **Phase 2**: Docker-based container management, comprehensive test suites 136 | - **Phase 3**: Migration tools, more advanced test validation 137 | 138 | See `notes/mcp_test_client_design.md` for the complete design document. 139 | -------------------------------------------------------------------------------- /build-and-register.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Exit on error 4 | set -e 5 | 6 | # Get absolute path of this script 7 | SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 8 | cd "$SCRIPT_DIR" 9 | 10 | # Install dependencies 11 | echo "Installing dependencies..." 12 | npm install 13 | 14 | # Build TypeScript project 15 | echo "Building project..." 16 | npm run build 17 | 18 | # Make sure the script is executable 19 | chmod +x dist/index.js 20 | 21 | # Check if mcp-test is already registered 22 | if claude mcp list | grep -q "mcp-test:"; then 23 | echo "Removing existing mcp-test registration..." 24 | claude mcp remove mcp-test 25 | fi 26 | 27 | # Register the MCP Test Client 28 | echo "Registering mcp-test with Claude..." 29 | claude mcp add mcp-test -- node "$SCRIPT_DIR/dist/index.js" 30 | 31 | echo "MCP Test Client successfully built and registered as 'mcp-test'" 32 | echo "You can now use tools like 'mcp__mcp-test__mcp_test_deploy_server'" -------------------------------------------------------------------------------- /docs/claude-code/cc-troubleshooting.md: -------------------------------------------------------------------------------- 1 | Claude Code troubleshooting - Anthropic 2 | 3 | [Anthropic home page![light logo](https://mintlify.s3.us-west-1.amazonaws.com/anthropic/logo/light.svg)![dark logo](https://mintlify.s3.us-west-1.amazonaws.com/anthropic/logo/dark.svg)](/) 4 | 5 | English 6 | 7 | Search... 8 | 9 | * [Research](https://www.anthropic.com/research) 10 | * [News](https://www.anthropic.com/news) 11 | * [Go to claude.ai](https://claude.ai/) 12 | * [Go to claude.ai](https://claude.ai/) 13 | 14 | Search... 15 | 16 | Navigation 17 | 18 | Claude Code 19 | 20 | Claude Code troubleshooting 21 | 22 | [Welcome](/en/home)[User Guides](/en/docs/welcome)[API Reference](/en/api/getting-started)[Prompt Library](/en/prompt-library/library)[Release Notes](/en/release-notes/overview)[Developer Newsletter](/en/developer-newsletter/overview) 23 | 24 | - [Developer Console](https://console.anthropic.com/) 25 | - [Developer Discord](https://www.anthropic.com/discord) 26 | - [Support](https://support.anthropic.com/) 27 | 28 | ##### Get started 29 | 30 | * [Overview](/en/docs/welcome) 31 | * [Initial setup](/en/docs/initial-setup) 32 | * [Intro to Claude](/en/docs/intro-to-claude) 33 | 34 | ##### Learn about Claude 35 | 36 | * Use cases 37 | * Models & pricing 38 | * [Security and compliance](https://trust.anthropic.com/) 39 | 40 | ##### Build with Claude 41 | 42 | * [Define success criteria](/en/docs/build-with-claude/define-success) 43 | * [Develop test cases](/en/docs/build-with-claude/develop-tests) 44 | * [Context windows](/en/docs/build-with-claude/context-windows) 45 | * [Vision](/en/docs/build-with-claude/vision) 46 | * Prompt engineering 47 | * [Extended thinking](/en/docs/build-with-claude/extended-thinking) 48 | * [Multilingual support](/en/docs/build-with-claude/multilingual-support) 49 | * Tool use (function calling) 50 | * [Prompt caching](/en/docs/build-with-claude/prompt-caching) 51 | * [PDF support](/en/docs/build-with-claude/pdf-support) 52 | * [Citations](/en/docs/build-with-claude/citations) 53 | * [Token counting](/en/docs/build-with-claude/token-counting) 54 | * [Batch processing](/en/docs/build-with-claude/batch-processing) 55 | * [Embeddings](/en/docs/build-with-claude/embeddings) 56 | 57 | ##### Agents and tools 58 | 59 | * Claude Code 60 | 61 | + [Overview](/en/docs/agents-and-tools/claude-code/overview) 62 | + [Claude Code tutorials](/en/docs/agents-and-tools/claude-code/tutorials) 63 | + [Troubleshooting](/en/docs/agents-and-tools/claude-code/troubleshooting) 64 | * [Computer use (beta)](/en/docs/agents-and-tools/computer-use) 65 | * [Model Context Protocol (MCP)](/en/docs/agents-and-tools/mcp) 66 | * [Google Sheets add-on](/en/docs/agents-and-tools/claude-for-sheets) 67 | 68 | ##### Test and evaluate 69 | 70 | * Strengthen guardrails 71 | * [Using the Evaluation Tool](/en/docs/test-and-evaluate/eval-tool) 72 | 73 | ##### Administration 74 | 75 | * [Admin API](/en/docs/administration/administration-api) 76 | 77 | ##### Resources 78 | 79 | * [Glossary](/en/docs/resources/glossary) 80 | * [Model deprecations](/en/docs/resources/model-deprecations) 81 | * [System status](https://status.anthropic.com/) 82 | * [Claude 3 model card](https://assets.anthropic.com/m/61e7d27f8c8f5919/original/Claude-3-Model-Card.pdf) 83 | * [Claude 3.7 system card](https://anthropic.com/claude-3-7-sonnet-system-card) 84 | * [Anthropic Cookbook](https://github.com/anthropics/anthropic-cookbook) 85 | * [Anthropic Courses](https://github.com/anthropics/courses) 86 | 87 | ##### Legal center 88 | 89 | * [Anthropic Privacy Policy](https://www.anthropic.com/legal/privacy) 90 | 91 | Claude Code 92 | 93 | # Claude Code troubleshooting 94 | 95 | Solutions for common issues with Claude Code installation and usage. 96 | 97 | ## [​](#common-installation-issues) Common installation issues 98 | 99 | ### [​](#linux-permission-issues) Linux permission issues 100 | 101 | When installing Claude Code with npm, you may encounter permission errors if your npm global prefix is not user writable (eg. `/usr`, or `/use/local`). 102 | 103 | #### [​](#recommended-solution-create-a-user-writable-npm-prefix) Recommended solution: Create a user-writable npm prefix 104 | 105 | The safest approach is to configure npm to use a directory within your home folder: 106 | 107 | ``` 108 | # First, save a list of your existing global packages for later migration 109 | npm list -g --depth=0 > ~/npm-global-packages.txt 110 | 111 | # Create a directory for your global packages 112 | mkdir -p ~/.npm-global 113 | 114 | # Configure npm to use the new directory path 115 | npm config set prefix ~/.npm-global 116 | 117 | # Note: Replace ~/.bashrc with ~/.zshrc, ~/.profile, or other appropriate file for your shell 118 | echo 'export PATH=~/.npm-global/bin:$PATH' >> ~/.bashrc 119 | 120 | # Apply the new PATH setting 121 | source ~/.bashrc 122 | 123 | # Now reinstall Claude Code in the new location 124 | npm install -g @anthropic-ai/claude-code 125 | 126 | # Optional: Reinstall your previous global packages in the new location 127 | # Look at ~/npm-global-packages.txt and install packages you want to keep 128 | 129 | ``` 130 | 131 | This solution is recommended because it: 132 | 133 | * Avoids modifying system directory permissions 134 | * Creates a clean, dedicated location for your global npm packages 135 | * Follows security best practices 136 | 137 | #### [​](#system-recovery-if-you-have-run-commands-that-change-ownership-and-permissions-of-system-files-or-similar) System Recovery: If you have run commands that change ownership and permissions of system files or similar 138 | 139 | If you’ve already run a command that changed system directory permissions (such as `sudo chown -R $USER:$(id -gn) /usr && sudo chmod -R u+w /usr`) and your system is now broken (for example, if you see `sudo: /usr/bin/sudo must be owned by uid 0 and have the setuid bit set`), you’ll need to perform recovery steps. 140 | 141 | ##### Ubuntu/Debian Recovery Method: 142 | 143 | 1. While rebooting, hold **SHIFT** to access the GRUB menu 144 | 2. Select “Advanced options for Ubuntu/Debian” 145 | 3. Choose the recovery mode option 146 | 4. Select “Drop to root shell prompt” 147 | 5. Remount the filesystem as writable: 148 | 149 | ``` 150 | mount -o remount,rw / 151 | 152 | ``` 153 | 6. Fix permissions: 154 | 155 | ``` 156 | # Restore root ownership 157 | chown -R root:root /usr 158 | chmod -R 755 /usr 159 | 160 | # Ensure /usr/local is owned by your user for npm packages 161 | chown -R YOUR_USERNAME:YOUR_USERNAME /usr/local 162 | 163 | # Set setuid bit for critical binaries 164 | chmod u+s /usr/bin/sudo 165 | chmod 4755 /usr/bin/sudo 166 | chmod u+s /usr/bin/su 167 | chmod u+s /usr/bin/passwd 168 | chmod u+s /usr/bin/newgrp 169 | chmod u+s /usr/bin/gpasswd 170 | chmod u+s /usr/bin/chsh 171 | chmod u+s /usr/bin/chfn 172 | 173 | # Fix sudo configuration 174 | chown root:root /usr/libexec/sudo/sudoers.so 175 | chmod 4755 /usr/libexec/sudo/sudoers.so 176 | chown root:root /etc/sudo.conf 177 | chmod 644 /etc/sudo.conf 178 | 179 | ``` 180 | 7. Reinstall affected packages (optional but recommended): 181 | 182 | ``` 183 | # Save list of installed packages 184 | dpkg --get-selections > /tmp/installed_packages.txt 185 | 186 | # Reinstall them 187 | awk '{print $1}' /tmp/installed_packages.txt | xargs -r apt-get install --reinstall -y 188 | 189 | ``` 190 | 8. Reboot: 191 | 192 | ``` 193 | reboot 194 | 195 | ``` 196 | 197 | ##### Alternative Live USB Recovery Method: 198 | 199 | If the recovery mode doesn’t work, you can use a live USB: 200 | 201 | 1. Boot from a live USB (Ubuntu, Debian, or any Linux distribution) 202 | 2. Find your system partition: 203 | 204 | ``` 205 | lsblk 206 | 207 | ``` 208 | 3. Mount your system partition: 209 | 210 | ``` 211 | sudo mount /dev/sdXY /mnt # replace sdXY with your actual system partition 212 | 213 | ``` 214 | 4. If you have a separate boot partition, mount it too: 215 | 216 | ``` 217 | sudo mount /dev/sdXZ /mnt/boot # if needed 218 | 219 | ``` 220 | 5. Chroot into your system: 221 | 222 | ``` 223 | # For Ubuntu/Debian: 224 | sudo chroot /mnt 225 | 226 | # For Arch-based systems: 227 | sudo arch-chroot /mnt 228 | 229 | ``` 230 | 6. Follow steps 6-8 from the Ubuntu/Debian recovery method above 231 | 232 | After restoring your system, follow the recommended solution above to set up a user-writable npm prefix. 233 | 234 | ## [​](#auto-updater-issues) Auto-updater issues 235 | 236 | If Claude Code can’t update automatically, it may be due to permission issues with your npm global prefix directory. Follow the [recommended solution](/_sites/docs.anthropic.com/en/docs/agents-and-tools/claude-code/troubleshooting#recommended-solution-create-a-user-writable-npm-prefix) above to fix this. 237 | 238 | If you prefer to disable the auto-updater instead, you can use: 239 | 240 | ``` 241 | claude config set -g autoUpdaterStatus disabled 242 | 243 | ``` 244 | 245 | ## [​](#permissions-and-authentication) Permissions and authentication 246 | 247 | ### [​](#repeated-permission-prompts) Repeated permission prompts 248 | 249 | If you find yourself repeatedly approving the same commands, you can allow specific tools to run without approval: 250 | 251 | ``` 252 | # Let npm test run without approval 253 | claude config add allowedTools "Bash(npm test)" 254 | 255 | # Let npm test and any of its sub-commands run without approval 256 | claude config add allowedTools "Bash(npm test:*)" 257 | 258 | ``` 259 | 260 | ### [​](#authentication-issues) Authentication issues 261 | 262 | If you’re experiencing authentication problems: 263 | 264 | 1. Run `/logout` to sign out completely 265 | 2. Close Claude Code 266 | 3. Restart with `claude` and complete the authentication process again 267 | 268 | If problems persist, try: 269 | 270 | ``` 271 | rm -rf ~/.config/claude-code/auth.json 272 | claude 273 | 274 | ``` 275 | 276 | This removes your stored authentication information and forces a clean login. 277 | 278 | ## [​](#performance-and-stability) Performance and stability 279 | 280 | ### [​](#high-cpu-or-memory-usage) High CPU or memory usage 281 | 282 | Claude Code is designed to work with most development environments, but may consume significant resources when processing large codebases. If you’re experiencing performance issues: 283 | 284 | 1. Use `/compact` regularly to reduce context size 285 | 2. Close and restart Claude Code between major tasks 286 | 3. Consider adding large build directories to your `.gitignore` and `.claudeignore` files 287 | 288 | ### [​](#command-hangs-or-freezes) Command hangs or freezes 289 | 290 | If Claude Code seems unresponsive: 291 | 292 | 1. Press Ctrl+C to attempt to cancel the current operation 293 | 2. If unresponsive, you may need to close the terminal and restart 294 | 3. For persistent issues, run Claude with verbose logging: `claude --verbose` 295 | 296 | ## [​](#getting-more-help) Getting more help 297 | 298 | If you’re experiencing issues not covered here: 299 | 300 | 1. Use the `/bug` command within Claude Code to report problems directly to Anthropic 301 | 2. Check the [GitHub repository](https://github.com/anthropics/claude-code) for known issues 302 | 3. Run `/doctor` to check the health of your Claude Code installation 303 | 304 | Was this page helpful? 305 | 306 | YesNo 307 | 308 | [Claude Code tutorials](/en/docs/agents-and-tools/claude-code/tutorials)[Computer use (beta)](/en/docs/agents-and-tools/computer-use) 309 | 310 | [x](https://x.com/AnthropicAI)[linkedin](https://www.linkedin.com/company/anthropicresearch) 311 | 312 | On this page 313 | 314 | * [Common installation issues](#common-installation-issues) 315 | * [Linux permission issues](#linux-permission-issues) 316 | * [Recommended solution: Create a user-writable npm prefix](#recommended-solution-create-a-user-writable-npm-prefix) 317 | * [System Recovery: If you have run commands that change ownership and permissions of system files or similar](#system-recovery-if-you-have-run-commands-that-change-ownership-and-permissions-of-system-files-or-similar) 318 | * [Auto-updater issues](#auto-updater-issues) 319 | * [Permissions and authentication](#permissions-and-authentication) 320 | * [Repeated permission prompts](#repeated-permission-prompts) 321 | * [Authentication issues](#authentication-issues) 322 | * [Performance and stability](#performance-and-stability) 323 | * [High CPU or memory usage](#high-cpu-or-memory-usage) 324 | * [Command hangs or freezes](#command-hangs-or-freezes) 325 | * [Getting more help](#getting-more-help) -------------------------------------------------------------------------------- /docs/mcp/github-modelcontextprotocol-java-sdk-README.md: -------------------------------------------------------------------------------- 1 | # MCP Java SDK 2 | [![Build Status](https://github.com/modelcontextprotocol/java-sdk/actions/workflows/continuous-integration.yml/badge.svg)](https://github.com/modelcontextprotocol/java-sdk/actions/workflows/continuous-integration.yml) 3 | 4 | A set of projects that provide Java SDK integration for the [Model Context Protocol](https://modelcontextprotocol.org/docs/concepts/architecture). 5 | This SDK enables Java applications to interact with AI models and tools through a standardized interface, supporting both synchronous and asynchronous communication patterns. 6 | 7 | ## 📚 Reference Documentation 8 | 9 | #### MCP Java SDK documentation 10 | For comprehensive guides and SDK API documentation, visit the [MCP Java SDK Reference Documentation](https://modelcontextprotocol.io/sdk/java/mcp-overview). 11 | 12 | #### Spring AI MCP documentation 13 | [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) starters. Bootstrap your AI applications with MCP support using [Spring Initializer](https://start.spring.io). 14 | 15 | ## Development 16 | 17 | ### Building from Source 18 | 19 | ```bash 20 | ./mvnw clean install -DskipTests 21 | ``` 22 | 23 | ### Running Tests 24 | 25 | To run the tests you have to pre-install `Docker` and `npx`. 26 | 27 | ```bash 28 | ./mvnw test 29 | ``` 30 | 31 | ## Contributing 32 | 33 | Contributions are welcome! Please: 34 | 35 | 1. Fork the repository 36 | 2. Create a feature branch 37 | 3. Submit a Pull Request 38 | 39 | ## Team 40 | 41 | - Christian Tzolov 42 | - Dariusz Jędrzejczyk 43 | 44 | ## Links 45 | 46 | - [GitHub Repository](https://github.com/modelcontextprotocol/java-sdk) 47 | - [Issue Tracker](https://github.com/modelcontextprotocol/java-sdk/issues) 48 | - [CI/CD](https://github.com/modelcontextprotocol/java-sdk/actions) 49 | 50 | ## License 51 | 52 | This project is licensed under the [MIT License](LICENSE). 53 | -------------------------------------------------------------------------------- /docs/mcp/github-modelcontextprotocol-kotlin-sdk-README.md: -------------------------------------------------------------------------------- 1 | # MCP Kotlin SDK 2 | 3 | Kotlin implementation of the [Model Context Protocol](https://modelcontextprotocol.io) (MCP), providing both client and server capabilities for integrating with LLM surfaces. 4 | 5 | ## Overview 6 | 7 | The Model Context Protocol allows applications to provide context for LLMs in a standardized way, separating the concerns of providing context from the actual LLM interaction. This Kotlin SDK implements the full MCP specification, making it easy to: 8 | 9 | - Build MCP clients that can connect to any MCP server 10 | - Create MCP servers that expose resources, prompts and tools 11 | - Use standard transports like stdio, SSE, and WebSocket 12 | - Handle all MCP protocol messages and lifecycle events 13 | 14 | ## Samples 15 | 16 | - [kotlin-mcp-server](./samples/kotlin-mcp-server): shows how to set up a Kotlin MCP server with different tools and other features. 17 | 18 | ## Installation 19 | 20 | Add the new repository to your build file: 21 | 22 | ```kotlin 23 | repositories { 24 | mavenCentral() 25 | } 26 | ``` 27 | 28 | Add the dependency: 29 | 30 | ```kotlin 31 | dependencies { 32 | implementation("io.modelcontextprotocol:kotlin-sdk:0.3.0") 33 | } 34 | ``` 35 | 36 | ## Quick Start 37 | 38 | ### Creating a Client 39 | 40 | ```kotlin 41 | import io.modelcontextprotocol.kotlin.sdk.client.Client 42 | import io.modelcontextprotocol.kotlin.sdk.client.StdioClientTransport 43 | import io.modelcontextprotocol.kotlin.sdk.Implementation 44 | 45 | val client = Client( 46 | clientInfo = Implementation( 47 | name = "example-client", 48 | version = "1.0.0" 49 | ) 50 | ) 51 | 52 | val transport = StdioClientTransport( 53 | inputStream = processInputStream, 54 | outputStream = processOutputStream 55 | ) 56 | 57 | // Connect to server 58 | client.connect(transport) 59 | 60 | // List available resources 61 | val resources = client.listResources() 62 | 63 | // Read a specific resource 64 | val resourceContent = client.readResource( 65 | ReadResourceRequest(uri = "file:///example.txt") 66 | ) 67 | ``` 68 | 69 | ### Creating a Server 70 | 71 | ```kotlin 72 | import io.modelcontextprotocol.kotlin.sdk.server.Server 73 | import io.modelcontextprotocol.kotlin.sdk.server.ServerOptions 74 | import io.modelcontextprotocol.kotlin.sdk.server.StdioServerTransport 75 | import io.modelcontextprotocol.kotlin.sdk.ServerCapabilities 76 | 77 | val server = Server( 78 | serverInfo = Implementation( 79 | name = "example-server", 80 | version = "1.0.0" 81 | ), 82 | options = ServerOptions( 83 | capabilities = ServerCapabilities( 84 | resources = ServerCapabilities.Resources( 85 | subscribe = true, 86 | listChanged = true 87 | ) 88 | ) 89 | ) 90 | ) 91 | 92 | // Add a resource 93 | server.addResource( 94 | uri = "file:///example.txt", 95 | name = "Example Resource", 96 | description = "An example text file", 97 | mimeType = "text/plain" 98 | ) { request -> 99 | ReadResourceResult( 100 | contents = listOf( 101 | TextResourceContents( 102 | text = "This is the content of the example resource.", 103 | uri = request.uri, 104 | mimeType = "text/plain" 105 | ) 106 | ) 107 | ) 108 | } 109 | 110 | // Start server with stdio transport 111 | val transport = StdioServerTransport() 112 | server.connect(transport) 113 | ``` 114 | 115 | ### Using SSE Transport 116 | 117 | Directly in Ktor's `Application`: 118 | ```kotlin 119 | import io.ktor.server.application.* 120 | import io.modelcontextprotocol.kotlin.sdk.server.mcp 121 | 122 | fun Application.module() { 123 | mcp { 124 | Server( 125 | serverInfo = Implementation( 126 | name = "example-sse-server", 127 | version = "1.0.0" 128 | ), 129 | options = ServerOptions( 130 | capabilities = ServerCapabilities( 131 | prompts = ServerCapabilities.Prompts(listChanged = null), 132 | resources = ServerCapabilities.Resources(subscribe = null, listChanged = null) 133 | ) 134 | ) 135 | ) 136 | } 137 | } 138 | ``` 139 | 140 | Inside a custom Ktor's `Route`: 141 | ```kotlin 142 | import io.ktor.server.application.* 143 | import io.ktor.server.sse.SSE 144 | import io.modelcontextprotocol.kotlin.sdk.server.mcp 145 | 146 | fun Application.module() { 147 | install(SSE) 148 | 149 | routing { 150 | route("myRoute") { 151 | mcp { 152 | Server( 153 | serverInfo = Implementation( 154 | name = "example-sse-server", 155 | version = "1.0.0" 156 | ), 157 | options = ServerOptions( 158 | capabilities = ServerCapabilities( 159 | prompts = ServerCapabilities.Prompts(listChanged = null), 160 | resources = ServerCapabilities.Resources(subscribe = null, listChanged = null) 161 | ) 162 | ) 163 | ) 164 | } 165 | } 166 | } 167 | } 168 | ``` 169 | ## Contributing 170 | 171 | Please see the [contribution guide](CONTRIBUTING.md) and the [Code of conduct](CODE_OF_CONDUCT.md) before contributing. 172 | 173 | ## License 174 | 175 | This project is licensed under the MIT License—see the [LICENSE](LICENSE) file for details. 176 | -------------------------------------------------------------------------------- /docs/mcp/modelcontextprotocol.io-development-contributing.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | > How to participate in Model Context Protocol development 4 | 5 | We welcome contributions from the community! Please review our [contributing guidelines](https://github.com/modelcontextprotocol/.github/blob/main/CONTRIBUTING.md) for details on how to submit changes. 6 | 7 | All contributors must adhere to our [Code of Conduct](https://github.com/modelcontextprotocol/.github/blob/main/CODE_OF_CONDUCT.md). 8 | 9 | For questions and discussions, please use [GitHub Discussions](https://github.com/orgs/modelcontextprotocol/discussions). 10 | -------------------------------------------------------------------------------- /docs/mcp/modelcontextprotocol.io-development-roadmap.md: -------------------------------------------------------------------------------- 1 | # Roadmap 2 | 3 | > Our plans for evolving Model Context Protocol (H1 2025) 4 | 5 | The Model Context Protocol is rapidly evolving. This page outlines our current thinking on key priorities and future direction for **the first half of 2025**, though these may change significantly as the project develops. 6 | 7 | The ideas presented here are not commitments—we may solve these challenges differently than described, or some may not materialize at all. This is also not an *exhaustive* list; we may incorporate work that isn't mentioned here. 8 | 9 | We encourage community participation! Each section links to relevant discussions where you can learn more and contribute your thoughts. 10 | 11 | ## Remote MCP Support 12 | 13 | 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: 14 | 15 | * [**Authentication & Authorization**](https://github.com/modelcontextprotocol/specification/discussions/64): Adding standardized auth capabilities, particularly focused on OAuth 2.0 support. 16 | 17 | * [**Service Discovery**](https://github.com/modelcontextprotocol/specification/discussions/69): Defining how clients can discover and connect to remote MCP servers. 18 | 19 | * [**Stateless Operations**](https://github.com/modelcontextprotocol/specification/discussions/102): Thinking about whether MCP could encompass serverless environments too, where they will need to be mostly stateless. 20 | 21 | ## Reference Implementations 22 | 23 | To help developers build with MCP, we want to offer documentation for: 24 | 25 | * **Client Examples**: Comprehensive reference client implementation(s), demonstrating all protocol features 26 | * **Protocol Drafting**: Streamlined process for proposing and incorporating new protocol features 27 | 28 | ## Distribution & Discovery 29 | 30 | Looking ahead, we're exploring ways to make MCP servers more accessible. Some areas we may investigate include: 31 | 32 | * **Package Management**: Standardized packaging format for MCP servers 33 | * **Installation Tools**: Simplified server installation across MCP clients 34 | * **Sandboxing**: Improved security through server isolation 35 | * **Server Registry**: A common directory for discovering available MCP servers 36 | 37 | ## Agent Support 38 | 39 | We're expanding MCP's capabilities for [complex agentic workflows](https://github.com/modelcontextprotocol/specification/discussions/111), particularly focusing on: 40 | 41 | * [**Hierarchical Agent Systems**](https://github.com/modelcontextprotocol/specification/discussions/94): Improved support for trees of agents through namespacing and topology awareness. 42 | 43 | * [**Interactive Workflows**](https://github.com/modelcontextprotocol/specification/issues/97): Better handling of user permissions and information requests across agent hierarchies, and ways to send output to users instead of models. 44 | 45 | * [**Streaming Results**](https://github.com/modelcontextprotocol/specification/issues/117): Real-time updates from long-running agent operations. 46 | 47 | ## Broader Ecosystem 48 | 49 | We're also invested in: 50 | 51 | * **Community-Led Standards Development**: Fostering a collaborative ecosystem where all AI providers can help shape MCP as an open standard through equal participation and shared governance, ensuring it meets the needs of diverse AI applications and use cases. 52 | * [**Additional Modalities**](https://github.com/modelcontextprotocol/specification/discussions/88): Expanding beyond text to support audio, video, and other formats. 53 | * \[**Standardization**] Considering standardization through a standardization body. 54 | 55 | ## Get Involved 56 | 57 | We welcome community participation in shaping MCP's future. Visit our [GitHub Discussions](https://github.com/orgs/modelcontextprotocol/discussions) to join the conversation and contribute your ideas. 58 | -------------------------------------------------------------------------------- /docs/mcp/modelcontextprotocol.io-development-updates.md: -------------------------------------------------------------------------------- 1 | # What's New 2 | 3 | > The latest updates and improvements to MCP 4 | 5 | 6 | * We're excited to announce that the Java SDK developed by Spring AI at VMware Tanzu is now 7 | the official [Java SDK](https://github.com/modelcontextprotocol/java-sdk) for MCP. 8 | This joins our existing Kotlin SDK in our growing list of supported languages. 9 | The Spring AI team will maintain the SDK as an integral part of the Model Context Protocol 10 | organization. We're thrilled to welcome them to the MCP community! 11 | 12 | 13 | 14 | * Version [1.2.1](https://github.com/modelcontextprotocol/python-sdk/releases/tag/v1.2.1) of the MCP Python SDK has been released, 15 | delivering important stability improvements and bug fixes. 16 | 17 | 18 | 19 | * Simplified, express-like API in the [TypeScript SDK](https://github.com/modelcontextprotocol/typescript-sdk) 20 | * Added 8 new clients to the [clients page](https://modelcontextprotocol.io/clients) 21 | 22 | 23 | 24 | * FastMCP API in the [Python SDK](https://github.com/modelcontextprotocol/python-sdk) 25 | * Dockerized MCP servers in the [servers repo](https://github.com/modelcontextprotocol/servers) 26 | 27 | 28 | 29 | * Jetbrains released a Kotlin SDK for MCP! 30 | * For a sample MCP Kotlin server, check out [this repository](https://github.com/modelcontextprotocol/kotlin-sdk/tree/main/samples/kotlin-mcp-server) 31 | 32 | -------------------------------------------------------------------------------- /docs/mcp/modelcontextprotocol.io-docs-concepts-architecture.md: -------------------------------------------------------------------------------- 1 | # Core architecture 2 | 3 | > Understand how MCP connects clients, servers, and LLMs 4 | 5 | The Model Context Protocol (MCP) is built on a flexible, extensible architecture that enables seamless communication between LLM applications and integrations. This document covers the core architectural components and concepts. 6 | 7 | ## Overview 8 | 9 | MCP follows a client-server architecture where: 10 | 11 | * **Hosts** are LLM applications (like Claude Desktop or IDEs) that initiate connections 12 | * **Clients** maintain 1:1 connections with servers, inside the host application 13 | * **Servers** provide context, tools, and prompts to clients 14 | 15 | ```mermaid 16 | flowchart LR 17 | subgraph " Host (e.g., Claude Desktop) " 18 | client1[MCP Client] 19 | client2[MCP Client] 20 | end 21 | subgraph "Server Process" 22 | server1[MCP Server] 23 | end 24 | subgraph "Server Process" 25 | server2[MCP Server] 26 | end 27 | 28 | client1 <-->|Transport Layer| server1 29 | client2 <-->|Transport Layer| server2 30 | ``` 31 | 32 | ## Core components 33 | 34 | ### Protocol layer 35 | 36 | The protocol layer handles message framing, request/response linking, and high-level communication patterns. 37 | 38 | 39 | 40 | ```typescript 41 | class Protocol { 42 | // Handle incoming requests 43 | setRequestHandler(schema: T, handler: (request: T, extra: RequestHandlerExtra) => Promise): void 44 | 45 | // Handle incoming notifications 46 | setNotificationHandler(schema: T, handler: (notification: T) => Promise): void 47 | 48 | // Send requests and await responses 49 | request(request: Request, schema: T, options?: RequestOptions): Promise 50 | 51 | // Send one-way notifications 52 | notification(notification: Notification): Promise 53 | } 54 | ``` 55 | 56 | 57 | 58 | ```python 59 | class Session(BaseSession[RequestT, NotificationT, ResultT]): 60 | async def send_request( 61 | self, 62 | request: RequestT, 63 | result_type: type[Result] 64 | ) -> Result: 65 | """ 66 | Send request and wait for response. Raises McpError if response contains error. 67 | """ 68 | # Request handling implementation 69 | 70 | async def send_notification( 71 | self, 72 | notification: NotificationT 73 | ) -> None: 74 | """Send one-way notification that doesn't expect response.""" 75 | # Notification handling implementation 76 | 77 | async def _received_request( 78 | self, 79 | responder: RequestResponder[ReceiveRequestT, ResultT] 80 | ) -> None: 81 | """Handle incoming request from other side.""" 82 | # Request handling implementation 83 | 84 | async def _received_notification( 85 | self, 86 | notification: ReceiveNotificationT 87 | ) -> None: 88 | """Handle incoming notification from other side.""" 89 | # Notification handling implementation 90 | ``` 91 | 92 | 93 | 94 | Key classes include: 95 | 96 | * `Protocol` 97 | * `Client` 98 | * `Server` 99 | 100 | ### Transport layer 101 | 102 | The transport layer handles the actual communication between clients and servers. MCP supports multiple transport mechanisms: 103 | 104 | 1. **Stdio transport** 105 | * Uses standard input/output for communication 106 | * Ideal for local processes 107 | 108 | 2. **HTTP with SSE transport** 109 | * Uses Server-Sent Events for server-to-client messages 110 | * HTTP POST for client-to-server messages 111 | 112 | All transports use [JSON-RPC](https://www.jsonrpc.org/) 2.0 to exchange messages. See the [specification](https://spec.modelcontextprotocol.io) for detailed information about the Model Context Protocol message format. 113 | 114 | ### Message types 115 | 116 | MCP has these main types of messages: 117 | 118 | 1. **Requests** expect a response from the other side: 119 | ```typescript 120 | interface Request { 121 | method: string; 122 | params?: { ... }; 123 | } 124 | ``` 125 | 126 | 2. **Results** are successful responses to requests: 127 | ```typescript 128 | interface Result { 129 | [key: string]: unknown; 130 | } 131 | ``` 132 | 133 | 3. **Errors** indicate that a request failed: 134 | ```typescript 135 | interface Error { 136 | code: number; 137 | message: string; 138 | data?: unknown; 139 | } 140 | ``` 141 | 142 | 4. **Notifications** are one-way messages that don't expect a response: 143 | ```typescript 144 | interface Notification { 145 | method: string; 146 | params?: { ... }; 147 | } 148 | ``` 149 | 150 | ## Connection lifecycle 151 | 152 | ### 1. Initialization 153 | 154 | ```mermaid 155 | sequenceDiagram 156 | participant Client 157 | participant Server 158 | 159 | Client->>Server: initialize request 160 | Server->>Client: initialize response 161 | Client->>Server: initialized notification 162 | 163 | Note over Client,Server: Connection ready for use 164 | ``` 165 | 166 | 1. Client sends `initialize` request with protocol version and capabilities 167 | 2. Server responds with its protocol version and capabilities 168 | 3. Client sends `initialized` notification as acknowledgment 169 | 4. Normal message exchange begins 170 | 171 | ### 2. Message exchange 172 | 173 | After initialization, the following patterns are supported: 174 | 175 | * **Request-Response**: Client or server sends requests, the other responds 176 | * **Notifications**: Either party sends one-way messages 177 | 178 | ### 3. Termination 179 | 180 | Either party can terminate the connection: 181 | 182 | * Clean shutdown via `close()` 183 | * Transport disconnection 184 | * Error conditions 185 | 186 | ## Error handling 187 | 188 | MCP defines these standard error codes: 189 | 190 | ```typescript 191 | enum ErrorCode { 192 | // Standard JSON-RPC error codes 193 | ParseError = -32700, 194 | InvalidRequest = -32600, 195 | MethodNotFound = -32601, 196 | InvalidParams = -32602, 197 | InternalError = -32603 198 | } 199 | ``` 200 | 201 | SDKs and applications can define their own error codes above -32000. 202 | 203 | Errors are propagated through: 204 | 205 | * Error responses to requests 206 | * Error events on transports 207 | * Protocol-level error handlers 208 | 209 | ## Implementation example 210 | 211 | Here's a basic example of implementing an MCP server: 212 | 213 | 214 | 215 | ```typescript 216 | import { Server } from "@modelcontextprotocol/sdk/server/index.js"; 217 | import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; 218 | 219 | const server = new Server({ 220 | name: "example-server", 221 | version: "1.0.0" 222 | }, { 223 | capabilities: { 224 | resources: {} 225 | } 226 | }); 227 | 228 | // Handle requests 229 | server.setRequestHandler(ListResourcesRequestSchema, async () => { 230 | return { 231 | resources: [ 232 | { 233 | uri: "example://resource", 234 | name: "Example Resource" 235 | } 236 | ] 237 | }; 238 | }); 239 | 240 | // Connect transport 241 | const transport = new StdioServerTransport(); 242 | await server.connect(transport); 243 | ``` 244 | 245 | 246 | 247 | ```python 248 | import asyncio 249 | import mcp.types as types 250 | from mcp.server import Server 251 | from mcp.server.stdio import stdio_server 252 | 253 | app = Server("example-server") 254 | 255 | @app.list_resources() 256 | async def list_resources() -> list[types.Resource]: 257 | return [ 258 | types.Resource( 259 | uri="example://resource", 260 | name="Example Resource" 261 | ) 262 | ] 263 | 264 | async def main(): 265 | async with stdio_server() as streams: 266 | await app.run( 267 | streams[0], 268 | streams[1], 269 | app.create_initialization_options() 270 | ) 271 | 272 | if __name__ == "__main__": 273 | asyncio.run(main) 274 | ``` 275 | 276 | 277 | 278 | ## Best practices 279 | 280 | ### Transport selection 281 | 282 | 1. **Local communication** 283 | * Use stdio transport for local processes 284 | * Efficient for same-machine communication 285 | * Simple process management 286 | 287 | 2. **Remote communication** 288 | * Use SSE for scenarios requiring HTTP compatibility 289 | * Consider security implications including authentication and authorization 290 | 291 | ### Message handling 292 | 293 | 1. **Request processing** 294 | * Validate inputs thoroughly 295 | * Use type-safe schemas 296 | * Handle errors gracefully 297 | * Implement timeouts 298 | 299 | 2. **Progress reporting** 300 | * Use progress tokens for long operations 301 | * Report progress incrementally 302 | * Include total progress when known 303 | 304 | 3. **Error management** 305 | * Use appropriate error codes 306 | * Include helpful error messages 307 | * Clean up resources on errors 308 | 309 | ## Security considerations 310 | 311 | 1. **Transport security** 312 | * Use TLS for remote connections 313 | * Validate connection origins 314 | * Implement authentication when needed 315 | 316 | 2. **Message validation** 317 | * Validate all incoming messages 318 | * Sanitize inputs 319 | * Check message size limits 320 | * Verify JSON-RPC format 321 | 322 | 3. **Resource protection** 323 | * Implement access controls 324 | * Validate resource paths 325 | * Monitor resource usage 326 | * Rate limit requests 327 | 328 | 4. **Error handling** 329 | * Don't leak sensitive information 330 | * Log security-relevant errors 331 | * Implement proper cleanup 332 | * Handle DoS scenarios 333 | 334 | ## Debugging and monitoring 335 | 336 | 1. **Logging** 337 | * Log protocol events 338 | * Track message flow 339 | * Monitor performance 340 | * Record errors 341 | 342 | 2. **Diagnostics** 343 | * Implement health checks 344 | * Monitor connection state 345 | * Track resource usage 346 | * Profile performance 347 | 348 | 3. **Testing** 349 | * Test different transports 350 | * Verify error handling 351 | * Check edge cases 352 | * Load test servers 353 | -------------------------------------------------------------------------------- /docs/mcp/modelcontextprotocol.io-docs-concepts-prompts.md: -------------------------------------------------------------------------------- 1 | # Prompts 2 | 3 | > Create reusable prompt templates and workflows 4 | 5 | Prompts enable servers to define reusable prompt templates and workflows that clients can easily surface to users and LLMs. They provide a powerful way to standardize and share common LLM interactions. 6 | 7 | 8 | Prompts are designed to be **user-controlled**, meaning they are exposed from servers to clients with the intention of the user being able to explicitly select them for use. 9 | 10 | 11 | ## Overview 12 | 13 | Prompts in MCP are predefined templates that can: 14 | 15 | * Accept dynamic arguments 16 | * Include context from resources 17 | * Chain multiple interactions 18 | * Guide specific workflows 19 | * Surface as UI elements (like slash commands) 20 | 21 | ## Prompt structure 22 | 23 | Each prompt is defined with: 24 | 25 | ```typescript 26 | { 27 | name: string; // Unique identifier for the prompt 28 | description?: string; // Human-readable description 29 | arguments?: [ // Optional list of arguments 30 | { 31 | name: string; // Argument identifier 32 | description?: string; // Argument description 33 | required?: boolean; // Whether argument is required 34 | } 35 | ] 36 | } 37 | ``` 38 | 39 | ## Discovering prompts 40 | 41 | Clients can discover available prompts through the `prompts/list` endpoint: 42 | 43 | ```typescript 44 | // Request 45 | { 46 | method: "prompts/list" 47 | } 48 | 49 | // Response 50 | { 51 | prompts: [ 52 | { 53 | name: "analyze-code", 54 | description: "Analyze code for potential improvements", 55 | arguments: [ 56 | { 57 | name: "language", 58 | description: "Programming language", 59 | required: true 60 | } 61 | ] 62 | } 63 | ] 64 | } 65 | ``` 66 | 67 | ## Using prompts 68 | 69 | To use a prompt, clients make a `prompts/get` request: 70 | 71 | ````typescript 72 | // Request 73 | { 74 | method: "prompts/get", 75 | params: { 76 | name: "analyze-code", 77 | arguments: { 78 | language: "python" 79 | } 80 | } 81 | } 82 | 83 | // Response 84 | { 85 | description: "Analyze Python code for potential improvements", 86 | messages: [ 87 | { 88 | role: "user", 89 | content: { 90 | type: "text", 91 | text: "Please analyze the following Python code for potential improvements:\n\n```python\ndef calculate_sum(numbers):\n total = 0\n for num in numbers:\n total = total + num\n return total\n\nresult = calculate_sum([1, 2, 3, 4, 5])\nprint(result)\n```" 92 | } 93 | } 94 | ] 95 | } 96 | ```` 97 | 98 | ## Dynamic prompts 99 | 100 | Prompts can be dynamic and include: 101 | 102 | ### Embedded resource context 103 | 104 | ```json 105 | { 106 | "name": "analyze-project", 107 | "description": "Analyze project logs and code", 108 | "arguments": [ 109 | { 110 | "name": "timeframe", 111 | "description": "Time period to analyze logs", 112 | "required": true 113 | }, 114 | { 115 | "name": "fileUri", 116 | "description": "URI of code file to review", 117 | "required": true 118 | } 119 | ] 120 | } 121 | ``` 122 | 123 | When handling the `prompts/get` request: 124 | 125 | ```json 126 | { 127 | "messages": [ 128 | { 129 | "role": "user", 130 | "content": { 131 | "type": "text", 132 | "text": "Analyze these system logs and the code file for any issues:" 133 | } 134 | }, 135 | { 136 | "role": "user", 137 | "content": { 138 | "type": "resource", 139 | "resource": { 140 | "uri": "logs://recent?timeframe=1h", 141 | "text": "[2024-03-14 15:32:11] ERROR: Connection timeout in network.py:127\n[2024-03-14 15:32:15] WARN: Retrying connection (attempt 2/3)\n[2024-03-14 15:32:20] ERROR: Max retries exceeded", 142 | "mimeType": "text/plain" 143 | } 144 | } 145 | }, 146 | { 147 | "role": "user", 148 | "content": { 149 | "type": "resource", 150 | "resource": { 151 | "uri": "file:///path/to/code.py", 152 | "text": "def connect_to_service(timeout=30):\n retries = 3\n for attempt in range(retries):\n try:\n return establish_connection(timeout)\n except TimeoutError:\n if attempt == retries - 1:\n raise\n time.sleep(5)\n\ndef establish_connection(timeout):\n # Connection implementation\n pass", 153 | "mimeType": "text/x-python" 154 | } 155 | } 156 | } 157 | ] 158 | } 159 | ``` 160 | 161 | ### Multi-step workflows 162 | 163 | ```typescript 164 | const debugWorkflow = { 165 | name: "debug-error", 166 | async getMessages(error: string) { 167 | return [ 168 | { 169 | role: "user", 170 | content: { 171 | type: "text", 172 | text: `Here's an error I'm seeing: ${error}` 173 | } 174 | }, 175 | { 176 | role: "assistant", 177 | content: { 178 | type: "text", 179 | text: "I'll help analyze this error. What have you tried so far?" 180 | } 181 | }, 182 | { 183 | role: "user", 184 | content: { 185 | type: "text", 186 | text: "I've tried restarting the service, but the error persists." 187 | } 188 | } 189 | ]; 190 | } 191 | }; 192 | ``` 193 | 194 | ## Example implementation 195 | 196 | Here's a complete example of implementing prompts in an MCP server: 197 | 198 | 199 | 200 | ```typescript 201 | import { Server } from "@modelcontextprotocol/sdk/server"; 202 | import { 203 | ListPromptsRequestSchema, 204 | GetPromptRequestSchema 205 | } from "@modelcontextprotocol/sdk/types"; 206 | 207 | const PROMPTS = { 208 | "git-commit": { 209 | name: "git-commit", 210 | description: "Generate a Git commit message", 211 | arguments: [ 212 | { 213 | name: "changes", 214 | description: "Git diff or description of changes", 215 | required: true 216 | } 217 | ] 218 | }, 219 | "explain-code": { 220 | name: "explain-code", 221 | description: "Explain how code works", 222 | arguments: [ 223 | { 224 | name: "code", 225 | description: "Code to explain", 226 | required: true 227 | }, 228 | { 229 | name: "language", 230 | description: "Programming language", 231 | required: false 232 | } 233 | ] 234 | } 235 | }; 236 | 237 | const server = new Server({ 238 | name: "example-prompts-server", 239 | version: "1.0.0" 240 | }, { 241 | capabilities: { 242 | prompts: {} 243 | } 244 | }); 245 | 246 | // List available prompts 247 | server.setRequestHandler(ListPromptsRequestSchema, async () => { 248 | return { 249 | prompts: Object.values(PROMPTS) 250 | }; 251 | }); 252 | 253 | // Get specific prompt 254 | server.setRequestHandler(GetPromptRequestSchema, async (request) => { 255 | const prompt = PROMPTS[request.params.name]; 256 | if (!prompt) { 257 | throw new Error(`Prompt not found: ${request.params.name}`); 258 | } 259 | 260 | if (request.params.name === "git-commit") { 261 | return { 262 | messages: [ 263 | { 264 | role: "user", 265 | content: { 266 | type: "text", 267 | text: `Generate a concise but descriptive commit message for these changes:\n\n${request.params.arguments?.changes}` 268 | } 269 | } 270 | ] 271 | }; 272 | } 273 | 274 | if (request.params.name === "explain-code") { 275 | const language = request.params.arguments?.language || "Unknown"; 276 | return { 277 | messages: [ 278 | { 279 | role: "user", 280 | content: { 281 | type: "text", 282 | text: `Explain how this ${language} code works:\n\n${request.params.arguments?.code}` 283 | } 284 | } 285 | ] 286 | }; 287 | } 288 | 289 | throw new Error("Prompt implementation not found"); 290 | }); 291 | ``` 292 | 293 | 294 | 295 | ```python 296 | from mcp.server import Server 297 | import mcp.types as types 298 | 299 | # Define available prompts 300 | PROMPTS = { 301 | "git-commit": types.Prompt( 302 | name="git-commit", 303 | description="Generate a Git commit message", 304 | arguments=[ 305 | types.PromptArgument( 306 | name="changes", 307 | description="Git diff or description of changes", 308 | required=True 309 | ) 310 | ], 311 | ), 312 | "explain-code": types.Prompt( 313 | name="explain-code", 314 | description="Explain how code works", 315 | arguments=[ 316 | types.PromptArgument( 317 | name="code", 318 | description="Code to explain", 319 | required=True 320 | ), 321 | types.PromptArgument( 322 | name="language", 323 | description="Programming language", 324 | required=False 325 | ) 326 | ], 327 | ) 328 | } 329 | 330 | # Initialize server 331 | app = Server("example-prompts-server") 332 | 333 | @app.list_prompts() 334 | async def list_prompts() -> list[types.Prompt]: 335 | return list(PROMPTS.values()) 336 | 337 | @app.get_prompt() 338 | async def get_prompt( 339 | name: str, arguments: dict[str, str] | None = None 340 | ) -> types.GetPromptResult: 341 | if name not in PROMPTS: 342 | raise ValueError(f"Prompt not found: {name}") 343 | 344 | if name == "git-commit": 345 | changes = arguments.get("changes") if arguments else "" 346 | return types.GetPromptResult( 347 | messages=[ 348 | types.PromptMessage( 349 | role="user", 350 | content=types.TextContent( 351 | type="text", 352 | text=f"Generate a concise but descriptive commit message " 353 | f"for these changes:\n\n{changes}" 354 | ) 355 | ) 356 | ] 357 | ) 358 | 359 | if name == "explain-code": 360 | code = arguments.get("code") if arguments else "" 361 | language = arguments.get("language", "Unknown") if arguments else "Unknown" 362 | return types.GetPromptResult( 363 | messages=[ 364 | types.PromptMessage( 365 | role="user", 366 | content=types.TextContent( 367 | type="text", 368 | text=f"Explain how this {language} code works:\n\n{code}" 369 | ) 370 | ) 371 | ] 372 | ) 373 | 374 | raise ValueError("Prompt implementation not found") 375 | ``` 376 | 377 | 378 | 379 | ## Best practices 380 | 381 | When implementing prompts: 382 | 383 | 1. Use clear, descriptive prompt names 384 | 2. Provide detailed descriptions for prompts and arguments 385 | 3. Validate all required arguments 386 | 4. Handle missing arguments gracefully 387 | 5. Consider versioning for prompt templates 388 | 6. Cache dynamic content when appropriate 389 | 7. Implement error handling 390 | 8. Document expected argument formats 391 | 9. Consider prompt composability 392 | 10. Test prompts with various inputs 393 | 394 | ## UI integration 395 | 396 | Prompts can be surfaced in client UIs as: 397 | 398 | * Slash commands 399 | * Quick actions 400 | * Context menu items 401 | * Command palette entries 402 | * Guided workflows 403 | * Interactive forms 404 | 405 | ## Updates and changes 406 | 407 | Servers can notify clients about prompt changes: 408 | 409 | 1. Server capability: `prompts.listChanged` 410 | 2. Notification: `notifications/prompts/list_changed` 411 | 3. Client re-fetches prompt list 412 | 413 | ## Security considerations 414 | 415 | When implementing prompts: 416 | 417 | * Validate all arguments 418 | * Sanitize user input 419 | * Consider rate limiting 420 | * Implement access controls 421 | * Audit prompt usage 422 | * Handle sensitive data appropriately 423 | * Validate generated content 424 | * Implement timeouts 425 | * Consider prompt injection risks 426 | * Document security requirements 427 | -------------------------------------------------------------------------------- /docs/mcp/modelcontextprotocol.io-docs-concepts-resources.md: -------------------------------------------------------------------------------- 1 | # Resources 2 | 3 | > Expose data and content from your servers to LLMs 4 | 5 | Resources are a core primitive in the Model Context Protocol (MCP) that allow servers to expose data and content that can be read by clients and used as context for LLM interactions. 6 | 7 | 8 | Resources are designed to be **application-controlled**, meaning that the client application can decide how and when they should be used. 9 | Different MCP clients may handle resources differently. For example: 10 | 11 | * Claude Desktop currently requires users to explicitly select resources before they can be used 12 | * Other clients might automatically select resources based on heuristics 13 | * Some implementations may even allow the AI model itself to determine which resources to use 14 | 15 | Server authors should be prepared to handle any of these interaction patterns when implementing resource support. In order to expose data to models automatically, server authors should use a **model-controlled** primitive such as [Tools](./tools). 16 | 17 | 18 | ## Overview 19 | 20 | Resources represent any kind of data that an MCP server wants to make available to clients. This can include: 21 | 22 | * File contents 23 | * Database records 24 | * API responses 25 | * Live system data 26 | * Screenshots and images 27 | * Log files 28 | * And more 29 | 30 | Each resource is identified by a unique URI and can contain either text or binary data. 31 | 32 | ## Resource URIs 33 | 34 | Resources are identified using URIs that follow this format: 35 | 36 | ``` 37 | [protocol]://[host]/[path] 38 | ``` 39 | 40 | For example: 41 | 42 | * `file:///home/user/documents/report.pdf` 43 | * `postgres://database/customers/schema` 44 | * `screen://localhost/display1` 45 | 46 | The protocol and path structure is defined by the MCP server implementation. Servers can define their own custom URI schemes. 47 | 48 | ## Resource types 49 | 50 | Resources can contain two types of content: 51 | 52 | ### Text resources 53 | 54 | Text resources contain UTF-8 encoded text data. These are suitable for: 55 | 56 | * Source code 57 | * Configuration files 58 | * Log files 59 | * JSON/XML data 60 | * Plain text 61 | 62 | ### Binary resources 63 | 64 | Binary resources contain raw binary data encoded in base64. These are suitable for: 65 | 66 | * Images 67 | * PDFs 68 | * Audio files 69 | * Video files 70 | * Other non-text formats 71 | 72 | ## Resource discovery 73 | 74 | Clients can discover available resources through two main methods: 75 | 76 | ### Direct resources 77 | 78 | Servers expose a list of concrete resources via the `resources/list` endpoint. Each resource includes: 79 | 80 | ```typescript 81 | { 82 | uri: string; // Unique identifier for the resource 83 | name: string; // Human-readable name 84 | description?: string; // Optional description 85 | mimeType?: string; // Optional MIME type 86 | } 87 | ``` 88 | 89 | ### Resource templates 90 | 91 | For dynamic resources, servers can expose [URI templates](https://datatracker.ietf.org/doc/html/rfc6570) that clients can use to construct valid resource URIs: 92 | 93 | ```typescript 94 | { 95 | uriTemplate: string; // URI template following RFC 6570 96 | name: string; // Human-readable name for this type 97 | description?: string; // Optional description 98 | mimeType?: string; // Optional MIME type for all matching resources 99 | } 100 | ``` 101 | 102 | ## Reading resources 103 | 104 | To read a resource, clients make a `resources/read` request with the resource URI. 105 | 106 | The server responds with a list of resource contents: 107 | 108 | ```typescript 109 | { 110 | contents: [ 111 | { 112 | uri: string; // The URI of the resource 113 | mimeType?: string; // Optional MIME type 114 | 115 | // One of: 116 | text?: string; // For text resources 117 | blob?: string; // For binary resources (base64 encoded) 118 | } 119 | ] 120 | } 121 | ``` 122 | 123 | 124 | Servers may return multiple resources in response to one `resources/read` request. This could be used, for example, to return a list of files inside a directory when the directory is read. 125 | 126 | 127 | ## Resource updates 128 | 129 | MCP supports real-time updates for resources through two mechanisms: 130 | 131 | ### List changes 132 | 133 | Servers can notify clients when their list of available resources changes via the `notifications/resources/list_changed` notification. 134 | 135 | ### Content changes 136 | 137 | Clients can subscribe to updates for specific resources: 138 | 139 | 1. Client sends `resources/subscribe` with resource URI 140 | 2. Server sends `notifications/resources/updated` when the resource changes 141 | 3. Client can fetch latest content with `resources/read` 142 | 4. Client can unsubscribe with `resources/unsubscribe` 143 | 144 | ## Example implementation 145 | 146 | Here's a simple example of implementing resource support in an MCP server: 147 | 148 | 149 | 150 | ```typescript 151 | const server = new Server({ 152 | name: "example-server", 153 | version: "1.0.0" 154 | }, { 155 | capabilities: { 156 | resources: {} 157 | } 158 | }); 159 | 160 | // List available resources 161 | server.setRequestHandler(ListResourcesRequestSchema, async () => { 162 | return { 163 | resources: [ 164 | { 165 | uri: "file:///logs/app.log", 166 | name: "Application Logs", 167 | mimeType: "text/plain" 168 | } 169 | ] 170 | }; 171 | }); 172 | 173 | // Read resource contents 174 | server.setRequestHandler(ReadResourceRequestSchema, async (request) => { 175 | const uri = request.params.uri; 176 | 177 | if (uri === "file:///logs/app.log") { 178 | const logContents = await readLogFile(); 179 | return { 180 | contents: [ 181 | { 182 | uri, 183 | mimeType: "text/plain", 184 | text: logContents 185 | } 186 | ] 187 | }; 188 | } 189 | 190 | throw new Error("Resource not found"); 191 | }); 192 | ``` 193 | 194 | 195 | 196 | ```python 197 | app = Server("example-server") 198 | 199 | @app.list_resources() 200 | async def list_resources() -> list[types.Resource]: 201 | return [ 202 | types.Resource( 203 | uri="file:///logs/app.log", 204 | name="Application Logs", 205 | mimeType="text/plain" 206 | ) 207 | ] 208 | 209 | @app.read_resource() 210 | async def read_resource(uri: AnyUrl) -> str: 211 | if str(uri) == "file:///logs/app.log": 212 | log_contents = await read_log_file() 213 | return log_contents 214 | 215 | raise ValueError("Resource not found") 216 | 217 | # Start server 218 | async with stdio_server() as streams: 219 | await app.run( 220 | streams[0], 221 | streams[1], 222 | app.create_initialization_options() 223 | ) 224 | ``` 225 | 226 | 227 | 228 | ## Best practices 229 | 230 | When implementing resource support: 231 | 232 | 1. Use clear, descriptive resource names and URIs 233 | 2. Include helpful descriptions to guide LLM understanding 234 | 3. Set appropriate MIME types when known 235 | 4. Implement resource templates for dynamic content 236 | 5. Use subscriptions for frequently changing resources 237 | 6. Handle errors gracefully with clear error messages 238 | 7. Consider pagination for large resource lists 239 | 8. Cache resource contents when appropriate 240 | 9. Validate URIs before processing 241 | 10. Document your custom URI schemes 242 | 243 | ## Security considerations 244 | 245 | When exposing resources: 246 | 247 | * Validate all resource URIs 248 | * Implement appropriate access controls 249 | * Sanitize file paths to prevent directory traversal 250 | * Be cautious with binary data handling 251 | * Consider rate limiting for resource reads 252 | * Audit resource access 253 | * Encrypt sensitive data in transit 254 | * Validate MIME types 255 | * Implement timeouts for long-running reads 256 | * Handle resource cleanup appropriately 257 | -------------------------------------------------------------------------------- /docs/mcp/modelcontextprotocol.io-docs-concepts-roots.md: -------------------------------------------------------------------------------- 1 | # Roots 2 | 3 | > Understanding roots in MCP 4 | 5 | Roots are a concept in MCP that define the boundaries where servers can operate. They provide a way for clients to inform servers about relevant resources and their locations. 6 | 7 | ## What are Roots? 8 | 9 | A root is a URI that a client suggests a server should focus on. When a client connects to a server, it declares which roots the server should work with. While primarily used for filesystem paths, roots can be any valid URI including HTTP URLs. 10 | 11 | For example, roots could be: 12 | 13 | ``` 14 | file:///home/user/projects/myapp 15 | https://api.example.com/v1 16 | ``` 17 | 18 | ## Why Use Roots? 19 | 20 | Roots serve several important purposes: 21 | 22 | 1. **Guidance**: They inform servers about relevant resources and locations 23 | 2. **Clarity**: Roots make it clear which resources are part of your workspace 24 | 3. **Organization**: Multiple roots let you work with different resources simultaneously 25 | 26 | ## How Roots Work 27 | 28 | When a client supports roots, it: 29 | 30 | 1. Declares the `roots` capability during connection 31 | 2. Provides a list of suggested roots to the server 32 | 3. Notifies the server when roots change (if supported) 33 | 34 | While roots are informational and not strictly enforcing, servers should: 35 | 36 | 1. Respect the provided roots 37 | 2. Use root URIs to locate and access resources 38 | 3. Prioritize operations within root boundaries 39 | 40 | ## Common Use Cases 41 | 42 | Roots are commonly used to define: 43 | 44 | * Project directories 45 | * Repository locations 46 | * API endpoints 47 | * Configuration locations 48 | * Resource boundaries 49 | 50 | ## Best Practices 51 | 52 | When working with roots: 53 | 54 | 1. Only suggest necessary resources 55 | 2. Use clear, descriptive names for roots 56 | 3. Monitor root accessibility 57 | 4. Handle root changes gracefully 58 | 59 | ## Example 60 | 61 | Here's how a typical MCP client might expose roots: 62 | 63 | ```json 64 | { 65 | "roots": [ 66 | { 67 | "uri": "file:///home/user/projects/frontend", 68 | "name": "Frontend Repository" 69 | }, 70 | { 71 | "uri": "https://api.example.com/v1", 72 | "name": "API Endpoint" 73 | } 74 | ] 75 | } 76 | ``` 77 | 78 | This configuration suggests the server focus on both a local repository and an API endpoint while keeping them logically separated. 79 | -------------------------------------------------------------------------------- /docs/mcp/modelcontextprotocol.io-docs-concepts-sampling.md: -------------------------------------------------------------------------------- 1 | # Sampling 2 | 3 | > Let your servers request completions from LLMs 4 | 5 | Sampling is a powerful MCP feature that allows servers to request LLM completions through the client, enabling sophisticated agentic behaviors while maintaining security and privacy. 6 | 7 | 8 | This feature of MCP is not yet supported in the Claude Desktop client. 9 | 10 | 11 | ## How sampling works 12 | 13 | The sampling flow follows these steps: 14 | 15 | 1. Server sends a `sampling/createMessage` request to the client 16 | 2. Client reviews the request and can modify it 17 | 3. Client samples from an LLM 18 | 4. Client reviews the completion 19 | 5. Client returns the result to the server 20 | 21 | This human-in-the-loop design ensures users maintain control over what the LLM sees and generates. 22 | 23 | ## Message format 24 | 25 | Sampling requests use a standardized message format: 26 | 27 | ```typescript 28 | { 29 | messages: [ 30 | { 31 | role: "user" | "assistant", 32 | content: { 33 | type: "text" | "image", 34 | 35 | // For text: 36 | text?: string, 37 | 38 | // For images: 39 | data?: string, // base64 encoded 40 | mimeType?: string 41 | } 42 | } 43 | ], 44 | modelPreferences?: { 45 | hints?: [{ 46 | name?: string // Suggested model name/family 47 | }], 48 | costPriority?: number, // 0-1, importance of minimizing cost 49 | speedPriority?: number, // 0-1, importance of low latency 50 | intelligencePriority?: number // 0-1, importance of capabilities 51 | }, 52 | systemPrompt?: string, 53 | includeContext?: "none" | "thisServer" | "allServers", 54 | temperature?: number, 55 | maxTokens: number, 56 | stopSequences?: string[], 57 | metadata?: Record 58 | } 59 | ``` 60 | 61 | ## Request parameters 62 | 63 | ### Messages 64 | 65 | The `messages` array contains the conversation history to send to the LLM. Each message has: 66 | 67 | * `role`: Either "user" or "assistant" 68 | * `content`: The message content, which can be: 69 | * Text content with a `text` field 70 | * Image content with `data` (base64) and `mimeType` fields 71 | 72 | ### Model preferences 73 | 74 | The `modelPreferences` object allows servers to specify their model selection preferences: 75 | 76 | * `hints`: Array of model name suggestions that clients can use to select an appropriate model: 77 | * `name`: String that can match full or partial model names (e.g. "claude-3", "sonnet") 78 | * Clients may map hints to equivalent models from different providers 79 | * Multiple hints are evaluated in preference order 80 | 81 | * Priority values (0-1 normalized): 82 | * `costPriority`: Importance of minimizing costs 83 | * `speedPriority`: Importance of low latency response 84 | * `intelligencePriority`: Importance of advanced model capabilities 85 | 86 | Clients make the final model selection based on these preferences and their available models. 87 | 88 | ### System prompt 89 | 90 | An optional `systemPrompt` field allows servers to request a specific system prompt. The client may modify or ignore this. 91 | 92 | ### Context inclusion 93 | 94 | The `includeContext` parameter specifies what MCP context to include: 95 | 96 | * `"none"`: No additional context 97 | * `"thisServer"`: Include context from the requesting server 98 | * `"allServers"`: Include context from all connected MCP servers 99 | 100 | The client controls what context is actually included. 101 | 102 | ### Sampling parameters 103 | 104 | Fine-tune the LLM sampling with: 105 | 106 | * `temperature`: Controls randomness (0.0 to 1.0) 107 | * `maxTokens`: Maximum tokens to generate 108 | * `stopSequences`: Array of sequences that stop generation 109 | * `metadata`: Additional provider-specific parameters 110 | 111 | ## Response format 112 | 113 | The client returns a completion result: 114 | 115 | ```typescript 116 | { 117 | model: string, // Name of the model used 118 | stopReason?: "endTurn" | "stopSequence" | "maxTokens" | string, 119 | role: "user" | "assistant", 120 | content: { 121 | type: "text" | "image", 122 | text?: string, 123 | data?: string, 124 | mimeType?: string 125 | } 126 | } 127 | ``` 128 | 129 | ## Example request 130 | 131 | Here's an example of requesting sampling from a client: 132 | 133 | ```json 134 | { 135 | "method": "sampling/createMessage", 136 | "params": { 137 | "messages": [ 138 | { 139 | "role": "user", 140 | "content": { 141 | "type": "text", 142 | "text": "What files are in the current directory?" 143 | } 144 | } 145 | ], 146 | "systemPrompt": "You are a helpful file system assistant.", 147 | "includeContext": "thisServer", 148 | "maxTokens": 100 149 | } 150 | } 151 | ``` 152 | 153 | ## Best practices 154 | 155 | When implementing sampling: 156 | 157 | 1. Always provide clear, well-structured prompts 158 | 2. Handle both text and image content appropriately 159 | 3. Set reasonable token limits 160 | 4. Include relevant context through `includeContext` 161 | 5. Validate responses before using them 162 | 6. Handle errors gracefully 163 | 7. Consider rate limiting sampling requests 164 | 8. Document expected sampling behavior 165 | 9. Test with various model parameters 166 | 10. Monitor sampling costs 167 | 168 | ## Human in the loop controls 169 | 170 | Sampling is designed with human oversight in mind: 171 | 172 | ### For prompts 173 | 174 | * Clients should show users the proposed prompt 175 | * Users should be able to modify or reject prompts 176 | * System prompts can be filtered or modified 177 | * Context inclusion is controlled by the client 178 | 179 | ### For completions 180 | 181 | * Clients should show users the completion 182 | * Users should be able to modify or reject completions 183 | * Clients can filter or modify completions 184 | * Users control which model is used 185 | 186 | ## Security considerations 187 | 188 | When implementing sampling: 189 | 190 | * Validate all message content 191 | * Sanitize sensitive information 192 | * Implement appropriate rate limits 193 | * Monitor sampling usage 194 | * Encrypt data in transit 195 | * Handle user data privacy 196 | * Audit sampling requests 197 | * Control cost exposure 198 | * Implement timeouts 199 | * Handle model errors gracefully 200 | 201 | ## Common patterns 202 | 203 | ### Agentic workflows 204 | 205 | Sampling enables agentic patterns like: 206 | 207 | * Reading and analyzing resources 208 | * Making decisions based on context 209 | * Generating structured data 210 | * Handling multi-step tasks 211 | * Providing interactive assistance 212 | 213 | ### Context management 214 | 215 | Best practices for context: 216 | 217 | * Request minimal necessary context 218 | * Structure context clearly 219 | * Handle context size limits 220 | * Update context as needed 221 | * Clean up stale context 222 | 223 | ### Error handling 224 | 225 | Robust error handling should: 226 | 227 | * Catch sampling failures 228 | * Handle timeout errors 229 | * Manage rate limits 230 | * Validate responses 231 | * Provide fallback behaviors 232 | * Log errors appropriately 233 | 234 | ## Limitations 235 | 236 | Be aware of these limitations: 237 | 238 | * Sampling depends on client capabilities 239 | * Users control sampling behavior 240 | * Context size has limits 241 | * Rate limits may apply 242 | * Costs should be considered 243 | * Model availability varies 244 | * Response times vary 245 | * Not all content types supported 246 | -------------------------------------------------------------------------------- /docs/mcp/modelcontextprotocol.io-docs-concepts-tools.md: -------------------------------------------------------------------------------- 1 | # Tools 2 | 3 | > Enable LLMs to perform actions through your server 4 | 5 | Tools are a powerful primitive in the Model Context Protocol (MCP) that enable servers to expose executable functionality to clients. Through tools, LLMs can interact with external systems, perform computations, and take actions in the real world. 6 | 7 | 8 | Tools are designed to be **model-controlled**, meaning that tools are exposed from servers to clients with the intention of the AI model being able to automatically invoke them (with a human in the loop to grant approval). 9 | 10 | 11 | ## Overview 12 | 13 | Tools in MCP allow servers to expose executable functions that can be invoked by clients and used by LLMs to perform actions. Key aspects of tools include: 14 | 15 | * **Discovery**: Clients can list available tools through the `tools/list` endpoint 16 | * **Invocation**: Tools are called using the `tools/call` endpoint, where servers perform the requested operation and return results 17 | * **Flexibility**: Tools can range from simple calculations to complex API interactions 18 | 19 | Like [resources](/docs/concepts/resources), tools are identified by unique names and can include descriptions to guide their usage. However, unlike resources, tools represent dynamic operations that can modify state or interact with external systems. 20 | 21 | ## Tool definition structure 22 | 23 | Each tool is defined with the following structure: 24 | 25 | ```typescript 26 | { 27 | name: string; // Unique identifier for the tool 28 | description?: string; // Human-readable description 29 | inputSchema: { // JSON Schema for the tool's parameters 30 | type: "object", 31 | properties: { ... } // Tool-specific parameters 32 | } 33 | } 34 | ``` 35 | 36 | ## Implementing tools 37 | 38 | Here's an example of implementing a basic tool in an MCP server: 39 | 40 | 41 | 42 | ```typescript 43 | const server = new Server({ 44 | name: "example-server", 45 | version: "1.0.0" 46 | }, { 47 | capabilities: { 48 | tools: {} 49 | } 50 | }); 51 | 52 | // Define available tools 53 | server.setRequestHandler(ListToolsRequestSchema, async () => { 54 | return { 55 | tools: [{ 56 | name: "calculate_sum", 57 | description: "Add two numbers together", 58 | inputSchema: { 59 | type: "object", 60 | properties: { 61 | a: { type: "number" }, 62 | b: { type: "number" } 63 | }, 64 | required: ["a", "b"] 65 | } 66 | }] 67 | }; 68 | }); 69 | 70 | // Handle tool execution 71 | server.setRequestHandler(CallToolRequestSchema, async (request) => { 72 | if (request.params.name === "calculate_sum") { 73 | const { a, b } = request.params.arguments; 74 | return { 75 | content: [ 76 | { 77 | type: "text", 78 | text: String(a + b) 79 | } 80 | ] 81 | }; 82 | } 83 | throw new Error("Tool not found"); 84 | }); 85 | ``` 86 | 87 | 88 | 89 | ```python 90 | app = Server("example-server") 91 | 92 | @app.list_tools() 93 | async def list_tools() -> list[types.Tool]: 94 | return [ 95 | types.Tool( 96 | name="calculate_sum", 97 | description="Add two numbers together", 98 | inputSchema={ 99 | "type": "object", 100 | "properties": { 101 | "a": {"type": "number"}, 102 | "b": {"type": "number"} 103 | }, 104 | "required": ["a", "b"] 105 | } 106 | ) 107 | ] 108 | 109 | @app.call_tool() 110 | async def call_tool( 111 | name: str, 112 | arguments: dict 113 | ) -> list[types.TextContent | types.ImageContent | types.EmbeddedResource]: 114 | if name == "calculate_sum": 115 | a = arguments["a"] 116 | b = arguments["b"] 117 | result = a + b 118 | return [types.TextContent(type="text", text=str(result))] 119 | raise ValueError(f"Tool not found: {name}") 120 | ``` 121 | 122 | 123 | 124 | ## Example tool patterns 125 | 126 | Here are some examples of types of tools that a server could provide: 127 | 128 | ### System operations 129 | 130 | Tools that interact with the local system: 131 | 132 | ```typescript 133 | { 134 | name: "execute_command", 135 | description: "Run a shell command", 136 | inputSchema: { 137 | type: "object", 138 | properties: { 139 | command: { type: "string" }, 140 | args: { type: "array", items: { type: "string" } } 141 | } 142 | } 143 | } 144 | ``` 145 | 146 | ### API integrations 147 | 148 | Tools that wrap external APIs: 149 | 150 | ```typescript 151 | { 152 | name: "github_create_issue", 153 | description: "Create a GitHub issue", 154 | inputSchema: { 155 | type: "object", 156 | properties: { 157 | title: { type: "string" }, 158 | body: { type: "string" }, 159 | labels: { type: "array", items: { type: "string" } } 160 | } 161 | } 162 | } 163 | ``` 164 | 165 | ### Data processing 166 | 167 | Tools that transform or analyze data: 168 | 169 | ```typescript 170 | { 171 | name: "analyze_csv", 172 | description: "Analyze a CSV file", 173 | inputSchema: { 174 | type: "object", 175 | properties: { 176 | filepath: { type: "string" }, 177 | operations: { 178 | type: "array", 179 | items: { 180 | enum: ["sum", "average", "count"] 181 | } 182 | } 183 | } 184 | } 185 | } 186 | ``` 187 | 188 | ## Best practices 189 | 190 | When implementing tools: 191 | 192 | 1. Provide clear, descriptive names and descriptions 193 | 2. Use detailed JSON Schema definitions for parameters 194 | 3. Include examples in tool descriptions to demonstrate how the model should use them 195 | 4. Implement proper error handling and validation 196 | 5. Use progress reporting for long operations 197 | 6. Keep tool operations focused and atomic 198 | 7. Document expected return value structures 199 | 8. Implement proper timeouts 200 | 9. Consider rate limiting for resource-intensive operations 201 | 10. Log tool usage for debugging and monitoring 202 | 203 | ## Security considerations 204 | 205 | When exposing tools: 206 | 207 | ### Input validation 208 | 209 | * Validate all parameters against the schema 210 | * Sanitize file paths and system commands 211 | * Validate URLs and external identifiers 212 | * Check parameter sizes and ranges 213 | * Prevent command injection 214 | 215 | ### Access control 216 | 217 | * Implement authentication where needed 218 | * Use appropriate authorization checks 219 | * Audit tool usage 220 | * Rate limit requests 221 | * Monitor for abuse 222 | 223 | ### Error handling 224 | 225 | * Don't expose internal errors to clients 226 | * Log security-relevant errors 227 | * Handle timeouts appropriately 228 | * Clean up resources after errors 229 | * Validate return values 230 | 231 | ## Tool discovery and updates 232 | 233 | MCP supports dynamic tool discovery: 234 | 235 | 1. Clients can list available tools at any time 236 | 2. Servers can notify clients when tools change using `notifications/tools/list_changed` 237 | 3. Tools can be added or removed during runtime 238 | 4. Tool definitions can be updated (though this should be done carefully) 239 | 240 | ## Error handling 241 | 242 | Tool errors should be reported within the result object, not as MCP protocol-level errors. This allows the LLM to see and potentially handle the error. When a tool encounters an error: 243 | 244 | 1. Set `isError` to `true` in the result 245 | 2. Include error details in the `content` array 246 | 247 | Here's an example of proper error handling for tools: 248 | 249 | 250 | 251 | ```typescript 252 | try { 253 | // Tool operation 254 | const result = performOperation(); 255 | return { 256 | content: [ 257 | { 258 | type: "text", 259 | text: `Operation successful: ${result}` 260 | } 261 | ] 262 | }; 263 | } catch (error) { 264 | return { 265 | isError: true, 266 | content: [ 267 | { 268 | type: "text", 269 | text: `Error: ${error.message}` 270 | } 271 | ] 272 | }; 273 | } 274 | ``` 275 | 276 | 277 | 278 | ```python 279 | try: 280 | # Tool operation 281 | result = perform_operation() 282 | return types.CallToolResult( 283 | content=[ 284 | types.TextContent( 285 | type="text", 286 | text=f"Operation successful: {result}" 287 | ) 288 | ] 289 | ) 290 | except Exception as error: 291 | return types.CallToolResult( 292 | isError=True, 293 | content=[ 294 | types.TextContent( 295 | type="text", 296 | text=f"Error: {str(error)}" 297 | ) 298 | ] 299 | ) 300 | ``` 301 | 302 | 303 | 304 | This approach allows the LLM to see that an error occurred and potentially take corrective action or request human intervention. 305 | 306 | ## Testing tools 307 | 308 | A comprehensive testing strategy for MCP tools should cover: 309 | 310 | * **Functional testing**: Verify tools execute correctly with valid inputs and handle invalid inputs appropriately 311 | * **Integration testing**: Test tool interaction with external systems using both real and mocked dependencies 312 | * **Security testing**: Validate authentication, authorization, input sanitization, and rate limiting 313 | * **Performance testing**: Check behavior under load, timeout handling, and resource cleanup 314 | * **Error handling**: Ensure tools properly report errors through the MCP protocol and clean up resources 315 | -------------------------------------------------------------------------------- /docs/mcp/modelcontextprotocol.io-docs-concepts-transports.md: -------------------------------------------------------------------------------- 1 | # Transports 2 | 3 | > Learn about MCP's communication mechanisms 4 | 5 | Transports in the Model Context Protocol (MCP) provide the foundation for communication between clients and servers. A transport handles the underlying mechanics of how messages are sent and received. 6 | 7 | ## Message Format 8 | 9 | MCP uses [JSON-RPC](https://www.jsonrpc.org/) 2.0 as its wire format. The transport layer is responsible for converting MCP protocol messages into JSON-RPC format for transmission and converting received JSON-RPC messages back into MCP protocol messages. 10 | 11 | There are three types of JSON-RPC messages used: 12 | 13 | ### Requests 14 | 15 | ```typescript 16 | { 17 | jsonrpc: "2.0", 18 | id: number | string, 19 | method: string, 20 | params?: object 21 | } 22 | ``` 23 | 24 | ### Responses 25 | 26 | ```typescript 27 | { 28 | jsonrpc: "2.0", 29 | id: number | string, 30 | result?: object, 31 | error?: { 32 | code: number, 33 | message: string, 34 | data?: unknown 35 | } 36 | } 37 | ``` 38 | 39 | ### Notifications 40 | 41 | ```typescript 42 | { 43 | jsonrpc: "2.0", 44 | method: string, 45 | params?: object 46 | } 47 | ``` 48 | 49 | ## Built-in Transport Types 50 | 51 | MCP includes two standard transport implementations: 52 | 53 | ### Standard Input/Output (stdio) 54 | 55 | The stdio transport enables communication through standard input and output streams. This is particularly useful for local integrations and command-line tools. 56 | 57 | Use stdio when: 58 | 59 | * Building command-line tools 60 | * Implementing local integrations 61 | * Needing simple process communication 62 | * Working with shell scripts 63 | 64 | 65 | 66 | ```typescript 67 | const server = new Server({ 68 | name: "example-server", 69 | version: "1.0.0" 70 | }, { 71 | capabilities: {} 72 | }); 73 | 74 | const transport = new StdioServerTransport(); 75 | await server.connect(transport); 76 | ``` 77 | 78 | 79 | 80 | ```typescript 81 | const client = new Client({ 82 | name: "example-client", 83 | version: "1.0.0" 84 | }, { 85 | capabilities: {} 86 | }); 87 | 88 | const transport = new StdioClientTransport({ 89 | command: "./server", 90 | args: ["--option", "value"] 91 | }); 92 | await client.connect(transport); 93 | ``` 94 | 95 | 96 | 97 | ```python 98 | app = Server("example-server") 99 | 100 | async with stdio_server() as streams: 101 | await app.run( 102 | streams[0], 103 | streams[1], 104 | app.create_initialization_options() 105 | ) 106 | ``` 107 | 108 | 109 | 110 | ```python 111 | params = StdioServerParameters( 112 | command="./server", 113 | args=["--option", "value"] 114 | ) 115 | 116 | async with stdio_client(params) as streams: 117 | async with ClientSession(streams[0], streams[1]) as session: 118 | await session.initialize() 119 | ``` 120 | 121 | 122 | 123 | ### Server-Sent Events (SSE) 124 | 125 | SSE transport enables server-to-client streaming with HTTP POST requests for client-to-server communication. 126 | 127 | Use SSE when: 128 | 129 | * Only server-to-client streaming is needed 130 | * Working with restricted networks 131 | * Implementing simple updates 132 | 133 | 134 | 135 | ```typescript 136 | import express from "express"; 137 | 138 | const app = express(); 139 | 140 | const server = new Server({ 141 | name: "example-server", 142 | version: "1.0.0" 143 | }, { 144 | capabilities: {} 145 | }); 146 | 147 | let transport: SSEServerTransport | null = null; 148 | 149 | app.get("/sse", (req, res) => { 150 | transport = new SSEServerTransport("/messages", res); 151 | server.connect(transport); 152 | }); 153 | 154 | app.post("/messages", (req, res) => { 155 | if (transport) { 156 | transport.handlePostMessage(req, res); 157 | } 158 | }); 159 | 160 | app.listen(3000); 161 | ``` 162 | 163 | 164 | 165 | ```typescript 166 | const client = new Client({ 167 | name: "example-client", 168 | version: "1.0.0" 169 | }, { 170 | capabilities: {} 171 | }); 172 | 173 | const transport = new SSEClientTransport( 174 | new URL("http://localhost:3000/sse") 175 | ); 176 | await client.connect(transport); 177 | ``` 178 | 179 | 180 | 181 | ```python 182 | from mcp.server.sse import SseServerTransport 183 | from starlette.applications import Starlette 184 | from starlette.routing import Route 185 | 186 | app = Server("example-server") 187 | sse = SseServerTransport("/messages") 188 | 189 | async def handle_sse(scope, receive, send): 190 | async with sse.connect_sse(scope, receive, send) as streams: 191 | await app.run(streams[0], streams[1], app.create_initialization_options()) 192 | 193 | async def handle_messages(scope, receive, send): 194 | await sse.handle_post_message(scope, receive, send) 195 | 196 | starlette_app = Starlette( 197 | routes=[ 198 | Route("/sse", endpoint=handle_sse), 199 | Route("/messages", endpoint=handle_messages, methods=["POST"]), 200 | ] 201 | ) 202 | ``` 203 | 204 | 205 | 206 | ```python 207 | async with sse_client("http://localhost:8000/sse") as streams: 208 | async with ClientSession(streams[0], streams[1]) as session: 209 | await session.initialize() 210 | ``` 211 | 212 | 213 | 214 | ## Custom Transports 215 | 216 | MCP makes it easy to implement custom transports for specific needs. Any transport implementation just needs to conform to the Transport interface: 217 | 218 | You can implement custom transports for: 219 | 220 | * Custom network protocols 221 | * Specialized communication channels 222 | * Integration with existing systems 223 | * Performance optimization 224 | 225 | 226 | 227 | ```typescript 228 | interface Transport { 229 | // Start processing messages 230 | start(): Promise; 231 | 232 | // Send a JSON-RPC message 233 | send(message: JSONRPCMessage): Promise; 234 | 235 | // Close the connection 236 | close(): Promise; 237 | 238 | // Callbacks 239 | onclose?: () => void; 240 | onerror?: (error: Error) => void; 241 | onmessage?: (message: JSONRPCMessage) => void; 242 | } 243 | ``` 244 | 245 | 246 | 247 | Note that while MCP Servers are often implemented with asyncio, we recommend 248 | implementing low-level interfaces like transports with `anyio` for wider compatibility. 249 | 250 | ```python 251 | @contextmanager 252 | async def create_transport( 253 | read_stream: MemoryObjectReceiveStream[JSONRPCMessage | Exception], 254 | write_stream: MemoryObjectSendStream[JSONRPCMessage] 255 | ): 256 | """ 257 | Transport interface for MCP. 258 | 259 | Args: 260 | read_stream: Stream to read incoming messages from 261 | write_stream: Stream to write outgoing messages to 262 | """ 263 | async with anyio.create_task_group() as tg: 264 | try: 265 | # Start processing messages 266 | tg.start_soon(lambda: process_messages(read_stream)) 267 | 268 | # Send messages 269 | async with write_stream: 270 | yield write_stream 271 | 272 | except Exception as exc: 273 | # Handle errors 274 | raise exc 275 | finally: 276 | # Clean up 277 | tg.cancel_scope.cancel() 278 | await write_stream.aclose() 279 | await read_stream.aclose() 280 | ``` 281 | 282 | 283 | 284 | ## Error Handling 285 | 286 | Transport implementations should handle various error scenarios: 287 | 288 | 1. Connection errors 289 | 2. Message parsing errors 290 | 3. Protocol errors 291 | 4. Network timeouts 292 | 5. Resource cleanup 293 | 294 | Example error handling: 295 | 296 | 297 | 298 | ```typescript 299 | class ExampleTransport implements Transport { 300 | async start() { 301 | try { 302 | // Connection logic 303 | } catch (error) { 304 | this.onerror?.(new Error(`Failed to connect: ${error}`)); 305 | throw error; 306 | } 307 | } 308 | 309 | async send(message: JSONRPCMessage) { 310 | try { 311 | // Sending logic 312 | } catch (error) { 313 | this.onerror?.(new Error(`Failed to send message: ${error}`)); 314 | throw error; 315 | } 316 | } 317 | } 318 | ``` 319 | 320 | 321 | 322 | Note that while MCP Servers are often implemented with asyncio, we recommend 323 | implementing low-level interfaces like transports with `anyio` for wider compatibility. 324 | 325 | ```python 326 | @contextmanager 327 | async def example_transport(scope: Scope, receive: Receive, send: Send): 328 | try: 329 | # Create streams for bidirectional communication 330 | read_stream_writer, read_stream = anyio.create_memory_object_stream(0) 331 | write_stream, write_stream_reader = anyio.create_memory_object_stream(0) 332 | 333 | async def message_handler(): 334 | try: 335 | async with read_stream_writer: 336 | # Message handling logic 337 | pass 338 | except Exception as exc: 339 | logger.error(f"Failed to handle message: {exc}") 340 | raise exc 341 | 342 | async with anyio.create_task_group() as tg: 343 | tg.start_soon(message_handler) 344 | try: 345 | # Yield streams for communication 346 | yield read_stream, write_stream 347 | except Exception as exc: 348 | logger.error(f"Transport error: {exc}") 349 | raise exc 350 | finally: 351 | tg.cancel_scope.cancel() 352 | await write_stream.aclose() 353 | await read_stream.aclose() 354 | except Exception as exc: 355 | logger.error(f"Failed to initialize transport: {exc}") 356 | raise exc 357 | ``` 358 | 359 | 360 | 361 | ## Best Practices 362 | 363 | When implementing or using MCP transport: 364 | 365 | 1. Handle connection lifecycle properly 366 | 2. Implement proper error handling 367 | 3. Clean up resources on connection close 368 | 4. Use appropriate timeouts 369 | 5. Validate messages before sending 370 | 6. Log transport events for debugging 371 | 7. Implement reconnection logic when appropriate 372 | 8. Handle backpressure in message queues 373 | 9. Monitor connection health 374 | 10. Implement proper security measures 375 | 376 | ## Security Considerations 377 | 378 | When implementing transport: 379 | 380 | ### Authentication and Authorization 381 | 382 | * Implement proper authentication mechanisms 383 | * Validate client credentials 384 | * Use secure token handling 385 | * Implement authorization checks 386 | 387 | ### Data Security 388 | 389 | * Use TLS for network transport 390 | * Encrypt sensitive data 391 | * Validate message integrity 392 | * Implement message size limits 393 | * Sanitize input data 394 | 395 | ### Network Security 396 | 397 | * Implement rate limiting 398 | * Use appropriate timeouts 399 | * Handle denial of service scenarios 400 | * Monitor for unusual patterns 401 | * Implement proper firewall rules 402 | 403 | ## Debugging Transport 404 | 405 | Tips for debugging transport issues: 406 | 407 | 1. Enable debug logging 408 | 2. Monitor message flow 409 | 3. Check connection states 410 | 4. Validate message formats 411 | 5. Test error scenarios 412 | 6. Use network analysis tools 413 | 7. Implement health checks 414 | 8. Monitor resource usage 415 | 9. Test edge cases 416 | 10. Use proper error tracking 417 | -------------------------------------------------------------------------------- /docs/mcp/modelcontextprotocol.io-docs-tools-debugging.md: -------------------------------------------------------------------------------- 1 | # Debugging 2 | 3 | > A comprehensive guide to debugging Model Context Protocol (MCP) integrations 4 | 5 | Effective debugging is essential when developing MCP servers or integrating them with applications. This guide covers the debugging tools and approaches available in the MCP ecosystem. 6 | 7 | 8 | This guide is for macOS. Guides for other platforms are coming soon. 9 | 10 | 11 | ## Debugging tools overview 12 | 13 | MCP provides several tools for debugging at different levels: 14 | 15 | 1. **MCP Inspector** 16 | * Interactive debugging interface 17 | * Direct server testing 18 | * See the [Inspector guide](/docs/tools/inspector) for details 19 | 20 | 2. **Claude Desktop Developer Tools** 21 | * Integration testing 22 | * Log collection 23 | * Chrome DevTools integration 24 | 25 | 3. **Server Logging** 26 | * Custom logging implementations 27 | * Error tracking 28 | * Performance monitoring 29 | 30 | ## Debugging in Claude Desktop 31 | 32 | ### Checking server status 33 | 34 | The Claude.app interface provides basic server status information: 35 | 36 | 1. Click the icon to view: 37 | * Connected servers 38 | * Available prompts and resources 39 | 40 | 2. Click the icon to view: 41 | * Tools made available to the model 42 | 43 | ### Viewing logs 44 | 45 | Review detailed MCP logs from Claude Desktop: 46 | 47 | ```bash 48 | # Follow logs in real-time 49 | tail -n 20 -F ~/Library/Logs/Claude/mcp*.log 50 | ``` 51 | 52 | The logs capture: 53 | 54 | * Server connection events 55 | * Configuration issues 56 | * Runtime errors 57 | * Message exchanges 58 | 59 | ### Using Chrome DevTools 60 | 61 | Access Chrome's developer tools inside Claude Desktop to investigate client-side errors: 62 | 63 | 1. Create a `developer_settings.json` file with `allowDevTools` set to true: 64 | 65 | ```bash 66 | echo '{"allowDevTools": true}' > ~/Library/Application\ Support/Claude/developer_settings.json 67 | ``` 68 | 69 | 2. Open DevTools: `Command-Option-Shift-i` 70 | 71 | Note: You'll see two DevTools windows: 72 | 73 | * Main content window 74 | * App title bar window 75 | 76 | Use the Console panel to inspect client-side errors. 77 | 78 | Use the Network panel to inspect: 79 | 80 | * Message payloads 81 | * Connection timing 82 | 83 | ## Common issues 84 | 85 | ### Working directory 86 | 87 | When using MCP servers with Claude Desktop: 88 | 89 | * The working directory for servers launched via `claude_desktop_config.json` may be undefined (like `/` on macOS) since Claude Desktop could be started from anywhere 90 | * Always use absolute paths in your configuration and `.env` files to ensure reliable operation 91 | * For testing servers directly via command line, the working directory will be where you run the command 92 | 93 | For example in `claude_desktop_config.json`, use: 94 | 95 | ```json 96 | { 97 | "command": "npx", 98 | "args": ["-y", "@modelcontextprotocol/server-filesystem", "/Users/username/data"] 99 | } 100 | ``` 101 | 102 | Instead of relative paths like `./data` 103 | 104 | ### Environment variables 105 | 106 | MCP servers inherit only a subset of environment variables automatically, like `USER`, `HOME`, and `PATH`. 107 | 108 | To override the default variables or provide your own, you can specify an `env` key in `claude_desktop_config.json`: 109 | 110 | ```json 111 | { 112 | "myserver": { 113 | "command": "mcp-server-myapp", 114 | "env": { 115 | "MYAPP_API_KEY": "some_key", 116 | } 117 | } 118 | } 119 | ``` 120 | 121 | ### Server initialization 122 | 123 | Common initialization problems: 124 | 125 | 1. **Path Issues** 126 | * Incorrect server executable path 127 | * Missing required files 128 | * Permission problems 129 | * Try using an absolute path for `command` 130 | 131 | 2. **Configuration Errors** 132 | * Invalid JSON syntax 133 | * Missing required fields 134 | * Type mismatches 135 | 136 | 3. **Environment Problems** 137 | * Missing environment variables 138 | * Incorrect variable values 139 | * Permission restrictions 140 | 141 | ### Connection problems 142 | 143 | When servers fail to connect: 144 | 145 | 1. Check Claude Desktop logs 146 | 2. Verify server process is running 147 | 3. Test standalone with [Inspector](/docs/tools/inspector) 148 | 4. Verify protocol compatibility 149 | 150 | ## Implementing logging 151 | 152 | ### Server-side logging 153 | 154 | When building a server that uses the local stdio [transport](/docs/concepts/transports), all messages logged to stderr (standard error) will be captured by the host application (e.g., Claude Desktop) automatically. 155 | 156 | 157 | Local MCP servers should not log messages to stdout (standard out), as this will interfere with protocol operation. 158 | 159 | 160 | For all [transports](/docs/concepts/transports), you can also provide logging to the client by sending a log message notification: 161 | 162 | 163 | 164 | ```python 165 | server.request_context.session.send_log_message( 166 | level="info", 167 | data="Server started successfully", 168 | ) 169 | ``` 170 | 171 | 172 | 173 | ```typescript 174 | server.sendLoggingMessage({ 175 | level: "info", 176 | data: "Server started successfully", 177 | }); 178 | ``` 179 | 180 | 181 | 182 | Important events to log: 183 | 184 | * Initialization steps 185 | * Resource access 186 | * Tool execution 187 | * Error conditions 188 | * Performance metrics 189 | 190 | ### Client-side logging 191 | 192 | In client applications: 193 | 194 | 1. Enable debug logging 195 | 2. Monitor network traffic 196 | 3. Track message exchanges 197 | 4. Record error states 198 | 199 | ## Debugging workflow 200 | 201 | ### Development cycle 202 | 203 | 1. Initial Development 204 | * Use [Inspector](/docs/tools/inspector) for basic testing 205 | * Implement core functionality 206 | * Add logging points 207 | 208 | 2. Integration Testing 209 | * Test in Claude Desktop 210 | * Monitor logs 211 | * Check error handling 212 | 213 | ### Testing changes 214 | 215 | To test changes efficiently: 216 | 217 | * **Configuration changes**: Restart Claude Desktop 218 | * **Server code changes**: Use Command-R to reload 219 | * **Quick iteration**: Use [Inspector](/docs/tools/inspector) during development 220 | 221 | ## Best practices 222 | 223 | ### Logging strategy 224 | 225 | 1. **Structured Logging** 226 | * Use consistent formats 227 | * Include context 228 | * Add timestamps 229 | * Track request IDs 230 | 231 | 2. **Error Handling** 232 | * Log stack traces 233 | * Include error context 234 | * Track error patterns 235 | * Monitor recovery 236 | 237 | 3. **Performance Tracking** 238 | * Log operation timing 239 | * Monitor resource usage 240 | * Track message sizes 241 | * Measure latency 242 | 243 | ### Security considerations 244 | 245 | When debugging: 246 | 247 | 1. **Sensitive Data** 248 | * Sanitize logs 249 | * Protect credentials 250 | * Mask personal information 251 | 252 | 2. **Access Control** 253 | * Verify permissions 254 | * Check authentication 255 | * Monitor access patterns 256 | 257 | ## Getting help 258 | 259 | When encountering issues: 260 | 261 | 1. **First Steps** 262 | * Check server logs 263 | * Test with [Inspector](/docs/tools/inspector) 264 | * Review configuration 265 | * Verify environment 266 | 267 | 2. **Support Channels** 268 | * GitHub issues 269 | * GitHub discussions 270 | 271 | 3. **Providing Information** 272 | * Log excerpts 273 | * Configuration files 274 | * Steps to reproduce 275 | * Environment details 276 | 277 | ## Next steps 278 | 279 | 280 | 281 | Learn to use the MCP Inspector 282 | 283 | 284 | -------------------------------------------------------------------------------- /docs/mcp/modelcontextprotocol.io-docs-tools-inspector.md: -------------------------------------------------------------------------------- 1 | # Inspector 2 | 3 | > In-depth guide to using the MCP Inspector for testing and debugging Model Context Protocol servers 4 | 5 | The [MCP Inspector](https://github.com/modelcontextprotocol/inspector) is an interactive developer tool for testing and debugging MCP servers. While the [Debugging Guide](/docs/tools/debugging) covers the Inspector as part of the overall debugging toolkit, this document provides a detailed exploration of the Inspector's features and capabilities. 6 | 7 | ## Getting started 8 | 9 | ### Installation and basic usage 10 | 11 | The Inspector runs directly through `npx` without requiring installation: 12 | 13 | ```bash 14 | npx @modelcontextprotocol/inspector 15 | ``` 16 | 17 | ```bash 18 | npx @modelcontextprotocol/inspector 19 | ``` 20 | 21 | #### Inspecting servers from NPM or PyPi 22 | 23 | A common way to start server packages from [NPM](https://npmjs.com) or [PyPi](https://pypi.com). 24 | 25 | 26 | 27 | ```bash 28 | npx -y @modelcontextprotocol/inspector npx 29 | # For example 30 | npx -y @modelcontextprotocol/inspector npx server-postgres postgres://127.0.0.1/testdb 31 | ``` 32 | 33 | 34 | 35 | ```bash 36 | npx @modelcontextprotocol/inspector uvx 37 | # For example 38 | npx @modelcontextprotocol/inspector uvx mcp-server-git --repository ~/code/mcp/servers.git 39 | ``` 40 | 41 | 42 | 43 | #### Inspecting locally developed servers 44 | 45 | To inspect servers locally developed or downloaded as a repository, the most common 46 | way is: 47 | 48 | 49 | 50 | ```bash 51 | npx @modelcontextprotocol/inspector node path/to/server/index.js args... 52 | ``` 53 | 54 | 55 | 56 | ```bash 57 | npx @modelcontextprotocol/inspector \ 58 | uv \ 59 | --directory path/to/server \ 60 | run \ 61 | package-name \ 62 | args... 63 | ``` 64 | 65 | 66 | 67 | Please carefully read any attached README for the most accurate instructions. 68 | 69 | ## Feature overview 70 | 71 | 72 | 73 | 74 | 75 | The Inspector provides several features for interacting with your MCP server: 76 | 77 | ### Server connection pane 78 | 79 | * Allows selecting the [transport](/docs/concepts/transports) for connecting to the server 80 | * For local servers, supports customizing the command-line arguments and environment 81 | 82 | ### Resources tab 83 | 84 | * Lists all available resources 85 | * Shows resource metadata (MIME types, descriptions) 86 | * Allows resource content inspection 87 | * Supports subscription testing 88 | 89 | ### Prompts tab 90 | 91 | * Displays available prompt templates 92 | * Shows prompt arguments and descriptions 93 | * Enables prompt testing with custom arguments 94 | * Previews generated messages 95 | 96 | ### Tools tab 97 | 98 | * Lists available tools 99 | * Shows tool schemas and descriptions 100 | * Enables tool testing with custom inputs 101 | * Displays tool execution results 102 | 103 | ### Notifications pane 104 | 105 | * Presents all logs recorded from the server 106 | * Shows notifications received from the server 107 | 108 | ## Best practices 109 | 110 | ### Development workflow 111 | 112 | 1. Start Development 113 | * Launch Inspector with your server 114 | * Verify basic connectivity 115 | * Check capability negotiation 116 | 117 | 2. Iterative testing 118 | * Make server changes 119 | * Rebuild the server 120 | * Reconnect the Inspector 121 | * Test affected features 122 | * Monitor messages 123 | 124 | 3. Test edge cases 125 | * Invalid inputs 126 | * Missing prompt arguments 127 | * Concurrent operations 128 | * Verify error handling and error responses 129 | 130 | ## Next steps 131 | 132 | 133 | 134 | Check out the MCP Inspector source code 135 | 136 | 137 | 138 | Learn about broader debugging strategies 139 | 140 | 141 | -------------------------------------------------------------------------------- /docs/mcp/modelcontextprotocol.io-examples.md: -------------------------------------------------------------------------------- 1 | # Example Servers 2 | 3 | > A list of example servers and implementations 4 | 5 | This page showcases various Model Context Protocol (MCP) servers that demonstrate the protocol's capabilities and versatility. These servers enable Large Language Models (LLMs) to securely access tools and data sources. 6 | 7 | ## Reference implementations 8 | 9 | These official reference servers demonstrate core MCP features and SDK usage: 10 | 11 | ### Data and file systems 12 | 13 | * **[Filesystem](https://github.com/modelcontextprotocol/servers/tree/main/src/filesystem)** - Secure file operations with configurable access controls 14 | * **[PostgreSQL](https://github.com/modelcontextprotocol/servers/tree/main/src/postgres)** - Read-only database access with schema inspection capabilities 15 | * **[SQLite](https://github.com/modelcontextprotocol/servers/tree/main/src/sqlite)** - Database interaction and business intelligence features 16 | * **[Google Drive](https://github.com/modelcontextprotocol/servers/tree/main/src/gdrive)** - File access and search capabilities for Google Drive 17 | 18 | ### Development tools 19 | 20 | * **[Git](https://github.com/modelcontextprotocol/servers/tree/main/src/git)** - Tools to read, search, and manipulate Git repositories 21 | * **[GitHub](https://github.com/modelcontextprotocol/servers/tree/main/src/github)** - Repository management, file operations, and GitHub API integration 22 | * **[GitLab](https://github.com/modelcontextprotocol/servers/tree/main/src/gitlab)** - GitLab API integration enabling project management 23 | * **[Sentry](https://github.com/modelcontextprotocol/servers/tree/main/src/sentry)** - Retrieving and analyzing issues from Sentry.io 24 | 25 | ### Web and browser automation 26 | 27 | * **[Brave Search](https://github.com/modelcontextprotocol/servers/tree/main/src/brave-search)** - Web and local search using Brave's Search API 28 | * **[Fetch](https://github.com/modelcontextprotocol/servers/tree/main/src/fetch)** - Web content fetching and conversion optimized for LLM usage 29 | * **[Puppeteer](https://github.com/modelcontextprotocol/servers/tree/main/src/puppeteer)** - Browser automation and web scraping capabilities 30 | 31 | ### Productivity and communication 32 | 33 | * **[Slack](https://github.com/modelcontextprotocol/servers/tree/main/src/slack)** - Channel management and messaging capabilities 34 | * **[Google Maps](https://github.com/modelcontextprotocol/servers/tree/main/src/google-maps)** - Location services, directions, and place details 35 | * **[Memory](https://github.com/modelcontextprotocol/servers/tree/main/src/memory)** - Knowledge graph-based persistent memory system 36 | 37 | ### AI and specialized tools 38 | 39 | * **[EverArt](https://github.com/modelcontextprotocol/servers/tree/main/src/everart)** - AI image generation using various models 40 | * **[Sequential Thinking](https://github.com/modelcontextprotocol/servers/tree/main/src/sequentialthinking)** - Dynamic problem-solving through thought sequences 41 | * **[AWS KB Retrieval](https://github.com/modelcontextprotocol/servers/tree/main/src/aws-kb-retrieval-server)** - Retrieval from AWS Knowledge Base using Bedrock Agent Runtime 42 | 43 | ## Official integrations 44 | 45 | These MCP servers are maintained by companies for their platforms: 46 | 47 | * **[Axiom](https://github.com/axiomhq/mcp-server-axiom)** - Query and analyze logs, traces, and event data using natural language 48 | * **[Browserbase](https://github.com/browserbase/mcp-server-browserbase)** - Automate browser interactions in the cloud 49 | * **[Cloudflare](https://github.com/cloudflare/mcp-server-cloudflare)** - Deploy and manage resources on the Cloudflare developer platform 50 | * **[E2B](https://github.com/e2b-dev/mcp-server)** - Execute code in secure cloud sandboxes 51 | * **[Neon](https://github.com/neondatabase/mcp-server-neon)** - Interact with the Neon serverless Postgres platform 52 | * **[Obsidian Markdown Notes](https://github.com/calclavia/mcp-obsidian)** - Read and search through Markdown notes in Obsidian vaults 53 | * **[Qdrant](https://github.com/qdrant/mcp-server-qdrant/)** - Implement semantic memory using the Qdrant vector search engine 54 | * **[Raygun](https://github.com/MindscapeHQ/mcp-server-raygun)** - Access crash reporting and monitoring data 55 | * **[Search1API](https://github.com/fatwang2/search1api-mcp)** - Unified API for search, crawling, and sitemaps 56 | * **[Stripe](https://github.com/stripe/agent-toolkit)** - Interact with the Stripe API 57 | * **[Tinybird](https://github.com/tinybirdco/mcp-tinybird)** - Interface with the Tinybird serverless ClickHouse platform 58 | 59 | ## Community highlights 60 | 61 | A growing ecosystem of community-developed servers extends MCP's capabilities: 62 | 63 | * **[Docker](https://github.com/ckreiling/mcp-server-docker)** - Manage containers, images, volumes, and networks 64 | * **[Kubernetes](https://github.com/Flux159/mcp-server-kubernetes)** - Manage pods, deployments, and services 65 | * **[Linear](https://github.com/jerhadf/linear-mcp-server)** - Project management and issue tracking 66 | * **[Snowflake](https://github.com/datawiz168/mcp-snowflake-service)** - Interact with Snowflake databases 67 | * **[Spotify](https://github.com/varunneal/spotify-mcp)** - Control Spotify playback and manage playlists 68 | * **[Todoist](https://github.com/abhiz123/todoist-mcp-server)** - Task management integration 69 | 70 | > **Note:** Community servers are untested and should be used at your own risk. They are not affiliated with or endorsed by Anthropic. 71 | 72 | For a complete list of community servers, visit the [MCP Servers Repository](https://github.com/modelcontextprotocol/servers). 73 | 74 | ## Getting started 75 | 76 | ### Using reference servers 77 | 78 | TypeScript-based servers can be used directly with `npx`: 79 | 80 | ```bash 81 | npx -y @modelcontextprotocol/server-memory 82 | ``` 83 | 84 | Python-based servers can be used with `uvx` (recommended) or `pip`: 85 | 86 | ```bash 87 | # Using uvx 88 | uvx mcp-server-git 89 | 90 | # Using pip 91 | pip install mcp-server-git 92 | python -m mcp_server_git 93 | ``` 94 | 95 | ### Configuring with Claude 96 | 97 | To use an MCP server with Claude, add it to your configuration: 98 | 99 | ```json 100 | { 101 | "mcpServers": { 102 | "memory": { 103 | "command": "npx", 104 | "args": ["-y", "@modelcontextprotocol/server-memory"] 105 | }, 106 | "filesystem": { 107 | "command": "npx", 108 | "args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/allowed/files"] 109 | }, 110 | "github": { 111 | "command": "npx", 112 | "args": ["-y", "@modelcontextprotocol/server-github"], 113 | "env": { 114 | "GITHUB_PERSONAL_ACCESS_TOKEN": "" 115 | } 116 | } 117 | } 118 | } 119 | ``` 120 | 121 | ## Additional resources 122 | 123 | * [MCP Servers Repository](https://github.com/modelcontextprotocol/servers) - Complete collection of reference implementations and community servers 124 | * [Awesome MCP Servers](https://github.com/punkpeye/awesome-mcp-servers) - Curated list of MCP servers 125 | * [MCP CLI](https://github.com/wong2/mcp-cli) - Command-line inspector for testing MCP servers 126 | * [MCP Get](https://mcp-get.com) - Tool for installing and managing MCP servers 127 | * [Supergateway](https://github.com/supercorp-ai/supergateway) - Run MCP stdio servers over SSE 128 | 129 | Visit our [GitHub Discussions](https://github.com/orgs/modelcontextprotocol/discussions) to engage with the MCP community. 130 | -------------------------------------------------------------------------------- /docs/mcp/modelcontextprotocol.io-introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | > Get started with the Model Context Protocol (MCP) 4 | 5 | Java SDK released! Check out [what else is new.](/development/updates) 6 | 7 | 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. 8 | 9 | ## Why MCP? 10 | 11 | MCP helps you build agents and complex workflows on top of LLMs. LLMs frequently need to integrate with data and tools, and MCP provides: 12 | 13 | * A growing list of pre-built integrations that your LLM can directly plug into 14 | * The flexibility to switch between LLM providers and vendors 15 | * Best practices for securing your data within your infrastructure 16 | 17 | ### General architecture 18 | 19 | At its core, MCP follows a client-server architecture where a host application can connect to multiple servers: 20 | 21 | ```mermaid 22 | flowchart LR 23 | subgraph "Your Computer" 24 | Host["Host with MCP Client\n(Claude, IDEs, Tools)"] 25 | S1["MCP Server A"] 26 | S2["MCP Server B"] 27 | S3["MCP Server C"] 28 | Host <-->|"MCP Protocol"| S1 29 | Host <-->|"MCP Protocol"| S2 30 | Host <-->|"MCP Protocol"| S3 31 | S1 <--> D1[("Local\nData Source A")] 32 | S2 <--> D2[("Local\nData Source B")] 33 | end 34 | subgraph "Internet" 35 | S3 <-->|"Web APIs"| D3[("Remote\nService C")] 36 | end 37 | ``` 38 | 39 | * **MCP Hosts**: Programs like Claude Desktop, IDEs, or AI tools that want to access data through MCP 40 | * **MCP Clients**: Protocol clients that maintain 1:1 connections with servers 41 | * **MCP Servers**: Lightweight programs that each expose specific capabilities through the standardized Model Context Protocol 42 | * **Local Data Sources**: Your computer's files, databases, and services that MCP servers can securely access 43 | * **Remote Services**: External systems available over the internet (e.g., through APIs) that MCP servers can connect to 44 | 45 | ## Get started 46 | 47 | Choose the path that best fits your needs: 48 | 49 | #### Quick Starts 50 | 51 | 52 | 53 | Get started building your own server to use in Claude for Desktop and other clients 54 | 55 | 56 | 57 | Get started building your own client that can integrate with all MCP servers 58 | 59 | 60 | 61 | Get started using pre-built servers in Claude for Desktop 62 | 63 | 64 | 65 | #### Examples 66 | 67 | 68 | 69 | Check out our gallery of official MCP servers and implementations 70 | 71 | 72 | 73 | View the list of clients that support MCP integrations 74 | 75 | 76 | 77 | ## Tutorials 78 | 79 | 80 | 81 | Learn how to use LLMs like Claude to speed up your MCP development 82 | 83 | 84 | 85 | Learn how to effectively debug MCP servers and integrations 86 | 87 | 88 | 89 | Test and inspect your MCP servers with our interactive debugging tool 90 | 91 | 92 | 93 | ## Explore MCP 94 | 95 | Dive deeper into MCP's core concepts and capabilities: 96 | 97 | 98 | 99 | Understand how MCP connects clients, servers, and LLMs 100 | 101 | 102 | 103 | Expose data and content from your servers to LLMs 104 | 105 | 106 | 107 | Create reusable prompt templates and workflows 108 | 109 | 110 | 111 | Enable LLMs to perform actions through your server 112 | 113 | 114 | 115 | Let your servers request completions from LLMs 116 | 117 | 118 | 119 | Learn about MCP's communication mechanism 120 | 121 | 122 | 123 | ## Contributing 124 | 125 | Want to contribute? Check out our [Contributing Guide](/development/contributing) to learn how you can help improve MCP. 126 | 127 | ## Support and Feedback 128 | 129 | Here's how to get help or provide feedback: 130 | 131 | * 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) 132 | * For discussions or Q\&A about the MCP specification, use the [specification discussions](https://github.com/modelcontextprotocol/specification/discussions) 133 | * For discussions or Q\&A about other MCP open source components, use the [organization discussions](https://github.com/orgs/modelcontextprotocol/discussions) 134 | * For bug reports, feature requests, and questions related to Claude.app and claude.ai's MCP integration, please email [mcp-support@anthropic.com](mailto:mcp-support@anthropic.com) 135 | -------------------------------------------------------------------------------- /docs/mcp/modelcontextprotocol.io-llms.txt: -------------------------------------------------------------------------------- 1 | # Model Context Protocol 2 | 3 | ## Docs 4 | 5 | - [Example Clients](https://modelcontextprotocol.io/clients.md): A list of applications that support MCP integrations 6 | - [Contributing](https://modelcontextprotocol.io/development/contributing.md): How to participate in Model Context Protocol development 7 | - [Roadmap](https://modelcontextprotocol.io/development/roadmap.md): Our plans for evolving Model Context Protocol (H1 2025) 8 | - [What's New](https://modelcontextprotocol.io/development/updates.md): The latest updates and improvements to MCP 9 | - [Core architecture](https://modelcontextprotocol.io/docs/concepts/architecture.md): Understand how MCP connects clients, servers, and LLMs 10 | - [Prompts](https://modelcontextprotocol.io/docs/concepts/prompts.md): Create reusable prompt templates and workflows 11 | - [Resources](https://modelcontextprotocol.io/docs/concepts/resources.md): Expose data and content from your servers to LLMs 12 | - [Roots](https://modelcontextprotocol.io/docs/concepts/roots.md): Understanding roots in MCP 13 | - [Sampling](https://modelcontextprotocol.io/docs/concepts/sampling.md): Let your servers request completions from LLMs 14 | - [Tools](https://modelcontextprotocol.io/docs/concepts/tools.md): Enable LLMs to perform actions through your server 15 | - [Transports](https://modelcontextprotocol.io/docs/concepts/transports.md): Learn about MCP's communication mechanisms 16 | - [Debugging](https://modelcontextprotocol.io/docs/tools/debugging.md): A comprehensive guide to debugging Model Context Protocol (MCP) integrations 17 | - [Inspector](https://modelcontextprotocol.io/docs/tools/inspector.md): In-depth guide to using the MCP Inspector for testing and debugging Model Context Protocol servers 18 | - [Example Servers](https://modelcontextprotocol.io/examples.md): A list of example servers and implementations 19 | - [Introduction](https://modelcontextprotocol.io/introduction.md): Get started with the Model Context Protocol (MCP) 20 | - [For Client Developers](https://modelcontextprotocol.io/quickstart/client.md): Get started building your own client that can integrate with all MCP servers. 21 | - [For Server Developers](https://modelcontextprotocol.io/quickstart/server.md): Get started building your own server to use in Claude for Desktop and other clients. 22 | - [For Claude Desktop Users](https://modelcontextprotocol.io/quickstart/user.md): Get started using pre-built servers in Claude for Desktop. 23 | - [MCP Client](https://modelcontextprotocol.io/sdk/java/mcp-client.md): Learn how to use the Model Context Protocol (MCP) client to interact with MCP servers 24 | - [Overview](https://modelcontextprotocol.io/sdk/java/mcp-overview.md): Introduction to the Model Context Protocol (MCP) Java SDK 25 | - [MCP Server](https://modelcontextprotocol.io/sdk/java/mcp-server.md): Learn how to implement and configure a Model Context Protocol (MCP) server 26 | - [Building MCP with LLMs](https://modelcontextprotocol.io/tutorials/building-mcp-with-llms.md): Speed up your MCP development using LLMs such as Claude! 27 | 28 | 29 | ## Optional 30 | 31 | - [Python SDK](https://github.com/modelcontextprotocol/python-sdk) 32 | - [TypeScript SDK](https://github.com/modelcontextprotocol/typescript-sdk) 33 | - [Java SDK](https://github.com/modelcontextprotocol/java-sdk) 34 | - [Kotlin SDK](https://github.com/modelcontextprotocol/kotlin-sdk) 35 | - [Specification](https://spec.modelcontextprotocol.io) 36 | -------------------------------------------------------------------------------- /docs/mcp/modelcontextprotocol.io-quickstart-user.md: -------------------------------------------------------------------------------- 1 | # For Claude Desktop Users 2 | 3 | > Get started using pre-built servers in Claude for Desktop. 4 | 5 | In this tutorial, you will extend [Claude for Desktop](https://claude.ai/download) so that it can read from your computer's file system, write new files, move files, and even search files. 6 | 7 | 8 | 9 | 10 | 11 | Don't worry — it will ask you for your permission before executing these actions! 12 | 13 | ## 1. Download Claude for Desktop 14 | 15 | Start by downloading [Claude for Desktop](https://claude.ai/download), choosing either macOS or Windows. (Linux is not yet supported for Claude for Desktop.) 16 | 17 | Follow the installation instructions. 18 | 19 | If you already have Claude for Desktop, make sure it's on the latest version by clicking on the Claude menu on your computer and selecting "Check for Updates..." 20 | 21 | 22 | Because servers are locally run, MCP currently only supports desktop hosts. Remote hosts are in active development. 23 | 24 | 25 | ## 2. Add the Filesystem MCP Server 26 | 27 | To add this filesystem functionality, we will be installing a pre-built [Filesystem MCP Server](https://github.com/modelcontextprotocol/servers/tree/main/src/filesystem) to Claude for Desktop. This is one of dozens of [servers](https://github.com/modelcontextprotocol/servers/tree/main) created by Anthropic and the community. 28 | 29 | Get started by opening up the Claude menu on your computer and select "Settings..." Please note that these are not the Claude Account Settings found in the app window itself. 30 | 31 | This is what it should look like on a Mac: 32 | 33 | 34 | 35 | 36 | 37 | Click on "Developer" in the lefthand bar of the Settings pane, and then click on "Edit Config": 38 | 39 | 40 | 41 | 42 | 43 | This will create a configuration file at: 44 | 45 | * macOS: `~/Library/Application Support/Claude/claude_desktop_config.json` 46 | * Windows: `%APPDATA%\Claude\claude_desktop_config.json` 47 | 48 | if you don't already have one, and will display the file in your file system. 49 | 50 | Open up the configuration file in any text editor. Replace the file contents with this: 51 | 52 | 53 | 54 | ```json 55 | { 56 | "mcpServers": { 57 | "filesystem": { 58 | "command": "npx", 59 | "args": [ 60 | "-y", 61 | "@modelcontextprotocol/server-filesystem", 62 | "/Users/username/Desktop", 63 | "/Users/username/Downloads" 64 | ] 65 | } 66 | } 67 | } 68 | ``` 69 | 70 | 71 | 72 | ```json 73 | { 74 | "mcpServers": { 75 | "filesystem": { 76 | "command": "npx", 77 | "args": [ 78 | "-y", 79 | "@modelcontextprotocol/server-filesystem", 80 | "C:\\Users\\username\\Desktop", 81 | "C:\\Users\\username\\Downloads" 82 | ] 83 | } 84 | } 85 | } 86 | ``` 87 | 88 | 89 | 90 | Make sure to replace `username` with your computer's username. The paths should point to valid directories that you want Claude to be able to access and modify. It's set up to work for Desktop and Downloads, but you can add more paths as well. 91 | 92 | You will also need [Node.js](https://nodejs.org) on your computer for this to run properly. To verify you have Node installed, open the command line on your computer. 93 | 94 | * On macOS, open the Terminal from your Applications folder 95 | * On Windows, press Windows + R, type "cmd", and press Enter 96 | 97 | Once in the command line, verify you have Node installed by entering in the following command: 98 | 99 | ```bash 100 | node --version 101 | ``` 102 | 103 | If you get an error saying "command not found" or "node is not recognized", download Node from [nodejs.org](https://nodejs.org/). 104 | 105 | 106 | **How does the configuration file work?** 107 | 108 | This configuration file tells Claude for Desktop which MCP servers to start up every time you start the application. In this case, we have added one server called "filesystem" that will use the Node `npx` command to install and run `@modelcontextprotocol/server-filesystem`. This server, described [here](https://github.com/modelcontextprotocol/servers/tree/main/src/filesystem), will let you access your file system in Claude for Desktop. 109 | 110 | 111 | 112 | **Command Privileges** 113 | 114 | Claude for Desktop will run the commands in the configuration file with the permissions of your user account, and access to your local files. Only add commands if you understand and trust the source. 115 | 116 | 117 | ## 3. Restart Claude 118 | 119 | After updating your configuration file, you need to restart Claude for Desktop. 120 | 121 | Upon restarting, you should see a hammer icon in the bottom right corner of the input box: 122 | 123 | 124 | 125 | 126 | 127 | After clicking on the hammer icon, you should see the tools that come with the Filesystem MCP Server: 128 | 129 | 130 | 131 | 132 | 133 | If your server isn't being picked up by Claude for Desktop, proceed to the [Troubleshooting](#troubleshooting) section for debugging tips. 134 | 135 | ## 4. Try it out! 136 | 137 | You can now talk to Claude and ask it about your filesystem. It should know when to call the relevant tools. 138 | 139 | Things you might try asking Claude: 140 | 141 | * Can you write a poem and save it to my desktop? 142 | * What are some work-related files in my downloads folder? 143 | * Can you take all the images on my desktop and move them to a new folder called "Images"? 144 | 145 | As needed, Claude will call the relevant tools and seek your approval before taking an action: 146 | 147 | 148 | 149 | 150 | 151 | ## Troubleshooting 152 | 153 | 154 | 155 | 1. Restart Claude for Desktop completely 156 | 2. Check your `claude_desktop_config.json` file syntax 157 | 3. Make sure the file paths included in `claude_desktop_config.json` are valid and that they are absolute and not relative 158 | 4. Look at [logs](#getting-logs-from-claude-for-desktop) to see why the server is not connecting 159 | 5. In your command line, try manually running the server (replacing `username` as you did in `claude_desktop_config.json`) to see if you get any errors: 160 | 161 | 162 | 163 | ```bash 164 | npx -y @modelcontextprotocol/server-filesystem /Users/username/Desktop /Users/username/Downloads 165 | ``` 166 | 167 | 168 | 169 | ```bash 170 | npx -y @modelcontextprotocol/server-filesystem C:\Users\username\Desktop C:\Users\username\Downloads 171 | ``` 172 | 173 | 174 | 175 | 176 | 177 | Claude.app logging related to MCP is written to log files in: 178 | 179 | * macOS: `~/Library/Logs/Claude` 180 | 181 | * Windows: `%APPDATA%\Claude\logs` 182 | 183 | * `mcp.log` will contain general logging about MCP connections and connection failures. 184 | 185 | * Files named `mcp-server-SERVERNAME.log` will contain error (stderr) logging from the named server. 186 | 187 | You can run the following command to list recent logs and follow along with any new ones (on Windows, it will only show recent logs): 188 | 189 | 190 | 191 | ```bash 192 | # Check Claude's logs for errors 193 | tail -n 20 -f ~/Library/Logs/Claude/mcp*.log 194 | ``` 195 | 196 | 197 | 198 | ```bash 199 | type "%APPDATA%\Claude\logs\mcp*.log" 200 | ``` 201 | 202 | 203 | 204 | 205 | 206 | If Claude attempts to use the tools but they fail: 207 | 208 | 1. Check Claude's logs for errors 209 | 2. Verify your server builds and runs without errors 210 | 3. Try restarting Claude for Desktop 211 | 212 | 213 | 214 | Please refer to our [debugging guide](/docs/tools/debugging) for better debugging tools and more detailed guidance. 215 | 216 | 217 | 218 | If your configured server fails to load, and you see within its logs an error referring to `${APPDATA}` within a path, you may need to add the expanded value of `%APPDATA%` to your `env` key in `claude_desktop_config.json`: 219 | 220 | ```json 221 | { 222 | "brave-search": { 223 | "command": "npx", 224 | "args": ["-y", "@modelcontextprotocol/server-brave-search"], 225 | "env": { 226 | "APPDATA": "C:\\Users\\user\\AppData\\Roaming\\", 227 | "BRAVE_API_KEY": "..." 228 | } 229 | } 230 | } 231 | ``` 232 | 233 | With this change in place, launch Claude Desktop once again. 234 | 235 | 236 | **NPM should be installed globally** 237 | 238 | The `npx` command may continue to fail if you have not installed NPM globally. If NPM is already installed globally, you will find `%APPDATA%\npm` exists on your system. If not, you can install NPM globally by running the following command: 239 | 240 | ```bash 241 | npm install -g npm 242 | ``` 243 | 244 | 245 | 246 | 247 | ## Next steps 248 | 249 | 250 | 251 | Check out our gallery of official MCP servers and implementations 252 | 253 | 254 | 255 | Now build your own custom server to use in Claude for Desktop and other clients 256 | 257 | 258 | -------------------------------------------------------------------------------- /docs/mcp/modelcontextprotocol.io-sdk-java-mcp-client.md: -------------------------------------------------------------------------------- 1 | # MCP Client 2 | 3 | > Learn how to use the Model Context Protocol (MCP) client to interact with MCP servers 4 | 5 | # Model Context Protocol Client 6 | 7 | The MCP Client is a key component in the Model Context Protocol (MCP) architecture, responsible for establishing and managing connections with MCP servers. It implements the client-side of the protocol, handling: 8 | 9 | * Protocol version negotiation to ensure compatibility with servers 10 | * Capability negotiation to determine available features 11 | * Message transport and JSON-RPC communication 12 | * Tool discovery and execution 13 | * Resource access and management 14 | * Prompt system interactions 15 | * Optional features like roots management and sampling support 16 | 17 | The client provides both synchronous and asynchronous APIs for flexibility in different application contexts. 18 | 19 | 20 | 21 | ```java 22 | // Create a sync client with custom configuration 23 | McpSyncClient client = McpClient.sync(transport) 24 | .requestTimeout(Duration.ofSeconds(10)) 25 | .capabilities(ClientCapabilities.builder() 26 | .roots(true) // Enable roots capability 27 | .sampling() // Enable sampling capability 28 | .build()) 29 | .sampling(request -> new CreateMessageResult(response)) 30 | .build(); 31 | 32 | // Initialize connection 33 | client.initialize(); 34 | 35 | // List available tools 36 | ListToolsResult tools = client.listTools(); 37 | 38 | // Call a tool 39 | CallToolResult result = client.callTool( 40 | new CallToolRequest("calculator", 41 | Map.of("operation", "add", "a", 2, "b", 3)) 42 | ); 43 | 44 | // List and read resources 45 | ListResourcesResult resources = client.listResources(); 46 | ReadResourceResult resource = client.readResource( 47 | new ReadResourceRequest("resource://uri") 48 | ); 49 | 50 | // List and use prompts 51 | ListPromptsResult prompts = client.listPrompts(); 52 | GetPromptResult prompt = client.getPrompt( 53 | new GetPromptRequest("greeting", Map.of("name", "Spring")) 54 | ); 55 | 56 | // Add/remove roots 57 | client.addRoot(new Root("file:///path", "description")); 58 | client.removeRoot("file:///path"); 59 | 60 | // Close client 61 | client.closeGracefully(); 62 | ``` 63 | 64 | 65 | 66 | ```java 67 | // Create an async client with custom configuration 68 | McpAsyncClient client = McpClient.async(transport) 69 | .requestTimeout(Duration.ofSeconds(10)) 70 | .capabilities(ClientCapabilities.builder() 71 | .roots(true) // Enable roots capability 72 | .sampling() // Enable sampling capability 73 | .build()) 74 | .sampling(request -> Mono.just(new CreateMessageResult(response))) 75 | .toolsChangeConsumer(tools -> Mono.fromRunnable(() -> { 76 | logger.info("Tools updated: {}", tools); 77 | })) 78 | .resourcesChangeConsumer(resources -> Mono.fromRunnable(() -> { 79 | logger.info("Resources updated: {}", resources); 80 | })) 81 | .promptsChangeConsumer(prompts -> Mono.fromRunnable(() -> { 82 | logger.info("Prompts updated: {}", prompts); 83 | })) 84 | .build(); 85 | 86 | // Initialize connection and use features 87 | client.initialize() 88 | .flatMap(initResult -> client.listTools()) 89 | .flatMap(tools -> { 90 | return client.callTool(new CallToolRequest( 91 | "calculator", 92 | Map.of("operation", "add", "a", 2, "b", 3) 93 | )); 94 | }) 95 | .flatMap(result -> { 96 | return client.listResources() 97 | .flatMap(resources -> 98 | client.readResource(new ReadResourceRequest("resource://uri")) 99 | ); 100 | }) 101 | .flatMap(resource -> { 102 | return client.listPrompts() 103 | .flatMap(prompts -> 104 | client.getPrompt(new GetPromptRequest( 105 | "greeting", 106 | Map.of("name", "Spring") 107 | )) 108 | ); 109 | }) 110 | .flatMap(prompt -> { 111 | return client.addRoot(new Root("file:///path", "description")) 112 | .then(client.removeRoot("file:///path")); 113 | }) 114 | .doFinally(signalType -> { 115 | client.closeGracefully().subscribe(); 116 | }) 117 | .subscribe(); 118 | ``` 119 | 120 | 121 | 122 | ## Client Transport 123 | 124 | The transport layer handles the communication between MCP clients and servers, providing different implementations for various use cases. The client transport manages message serialization, connection establishment, and protocol-specific communication patterns. 125 | 126 | 127 | 128 | Creates transport for in-process based communication 129 | 130 | ```java 131 | ServerParameters params = ServerParameters.builder("npx") 132 | .args("-y", "@modelcontextprotocol/server-everything", "dir") 133 | .build(); 134 | McpTransport transport = new StdioClientTransport(params); 135 | ``` 136 | 137 | 138 | 139 | Creates a framework agnostic (pure Java API) SSE client transport. Included in the core mcp module. 140 | 141 | ```java 142 | McpTransport transport = new HttpClientSseClientTransport("http://your-mcp-server"); 143 | ``` 144 | 145 | 146 | 147 | Creates WebFlux-based SSE client transport. Requires the mcp-webflux-sse-transport dependency. 148 | 149 | ```java 150 | WebClient.Builder webClientBuilder = WebClient.builder() 151 | .baseUrl("http://your-mcp-server"); 152 | McpTransport transport = new WebFluxSseClientTransport(webClientBuilder); 153 | ``` 154 | 155 | 156 | 157 | ## Client Capabilities 158 | 159 | The client can be configured with various capabilities: 160 | 161 | ```java 162 | var capabilities = ClientCapabilities.builder() 163 | .roots(true) // Enable filesystem roots support with list changes notifications 164 | .sampling() // Enable LLM sampling support 165 | .build(); 166 | ``` 167 | 168 | ### Roots Support 169 | 170 | Roots define the boundaries of where servers can operate within the filesystem: 171 | 172 | ```java 173 | // Add a root dynamically 174 | client.addRoot(new Root("file:///path", "description")); 175 | 176 | // Remove a root 177 | client.removeRoot("file:///path"); 178 | 179 | // Notify server of roots changes 180 | client.rootsListChangedNotification(); 181 | ``` 182 | 183 | The roots capability allows servers to: 184 | 185 | * Request the list of accessible filesystem roots 186 | * Receive notifications when the roots list changes 187 | * Understand which directories and files they have access to 188 | 189 | ### Sampling Support 190 | 191 | Sampling enables servers to request LLM interactions ("completions" or "generations") through the client: 192 | 193 | ```java 194 | // Configure sampling handler 195 | Function samplingHandler = request -> { 196 | // Sampling implementation that interfaces with LLM 197 | return new CreateMessageResult(response); 198 | }; 199 | 200 | // Create client with sampling support 201 | var client = McpClient.sync(transport) 202 | .capabilities(ClientCapabilities.builder() 203 | .sampling() 204 | .build()) 205 | .sampling(samplingHandler) 206 | .build(); 207 | ``` 208 | 209 | This capability allows: 210 | 211 | * Servers to leverage AI capabilities without requiring API keys 212 | * Clients to maintain control over model access and permissions 213 | * Support for both text and image-based interactions 214 | * Optional inclusion of MCP server context in prompts 215 | 216 | ## Using MCP Clients 217 | 218 | ### Tool Execution 219 | 220 | Tools are server-side functions that clients can discover and execute. The MCP client provides methods to list available tools and execute them with specific parameters. Each tool has a unique name and accepts a map of parameters. 221 | 222 | 223 | 224 | ```java 225 | // List available tools and their names 226 | var tools = client.listTools(); 227 | tools.forEach(tool -> System.out.println(tool.getName())); 228 | 229 | // Execute a tool with parameters 230 | var result = client.callTool("calculator", Map.of( 231 | "operation", "add", 232 | "a", 1, 233 | "b", 2 234 | )); 235 | ``` 236 | 237 | 238 | 239 | ```java 240 | // List available tools asynchronously 241 | client.listTools() 242 | .doOnNext(tools -> tools.forEach(tool -> 243 | System.out.println(tool.getName()))) 244 | .subscribe(); 245 | 246 | // Execute a tool asynchronously 247 | client.callTool("calculator", Map.of( 248 | "operation", "add", 249 | "a", 1, 250 | "b", 2 251 | )) 252 | .subscribe(); 253 | ``` 254 | 255 | 256 | 257 | ### Resource Access 258 | 259 | Resources represent server-side data sources that clients can access using URI templates. The MCP client provides methods to discover available resources and retrieve their contents through a standardized interface. 260 | 261 | 262 | 263 | ```java 264 | // List available resources and their names 265 | var resources = client.listResources(); 266 | resources.forEach(resource -> System.out.println(resource.getName())); 267 | 268 | // Retrieve resource content using a URI template 269 | var content = client.getResource("file", Map.of( 270 | "path", "/path/to/file.txt" 271 | )); 272 | ``` 273 | 274 | 275 | 276 | ```java 277 | // List available resources asynchronously 278 | client.listResources() 279 | .doOnNext(resources -> resources.forEach(resource -> 280 | System.out.println(resource.getName()))) 281 | .subscribe(); 282 | 283 | // Retrieve resource content asynchronously 284 | client.getResource("file", Map.of( 285 | "path", "/path/to/file.txt" 286 | )) 287 | .subscribe(); 288 | ``` 289 | 290 | 291 | 292 | ### Prompt System 293 | 294 | The prompt system enables interaction with server-side prompt templates. These templates can be discovered and executed with custom parameters, allowing for dynamic text generation based on predefined patterns. 295 | 296 | 297 | 298 | ```java 299 | // List available prompt templates 300 | var prompts = client.listPrompts(); 301 | prompts.forEach(prompt -> System.out.println(prompt.getName())); 302 | 303 | // Execute a prompt template with parameters 304 | var response = client.executePrompt("echo", Map.of( 305 | "text", "Hello, World!" 306 | )); 307 | ``` 308 | 309 | 310 | 311 | ```java 312 | // List available prompt templates asynchronously 313 | client.listPrompts() 314 | .doOnNext(prompts -> prompts.forEach(prompt -> 315 | System.out.println(prompt.getName()))) 316 | .subscribe(); 317 | 318 | // Execute a prompt template asynchronously 319 | client.executePrompt("echo", Map.of( 320 | "text", "Hello, World!" 321 | )) 322 | .subscribe(); 323 | ``` 324 | 325 | 326 | -------------------------------------------------------------------------------- /docs/mcp/modelcontextprotocol.io-sdk-java-mcp-overview.md: -------------------------------------------------------------------------------- 1 | # Overview 2 | 3 | > Introduction to the Model Context Protocol (MCP) Java SDK 4 | 5 | Java SDK for the [Model Context Protocol](https://modelcontextprotocol.org/docs/concepts/architecture) 6 | enables standardized integration between AI models and tools. 7 | 8 | ## Features 9 | 10 | * MCP Client and MCP Server implementations supporting: 11 | * Protocol [version compatibility negotiation](https://spec.modelcontextprotocol.io/specification/2024-11-05/basic/lifecycle/#initialization) 12 | * [Tool](https://spec.modelcontextprotocol.io/specification/2024-11-05/server/tools/) discovery, execution, list change notifications 13 | * [Resource](https://spec.modelcontextprotocol.io/specification/2024-11-05/server/resources/) management with URI templates 14 | * [Roots](https://spec.modelcontextprotocol.io/specification/2024-11-05/client/roots/) list management and notifications 15 | * [Prompt](https://spec.modelcontextprotocol.io/specification/2024-11-05/server/prompts/) handling and management 16 | * [Sampling](https://spec.modelcontextprotocol.io/specification/2024-11-05/client/sampling/) support for AI model interactions 17 | * Multiple transport implementations: 18 | * Default transports: 19 | * Stdio-based transport for process-based communication 20 | * Java HttpClient-based SSE client transport for HTTP SSE Client-side streaming 21 | * Servlet-based SSE server transport for HTTP SSE Server streaming 22 | * Spring-based transports: 23 | * WebFlux SSE client and server transports for reactive HTTP streaming 24 | * WebMVC SSE transport for servlet-based HTTP streaming 25 | * Supports Synchronous and Asynchronous programming paradigms 26 | 27 | ## Architecture 28 | 29 | The SDK follows a layered architecture with clear separation of concerns: 30 | 31 | ![MCP Stack Architecture](https://mintlify.s3.us-west-1.amazonaws.com/mcp/images/java/mcp-stack.svg) 32 | 33 | * **Client/Server Layer (McpClient/McpServer)**: Both use McpSession for sync/async operations, 34 | with McpClient handling client-side protocol operations and McpServer managing server-side protocol operations. 35 | * **Session Layer (McpSession)**: Manages communication patterns and state using DefaultMcpSession implementation. 36 | * **Transport Layer (McpTransport)**: Handles JSON-RPC message serialization/deserialization via: 37 | * StdioTransport (stdin/stdout) in the core module 38 | * HTTP SSE transports in dedicated transport modules (Java HttpClient, Spring WebFlux, Spring WebMVC) 39 | 40 | The MCP Client is a key component in the Model Context Protocol (MCP) architecture, responsible for establishing and managing connections with MCP servers. 41 | It implements the client-side of the protocol. 42 | 43 | ![Java MCP Client Architecture](https://mintlify.s3.us-west-1.amazonaws.com/mcp/images/java/java-mcp-client-architecture.jpg) 44 | 45 | The MCP Server is a foundational component in the Model Context Protocol (MCP) architecture that provides tools, resources, and capabilities to clients. 46 | It implements the server-side of the protocol. 47 | 48 | ![Java MCP Server Architecture](https://mintlify.s3.us-west-1.amazonaws.com/mcp/images/java/java-mcp-server-architecture.jpg) 49 | 50 | Key Interactions: 51 | 52 | * **Client/Server Initialization**: Transport setup, protocol compatibility check, capability negotiation, and implementation details exchange. 53 | * **Message Flow**: JSON-RPC message handling with validation, type-safe response processing, and error handling. 54 | * **Resource Management**: Resource discovery, URI template-based access, subscription system, and content retrieval. 55 | 56 | ## Dependencies 57 | 58 | Add the following Maven dependency to your project: 59 | 60 | 61 | 62 | The core MCP functionality: 63 | 64 | ```xml 65 | 66 | io.modelcontextprotocol.sdk 67 | mcp 68 | 69 | ``` 70 | 71 | For HTTP SSE transport implementations, add one of the following dependencies: 72 | 73 | ```xml 74 | 75 | 76 | io.modelcontextprotocol.sdk 77 | mcp-spring-webflux 78 | 79 | 80 | 81 | 82 | io.modelcontextprotocol.sdk 83 | mcp-spring-webmvc 84 | 85 | ``` 86 | 87 | 88 | 89 | The core MCP functionality: 90 | 91 | ```groovy 92 | dependencies { 93 | implementation platform("io.modelcontextprotocol.sdk:mcp") 94 | //... 95 | } 96 | ``` 97 | 98 | For HTTP SSE transport implementations, add one of the following dependencies: 99 | 100 | ```groovy 101 | // Spring WebFlux-based SSE client and server transport 102 | dependencies { 103 | implementation platform("io.modelcontextprotocol.sdk:mcp-spring-webflux") 104 | } 105 | 106 | // Spring WebMVC-based SSE server transport 107 | dependencies { 108 | implementation platform("io.modelcontextprotocol.sdk:mcp-spring-webmvc") 109 | } 110 | ``` 111 | 112 | 113 | 114 | ### Bill of Materials (BOM) 115 | 116 | The Bill of Materials (BOM) declares the recommended versions of all the dependencies used by a given release. 117 | Using the BOM from your application's build script avoids the need for you to specify and maintain the dependency versions yourself. 118 | Instead, the version of the BOM you're using determines the utilized dependency versions. 119 | It also ensures that you're using supported and tested versions of the dependencies by default, unless you choose to override them. 120 | 121 | Add the BOM to your project: 122 | 123 | 124 | 125 | ```xml 126 | 127 | 128 | 129 | io.modelcontextprotocol.sdk 130 | mcp-bom 131 | 0.7.0 132 | pom 133 | import 134 | 135 | 136 | 137 | ``` 138 | 139 | 140 | 141 | ```groovy 142 | dependencies { 143 | implementation platform("io.modelcontextprotocol.sdk:mcp-bom:0.7.0") 144 | //... 145 | } 146 | ``` 147 | 148 | Gradle users can also use the Spring AI MCP BOM by leveraging Gradle (5.0+) native support for declaring dependency constraints using a Maven BOM. 149 | This is implemented by adding a 'platform' dependency handler method to the dependencies section of your Gradle build script. 150 | As shown in the snippet above this can then be followed by version-less declarations of the Starter Dependencies for the one or more spring-ai modules you wish to use, e.g. spring-ai-openai. 151 | 152 | 153 | 154 | Replace the version number with the version of the BOM you want to use. 155 | 156 | ### Available Dependencies 157 | 158 | The following dependencies are available and managed by the BOM: 159 | 160 | * Core Dependencies 161 | * `io.modelcontextprotocol.sdk:mcp` - Core MCP library providing the base functionality and APIs for Model Context Protocol implementation. 162 | * Transport Dependencies 163 | * `io.modelcontextprotocol.sdk:mcp-spring-webflux` - WebFlux-based Server-Sent Events (SSE) transport implementation for reactive applications. 164 | * `io.modelcontextprotocol.sdk:mcp-spring-webmvc` - WebMVC-based Server-Sent Events (SSE) transport implementation for servlet-based applications. 165 | * Testing Dependencies 166 | * `io.modelcontextprotocol.sdk:mcp-test` - Testing utilities and support for MCP-based applications. 167 | -------------------------------------------------------------------------------- /docs/mcp/modelcontextprotocol.io-sdk-java-mcp-server.md: -------------------------------------------------------------------------------- 1 | # MCP Server 2 | 3 | > Learn how to implement and configure a Model Context Protocol (MCP) server 4 | 5 | ## Overview 6 | 7 | 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: 8 | 9 | * Exposing tools that clients can discover and execute 10 | * Managing resources with URI-based access patterns 11 | * Providing prompt templates and handling prompt requests 12 | * Supporting capability negotiation with clients 13 | * Implementing server-side protocol operations 14 | * Managing concurrent client connections 15 | * Providing structured logging and notifications 16 | 17 | The server supports both synchronous and asynchronous APIs, allowing for flexible integration in different application contexts. 18 | 19 | 20 | 21 | ```java 22 | // Create a server with custom configuration 23 | McpSyncServer syncServer = McpServer.sync(transport) 24 | .serverInfo("my-server", "1.0.0") 25 | .capabilities(ServerCapabilities.builder() 26 | .resources(true) // Enable resource support 27 | .tools(true) // Enable tool support 28 | .prompts(true) // Enable prompt support 29 | .logging() // Enable logging support 30 | .build()) 31 | .build(); 32 | 33 | // Register tools, resources, and prompts 34 | syncServer.addTool(syncToolRegistration); 35 | syncServer.addResource(syncResourceRegistration); 36 | syncServer.addPrompt(syncPromptRegistration); 37 | 38 | // Send logging notifications 39 | syncServer.loggingNotification(LoggingMessageNotification.builder() 40 | .level(LoggingLevel.INFO) 41 | .logger("custom-logger") 42 | .data("Server initialized") 43 | .build()); 44 | 45 | // Close the server when done 46 | syncServer.close(); 47 | ``` 48 | 49 | 50 | 51 | ```java 52 | // Create an async server with custom configuration 53 | McpAsyncServer asyncServer = McpServer.async(transport) 54 | .serverInfo("my-server", "1.0.0") 55 | .capabilities(ServerCapabilities.builder() 56 | .resources(true) // Enable resource support 57 | .tools(true) // Enable tool support 58 | .prompts(true) // Enable prompt support 59 | .logging() // Enable logging support 60 | .build()) 61 | .build(); 62 | 63 | // Register tools, resources, and prompts 64 | asyncServer.addTool(asyncToolRegistration) 65 | .doOnSuccess(v -> logger.info("Tool registered")) 66 | .subscribe(); 67 | 68 | asyncServer.addResource(asyncResourceRegistration) 69 | .doOnSuccess(v -> logger.info("Resource registered")) 70 | .subscribe(); 71 | 72 | asyncServer.addPrompt(asyncPromptRegistration) 73 | .doOnSuccess(v -> logger.info("Prompt registered")) 74 | .subscribe(); 75 | 76 | // Send logging notifications 77 | asyncServer.loggingNotification(LoggingMessageNotification.builder() 78 | .level(LoggingLevel.INFO) 79 | .logger("custom-logger") 80 | .data("Server initialized") 81 | .build()); 82 | 83 | // Close the server when done 84 | asyncServer.close() 85 | .doOnSuccess(v -> logger.info("Server closed")) 86 | .subscribe(); 87 | ``` 88 | 89 | 90 | 91 | ## Server Transport 92 | 93 | 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: 94 | 95 | 96 | 97 | <> 98 | Create in-process based transport: 99 | 100 | ```java 101 | StdioServerTransport transport = new StdioServerTransport(new ObjectMapper()); 102 | ``` 103 | 104 | Provides bidirectional JSON-RPC message handling over standard input/output streams with non-blocking message processing, serialization/deserialization, and graceful shutdown support. 105 | 106 | Key features: 107 | 108 |
    109 |
  • Bidirectional communication through stdin/stdout
  • 110 |
  • Process-based integration support
  • 111 |
  • Simple setup and configuration
  • 112 |
  • Lightweight implementation
  • 113 |
114 | 115 |
116 | 117 | 118 | <> 119 |

Creates WebFlux-based SSE server transport.
Requires the mcp-spring-webflux dependency.

120 | 121 | ```java 122 | @Configuration 123 | class McpConfig { 124 | @Bean 125 | WebFluxSseServerTransport webFluxSseServerTransport(ObjectMapper mapper) { 126 | return new WebFluxSseServerTransport(mapper, "/mcp/message"); 127 | } 128 | 129 | @Bean 130 | RouterFunction mcpRouterFunction(WebFluxSseServerTransport transport) { 131 | return transport.getRouterFunction(); 132 | } 133 | } 134 | ``` 135 | 136 |

Implements the MCP HTTP with SSE transport specification, providing:

137 | 138 |
    139 |
  • Reactive HTTP streaming with WebFlux
  • 140 |
  • Concurrent client connections through SSE endpoints
  • 141 |
  • Message routing and session management
  • 142 |
  • Graceful shutdown capabilities
  • 143 |
144 | 145 |
146 | 147 | 148 | <> 149 |

Creates WebMvc-based SSE server transport.
Requires the mcp-spring-webmvc dependency.

150 | 151 | ```java 152 | @Configuration 153 | @EnableWebMvc 154 | class McpConfig { 155 | @Bean 156 | WebMvcSseServerTransport webMvcSseServerTransport(ObjectMapper mapper) { 157 | return new WebMvcSseServerTransport(mapper, "/mcp/message"); 158 | } 159 | 160 | @Bean 161 | RouterFunction mcpRouterFunction(WebMvcSseServerTransport transport) { 162 | return transport.getRouterFunction(); 163 | } 164 | } 165 | ``` 166 | 167 |

Implements the MCP HTTP with SSE transport specification, providing:

168 | 169 |
    170 |
  • Server-side event streaming
  • 171 |
  • Integration with Spring WebMVC
  • 172 |
  • Support for traditional web applications
  • 173 |
  • Synchronous operation handling
  • 174 |
175 | 176 |
177 | 178 | 179 | <> 180 |

181 | Creates a Servlet-based SSE server transport. It is included in the core mcp module.
182 | The HttpServletSseServerTransport can be used with any Servlet container.
183 | To use it with a Spring Web application, you can register it as a Servlet bean: 184 |

185 | 186 | ```java 187 | @Configuration 188 | @EnableWebMvc 189 | public class McpServerConfig implements WebMvcConfigurer { 190 | 191 | @Bean 192 | public HttpServletSseServerTransport servletSseServerTransport() { 193 | return new HttpServletSseServerTransport(new ObjectMapper(), "/mcp/message"); 194 | } 195 | 196 | @Bean 197 | public ServletRegistrationBean customServletBean(HttpServletSseServerTransport servlet) { 198 | return new ServletRegistrationBean(servlet); 199 | } 200 | } 201 | ``` 202 | 203 |

204 | Implements the MCP HTTP with SSE transport specification using the traditional Servlet API, providing: 205 |

206 | 207 |
    208 |
  • Asynchronous message handling using Servlet 6.0 async support
  • 209 |
  • Session management for multiple client connections
  • 210 | 211 |
  • 212 | Two types of endpoints: 213 | 214 |
      215 |
    • SSE endpoint (/sse) for server-to-client events
    • 216 |
    • Message endpoint (configurable) for client-to-server requests
    • 217 |
    218 |
  • 219 | 220 |
  • Error handling and response formatting
  • 221 |
  • Graceful shutdown support
  • 222 |
223 | 224 |
225 |
226 | 227 | ## Server Capabilities 228 | 229 | The server can be configured with various capabilities: 230 | 231 | ```java 232 | var capabilities = ServerCapabilities.builder() 233 | .resources(false, true) // Resource support with list changes notifications 234 | .tools(true) // Tool support with list changes notifications 235 | .prompts(true) // Prompt support with list changes notifications 236 | .logging() // Enable logging support (enabled by default with loging level INFO) 237 | .build(); 238 | ``` 239 | 240 | ### Logging Support 241 | 242 | The server provides structured logging capabilities that allow sending log messages to clients with different severity levels: 243 | 244 | ```java 245 | // Send a log message to clients 246 | server.loggingNotification(LoggingMessageNotification.builder() 247 | .level(LoggingLevel.INFO) 248 | .logger("custom-logger") 249 | .data("Custom log message") 250 | .build()); 251 | ``` 252 | 253 | Clients can control the minimum logging level they receive through the `mcpClient.setLoggingLevel(level)` request. Messages below the set level will be filtered out. 254 | Supported logging levels (in order of increasing severity): DEBUG (0), INFO (1), NOTICE (2), WARNING (3), ERROR (4), CRITICAL (5), ALERT (6), EMERGENCY (7) 255 | 256 | ### Tool Registration 257 | 258 | 259 | 260 | ```java 261 | // Sync tool registration 262 | var syncToolRegistration = new McpServerFeatures.SyncToolRegistration( 263 | new Tool("calculator", "Basic calculator", Map.of( 264 | "operation", "string", 265 | "a", "number", 266 | "b", "number" 267 | )), 268 | arguments -> { 269 | // Tool implementation 270 | return new CallToolResult(result, false); 271 | } 272 | ); 273 | ``` 274 | 275 | 276 | 277 | ```java 278 | // Async tool registration 279 | var asyncToolRegistration = new McpServerFeatures.AsyncToolRegistration( 280 | new Tool("calculator", "Basic calculator", Map.of( 281 | "operation", "string", 282 | "a", "number", 283 | "b", "number" 284 | )), 285 | arguments -> { 286 | // Tool implementation 287 | return Mono.just(new CallToolResult(result, false)); 288 | } 289 | ); 290 | ``` 291 | 292 | 293 | 294 | ### Resource Registration 295 | 296 | 297 | 298 | ```java 299 | // Sync resource registration 300 | var syncResourceRegistration = new McpServerFeatures.SyncResourceRegistration( 301 | new Resource("custom://resource", "name", "description", "mime-type", null), 302 | request -> { 303 | // Resource read implementation 304 | return new ReadResourceResult(contents); 305 | } 306 | ); 307 | ``` 308 | 309 | 310 | 311 | ```java 312 | // Async resource registration 313 | var asyncResourceRegistration = new McpServerFeatures.AsyncResourceRegistration( 314 | new Resource("custom://resource", "name", "description", "mime-type", null), 315 | request -> { 316 | // Resource read implementation 317 | return Mono.just(new ReadResourceResult(contents)); 318 | } 319 | ); 320 | ``` 321 | 322 | 323 | 324 | ### Prompt Registration 325 | 326 | 327 | 328 | ```java 329 | // Sync prompt registration 330 | var syncPromptRegistration = new McpServerFeatures.SyncPromptRegistration( 331 | new Prompt("greeting", "description", List.of( 332 | new PromptArgument("name", "description", true) 333 | )), 334 | request -> { 335 | // Prompt implementation 336 | return new GetPromptResult(description, messages); 337 | } 338 | ); 339 | ``` 340 | 341 | 342 | 343 | ```java 344 | // Async prompt registration 345 | var asyncPromptRegistration = new McpServerFeatures.AsyncPromptRegistration( 346 | new Prompt("greeting", "description", List.of( 347 | new PromptArgument("name", "description", true) 348 | )), 349 | request -> { 350 | // Prompt implementation 351 | return Mono.just(new GetPromptResult(description, messages)); 352 | } 353 | ); 354 | ``` 355 | 356 | 357 | 358 | ## Error Handling 359 | 360 | 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. 361 | -------------------------------------------------------------------------------- /docs/mcp/modelcontextprotocol.io-tutorials-building-mcp-with-llms.md: -------------------------------------------------------------------------------- 1 | # Building MCP with LLMs 2 | 3 | > Speed up your MCP development using LLMs such as Claude! 4 | 5 | This guide will help you use LLMs to help you build custom Model Context Protocol (MCP) servers and clients. We'll be focusing on Claude for this tutorial, but you can do this with any frontier LLM. 6 | 7 | ## Preparing the documentation 8 | 9 | Before starting, gather the necessary documentation to help Claude understand MCP: 10 | 11 | 1. Visit [https://modelcontextprotocol.io/llms-full.txt](https://modelcontextprotocol.io/llms-full.txt) and copy the full documentation text 12 | 2. Navigate to either the [MCP TypeScript SDK](https://github.com/modelcontextprotocol/typescript-sdk) or [Python SDK repository](https://github.com/modelcontextprotocol/python-sdk) 13 | 3. Copy the README files and other relevant documentation 14 | 4. Paste these documents into your conversation with Claude 15 | 16 | ## Describing your server 17 | 18 | Once you've provided the documentation, clearly describe to Claude what kind of server you want to build. Be specific about: 19 | 20 | * What resources your server will expose 21 | * What tools it will provide 22 | * Any prompts it should offer 23 | * What external systems it needs to interact with 24 | 25 | For example: 26 | 27 | ``` 28 | Build an MCP server that: 29 | - Connects to my company's PostgreSQL database 30 | - Exposes table schemas as resources 31 | - Provides tools for running read-only SQL queries 32 | - Includes prompts for common data analysis tasks 33 | ``` 34 | 35 | ## Working with Claude 36 | 37 | When working with Claude on MCP servers: 38 | 39 | 1. Start with the core functionality first, then iterate to add more features 40 | 2. Ask Claude to explain any parts of the code you don't understand 41 | 3. Request modifications or improvements as needed 42 | 4. Have Claude help you test the server and handle edge cases 43 | 44 | Claude can help implement all the key MCP features: 45 | 46 | * Resource management and exposure 47 | * Tool definitions and implementations 48 | * Prompt templates and handlers 49 | * Error handling and logging 50 | * Connection and transport setup 51 | 52 | ## Best practices 53 | 54 | When building MCP servers with Claude: 55 | 56 | * Break down complex servers into smaller pieces 57 | * Test each component thoroughly before moving on 58 | * Keep security in mind - validate inputs and limit access appropriately 59 | * Document your code well for future maintenance 60 | * Follow MCP protocol specifications carefully 61 | 62 | ## Next steps 63 | 64 | After Claude helps you build your server: 65 | 66 | 1. Review the generated code carefully 67 | 2. Test the server with the MCP Inspector tool 68 | 3. Connect it to Claude.app or other MCP clients 69 | 4. Iterate based on real usage and feedback 70 | 71 | Remember that Claude can help you modify and improve your server as requirements change over time. 72 | 73 | Need more guidance? Just ask Claude specific questions about implementing MCP features or troubleshooting issues that arise. 74 | -------------------------------------------------------------------------------- /examples/example-usage.md: -------------------------------------------------------------------------------- 1 | # MCP Test Client Example Usage 2 | 3 | This document provides examples of how to use the MCP Test Client for testing MCP servers during development. 4 | 5 | ## Deploying a Server 6 | 7 | ```typescript 8 | // Deploy a server to the test environment 9 | mcp__mcp-test__mcp_test_deploy_server({ 10 | name: "claude-chat", 11 | source_path: "/Users/williambrown/dev/claude-code/playground/claude-chat-mcp", 12 | env_vars: { 13 | "ANTHROPIC_API_KEY": "${ANTHROPIC_API_KEY}" 14 | }, 15 | persistent: true 16 | }) 17 | ``` 18 | 19 | ## Calling a Tool 20 | 21 | ```typescript 22 | // Call a tool on the deployed server 23 | mcp__mcp-test__mcp_test_call_tool({ 24 | server_name: "claude-chat", 25 | tool_name: "claude_send_message", 26 | arguments: { 27 | prompt: "Tell me a fun fact about AI development" 28 | } 29 | }) 30 | ``` 31 | 32 | ## Running Tests 33 | 34 | ```typescript 35 | // Run automated tests against the server 36 | mcp__mcp-test__mcp_test_run_tests({ 37 | server_name: "claude-chat", 38 | test_suite: "basic" 39 | }) 40 | ``` 41 | 42 | ## Getting Logs 43 | 44 | ```typescript 45 | // View server logs for debugging 46 | mcp__mcp-test__mcp_test_get_logs({ 47 | server_name: "claude-chat", 48 | lines: 100 49 | }) 50 | ``` 51 | 52 | ## Listing Servers 53 | 54 | ```typescript 55 | // List all deployed servers 56 | mcp__mcp-test__mcp_test_list_servers({ 57 | status: "running" 58 | }) 59 | ``` 60 | 61 | ## Stopping a Server 62 | 63 | ```typescript 64 | // Stop a server when done testing 65 | mcp__mcp-test__mcp_test_stop_server({ 66 | server_name: "claude-chat" 67 | }) 68 | ``` 69 | 70 | ## Complete Development Workflow 71 | 72 | Here's an example of a complete development workflow: 73 | 74 | 1. **Develop MCP Server**: Create or modify a server in the playground directory 75 | 76 | 2. **Deploy for Testing**: 77 | ```typescript 78 | mcp__mcp-test__mcp_test_deploy_server({ 79 | name: "my-server", 80 | source_path: "/Users/williambrown/dev/claude-code/playground/my-server" 81 | }) 82 | ``` 83 | 84 | 3. **Run Tests**: 85 | ```typescript 86 | mcp__mcp-test__mcp_test_run_tests({ 87 | server_name: "my-server" 88 | }) 89 | ``` 90 | 91 | 4. **Debug Issues**: 92 | ```typescript 93 | mcp__mcp-test__mcp_test_get_logs({ 94 | server_name: "my-server" 95 | }) 96 | ``` 97 | 98 | 5. **Fix and Iterate**: Make changes to your code (they will be immediately available) 99 | 100 | 6. **Re-run Tests**: 101 | ```typescript 102 | mcp__mcp-test__mcp_test_run_tests({ 103 | server_name: "my-server" 104 | }) 105 | ``` 106 | 107 | 7. **Clean Up**: 108 | ```typescript 109 | mcp__mcp-test__mcp_test_stop_server({ 110 | server_name: "my-server" 111 | }) 112 | ``` 113 | 114 | This workflow allows for rapid iteration without needing to restart Claude sessions or formally register the server during development. -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mcp-test-client", 3 | "version": "0.1.0", 4 | "description": "MCP Test Client for testing MCP servers during development", 5 | "type": "module", 6 | "main": "dist/index.js", 7 | "scripts": { 8 | "build": "tsc", 9 | "start": "node dist/index.js", 10 | "dev": "ts-node --esm src/index.ts", 11 | "test": "ts-node --esm src/test-runner.ts" 12 | }, 13 | "keywords": [ 14 | "mcp", 15 | "test", 16 | "client", 17 | "development" 18 | ], 19 | "author": "", 20 | "license": "ISC", 21 | "dependencies": { 22 | "@modelcontextprotocol/sdk": "^1.6.1", 23 | "dockerode": "^3.3.5", 24 | "zod": "^3.24.2" 25 | }, 26 | "devDependencies": { 27 | "@types/dockerode": "^3.3.35", 28 | "@types/node": "^22.13.9", 29 | "ts-node": "^10.9.2", 30 | "typescript": "^5.8.2" 31 | }, 32 | "directories": { 33 | "test": "test" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /scripts/build-and-register.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Script to build and register the MCP Test Client with Claude 4 | 5 | # Exit on error 6 | set -e 7 | 8 | echo "Building MCP Test Client..." 9 | cd "$(dirname "$0")/.." 10 | npm run build 11 | 12 | echo "Making index.js executable..." 13 | chmod +x dist/index.js 14 | 15 | echo "Registering MCP Test Client with Claude..." 16 | cd - 17 | cd "$(dirname "$0")/../../" 18 | claude mcp add mcp-test -- node "$(dirname "$0")/../dist/index.js" 19 | 20 | echo "MCP Test Client registered successfully!" 21 | echo "You can now use the mcp_test_* tools in Claude." -------------------------------------------------------------------------------- /scripts/register-with-claude.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Check if the client is built 4 | if [ ! -f "$(dirname "$0")/../dist/index.js" ]; then 5 | echo "Error: MCP Test Client is not built. Run 'npm run build' first." 6 | exit 1 7 | fi 8 | 9 | # Make sure it's executable 10 | chmod +x "$(dirname "$0")/../dist/index.js" 11 | 12 | # Register with Claude 13 | echo "Registering MCP Test Client with Claude..." 14 | cd "$(dirname "$0")/../../.." 15 | claude mcp add mcp-test -- node "$(dirname "$0")/../dist/index.js" 16 | 17 | echo "Successfully registered MCP Test Client!" 18 | echo "You can now use the following tools in Claude:" 19 | echo "- mcp_test_deploy_server" 20 | echo "- mcp_test_call_tool" 21 | echo "- mcp_test_get_logs" 22 | echo "- mcp_test_list_servers" 23 | echo "- mcp_test_run_tests" 24 | echo "- mcp_test_stop_server" -------------------------------------------------------------------------------- /src/common/errors.ts: -------------------------------------------------------------------------------- 1 | export class MCPTestError extends Error { 2 | constructor(message: string) { 3 | super(message); 4 | this.name = "MCPTestError"; 5 | } 6 | } 7 | 8 | export class ServerDeploymentError extends MCPTestError { 9 | constructor(message: string) { 10 | super(message); 11 | this.name = "ServerDeploymentError"; 12 | } 13 | } 14 | 15 | export class TestExecutionError extends MCPTestError { 16 | constructor(message: string) { 17 | super(message); 18 | this.name = "TestExecutionError"; 19 | } 20 | } 21 | 22 | export class ServerNotFoundError extends MCPTestError { 23 | serverName: string; 24 | 25 | constructor(serverName: string) { 26 | super(`Server '${serverName}' not found in test environment`); 27 | this.name = "ServerNotFoundError"; 28 | this.serverName = serverName; 29 | } 30 | } 31 | 32 | export class DockerConnectionError extends MCPTestError { 33 | constructor(message: string) { 34 | super(`Docker connection error: ${message}`); 35 | this.name = "DockerConnectionError"; 36 | } 37 | } 38 | 39 | export class ToolCallError extends MCPTestError { 40 | serverName: string; 41 | toolName: string; 42 | 43 | constructor(serverName: string, toolName: string, message: string) { 44 | super(`Error calling tool '${toolName}' on server '${serverName}': ${message}`); 45 | this.name = "ToolCallError"; 46 | this.serverName = serverName; 47 | this.toolName = toolName; 48 | } 49 | } -------------------------------------------------------------------------------- /src/common/logger.ts: -------------------------------------------------------------------------------- 1 | enum LogLevel { 2 | DEBUG = 0, 3 | INFO = 1, 4 | WARN = 2, 5 | ERROR = 3 6 | } 7 | 8 | class LoggerClass { 9 | private level: LogLevel = LogLevel.INFO; 10 | 11 | constructor() { 12 | // Set log level from environment variable 13 | const envLevel = process.env.LOG_LEVEL?.toUpperCase(); 14 | if (envLevel) { 15 | switch (envLevel) { 16 | case 'DEBUG': this.level = LogLevel.DEBUG; break; 17 | case 'INFO': this.level = LogLevel.INFO; break; 18 | case 'WARN': this.level = LogLevel.WARN; break; 19 | case 'ERROR': this.level = LogLevel.ERROR; break; 20 | default: 21 | // Keep default level 22 | break; 23 | } 24 | } 25 | } 26 | 27 | init(): void { 28 | // Initialize logger 29 | this.info(`Logger initialized at level: ${LogLevel[this.level]}`); 30 | } 31 | 32 | setLevel(level: LogLevel): void { 33 | this.level = level; 34 | this.info(`Log level set to: ${LogLevel[level]}`); 35 | } 36 | 37 | debug(message: string, ...args: any[]): void { 38 | if (this.level <= LogLevel.DEBUG) { 39 | this.log('DEBUG', message, ...args); 40 | } 41 | } 42 | 43 | info(message: string, ...args: any[]): void { 44 | if (this.level <= LogLevel.INFO) { 45 | this.log('INFO', message, ...args); 46 | } 47 | } 48 | 49 | warn(message: string, ...args: any[]): void { 50 | if (this.level <= LogLevel.WARN) { 51 | this.log('WARN', message, ...args); 52 | } 53 | } 54 | 55 | error(message: string, ...args: any[]): void { 56 | if (this.level <= LogLevel.ERROR) { 57 | this.log('ERROR', message, ...args); 58 | } 59 | } 60 | 61 | private log(level: string, message: string, ...args: any[]): void { 62 | const timestamp = new Date().toISOString(); 63 | const prefix = `[${timestamp}] ${level}:`; 64 | 65 | if (args.length > 0) { 66 | console.error(prefix, message, ...args); 67 | } else { 68 | console.error(prefix, message); 69 | } 70 | } 71 | } 72 | 73 | // Export singleton instance 74 | export const Logger = new LoggerClass(); -------------------------------------------------------------------------------- /src/common/version.ts: -------------------------------------------------------------------------------- 1 | export const VERSION = "0.1.0"; -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import { Server } from '@modelcontextprotocol/sdk/server/index.js'; 4 | import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; 5 | import { 6 | CallToolRequestSchema, 7 | ListToolsRequestSchema, 8 | } from '@modelcontextprotocol/sdk/types.js'; 9 | 10 | import { deployServer, listServers, getServerLogs, stopServer } from './operations/docker.js'; 11 | import { callTool, runTests } from './operations/mcp-client.js'; 12 | 13 | import { 14 | DeployServerSchema, 15 | CallToolSchema, 16 | GetLogsSchema, 17 | ListServersSchema, 18 | RunTestsSchema, 19 | ServerOperationSchema 20 | } from './types/schemas.js'; 21 | 22 | import { VERSION } from './common/version.js'; 23 | import { Logger } from './common/logger.js'; 24 | import { MCPTestError } from './common/errors.js'; 25 | 26 | // Initialize logger 27 | Logger.init(); 28 | 29 | // Create MCP server instance 30 | const server = new Server( 31 | { 32 | name: 'mcp-test-client', 33 | version: VERSION, 34 | }, 35 | { 36 | capabilities: { 37 | tools: {}, 38 | }, 39 | }, 40 | ); 41 | 42 | // Handle listing tools 43 | server.setRequestHandler(ListToolsRequestSchema, async () => { 44 | Logger.debug('Handling list tools request'); 45 | 46 | return { 47 | tools: [ 48 | { 49 | name: 'mcp_test_deploy_server', 50 | description: 'Deploy an MCP server to a test environment', 51 | inputSchema: { 52 | type: 'object', 53 | properties: { 54 | name: { 55 | type: 'string', 56 | description: 'Name for the deployed server' 57 | }, 58 | source_path: { 59 | type: 'string', 60 | description: 'Absolute path to the server source code' 61 | }, 62 | env_vars: { 63 | type: 'object', 64 | additionalProperties: { type: 'string' }, 65 | description: 'Environment variables to pass to the server' 66 | }, 67 | persistent: { 68 | type: 'boolean', 69 | description: 'Whether to keep the server running after tests', 70 | default: true 71 | } 72 | }, 73 | required: ['name', 'source_path'] 74 | } 75 | }, 76 | { 77 | name: 'mcp_test_call_tool', 78 | description: 'Call a tool on a deployed MCP server', 79 | inputSchema: { 80 | type: 'object', 81 | properties: { 82 | server_name: { 83 | type: 'string', 84 | description: 'Name of the deployed server to call' 85 | }, 86 | tool_name: { 87 | type: 'string', 88 | description: 'Name of the tool to call' 89 | }, 90 | arguments: { 91 | type: 'object', 92 | additionalProperties: true, 93 | description: 'Arguments to pass to the tool' 94 | } 95 | }, 96 | required: ['server_name', 'tool_name', 'arguments'] 97 | } 98 | }, 99 | { 100 | name: 'mcp_test_get_logs', 101 | description: 'Get logs from a deployed MCP server', 102 | inputSchema: { 103 | type: 'object', 104 | properties: { 105 | server_name: { 106 | type: 'string', 107 | description: 'Name of the deployed server' 108 | }, 109 | lines: { 110 | type: 'number', 111 | description: 'Number of log lines to return', 112 | default: 100 113 | } 114 | }, 115 | required: ['server_name'] 116 | } 117 | }, 118 | { 119 | name: 'mcp_test_list_servers', 120 | description: 'List all deployed MCP servers', 121 | inputSchema: { 122 | type: 'object', 123 | properties: { 124 | status: { 125 | type: 'string', 126 | enum: ['running', 'all'], 127 | description: 'Status of servers to list', 128 | default: 'running' 129 | } 130 | } 131 | } 132 | }, 133 | { 134 | name: 'mcp_test_run_tests', 135 | description: 'Run tests against a deployed MCP server', 136 | inputSchema: { 137 | type: 'object', 138 | properties: { 139 | server_name: { 140 | type: 'string', 141 | description: 'Name of the deployed server to test' 142 | }, 143 | test_suite: { 144 | type: 'string', 145 | description: 'Name of the test suite to run' 146 | }, 147 | interactive: { 148 | type: 'boolean', 149 | description: 'Whether to run tests interactively', 150 | default: false 151 | } 152 | }, 153 | required: ['server_name'] 154 | } 155 | }, 156 | { 157 | name: 'mcp_test_stop_server', 158 | description: 'Stop a deployed MCP server', 159 | inputSchema: { 160 | type: 'object', 161 | properties: { 162 | server_name: { 163 | type: 'string', 164 | description: 'Name of the deployed server' 165 | } 166 | }, 167 | required: ['server_name'] 168 | } 169 | } 170 | ] 171 | }; 172 | }); 173 | 174 | // Handle tool calls 175 | server.setRequestHandler(CallToolRequestSchema, async (request) => { 176 | const { name, arguments: args } = request.params; 177 | Logger.debug(`Handling tool call: ${name}`, args); 178 | 179 | if (!args) { 180 | throw new Error(`No arguments provided for tool: ${name}`); 181 | } 182 | 183 | try { 184 | let result; 185 | 186 | switch (name) { 187 | case 'mcp_test_deploy_server': { 188 | const input = DeployServerSchema.parse(args); 189 | result = await deployServer(input); 190 | break; 191 | } 192 | 193 | case 'mcp_test_call_tool': { 194 | const input = CallToolSchema.parse(args); 195 | result = await callTool(input); 196 | break; 197 | } 198 | 199 | case 'mcp_test_get_logs': { 200 | const input = GetLogsSchema.parse(args); 201 | result = await getServerLogs(input); 202 | break; 203 | } 204 | 205 | case 'mcp_test_list_servers': { 206 | const input = ListServersSchema.parse(args); 207 | result = await listServers(input); 208 | break; 209 | } 210 | 211 | case 'mcp_test_run_tests': { 212 | const input = RunTestsSchema.parse(args); 213 | result = await runTests(input); 214 | break; 215 | } 216 | 217 | case 'mcp_test_stop_server': { 218 | const input = ServerOperationSchema.parse(args); 219 | result = await stopServer(input); 220 | break; 221 | } 222 | 223 | default: 224 | throw new Error(`Unknown tool: ${name}`); 225 | } 226 | 227 | return { 228 | content: [ 229 | { 230 | type: "text", 231 | text: JSON.stringify(result, null, 2) 232 | } 233 | ], 234 | isError: false 235 | }; 236 | } catch (error) { 237 | Logger.error(`Error executing tool ${name}:`, error); 238 | 239 | const errorMessage = error instanceof Error ? error.message : String(error); 240 | const errorName = error instanceof MCPTestError ? error.name : 'InternalServerError'; 241 | 242 | return { 243 | content: [ 244 | { 245 | type: "text", 246 | text: JSON.stringify({ 247 | error: errorMessage, 248 | errorType: errorName 249 | }, null, 2) 250 | } 251 | ], 252 | isError: true 253 | }; 254 | } 255 | }); 256 | 257 | // Start the server 258 | async function main() { 259 | try { 260 | Logger.info('Starting MCP Test Client...'); 261 | 262 | const transport = new StdioServerTransport(); 263 | await server.connect(transport); 264 | 265 | Logger.info('MCP Test Client running on stdio'); 266 | } catch (error) { 267 | Logger.error('Failed to start server:', error); 268 | process.exit(1); 269 | } 270 | } 271 | 272 | main().catch((error) => { 273 | Logger.error('Fatal error in main():', error); 274 | process.exit(1); 275 | }); -------------------------------------------------------------------------------- /src/operations/docker.ts: -------------------------------------------------------------------------------- 1 | import Dockerode from 'dockerode'; 2 | import path from 'path'; 3 | import { spawn } from 'child_process'; 4 | import fs from 'fs'; 5 | import crypto from 'crypto'; 6 | import { 7 | DockerConnectionError, 8 | ServerDeploymentError, 9 | ServerNotFoundError 10 | } from '../common/errors.js'; 11 | import { Logger } from '../common/logger.js'; 12 | import { 13 | DeployServerInput, 14 | DeployServerResponse, 15 | GetLogsInput, 16 | GetLogsResponse, 17 | ListServersInput, 18 | ServerInfo, 19 | ServerOperationInput, 20 | ServerOperationResponse 21 | } from '../types/schemas.js'; 22 | 23 | // Initialize Docker client 24 | const docker = new Dockerode({ 25 | socketPath: process.env.DOCKER_HOST || '/var/run/docker.sock' 26 | }); 27 | 28 | // Container name prefix to avoid conflicts 29 | const CONTAINER_PREFIX = 'mcp-test-'; 30 | 31 | // Storage for running server processes (for stdio communication) 32 | interface ServerProcess { 33 | process: ReturnType; 34 | stdin: NodeJS.WritableStream; 35 | stdout: NodeJS.ReadableStream; 36 | name: string; 37 | source_path: string; 38 | deployed_at: Date; 39 | } 40 | 41 | // Map of running server processes by name 42 | const runningServers = new Map(); 43 | 44 | // Deploy a server to a Docker container 45 | export async function deployServer(input: DeployServerInput): Promise { 46 | const { name, source_path, env_vars, persistent } = input; 47 | const containerId = `${CONTAINER_PREFIX}${name}`; 48 | 49 | try { 50 | // Check if source path exists 51 | if (!fs.existsSync(source_path)) { 52 | throw new ServerDeploymentError(`Source path not found: ${source_path}`); 53 | } 54 | 55 | // Check if package.json exists 56 | const packageJsonPath = path.join(source_path, 'package.json'); 57 | if (!fs.existsSync(packageJsonPath)) { 58 | throw new ServerDeploymentError(`package.json not found in ${source_path}`); 59 | } 60 | 61 | // Check if server with this name already exists 62 | if (runningServers.has(name)) { 63 | throw new ServerDeploymentError(`Server with name '${name}' is already running`); 64 | } 65 | 66 | // Read package.json to determine how to run the server 67 | const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8')); 68 | 69 | // Determine the start command 70 | let startCommand = 'node dist/index.js'; 71 | if (packageJson.scripts && packageJson.scripts.start) { 72 | startCommand = 'npm run start'; 73 | } 74 | 75 | // Set up environment variables 76 | const environment: Record = {}; 77 | 78 | // Add current environment, filtering out undefined values 79 | if (process.env) { 80 | Object.entries(process.env).forEach(([key, value]) => { 81 | if (value !== undefined) { 82 | environment[key] = value; 83 | } 84 | }); 85 | } 86 | 87 | // Add provided environment variables 88 | if (env_vars) { 89 | Object.entries(env_vars).forEach(([key, value]) => { 90 | environment[key] = value; 91 | }); 92 | } 93 | 94 | // Start the server process 95 | Logger.info(`Starting server '${name}' from ${source_path}`); 96 | const serverProcess = spawn('sh', ['-c', startCommand], { 97 | cwd: source_path, 98 | env: environment, 99 | stdio: ['pipe', 'pipe', 'pipe'] 100 | }); 101 | 102 | // Set up logging 103 | const logDir = path.join(process.cwd(), 'logs'); 104 | if (!fs.existsSync(logDir)) { 105 | fs.mkdirSync(logDir, { recursive: true }); 106 | } 107 | 108 | const logFile = path.join(logDir, `${name}.log`); 109 | const logStream = fs.createWriteStream(logFile, { flags: 'a' }); 110 | 111 | serverProcess.stdout.pipe(logStream); 112 | serverProcess.stderr.pipe(logStream); 113 | 114 | // Store server process information 115 | const deployedAt = new Date(); 116 | runningServers.set(name, { 117 | process: serverProcess, 118 | stdin: serverProcess.stdin, 119 | stdout: serverProcess.stdout, 120 | name, 121 | source_path, 122 | deployed_at: deployedAt 123 | }); 124 | 125 | // Handle process exit 126 | serverProcess.on('exit', (code) => { 127 | Logger.info(`Server '${name}' exited with code ${code}`); 128 | 129 | // If not persistent, remove from running servers 130 | if (!persistent) { 131 | runningServers.delete(name); 132 | } 133 | }); 134 | 135 | // Give server time to initialize 136 | await new Promise((resolve) => setTimeout(resolve, 1000)); 137 | 138 | return { 139 | name, 140 | id: containerId, 141 | status: 'running' 142 | }; 143 | } catch (error) { 144 | Logger.error(`Error deploying server '${name}':`, error); 145 | 146 | if (error instanceof ServerDeploymentError) { 147 | throw error; 148 | } 149 | 150 | throw new ServerDeploymentError( 151 | error instanceof Error ? error.message : String(error) 152 | ); 153 | } 154 | } 155 | 156 | // Get server process by name 157 | export function getServerProcess(name: string): ServerProcess { 158 | const server = runningServers.get(name); 159 | if (!server) { 160 | throw new ServerNotFoundError(name); 161 | } 162 | return server; 163 | } 164 | 165 | // Get logs from a server 166 | export async function getServerLogs(input: GetLogsInput): Promise { 167 | const { server_name, lines } = input; 168 | 169 | try { 170 | // Make sure server exists 171 | getServerProcess(server_name); 172 | 173 | // Read log file 174 | const logDir = path.join(process.cwd(), 'logs'); 175 | const logFile = path.join(logDir, `${server_name}.log`); 176 | 177 | if (!fs.existsSync(logFile)) { 178 | return { 179 | logs: `No logs found for server '${server_name}'` 180 | }; 181 | } 182 | 183 | // Read the last N lines from log file 184 | const logs = await readLastLines(logFile, lines); 185 | 186 | return { 187 | logs 188 | }; 189 | } catch (error) { 190 | Logger.error(`Error getting logs for server '${server_name}':`, error); 191 | 192 | if (error instanceof ServerNotFoundError) { 193 | throw error; 194 | } 195 | 196 | return { 197 | logs: "", 198 | error: error instanceof Error ? error.message : String(error) 199 | }; 200 | } 201 | } 202 | 203 | // Read last N lines from a file 204 | async function readLastLines(filePath: string, lineCount: number): Promise { 205 | return new Promise((resolve, reject) => { 206 | try { 207 | const lines: string[] = []; 208 | 209 | // Create read stream with high water mark to avoid loading too much at once 210 | const stream = fs.createReadStream(filePath, { 211 | encoding: 'utf-8', 212 | highWaterMark: 1024 // 1KB chunks 213 | }); 214 | 215 | let buffer = ''; 216 | 217 | stream.on('data', (chunk) => { 218 | buffer += chunk.toString(); 219 | const linesToAdd = buffer.split('\n'); 220 | buffer = linesToAdd.pop() || ''; 221 | 222 | lines.push(...linesToAdd); 223 | 224 | // Keep only the last N+1 lines (accounting for potential incomplete line in buffer) 225 | if (lines.length > lineCount) { 226 | lines.splice(0, lines.length - lineCount); 227 | } 228 | }); 229 | 230 | stream.on('end', () => { 231 | // Add any remaining content in buffer 232 | if (buffer.length > 0) { 233 | lines.push(buffer); 234 | } 235 | 236 | // Return the last N lines 237 | resolve(lines.slice(-lineCount).join('\n')); 238 | }); 239 | 240 | stream.on('error', (err) => { 241 | reject(err); 242 | }); 243 | } catch (error) { 244 | reject(error); 245 | } 246 | }); 247 | } 248 | 249 | // List running servers 250 | export async function listServers(input: ListServersInput): Promise { 251 | try { 252 | return Array.from(runningServers.entries()).map(([name, server]) => { 253 | return { 254 | name, 255 | id: `${CONTAINER_PREFIX}${name}`, 256 | status: 'running', 257 | source_path: server.source_path, 258 | deployed_at: server.deployed_at.toISOString() 259 | }; 260 | }); 261 | } catch (error) { 262 | Logger.error('Error listing servers:', error); 263 | throw new DockerConnectionError( 264 | error instanceof Error ? error.message : String(error) 265 | ); 266 | } 267 | } 268 | 269 | // Stop a server 270 | export async function stopServer(input: ServerOperationInput): Promise { 271 | const { server_name } = input; 272 | 273 | try { 274 | const server = getServerProcess(server_name); 275 | 276 | // Kill the process 277 | server.process.kill(); 278 | 279 | // Remove from running servers 280 | runningServers.delete(server_name); 281 | 282 | return { 283 | name: server_name, 284 | status: 'stopped' 285 | }; 286 | } catch (error) { 287 | Logger.error(`Error stopping server '${server_name}':`, error); 288 | 289 | if (error instanceof ServerNotFoundError) { 290 | throw error; 291 | } 292 | 293 | throw new Error( 294 | error instanceof Error ? error.message : String(error) 295 | ); 296 | } 297 | } -------------------------------------------------------------------------------- /src/operations/mcp-client.ts: -------------------------------------------------------------------------------- 1 | import { Client } from '@modelcontextprotocol/sdk/client/index.js'; 2 | import { Transport } from '@modelcontextprotocol/sdk/shared/transport.js'; 3 | import { JSONRPCMessage } from '@modelcontextprotocol/sdk/types.js'; 4 | import { ServerNotFoundError, ToolCallError } from '../common/errors.js'; 5 | import { Logger } from '../common/logger.js'; 6 | import { 7 | CallToolInput, 8 | CallToolResponse, 9 | TestCase, 10 | TestResult, 11 | RunTestsInput, 12 | RunTestsResponse 13 | } from '../types/schemas.js'; 14 | import { getServerProcess } from './docker.js'; 15 | 16 | // Cache of connected clients by server name 17 | const connectedClients = new Map(); 18 | 19 | // Create a custom Transport implementation for process communication 20 | class ProcessTransport implements Transport { 21 | private messageBuffer = ''; 22 | 23 | constructor(private server: ReturnType) {} 24 | 25 | async start(): Promise { 26 | // Set up data handler for stdout 27 | this.server.stdout.on('data', (data: Buffer) => { 28 | this.handleData(data.toString()); 29 | }); 30 | 31 | // Handle process exit 32 | this.server.process.on('exit', (code) => { 33 | Logger.warn(`Server process exited with code ${code}`); 34 | if (this.onclose) { 35 | this.onclose(); 36 | } 37 | }); 38 | 39 | return Promise.resolve(); 40 | } 41 | 42 | async send(message: JSONRPCMessage): Promise { 43 | try { 44 | // Send message to server's stdin 45 | this.server.stdin.write(JSON.stringify(message) + '\n'); 46 | return Promise.resolve(); 47 | } catch (error) { 48 | if (this.onerror && error instanceof Error) { 49 | this.onerror(error); 50 | } 51 | return Promise.reject(error); 52 | } 53 | } 54 | 55 | async close(): Promise { 56 | // Try to gracefully end the process 57 | this.server.process.kill(); 58 | 59 | if (this.onclose) { 60 | this.onclose(); 61 | } 62 | 63 | return Promise.resolve(); 64 | } 65 | 66 | private handleData(data: string): void { 67 | // Add data to buffer 68 | this.messageBuffer += data; 69 | 70 | // Process complete messages 71 | let messageEndIndex; 72 | while ((messageEndIndex = this.messageBuffer.indexOf('\n')) !== -1) { 73 | const messageStr = this.messageBuffer.slice(0, messageEndIndex); 74 | this.messageBuffer = this.messageBuffer.slice(messageEndIndex + 1); 75 | 76 | if (messageStr.trim()) { 77 | try { 78 | const message = JSON.parse(messageStr) as JSONRPCMessage; 79 | 80 | // Call message handler if available 81 | if (this.onmessage) { 82 | this.onmessage(message); 83 | } 84 | } catch (error) { 85 | Logger.error('Error parsing message:', error); 86 | if (this.onerror && error instanceof Error) { 87 | this.onerror(error); 88 | } 89 | } 90 | } 91 | } 92 | } 93 | 94 | // These will be set by the Client 95 | onclose?: () => void; 96 | onerror?: (error: Error) => void; 97 | onmessage?: (message: JSONRPCMessage) => void; 98 | } 99 | 100 | // Get or create a client for a server 101 | async function getClient(serverName: string): Promise { 102 | // Check if we already have a connected client 103 | if (connectedClients.has(serverName)) { 104 | return connectedClients.get(serverName)!; 105 | } 106 | 107 | try { 108 | // Get the server process 109 | const server = getServerProcess(serverName); 110 | 111 | // Create transport for the server process 112 | const transport = new ProcessTransport(server); 113 | 114 | // Create the client 115 | const client = new Client({ 116 | name: `test-client-${serverName}`, 117 | version: '0.1.0', 118 | transport 119 | }); 120 | 121 | // Connect to the server 122 | Logger.debug(`Connecting to server '${serverName}'...`); 123 | // The connect method requires a transport parameter in the MCP SDK 124 | // But our Client constructor already has it, so we'll pass an empty object 125 | await client.connect(transport); 126 | Logger.debug(`Connected to server '${serverName}'`); 127 | 128 | // Cache the client for future use 129 | connectedClients.set(serverName, client); 130 | 131 | return client; 132 | } catch (error) { 133 | Logger.error(`Error creating client for server '${serverName}':`, error); 134 | throw new ToolCallError( 135 | serverName, 136 | 'connect', 137 | error instanceof Error ? error.message : String(error) 138 | ); 139 | } 140 | } 141 | 142 | // Call a tool on a server 143 | export async function callTool(input: CallToolInput): Promise { 144 | const { server_name, tool_name, arguments: args } = input; 145 | const startTime = Date.now(); 146 | 147 | try { 148 | // Get client for this server 149 | const client = await getClient(server_name); 150 | 151 | // Call the tool 152 | Logger.debug(`Calling tool '${tool_name}' on server '${server_name}'`, args); 153 | const response = await client.callTool({ 154 | name: tool_name, 155 | arguments: args 156 | }); 157 | 158 | const duration = Date.now() - startTime; 159 | Logger.debug(`Tool call completed in ${duration}ms`, response); 160 | 161 | // Extract the result from the response 162 | let result = response; 163 | 164 | // Handle different response formats 165 | if (response && response.content && Array.isArray(response.content)) { 166 | // Handle standard MCP response format 167 | const textContent = response.content.find((item: any) => item.type === 'text'); 168 | if (textContent && textContent.text) { 169 | try { 170 | // Try to parse JSON from text content 171 | result = JSON.parse(textContent.text); 172 | } catch (e) { 173 | // If not valid JSON, use the text directly 174 | result = textContent.text; 175 | } 176 | } 177 | } 178 | 179 | return { 180 | result, 181 | duration_ms: duration 182 | }; 183 | } catch (error) { 184 | const duration = Date.now() - startTime; 185 | Logger.error(`Error calling tool '${tool_name}' on server '${server_name}':`, error); 186 | 187 | return { 188 | result: null, 189 | error: error instanceof Error ? error.message : String(error), 190 | duration_ms: duration 191 | }; 192 | } 193 | } 194 | 195 | // List tools available on a server 196 | export async function listTools(serverName: string): Promise { 197 | try { 198 | // Get client for this server 199 | const client = await getClient(serverName); 200 | 201 | // List tools 202 | Logger.debug(`Listing tools for server '${serverName}'`); 203 | const response = await client.listTools(); 204 | 205 | // Debug the response 206 | Logger.debug(`Tool list response:`, response); 207 | 208 | // Extract tools from the response 209 | let tools = response?.tools || []; 210 | 211 | // Debug the extracted tools 212 | Logger.debug(`Extracted ${tools.length} tools from response`); 213 | 214 | return tools.map((tool: { name: string }) => tool.name); 215 | } catch (error) { 216 | Logger.error(`Error listing tools for server '${serverName}':`, error); 217 | throw new ToolCallError( 218 | serverName, 219 | 'listTools', 220 | error instanceof Error ? error.message : String(error) 221 | ); 222 | } 223 | } 224 | 225 | // Run a single test case 226 | async function runTestCase(serverName: string, test: TestCase): Promise { 227 | const startTime = Date.now(); 228 | 229 | try { 230 | // Call the tool 231 | const result = await callTool({ 232 | server_name: serverName, 233 | tool_name: test.tool, 234 | arguments: test.input 235 | }); 236 | 237 | const duration = Date.now() - startTime; 238 | 239 | // Check for errors 240 | if (result.error) { 241 | return { 242 | name: test.name, 243 | passed: false, 244 | message: `Tool call failed: ${result.error}`, 245 | duration_ms: duration, 246 | error: result.error 247 | }; 248 | } 249 | 250 | // If there's an expected result, check it 251 | if (test.expected) { 252 | let passed = false; 253 | 254 | if (test.expected.type === 'equals') { 255 | passed = JSON.stringify(result.result) === JSON.stringify(test.expected.value); 256 | } else if (test.expected.type === 'contains') { 257 | const resultStr = JSON.stringify(result.result); 258 | const expectedStr = JSON.stringify(test.expected.value); 259 | passed = resultStr.includes(expectedStr); 260 | } else if (test.expected.type === 'regex') { 261 | const regex = new RegExp(test.expected.value); 262 | passed = regex.test(JSON.stringify(result.result)); 263 | } 264 | 265 | return { 266 | name: test.name, 267 | passed, 268 | message: passed ? 'Test passed' : 'Test failed: result did not match expected value', 269 | duration_ms: duration 270 | }; 271 | } 272 | 273 | // If no expected result, assume success 274 | return { 275 | name: test.name, 276 | passed: true, 277 | message: 'Test passed', 278 | duration_ms: duration 279 | }; 280 | } catch (error) { 281 | const duration = Date.now() - startTime; 282 | 283 | return { 284 | name: test.name, 285 | passed: false, 286 | message: `Test failed with error: ${error instanceof Error ? error.message : String(error)}`, 287 | duration_ms: duration, 288 | error: error instanceof Error ? error.message : String(error) 289 | }; 290 | } 291 | } 292 | 293 | // Run tests for a server 294 | export async function runTests(input: RunTestsInput): Promise { 295 | const { server_name, test_suite } = input; 296 | const startTime = Date.now(); 297 | 298 | try { 299 | // For now, we'll just run a basic test to list tools 300 | // In a real implementation, this would load test suites from files 301 | 302 | // First, let's check that the server exists 303 | getServerProcess(server_name); 304 | 305 | // Get the tools available on the server 306 | const tools = await listTools(server_name); 307 | 308 | // Create a basic test for each tool 309 | const basicTests: TestCase[] = tools.map(tool => ({ 310 | name: `List ${tool} schema`, 311 | description: `Check that ${tool} is available and has a valid schema`, 312 | tool, 313 | // Send an empty input just to see if the tool exists 314 | // This will likely fail for most tools, but will show the schema 315 | input: {} 316 | })); 317 | 318 | // Run each test 319 | const results: TestResult[] = []; 320 | for (const test of basicTests) { 321 | const result = await runTestCase(server_name, test); 322 | results.push(result); 323 | } 324 | 325 | // Calculate summary 326 | const passed = results.filter(r => r.passed).length; 327 | const total = results.length; 328 | const failed = total - passed; 329 | const duration = Date.now() - startTime; 330 | 331 | return { 332 | results, 333 | summary: { 334 | total, 335 | passed, 336 | failed, 337 | duration_ms: duration 338 | } 339 | }; 340 | } catch (error) { 341 | Logger.error(`Error running tests for server '${server_name}':`, error); 342 | 343 | if (error instanceof ServerNotFoundError) { 344 | throw error; 345 | } 346 | 347 | const duration = Date.now() - startTime; 348 | 349 | return { 350 | results: [{ 351 | name: 'Test suite setup', 352 | passed: false, 353 | message: `Failed to setup test suite: ${error instanceof Error ? error.message : String(error)}`, 354 | duration_ms: duration, 355 | error: error instanceof Error ? error.message : String(error) 356 | }], 357 | summary: { 358 | total: 1, 359 | passed: 0, 360 | failed: 1, 361 | duration_ms: duration 362 | } 363 | }; 364 | } 365 | } -------------------------------------------------------------------------------- /src/test-runner.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import readline from 'readline'; 4 | import { deployServer, listServers, getServerLogs, stopServer } from './operations/docker.js'; 5 | import { callTool, runTests } from './operations/mcp-client.js'; 6 | import { Logger } from './common/logger.js'; 7 | 8 | // Initialize logger 9 | Logger.init(); 10 | 11 | // Create readline interface 12 | const rl = readline.createInterface({ 13 | input: process.stdin, 14 | output: process.stdout 15 | }); 16 | 17 | // Display menu 18 | function showMenu() { 19 | console.log('\n=== MCP Test Client CLI ==='); 20 | console.log('1. Deploy server'); 21 | console.log('2. List servers'); 22 | console.log('3. Get server logs'); 23 | console.log('4. Stop server'); 24 | console.log('5. Call tool'); 25 | console.log('6. Run tests'); 26 | console.log('7. Exit'); 27 | rl.question('Select an option: ', handleMenuOption); 28 | } 29 | 30 | // Handle menu options 31 | async function handleMenuOption(option: string) { 32 | try { 33 | switch (option) { 34 | case '1': 35 | await handleDeployServer(); 36 | break; 37 | case '2': 38 | await handleListServers(); 39 | break; 40 | case '3': 41 | await handleGetLogs(); 42 | break; 43 | case '4': 44 | await handleStopServer(); 45 | break; 46 | case '5': 47 | await handleCallTool(); 48 | break; 49 | case '6': 50 | await handleRunTests(); 51 | break; 52 | case '7': 53 | rl.close(); 54 | process.exit(0); 55 | break; 56 | default: 57 | console.log('Invalid option'); 58 | showMenu(); 59 | break; 60 | } 61 | } catch (error) { 62 | console.error('Error:', error); 63 | showMenu(); 64 | } 65 | } 66 | 67 | // Handle deploy server 68 | async function handleDeployServer() { 69 | rl.question('Server name: ', (name) => { 70 | rl.question('Source path: ', (source_path) => { 71 | rl.question('Environment variables (JSON, empty for none): ', async (envVarsJson) => { 72 | try { 73 | const env_vars = envVarsJson.trim() ? JSON.parse(envVarsJson) : undefined; 74 | const result = await deployServer({ 75 | name, 76 | source_path, 77 | env_vars, 78 | persistent: true 79 | }); 80 | 81 | console.log('Server deployed successfully:'); 82 | console.log(JSON.stringify(result, null, 2)); 83 | } catch (error) { 84 | console.error('Error deploying server:', error); 85 | } 86 | 87 | showMenu(); 88 | }); 89 | }); 90 | }); 91 | } 92 | 93 | // Handle list servers 94 | async function handleListServers() { 95 | try { 96 | const servers = await listServers({ status: "running" }); 97 | console.log('Servers:'); 98 | console.log(JSON.stringify(servers, null, 2)); 99 | } catch (error) { 100 | console.error('Error listing servers:', error); 101 | } 102 | 103 | showMenu(); 104 | } 105 | 106 | // Handle get logs 107 | async function handleGetLogs() { 108 | rl.question('Server name: ', async (server_name) => { 109 | try { 110 | const result = await getServerLogs({ 111 | server_name, 112 | lines: 20 113 | }); 114 | 115 | console.log('Logs:'); 116 | console.log(result.logs); 117 | } catch (error) { 118 | console.error('Error getting logs:', error); 119 | } 120 | 121 | showMenu(); 122 | }); 123 | } 124 | 125 | // Handle stop server 126 | async function handleStopServer() { 127 | rl.question('Server name: ', async (server_name) => { 128 | try { 129 | const result = await stopServer({ 130 | server_name 131 | }); 132 | 133 | console.log('Server stopped:'); 134 | console.log(JSON.stringify(result, null, 2)); 135 | } catch (error) { 136 | console.error('Error stopping server:', error); 137 | } 138 | 139 | showMenu(); 140 | }); 141 | } 142 | 143 | // Handle call tool 144 | async function handleCallTool() { 145 | rl.question('Server name: ', (server_name) => { 146 | rl.question('Tool name: ', (tool_name) => { 147 | rl.question('Arguments (JSON): ', async (argsJson) => { 148 | try { 149 | const args = JSON.parse(argsJson); 150 | const result = await callTool({ 151 | server_name, 152 | tool_name, 153 | arguments: args 154 | }); 155 | 156 | console.log('Tool call result:'); 157 | console.log(JSON.stringify(result, null, 2)); 158 | } catch (error) { 159 | console.error('Error calling tool:', error); 160 | } 161 | 162 | showMenu(); 163 | }); 164 | }); 165 | }); 166 | } 167 | 168 | // Handle run tests 169 | async function handleRunTests() { 170 | rl.question('Server name: ', async (server_name) => { 171 | try { 172 | const result = await runTests({ 173 | server_name, 174 | interactive: false 175 | }); 176 | 177 | console.log('Test results:'); 178 | console.log(JSON.stringify(result, null, 2)); 179 | } catch (error) { 180 | console.error('Error running tests:', error); 181 | } 182 | 183 | showMenu(); 184 | }); 185 | } 186 | 187 | // Start the CLI 188 | console.log('MCP Test Client CLI'); 189 | showMenu(); 190 | 191 | // Handle exit 192 | rl.on('close', () => { 193 | console.log('Exiting...'); 194 | process.exit(0); 195 | }); 196 | 197 | // Handle SIGINT (Ctrl+C) 198 | process.on('SIGINT', () => { 199 | console.log('\nReceived SIGINT. Cleaning up...'); 200 | rl.close(); 201 | }); 202 | 203 | // Handle SIGTERM 204 | process.on('SIGTERM', () => { 205 | console.log('\nReceived SIGTERM. Cleaning up...'); 206 | rl.close(); 207 | }); -------------------------------------------------------------------------------- /src/types/schemas.ts: -------------------------------------------------------------------------------- 1 | import { z } from 'zod'; 2 | 3 | // Server deployment schema 4 | export const DeployServerSchema = z.object({ 5 | name: z.string().describe("Name for the deployed server"), 6 | source_path: z.string().describe("Absolute path to the server source code"), 7 | env_vars: z.record(z.string()).optional().describe("Environment variables to pass to the server"), 8 | persistent: z.boolean().optional().default(true).describe("Whether to keep the server running after tests") 9 | }); 10 | 11 | export type DeployServerInput = z.infer; 12 | export type DeployServerResponse = { 13 | name: string; 14 | id: string; 15 | status: "running" | "error"; 16 | url?: string; 17 | error?: string; 18 | }; 19 | 20 | // Tool call schema 21 | export const CallToolSchema = z.object({ 22 | server_name: z.string().describe("Name of the deployed server to call"), 23 | tool_name: z.string().describe("Name of the tool to call"), 24 | arguments: z.record(z.any()).describe("Arguments to pass to the tool") 25 | }); 26 | 27 | export type CallToolInput = z.infer; 28 | export type CallToolResponse = { 29 | result: any; 30 | error?: string; 31 | duration_ms: number; 32 | }; 33 | 34 | // Server logs schema 35 | export const GetLogsSchema = z.object({ 36 | server_name: z.string().describe("Name of the deployed server"), 37 | lines: z.number().optional().default(100).describe("Number of log lines to return") 38 | }); 39 | 40 | export type GetLogsInput = z.infer; 41 | export type GetLogsResponse = { 42 | logs: string; 43 | error?: string; 44 | }; 45 | 46 | // List servers schema 47 | export const ListServersSchema = z.object({ 48 | status: z.enum(["running", "all"]).optional().default("running").describe("Status of servers to list") 49 | }).optional().default({ 50 | status: "running" 51 | }); 52 | 53 | export type ListServersInput = z.infer; 54 | export type ServerInfo = { 55 | name: string; 56 | id: string; 57 | status: string; 58 | source_path: string; 59 | deployed_at: string; 60 | }; 61 | 62 | // Test execution schema 63 | export const RunTestsSchema = z.object({ 64 | server_name: z.string().describe("Name of the deployed server to test"), 65 | test_suite: z.string().optional().describe("Name of the test suite to run"), 66 | interactive: z.boolean().optional().default(false).describe("Whether to run tests interactively") 67 | }); 68 | 69 | export type RunTestsInput = z.infer; 70 | export type TestResult = { 71 | name: string; 72 | passed: boolean; 73 | message?: string; 74 | duration_ms: number; 75 | error?: string; 76 | }; 77 | 78 | export type RunTestsResponse = { 79 | results: TestResult[]; 80 | summary: { 81 | total: number; 82 | passed: number; 83 | failed: number; 84 | duration_ms: number; 85 | }; 86 | }; 87 | 88 | // Server operation schema 89 | export const ServerOperationSchema = z.object({ 90 | server_name: z.string().describe("Name of the deployed server") 91 | }); 92 | 93 | export type ServerOperationInput = z.infer; 94 | export type ServerOperationResponse = { 95 | name: string; 96 | status: string; 97 | }; 98 | 99 | // Test case definition 100 | export type TestCase = { 101 | name: string; 102 | description: string; 103 | tool: string; 104 | input: Record; 105 | expected?: { 106 | type: "contains" | "equals" | "regex"; 107 | value: any; 108 | }; 109 | }; 110 | 111 | // Test suite definition 112 | export type TestSuite = { 113 | name: string; 114 | description: string; 115 | tests: TestCase[]; 116 | }; -------------------------------------------------------------------------------- /test/basic-test-suite.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Basic Server Tests", 3 | "description": "Tests basic functionality of any MCP server", 4 | "tests": [ 5 | { 6 | "name": "Server Connection", 7 | "description": "Test that server can be connected to and lists tools", 8 | "tool": "list_tools", 9 | "input": {}, 10 | "expected": { 11 | "type": "contains", 12 | "value": [] 13 | } 14 | }, 15 | { 16 | "name": "Tool Schema Validation", 17 | "description": "Test that tools have proper schemas", 18 | "tool": "tool_details", 19 | "input": {}, 20 | "expected": { 21 | "type": "contains", 22 | "value": { "tools": [] } 23 | } 24 | } 25 | ] 26 | } -------------------------------------------------------------------------------- /test/claude-chat-test-suite.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Claude Chat MCP Server Tests", 3 | "description": "Tests for the Claude Chat MCP server", 4 | "tests": [ 5 | { 6 | "name": "Server Connection", 7 | "description": "Test that server can be connected to and lists tools", 8 | "tool": "list_tools", 9 | "input": {}, 10 | "expected": { 11 | "type": "contains", 12 | "value": ["claude_send_message", "claude_chat_completion"] 13 | } 14 | }, 15 | { 16 | "name": "Simple Message", 17 | "description": "Test sending a simple message to Claude", 18 | "tool": "claude_send_message", 19 | "input": { 20 | "prompt": "Tell me a fun fact about AI in exactly one short sentence.", 21 | "temperature": 0.7 22 | }, 23 | "expected": { 24 | "type": "nonEmpty", 25 | "value": true 26 | } 27 | }, 28 | { 29 | "name": "Chat Completion", 30 | "description": "Test chat completion functionality", 31 | "tool": "claude_chat_completion", 32 | "input": { 33 | "messages": [ 34 | { "role": "user", "content": "Write a haiku about artificial intelligence." } 35 | ], 36 | "temperature": 0.7 37 | }, 38 | "expected": { 39 | "type": "nonEmpty", 40 | "value": true 41 | } 42 | }, 43 | { 44 | "name": "Multi-turn Conversation", 45 | "description": "Test multi-turn conversation with history", 46 | "tool": "claude_chat_completion", 47 | "input": { 48 | "messages": [ 49 | { "role": "user", "content": "Let's play a game. I'll provide the first line of a story, and you continue it with one more sentence." }, 50 | { "role": "assistant", "content": "That sounds like a fun game! I'm ready when you are. What's the first line of the story?" }, 51 | { "role": "user", "content": "The old clock struck midnight, and the door creaked open by itself." } 52 | ], 53 | "temperature": 0.8 54 | }, 55 | "expected": { 56 | "type": "nonEmpty", 57 | "value": true 58 | } 59 | }, 60 | { 61 | "name": "System Prompt", 62 | "description": "Test including a system prompt", 63 | "tool": "claude_send_message", 64 | "input": { 65 | "prompt": "What are you designed to do?", 66 | "system": "You are a specialized AI assistant for weather forecasting. You only talk about weather.", 67 | "temperature": 0.7 68 | }, 69 | "expected": { 70 | "type": "contains", 71 | "value": "weather" 72 | } 73 | } 74 | ] 75 | } -------------------------------------------------------------------------------- /test/docker-mcp-test-suite.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Docker MCP Server Tests", 3 | "description": "Tests for the Docker MCP server", 4 | "tests": [ 5 | { 6 | "name": "Server Connection", 7 | "description": "Test that server can be connected to and lists tools", 8 | "tool": "list_tools", 9 | "input": {}, 10 | "expected": { 11 | "type": "contains", 12 | "value": [ 13 | "docker_run_code", 14 | "docker_build_image", 15 | "docker_list_templates", 16 | "docker_create_server", 17 | "docker_list_servers" 18 | ] 19 | } 20 | }, 21 | { 22 | "name": "List Templates", 23 | "description": "Test listing available Docker templates", 24 | "tool": "docker_list_templates", 25 | "input": {}, 26 | "expected": { 27 | "type": "nonEmpty", 28 | "value": true 29 | } 30 | }, 31 | { 32 | "name": "Run Python Code", 33 | "description": "Test running Python code in an ephemeral container", 34 | "tool": "docker_run_code", 35 | "input": { 36 | "language": "python", 37 | "code": "print('Hello, Docker MCP!')\nprint(2 + 2)", 38 | "timeout": 5000 39 | }, 40 | "expected": { 41 | "type": "contains", 42 | "value": "Hello, Docker MCP!" 43 | } 44 | }, 45 | { 46 | "name": "Run JavaScript Code", 47 | "description": "Test running JavaScript code in an ephemeral container", 48 | "tool": "docker_run_code", 49 | "input": { 50 | "language": "javascript", 51 | "code": "console.log('Hello from JavaScript!');\nconsole.log(2 + 2);", 52 | "timeout": 5000 53 | }, 54 | "expected": { 55 | "type": "contains", 56 | "value": "Hello from JavaScript!" 57 | } 58 | }, 59 | { 60 | "name": "Run Code with Dependencies", 61 | "description": "Test running code with dependencies", 62 | "tool": "docker_run_code", 63 | "input": { 64 | "language": "python", 65 | "code": "import requests\nresponse = requests.get('https://httpbin.org/get')\nprint(response.status_code)", 66 | "dependencies": ["requests"], 67 | "timeout": 10000 68 | }, 69 | "expected": { 70 | "type": "contains", 71 | "value": "200" 72 | } 73 | }, 74 | { 75 | "name": "Create and List Servers", 76 | "description": "Test creating a server and listing it", 77 | "tool": "docker_create_server", 78 | "input": { 79 | "server_type": "python-test", 80 | "server_name": "test-server-1" 81 | }, 82 | "expected": { 83 | "type": "contains", 84 | "value": "test-server-1" 85 | }, 86 | "cleanup": { 87 | "tool": "docker_stop_server", 88 | "input": { 89 | "server_name": "test-server-1" 90 | } 91 | } 92 | } 93 | ] 94 | } -------------------------------------------------------------------------------- /test/docker-production-test.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Docker Production Test", 3 | "description": "Tests for the Docker MCP server in production", 4 | "tests": [ 5 | { 6 | "name": "Server Connection", 7 | "description": "Test that server can be connected to and lists tools", 8 | "tool": "list_tools", 9 | "input": {}, 10 | "expected": { 11 | "type": "contains", 12 | "value": ["docker_run_code", "docker_register_template", "docker_list_templates"] 13 | } 14 | }, 15 | { 16 | "name": "Run Python Code", 17 | "description": "Test running Python code with network access", 18 | "tool": "docker_run_code", 19 | "input": { 20 | "language": "python", 21 | "code": "import os\nprint('Hello from Production Docker MCP!')\nprint(f'Python version: {os.sys.version}')", 22 | "timeout": 5000 23 | }, 24 | "expected": { 25 | "type": "contains", 26 | "value": "Hello from Production Docker MCP!" 27 | } 28 | }, 29 | { 30 | "name": "Register Custom Template", 31 | "description": "Test registering a custom template", 32 | "tool": "docker_register_template", 33 | "input": { 34 | "name": "production-test", 35 | "image": "python:3.11-slim", 36 | "description": "Production test template created during testing" 37 | }, 38 | "expected": { 39 | "type": "contains", 40 | "value": "success" 41 | } 42 | }, 43 | { 44 | "name": "Verify Template", 45 | "description": "Test that the new template is available", 46 | "tool": "docker_list_templates", 47 | "input": {}, 48 | "expected": { 49 | "type": "contains", 50 | "value": "production-test" 51 | } 52 | }, 53 | { 54 | "name": "Create Server", 55 | "description": "Test creating a server from the new template", 56 | "tool": "docker_create_server", 57 | "input": { 58 | "server_type": "production-test", 59 | "server_name": "prod-test-server" 60 | }, 61 | "expected": { 62 | "type": "contains", 63 | "value": "prod-test-server" 64 | } 65 | }, 66 | { 67 | "name": "Stop Server", 68 | "description": "Test stopping the server", 69 | "tool": "docker_stop_server", 70 | "input": { 71 | "server_name": "prod-test-server" 72 | }, 73 | "expected": { 74 | "type": "contains", 75 | "value": "stopped" 76 | } 77 | } 78 | ] 79 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2022", 4 | "module": "NodeNext", 5 | "moduleResolution": "NodeNext", 6 | "esModuleInterop": true, 7 | "strict": true, 8 | "outDir": "dist", 9 | "sourceMap": true, 10 | "declaration": true, 11 | "resolveJsonModule": true 12 | }, 13 | "include": ["src/**/*"], 14 | "exclude": ["node_modules", "dist"] 15 | } --------------------------------------------------------------------------------