项目文件夹

文件
Asim Aslam 59397834b4
goreleaser / goreleaser (push) Has been cancelled
gateway/mcp: swappable Resolver + mountable JSON-RPC HTTP handler (#3331)
* gateway/mcp: swappable Resolver + mountable JSON-RPC HTTP handler

Adds a Resolver interface (Manual/Registry) so the tool source is
pluggable, and NewHandler(resolver) serving standard MCP JSON-RPC over
HTTP as an http.Handler you can mount on your own server. Neither
resolver exposes the internal store/broker tools. Additive — the
existing Serve() path is unchanged.

* gateway/mcp: swappable Resolver + mountable JSON-RPC HTTP handler

Adds a Resolver interface (Manual/Registry) so the tool source is
pluggable, and NewHandler(resolver) serving standard MCP JSON-RPC over
HTTP as an http.Handler you can mount on your own server. Neither
resolver exposes the internal store/broker tools. Additive — the
existing Serve() path is unchanged.

* gateway/mcp: swappable Resolver + mountable JSON-RPC HTTP handler

Adds a Resolver interface (Manual/Registry) so the tool source is
pluggable, and NewHandler(resolver) serving standard MCP JSON-RPC over
HTTP as an http.Handler you can mount on your own server. Neither
resolver exposes the internal store/broker tools. Additive — the
existing Serve() path is unchanged.
2026-06-29 07:03:23 +01:00

59 行
1.8 KiB
Go

package mcp
import (
"context"
"encoding/json"
"net/http"
"net/http/httptest"
"strings"
"testing"
)
func TestManualResolverHandler(t *testing.T) {
res := NewManualResolver().Add(
Tool{Name: "echo", Description: "echoes text", InputSchema: map[string]interface{}{
"type": "object", "properties": map[string]interface{}{"text": map[string]interface{}{"type": "string"}},
}},
func(_ context.Context, args map[string]interface{}) (string, error) {
s, _ := args["text"].(string)
return "you said: " + s, nil
},
)
ts := httptest.NewServer(NewHandler(res))
defer ts.Close()
rpc := func(body string) map[string]interface{} {
resp, err := http.Post(ts.URL, "application/json", strings.NewReader(body))
if err != nil {
t.Fatalf("post: %v", err)
}
defer resp.Body.Close()
var out map[string]interface{}
json.NewDecoder(resp.Body).Decode(&out)
return out
}
// initialize
if out := rpc(`{"jsonrpc":"2.0","id":1,"method":"initialize"}`); out["result"] == nil {
t.Fatalf("initialize: %v", out)
}
// tools/list
out := rpc(`{"jsonrpc":"2.0","id":2,"method":"tools/list"}`)
tools := out["result"].(map[string]interface{})["tools"].([]interface{})
if len(tools) != 1 || tools[0].(map[string]interface{})["name"] != "echo" {
t.Fatalf("tools/list: %v", out)
}
// tools/call
out = rpc(`{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"echo","arguments":{"text":"hi"}}}`)
content := out["result"].(map[string]interface{})["content"].([]interface{})
got := content[0].(map[string]interface{})["text"].(string)
if got != "you said: hi" {
t.Fatalf("tools/call text = %q", got)
}
// unknown tool -> error
out = rpc(`{"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"nope","arguments":{}}}`)
if out["error"] == nil {
t.Fatalf("expected error for unknown tool, got %v", out)
}
}