This guide covers debugging techniques specific to MCP (Model Context Protocol) servers when using the Copilot SDK.
- Quick Diagnostics
- Testing MCP Servers Independently
- Common Issues
- Platform-Specific Issues
- Advanced Debugging
Before diving deep, verify these basics:
- MCP server executable exists and is runnable
- Command path is correct (use absolute paths when in doubt)
- Tools are enabled (
tools: ["*"]or specific tool names) - Server implements MCP protocol correctly (responds to
initialize) - No firewall/antivirus blocking the process (Windows)
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.exeExpected 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-serverExpected 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
catUsage:
./test-mcp.sh | /path/to/mcp-serverSymptoms: 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 arg2Symptoms: 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:
- Test with
tools/listrequest manually - Check server implements
tools/listmethod
- Test with
-
Initialization handshake fails:
- Server must respond to
initializecorrectly - Server must handle
notifications/initialized
- Server must respond to
Symptoms: 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:
- Ensure
inputSchemais valid JSON Schema - Required fields must be in
requiredarray
- Ensure
Symptoms: MCP tool call timed out errors.
Solutions:
-
Increase timeout:
mcpServers: { "slow-server": { // ... timeout: 300000, // 5 minutes }, }
-
Optimize server performance:
- Add progress logging to identify bottleneck
- Consider async operations
- Check for blocking I/O
-
For long-running tools, consider streaming responses if supported.
Symptoms: Parse errors, invalid request errors.
Common causes:
-
Server writes to stdout incorrectly:
- Debug output going to stdout instead of stderr
- Extra newlines or whitespace
// Wrong - pollutes stdout console.log("Debug info"); // Correct - use stderr for debug console.error("Debug info");
-
Encoding issues:
- Ensure UTF-8 encoding
- No BOM (Byte Order Mark)
-
Message framing:
- Each message must be a complete JSON object
- Newline-delimited (one message per line)
// 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> { "*" },
}- Use raw strings (
@"C:\path") or forward slashes ("C:/path") - Avoid spaces in paths when possible
- If spaces required, ensure proper quoting
Windows Defender or other AV may block:
- New executables
- Processes communicating via stdin/stdout
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/CentOSCreate 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-serverThis provides a web UI to:
- Send test requests
- View responses
- Inspect tool schemas
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:
- SDK language and version
- CLI version (
copilot --version) - MCP server type (Node.js, Python, .NET, Go, etc.)
- Full MCP server configuration (redact secrets)
- Result of manual
initializetest - Result of manual
tools/listtest - Debug logs from SDK
- Any error messages
- MCP Overview - Configuration and setup
- General Debugging Guide - SDK-wide debugging
- MCP Specification - Official protocol docs