1. What's the Issue
MCP clients (such as MCP Inspector) fail to process responses from gopher-mcp servers because the response formats don't comply with the MCP protocol specification.
Three methods return incorrectly formatted responses:
Problem 1: initialize Uses Flattened Dot Notation
The initialize response used flattened keys with dot notation instead of proper nested JSON objects.
Actual (incorrect):
{
"result": {
"protocolVersion": "2024-11-05",
"serverInfo.name": "my-server",
"serverInfo.version": "1.0.0",
"capabilities.tools": true
}
}
Expected (correct):
{
"result": {
"protocolVersion": "2024-11-05",
"serverInfo": {
"name": "my-server",
"version": "1.0.0"
},
"capabilities": {
"tools": {}
}
}
}
Problem 2: tools/list Returns Bare Array
The tools/list response returned a bare array instead of wrapping it in an object with a "tools" key.
Actual (incorrect):
{
"result": [
{"name": "get-weather", "description": "..."}
]
}
Expected (correct):
{
"result": {
"tools": [
{"name": "get-weather", "description": "..."}
]
}
}
Problem 3: prompts/list Returns Bare Array
Same issue as tools/list - returned bare array instead of wrapped object.
Error observed in MCP Inspector:
Error [ { "code": "invalid_union", "unionErrors": [...] } ]
Invalid input
2. How to Reproduce
Prerequisites
- Build gopher-mcp with HTTP/SSE transport enabled
- Run an MCP server with tools and prompts registered
Steps to Reproduce
-
Start the MCP server:
./mcp_example_server # or any gopher-mcp server with HTTP/SSE transport
-
Send an initialize request and inspect the response format:
curl -s -X POST http://localhost:3001/mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}' | jq .
-
Expected: Nested serverInfo and capabilities objects
-
Actual (before fix): Flattened serverInfo.name, capabilities.tools keys
-
Send a tools/list request:
curl -s -X POST http://localhost:3001/mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}' | jq .
-
Expected: {"result": {"tools": [...]}}
-
Actual (before fix): {"result": [...]}
Using MCP Inspector
- Connect to the server via MCP Inspector
- Click "List Tools" or "List Prompts"
- Before fix: Error dialog shows "Invalid input" with validation errors
3. How to Fix It
The fix modifies three handler methods in src/server/mcp_server.cc.
Fix 1: handleInitialize - Use Nested JSON Structure
Replace the flattened Metadata builder with proper nested JsonValue construction:
jsonrpc::Response McpServer::handleInitialize(const jsonrpc::Request& request,
SessionContext& session) {
// Build initialize result as proper nested JSON structure
// MCP protocol requires nested objects, not flattened dot notation
json::JsonValue result_json;
result_json["protocolVersion"] = config_.protocol_version;
// Add serverInfo as nested object
json::JsonValue server_info;
server_info["name"] = config_.server_name;
server_info["version"] = config_.server_version;
result_json["serverInfo"] = std::move(server_info);
// Add capabilities as nested object with empty objects for enabled caps
json::JsonValue capabilities = json::JsonValue::object();
if (config_.capabilities.tools.has_value() &&
config_.capabilities.tools.value()) {
capabilities["tools"] = json::JsonValue::object();
}
if (config_.capabilities.prompts.has_value() &&
config_.capabilities.prompts.value()) {
capabilities["prompts"] = json::JsonValue::object();
}
result_json["capabilities"] = std::move(capabilities);
return jsonrpc::Response::success(request.id,
jsonrpc::ResponseResult(result_json));
}
Fix 2: handleListTools - Wrap Array in Object
Wrap the tools array in an object with "tools" key:
jsonrpc::Response McpServer::handleListTools(const jsonrpc::Request& request,
SessionContext& session) {
// Get tools from tool registry
auto result = tool_registry_->listTools();
// Build response as JsonValue with "tools" key per MCP spec
json::JsonValue tools_array = json::JsonValue::array();
for (const auto& tool : result.tools) {
tools_array.push_back(json::to_json(tool));
}
json::JsonValue response_obj = json::JsonValue::object();
response_obj["tools"] = std::move(tools_array);
return jsonrpc::Response::success(request.id,
jsonrpc::ResponseResult(response_obj));
}
Fix 3: handleListPrompts - Wrap Array in Object
Same pattern as tools/list:
jsonrpc::Response McpServer::handleListPrompts(const jsonrpc::Request& request,
SessionContext& session) {
auto result = prompt_registry_->listPrompts(cursor);
// Build response as JsonValue with "prompts" key per MCP spec
json::JsonValue prompts_array = json::JsonValue::array();
for (const auto& prompt : result.prompts) {
prompts_array.push_back(json::to_json(prompt));
}
json::JsonValue response_obj = json::JsonValue::object();
response_obj["prompts"] = std::move(prompts_array);
return jsonrpc::Response::success(request.id,
jsonrpc::ResponseResult(response_obj));
}
Verification
After the fix:
# Initialize returns nested structure
$ curl -s -X POST http://localhost:3001/mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{...}}' | jq .result
{
"protocolVersion": "2024-11-05",
"serverInfo": {
"name": "my-server",
"version": "1.0.0"
},
"capabilities": {
"tools": {},
"prompts": {}
}
}
# tools/list returns wrapped array
$ curl -s -X POST http://localhost:3001/mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}' | jq .result
{
"tools": [
{"name": "get-weather", "description": "..."}
]
}
MCP Inspector can now successfully parse and display tools and prompts.
1. What's the Issue
MCP clients (such as MCP Inspector) fail to process responses from gopher-mcp servers because the response formats don't comply with the MCP protocol specification.
Three methods return incorrectly formatted responses:
Problem 1:
initializeUses Flattened Dot NotationThe initialize response used flattened keys with dot notation instead of proper nested JSON objects.
Actual (incorrect):
{ "result": { "protocolVersion": "2024-11-05", "serverInfo.name": "my-server", "serverInfo.version": "1.0.0", "capabilities.tools": true } }Expected (correct):
{ "result": { "protocolVersion": "2024-11-05", "serverInfo": { "name": "my-server", "version": "1.0.0" }, "capabilities": { "tools": {} } } }Problem 2:
tools/listReturns Bare ArrayThe tools/list response returned a bare array instead of wrapping it in an object with a
"tools"key.Actual (incorrect):
{ "result": [ {"name": "get-weather", "description": "..."} ] }Expected (correct):
{ "result": { "tools": [ {"name": "get-weather", "description": "..."} ] } }Problem 3:
prompts/listReturns Bare ArraySame issue as tools/list - returned bare array instead of wrapped object.
Error observed in MCP Inspector:
2. How to Reproduce
Prerequisites
Steps to Reproduce
Start the MCP server:
./mcp_example_server # or any gopher-mcp server with HTTP/SSE transportSend an initialize request and inspect the response format:
Expected: Nested
serverInfoandcapabilitiesobjectsActual (before fix): Flattened
serverInfo.name,capabilities.toolskeysSend a tools/list request:
Expected:
{"result": {"tools": [...]}}Actual (before fix):
{"result": [...]}Using MCP Inspector
3. How to Fix It
The fix modifies three handler methods in
src/server/mcp_server.cc.Fix 1: handleInitialize - Use Nested JSON Structure
Replace the flattened
Metadatabuilder with proper nestedJsonValueconstruction:Fix 2: handleListTools - Wrap Array in Object
Wrap the tools array in an object with
"tools"key:Fix 3: handleListPrompts - Wrap Array in Object
Same pattern as tools/list:
Verification
After the fix:
MCP Inspector can now successfully parse and display tools and prompts.