feat(server/mcp): Support ping mechanism (#1178)

Send back an empty result with a `ping` request following the [MCP ping
spec](https://modelcontextprotocol.io/specification/2025-06-18/basic/utilities/ping).

<img width="577" height="481" alt="Screenshot 2025-08-18 at 4 20 09 PM"
src="https://github.com/user-attachments/assets/fd48725e-298e-4938-9368-d704bea0a546"
/>
This commit is contained in:
Wenxin Du
2025-08-20 15:04:47 -04:00
committed by GitHub
parent 212aaba74c
commit 5dcc66c84f
7 changed files with 69 additions and 0 deletions

View File

@@ -28,6 +28,8 @@ import (
// ProcessMethod returns a response for the request.
func ProcessMethod(ctx context.Context, id jsonrpc.RequestId, method string, toolset tools.Toolset, tools map[string]tools.Tool, body []byte) (any, error) {
switch method {
case PING:
return pingHandler(id)
case TOOLS_LIST:
return toolsListHandler(id, toolset, body)
case TOOLS_CALL:
@@ -38,6 +40,15 @@ func ProcessMethod(ctx context.Context, id jsonrpc.RequestId, method string, too
}
}
// pingHandler handles the "ping" method by returning an empty response.
func pingHandler(id jsonrpc.RequestId) (any, error) {
return jsonrpc.JSONRPCResponse{
Jsonrpc: jsonrpc.JSONRPC_VERSION,
Id: id,
Result: struct{}{},
}, nil
}
func toolsListHandler(id jsonrpc.RequestId, toolset tools.Toolset, body []byte) (any, error) {
var req ListToolsRequest
if err := json.Unmarshal(body, &req); err != nil {

View File

@@ -27,6 +27,7 @@ const PROTOCOL_VERSION = "2024-11-05"
// methods that are supported.
const (
PING = "ping"
TOOLS_LIST = "tools/list"
TOOLS_CALL = "tools/call"
)

View File

@@ -28,6 +28,8 @@ import (
// ProcessMethod returns a response for the request.
func ProcessMethod(ctx context.Context, id jsonrpc.RequestId, method string, toolset tools.Toolset, tools map[string]tools.Tool, body []byte) (any, error) {
switch method {
case PING:
return pingHandler(id)
case TOOLS_LIST:
return toolsListHandler(id, toolset, body)
case TOOLS_CALL:
@@ -38,6 +40,15 @@ func ProcessMethod(ctx context.Context, id jsonrpc.RequestId, method string, too
}
}
// pingHandler handles the "ping" method by returning an empty response.
func pingHandler(id jsonrpc.RequestId) (any, error) {
return jsonrpc.JSONRPCResponse{
Jsonrpc: jsonrpc.JSONRPC_VERSION,
Id: id,
Result: struct{}{},
}, nil
}
func toolsListHandler(id jsonrpc.RequestId, toolset tools.Toolset, body []byte) (any, error) {
var req ListToolsRequest
if err := json.Unmarshal(body, &req); err != nil {

View File

@@ -27,6 +27,7 @@ const PROTOCOL_VERSION = "2025-03-26"
// methods that are supported.
const (
PING = "ping"
TOOLS_LIST = "tools/list"
TOOLS_CALL = "tools/call"
)

View File

@@ -28,6 +28,8 @@ import (
// ProcessMethod returns a response for the request.
func ProcessMethod(ctx context.Context, id jsonrpc.RequestId, method string, toolset tools.Toolset, tools map[string]tools.Tool, body []byte) (any, error) {
switch method {
case PING:
return pingHandler(id)
case TOOLS_LIST:
return toolsListHandler(id, toolset, body)
case TOOLS_CALL:
@@ -38,6 +40,15 @@ func ProcessMethod(ctx context.Context, id jsonrpc.RequestId, method string, too
}
}
// pingHandler handles the "ping" method by returning an empty response.
func pingHandler(id jsonrpc.RequestId) (any, error) {
return jsonrpc.JSONRPCResponse{
Jsonrpc: jsonrpc.JSONRPC_VERSION,
Id: id,
Result: struct{}{},
}, nil
}
func toolsListHandler(id jsonrpc.RequestId, toolset tools.Toolset, body []byte) (any, error) {
var req ListToolsRequest
if err := json.Unmarshal(body, &req); err != nil {

View File

@@ -27,6 +27,7 @@ const PROTOCOL_VERSION = "2025-06-18"
// methods that are supported.
const (
PING = "ping"
TOOLS_LIST = "tools/list"
TOOLS_CALL = "tools/call"
)

View File

@@ -81,6 +81,23 @@ func TestMcpEndpointWithoutInitialized(t *testing.T) {
body jsonrpc.JSONRPCRequest
want map[string]any
}{
{
name: "ping",
url: "/",
body: jsonrpc.JSONRPCRequest{
Jsonrpc: jsonrpcVersion,
Id: "ping-test-123",
Request: jsonrpc.Request{
Method: "ping",
},
},
isErr: false,
want: map[string]any{
"jsonrpc": "2.0",
"id": "ping-test-123",
"result": map[string]any{},
},
},
{
name: "tools/list",
url: "/",
@@ -333,6 +350,22 @@ func TestMcpEndpoint(t *testing.T) {
},
},
},
{
name: "ping",
url: "/",
body: jsonrpc.JSONRPCRequest{
Jsonrpc: jsonrpcVersion,
Id: "ping-test-123",
Request: jsonrpc.Request{
Method: "ping",
},
},
want: map[string]any{
"jsonrpc": "2.0",
"id": "ping-test-123",
"result": map[string]any{},
},
},
{
name: "tools/list",
url: "/",