diff --git a/ldk-server-mcp/CLAUDE.md b/ldk-server-mcp/CLAUDE.md index af791b91..0a17e8b8 100644 --- a/ldk-server-mcp/CLAUDE.md +++ b/ldk-server-mcp/CLAUDE.md @@ -35,7 +35,7 @@ src/ - **Version**: `2025-11-25` - **Spec**: https://spec.modelcontextprotocol.io/ - **Transport**: stdio (one JSON-RPC 2.0 message per line) -- **Methods implemented**: `initialize`, `tools/list`, `tools/call` +- **Methods implemented**: `initialize`, `tools/list`, `tools/call`, `ping` - **Notifications handled**: `notifications/initialized` (ignored, no response) ## Config diff --git a/ldk-server-mcp/README.md b/ldk-server-mcp/README.md index 56b79d7d..3d958a3d 100644 --- a/ldk-server-mcp/README.md +++ b/ldk-server-mcp/README.md @@ -101,7 +101,7 @@ Streaming RPCs such as `subscribe_events` and non-RPC HTTP endpoints such as `me - **Protocol version**: `2025-11-25` - **Transport**: stdio (one JSON-RPC 2.0 message per line) -- **Methods**: `initialize`, `tools/list`, `tools/call` +- **Methods**: `initialize`, `tools/list`, `tools/call`, `ping` ## Testing diff --git a/ldk-server-mcp/src/main.rs b/ldk-server-mcp/src/main.rs index 25f95b7f..0f48f6aa 100644 --- a/ldk-server-mcp/src/main.rs +++ b/ldk-server-mcp/src/main.rs @@ -124,6 +124,11 @@ async fn main() { let resp = JsonRpcResponse::new(id, serde_json::json!({ "tools": tools })); serde_json::to_string(&resp).unwrap() }, + "ping" => { + // Per the MCP spec, a ping must be answered with an empty result object. + let resp = JsonRpcResponse::new(id, serde_json::json!({})); + serde_json::to_string(&resp).unwrap() + }, "tools/call" => { let params = request.params.unwrap_or(Value::Null); match params.get("name").and_then(|v| v.as_str()) { diff --git a/ldk-server-mcp/tests/integration.rs b/ldk-server-mcp/tests/integration.rs index 98a2a1bf..891956c3 100644 --- a/ldk-server-mcp/tests/integration.rs +++ b/ldk-server-mcp/tests/integration.rs @@ -185,6 +185,25 @@ fn test_tools_list() { } } +#[test] +fn test_ping() { + let mut proc = McpProcess::spawn(); + + proc.send(&json!({ + "jsonrpc": "2.0", + "id": 1, + "method": "ping" + })); + + let resp = proc.recv(); + assert_eq!(resp["jsonrpc"], "2.0"); + assert_eq!(resp["id"], 1); + // Per the MCP spec, ping is answered with an empty result object. + assert!(resp["result"].is_object(), "Expected result object, got: {}", resp["result"]); + assert_eq!(resp["result"].as_object().unwrap().len(), 0, "Expected empty result object"); + assert!(resp.get("error").is_none(), "Ping must not return an error"); +} + #[test] fn test_tools_call_unknown_tool() { let mut proc = McpProcess::spawn();