This guide covers debugging techniques specific to MCP (Model Context Protocol) servers when using the Copilot SDK.
Before diving deep, verify these basics:
tools: ["*"] or specific tool names)initialize)Add environment variables to your MCP server config:
mcpServers: {
"my-server": {
type: "local",
command: "/path/to/server",
args: [],
env: {
MCP_DEBUG: "1",
DEBUG: "*",
NODE_DEBUG: "mcp", // For Node.js MCP servers
},
},
}
Always test your MCP server outside the SDK first.
Send an initialize request via stdin:
# Unix/macOS
echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}' | /path/to/your/mcp-server
# Windows (PowerShell)
'{"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
Expected response:
{"jsonrpc":"2.0","id":1,"result":{"protocolVersion":"2024-11-05","capabilities":{"tools":{}},"serverInfo":{"name":"your-server","version":"1.0"}}}
After initialization, request the tools list:
echo '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}' | /path/to/your/mcp-server
Expected response:
{"jsonrpc":"2.0","id":2,"result":{"tools":[{"name":"my_tool","description":"Does something","inputSchema":{...}}]}}
Create a test script to interactively debug your MCP server:
#!/bin/bash
# test-mcp.sh
SERVER="$1"
# Initialize
echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}'
# Send initialized notification
echo '{"jsonrpc":"2.0","method":"notifications/initialized"}'
# List tools
echo '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}'
# Keep stdin open
cat
Usage:
./test-mcp.sh | /path/to/mcp-server
Symptoms: No tools appear, no errors in logs.
Causes & Solutions:
| Cause | Solution |
|---|---|
| Wrong command path | Use absolute path: /usr/local/bin/server |
| Missing executable permission | Run chmod +x /path/to/server |
| Missing dependencies | Check with ldd (Linux) or run manually |
| Working directory issues | Set cwd in config |
Debug by running manually:
# Run exactly what the SDK would run
cd /expected/working/dir
/path/to/command arg1 arg2
Symptoms: Server process runs but no tools are available.
Causes & Solutions:
Tools not enabled in config:
mcpServers: {
"server": {
// ...
tools: ["*"], // Must be "*" or list of tool names
},
}
Server doesn't expose tools:
tools/list request manuallytools/list methodInitialization handshake fails:
initialize correctlynotifications/initializedSymptoms: Tools appear in debug logs but model doesn't use them.
Causes & Solutions:
Prompt doesn't clearly need the tool:
// Too vague
await session.sendAndWait({ prompt: "What's the weather?" });
// Better - explicitly mentions capability
await session.sendAndWait({
prompt: "Use the weather tool to get the current temperature in Seattle"
});
Tool description unclear:
// Bad - model doesn't know when to use it
{ name: "do_thing", description: "Does a thing" }
// Good - clear purpose
{ name: "get_weather", description: "Get current weather conditions for a city. Returns temperature, humidity, and conditions." }
Tool schema issues:
inputSchema is valid JSON Schemarequired arraySymptoms: MCP tool call timed out errors.
Solutions:
Increase timeout:
mcpServers: {
"slow-server": {
// ...
timeout: 300000, // 5 minutes
},
}
Optimize server performance:
For long-running tools, consider streaming responses if supported.
Symptoms: Parse errors, invalid request errors.
Common causes:
Server writes to stdout incorrectly:
// Wrong - pollutes stdout
console.log("Debug info");
// Correct - use stderr for debug
console.error("Debug info");
Encoding issues:
Message framing:
// Correct configuration for .NET exe
["my-dotnet-server"] = new McpLocalServerConfig
{
Type = "local",
Command = @"C:\Tools\MyServer\MyServer.exe", // Full path with .exe
Args = new List<string>(),
Cwd = @"C:\Tools\MyServer", // Set working directory
Tools = new List<string> { "*" },
}
// For dotnet tool (DLL)
["my-dotnet-tool"] = new McpLocalServerConfig
{
Type = "local",
Command = "dotnet",
Args = new List<string> { @"C:\Tools\MyTool\MyTool.dll" },
Cwd = @"C:\Tools\MyTool",
Tools = new List<string> { "*" },
}
// Windows needs cmd /c for npx
["filesystem"] = new McpLocalServerConfig
{
Type = "local",
Command = "cmd",
Args = new List<string> { "/c", "npx", "-y", "@modelcontextprotocol/server-filesystem", "C:\\allowed\\path" },
Tools = new List<string> { "*" },
}
@"C:\path") or forward slashes ("C:/path")Windows Defender or other AV may block:
Solution: Add exclusions for your MCP server executable.
# If server is blocked
xattr -d com.apple.quarantine /path/to/mcp-server
// GUI apps may not have /opt/homebrew in PATH
mcpServers: {
"my-server": {
command: "/opt/homebrew/bin/node", // Full path
args: ["/path/to/server.js"],
},
}
chmod +x /path/to/mcp-server
# Check dependencies
ldd /path/to/mcp-server
# Install missing libraries
apt install libfoo # Debian/Ubuntu
yum install libfoo # RHEL/CentOS
Create a wrapper script to log all communication:
#!/bin/bash
# mcp-debug-wrapper.sh
LOG="/tmp/mcp-debug-$(date +%s).log"
ACTUAL_SERVER="$1"
shift
echo "=== MCP Debug Session ===" >> "$LOG"
echo "Server: $ACTUAL_SERVER" >> "$LOG"
echo "Args: $@" >> "$LOG"
echo "=========================" >> "$LOG"
# Tee stdin/stdout to log file
tee -a "$LOG" | "$ACTUAL_SERVER" "$@" 2>> "$LOG" | tee -a "$LOG"
Use it:
mcpServers: {
"debug-server": {
command: "/path/to/mcp-debug-wrapper.sh",
args: ["/actual/server/path", "arg1", "arg2"],
},
}
Use the official MCP Inspector tool:
npx @modelcontextprotocol/inspector /path/to/your/mcp-server
This provides a web UI to:
Check your server supports the protocol version the SDK uses:
// In initialize response, check protocolVersion
{"result":{"protocolVersion":"2024-11-05",...}}
If versions don't match, update your MCP server library.
When opening an issue or asking for help, collect:
copilot --version)initialize testtools/list testCan you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |