{"meta":{"title":"MCP server debugging guide","intro":"This guide covers debugging techniques specific to MCP (Model Context Protocol) servers when using the Copilot SDK.","product":"GitHub Copilot","breadcrumbs":[{"href":"/en/copilot","title":"GitHub Copilot"},{"href":"/en/copilot/how-tos","title":"How-tos"},{"href":"/en/copilot/how-tos/copilot-sdk","title":"Copilot SDK"},{"href":"/en/copilot/how-tos/copilot-sdk/troubleshooting","title":"Troubleshooting"},{"href":"/en/copilot/how-tos/copilot-sdk/troubleshooting/mcp-debugging","title":"MCP Debugging"}],"documentType":"article"},"body":"# MCP server debugging guide\n\nThis guide covers debugging techniques specific to MCP (Model Context Protocol) servers when using the Copilot SDK.\n\n<!-- markdownlint-disable GHD046 GHD005 -->\n\n<!-- Suppressed: GHD046 (outdated release terminology), GHD005 (hardcoded data variable) -->\n\n## Table of contents\n\n* [Quick Diagnostics](#quick-diagnostics)\n* [Testing MCP Servers Independently](#testing-mcp-servers-independently)\n* [Common Issues](#common-issues)\n* [Platform-Specific Issues](#platform-specific-issues)\n* [Advanced Debugging](#advanced-debugging)\n\n## Quick diagnostics\n\n### Checklist\n\nBefore diving deep, verify these basics:\n\n* [ ] MCP server executable exists and is runnable\n* [ ] Command path is correct (use absolute paths when in doubt)\n* [ ] Tools are enabled (`tools: [\"*\"]` or specific tool names)\n* [ ] Server implements MCP protocol correctly (responds to `initialize`)\n* [ ] No firewall/antivirus blocking the process (Windows)\n\n### Enable MCP debug logging\n\nAdd environment variables to your MCP server config:\n\n```typescript\nmcpServers: {\n  \"my-server\": {\n    type: \"local\",\n    command: \"/path/to/server\",\n    args: [],\n    env: {\n      MCP_DEBUG: \"1\",\n      DEBUG: \"*\",\n      NODE_DEBUG: \"mcp\",  // For Node.js MCP servers\n    },\n  },\n}\n```\n\n## Testing MCP servers independently\n\nAlways test your MCP server outside the SDK first.\n\n### Manual protocol test\n\nSend an `initialize` request via stdin:\n\n```bash\n# Unix/macOS\necho '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"initialize\",\"params\":{\"protocolVersion\":\"2024-11-05\",\"capabilities\":{},\"clientInfo\":{\"name\":\"test\",\"version\":\"1.0\"}}}' | /path/to/your/mcp-server\n\n# Windows (PowerShell)\n'{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"initialize\",\"params\":{\"protocolVersion\":\"2024-11-05\",\"capabilities\":{},\"clientInfo\":{\"name\":\"test\",\"version\":\"1.0\"}}}' | C:\\path\\to\\your\\mcp-server.exe\n```\n\n**Expected response:**\n\n```json\n{\"jsonrpc\":\"2.0\",\"id\":1,\"result\":{\"protocolVersion\":\"2024-11-05\",\"capabilities\":{\"tools\":{}},\"serverInfo\":{\"name\":\"your-server\",\"version\":\"1.0\"}}}\n```\n\n### Test tool listing\n\nAfter initialization, request the tools list:\n\n```bash\necho '{\"jsonrpc\":\"2.0\",\"id\":2,\"method\":\"tools/list\",\"params\":{}}' | /path/to/your/mcp-server\n```\n\n**Expected response:**\n\n```json\n{\"jsonrpc\":\"2.0\",\"id\":2,\"result\":{\"tools\":[{\"name\":\"my_tool\",\"description\":\"Does something\",\"inputSchema\":{...}}]}}\n```\n\n### Interactive testing script\n\nCreate a test script to interactively debug your MCP server:\n\n```bash\n#!/bin/bash\n# test-mcp.sh\n\nSERVER=\"$1\"\n\n# Initialize\necho '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"initialize\",\"params\":{\"protocolVersion\":\"2024-11-05\",\"capabilities\":{},\"clientInfo\":{\"name\":\"test\",\"version\":\"1.0\"}}}'\n\n# Send initialized notification\necho '{\"jsonrpc\":\"2.0\",\"method\":\"notifications/initialized\"}'\n\n# List tools\necho '{\"jsonrpc\":\"2.0\",\"id\":2,\"method\":\"tools/list\",\"params\":{}}'\n\n# Keep stdin open\ncat\n```\n\nUsage:\n\n```bash\n./test-mcp.sh | /path/to/mcp-server\n```\n\n## Common issues\n\n### Server not starting\n\n**Symptoms:** No tools appear, no errors in logs.\n\n**Causes & Solutions:**\n\n| Cause                         | Solution                                   |\n| ----------------------------- | ------------------------------------------ |\n| Wrong command path            | Use absolute path: `/usr/local/bin/server` |\n| Missing executable permission | Run `chmod +x /path/to/server`             |\n| Missing dependencies          | Check with `ldd` (Linux) or run manually   |\n| Working directory issues      | Set `cwd` in config                        |\n\n**Debug by running manually:**\n\n```bash\n# Run exactly what the SDK would run\ncd /expected/working/dir\n/path/to/command arg1 arg2\n```\n\n### Server starts but tools don't appear\n\n**Symptoms:** Server process runs but no tools are available.\n\n**Causes & Solutions:**\n\n1. **Tools not enabled in config:**\n\n   ```typescript\n   mcpServers: {\n     \"server\": {\n       // ...\n       tools: [\"*\"],  // Must be \"*\" or list of tool names\n     },\n   }\n   ```\n\n2. **Server doesn't expose tools:**\n   * Test with `tools/list` request manually\n   * Check server implements `tools/list` method\n\n3. **Initialization handshake fails:**\n   * Server must respond to `initialize` correctly\n   * Server must handle `notifications/initialized`\n\n### Tools listed but never called\n\n**Symptoms:** Tools appear in debug logs but model doesn't use them.\n\n**Causes & Solutions:**\n\n1. **Prompt doesn't clearly need the tool:**\n\n   ```typescript\n   // Too vague\n   await session.sendAndWait({ prompt: \"What's the weather?\" });\n\n   // Better - explicitly mentions capability\n   await session.sendAndWait({ \n     prompt: \"Use the weather tool to get the current temperature in Seattle\" \n   });\n   ```\n\n2. **Tool description unclear:**\n\n   ```typescript\n   // Bad - model doesn't know when to use it\n   { name: \"do_thing\", description: \"Does a thing\" }\n\n   // Good - clear purpose\n   { name: \"get_weather\", description: \"Get current weather conditions for a city. Returns temperature, humidity, and conditions.\" }\n   ```\n\n3. **Tool schema issues:**\n   * Ensure `inputSchema` is valid JSON Schema\n   * Required fields must be in `required` array\n\n### Timeout errors\n\n**Symptoms:** `MCP tool call timed out` errors.\n\n**Solutions:**\n\n1. **Increase timeout:**\n\n   ```typescript\n   mcpServers: {\n     \"slow-server\": {\n       // ...\n       timeout: 300000,  // 5 minutes\n     },\n   }\n   ```\n\n2. **Optimize server performance:**\n   * Add progress logging to identify bottleneck\n   * Consider async operations\n   * Check for blocking I/O\n\n3. **For long-running tools**, consider streaming responses if supported.\n\n### JSON-RPC errors\n\n**Symptoms:** Parse errors, invalid request errors.\n\n**Common causes:**\n\n1. **Server writes to stdout incorrectly:**\n   * Debug output going to stdout instead of stderr\n   * Extra newlines or whitespace\n   ```typescript\n   // Wrong - pollutes stdout\n   console.log(\"Debug info\");\n\n   // Correct - use stderr for debug\n   console.error(\"Debug info\");\n   ```\n\n2. **Encoding issues:**\n   * Ensure UTF-8 encoding\n   * No BOM (Byte Order Mark)\n\n3. **Message framing:**\n   * Each message must be a complete JSON object\n   * Newline-delimited (one message per line)\n\n## Platform-specific issues\n\n### Windows\n\n#### .NET console apps / tools\n\n```csharp\n// Correct configuration for .NET exe\n[\"my-dotnet-server\"] = new McpStdioServerConfig\n{\n    Command = @\"C:\\Tools\\MyServer\\MyServer.exe\",  // Full path with .exe\n    Args = new List<string>(),\n    WorkingDirectory = @\"C:\\Tools\\MyServer\",  // Set working directory\n    Tools = new List<string> { \"*\" },\n}\n\n// For dotnet tool (DLL)\n[\"my-dotnet-tool\"] = new McpStdioServerConfig\n{\n    Command = \"dotnet\",\n    Args = new List<string> { @\"C:\\Tools\\MyTool\\MyTool.dll\" },\n    WorkingDirectory = @\"C:\\Tools\\MyTool\",\n    Tools = new List<string> { \"*\" },\n}\n```\n\n#### npx commands\n\n```csharp\n// Windows needs cmd /c for npx\n[\"filesystem\"] = new McpStdioServerConfig\n{\n    Command = \"cmd\",\n    Args = new List<string> { \"/c\", \"npx\", \"-y\", \"@modelcontextprotocol/server-filesystem\", \"C:\\\\allowed\\\\path\" },\n    Tools = new List<string> { \"*\" },\n}\n```\n\n#### Path issues\n\n* Use raw strings (`@\"C:\\path\"`) or forward slashes (`\"C:/path\"`)\n* Avoid spaces in paths when possible\n* If spaces required, ensure proper quoting\n\n#### Antivirus/firewall\n\nWindows Defender or other AV may block:\n\n* New executables\n* Processes communicating via stdin/stdout\n\n**Solution:** Add exclusions for your MCP server executable.\n\n### macOS\n\n#### Gatekeeper blocking\n\n```bash\n# If the server is blocked\nxattr -d com.apple.quarantine /path/to/mcp-server\n```\n\n#### Homebrew paths\n\n```typescript\n// GUI apps may not have /opt/homebrew in PATH\nmcpServers: {\n  \"my-server\": {\n    command: \"/opt/homebrew/bin/node\",  // Full path\n    args: [\"/path/to/server.js\"],\n  },\n}\n```\n\n### Linux\n\n#### Permission issues\n\n```bash\nchmod +x /path/to/mcp-server\n```\n\n#### Missing shared libraries\n\n```bash\n# Check dependencies\nldd /path/to/mcp-server\n\n# Install missing libraries\napt install libfoo  # Debian/Ubuntu\nyum install libfoo  # RHEL/CentOS\n```\n\n## Advanced debugging\n\n### Capture all MCP traffic\n\nCreate a wrapper script to log all communication:\n\n```bash\n#!/bin/bash\n# mcp-debug-wrapper.sh\n\nLOG=\"./mcp-debug-$(date +%s).log\"\nACTUAL_SERVER=\"$1\"\nshift\n\necho \"=== MCP Debug Session ===\" >> \"$LOG\"\necho \"Server: $ACTUAL_SERVER\" >> \"$LOG\"\necho \"Args: $@\" >> \"$LOG\"\necho \"=========================\" >> \"$LOG\"\n\n# Tee stdin/stdout to log file\ntee -a \"$LOG\" | \"$ACTUAL_SERVER\" \"$@\" 2>> \"$LOG\" | tee -a \"$LOG\"\n```\n\nUse it:\n\n```typescript\nmcpServers: {\n  \"debug-server\": {\n    command: \"/path/to/mcp-debug-wrapper.sh\",\n    args: [\"/actual/server/path\", \"arg1\", \"arg2\"],\n  },\n}\n```\n\n### Inspect with MCP inspector\n\nUse the official MCP Inspector tool:\n\n```bash\nnpx @modelcontextprotocol/inspector /path/to/your/mcp-server\n```\n\nThis provides a web UI to:\n\n* Send test requests\n* View responses\n* Inspect tool schemas\n\n### Protocol version mismatches\n\nCheck your server supports the protocol version the SDK uses:\n\n```json\n// In initialize response, check protocolVersion\n{\"result\":{\"protocolVersion\":\"2024-11-05\",...}}\n```\n\nIf versions don't match, update your MCP server library.\n\n## Debugging checklist\n\nWhen opening an issue or asking for help, collect:\n\n* [ ] SDK language and version\n* [ ] CLI version (`copilot --version`)\n* [ ] MCP server type (Node.js, Python, .NET, Go, Rust, and more)\n* [ ] Full MCP server configuration (redact secrets)\n* [ ] Result of manual `initialize` test\n* [ ] Result of manual `tools/list` test\n* [ ] Debug logs from SDK\n* [ ] Any error messages\n\n## See also\n\n* [Using MCP servers with the GitHub Copilot SDK](/en/copilot/how-tos/copilot-sdk/features/mcp) - Configuration and setup\n* [Debugging guide](/en/copilot/how-tos/copilot-sdk/troubleshooting/debugging) - SDK-wide debugging\n* [MCP Specification](https://modelcontextprotocol.io/) - Official protocol docs"}