internal/mcp: change function signatures match design doc
To ensure backward compatibility, every method in the spec now takes a *Params struct and returns a *Result struct. CallTools is an exception: we'll change that in the next CL. Change-Id: I58835239c67582401b8c9c2d070702d270131c08 Reviewed-on: https://go-review.googlesource.com/c/tools/+/672595 Reviewed-by: Robert Findley <rfindley@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
This commit is contained in:
parent
02fa1b3ea6
commit
4721f501df
6 changed files with 38 additions and 48 deletions
|
|
@ -154,47 +154,23 @@ func (c *Client) handle(ctx context.Context, req *jsonrpc2.Request) (any, error)
|
|||
}
|
||||
|
||||
// Ping makes an MCP "ping" request to the server.
|
||||
func (c *Client) Ping(ctx context.Context) error {
|
||||
return call(ctx, c.conn, "ping", nil, nil)
|
||||
func (c *Client) Ping(ctx context.Context, params *PingParams) error {
|
||||
return call(ctx, c.conn, "ping", params, nil)
|
||||
}
|
||||
|
||||
// ListPrompts lists prompts that are currently available on the server.
|
||||
func (c *Client) ListPrompts(ctx context.Context) ([]*Prompt, error) {
|
||||
var (
|
||||
params = &ListPromptsParams{}
|
||||
result ListPromptsResult
|
||||
)
|
||||
if err := call(ctx, c.conn, "prompts/list", params, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result.Prompts, nil
|
||||
func (c *Client) ListPrompts(ctx context.Context, params *ListPromptsParams) (*ListPromptsResult, error) {
|
||||
return standardCall[ListPromptsResult](ctx, c.conn, "prompts/list", params)
|
||||
}
|
||||
|
||||
// GetPrompt gets a prompt from the server.
|
||||
func (c *Client) GetPrompt(ctx context.Context, name string, args map[string]string) (*GetPromptResult, error) {
|
||||
var (
|
||||
params = &GetPromptParams{
|
||||
Name: name,
|
||||
Arguments: args,
|
||||
}
|
||||
result = &GetPromptResult{}
|
||||
)
|
||||
if err := call(ctx, c.conn, "prompts/get", params, result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
func (c *Client) GetPrompt(ctx context.Context, params *GetPromptParams) (*GetPromptResult, error) {
|
||||
return standardCall[GetPromptResult](ctx, c.conn, "prompts/get", params)
|
||||
}
|
||||
|
||||
// ListTools lists tools that are currently available on the server.
|
||||
func (c *Client) ListTools(ctx context.Context) ([]*Tool, error) {
|
||||
var (
|
||||
params = &ListToolsParams{}
|
||||
result ListToolsResult
|
||||
)
|
||||
if err := call(ctx, c.conn, "tools/list", params, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result.Tools, nil
|
||||
func (c *Client) ListTools(ctx context.Context, params *ListToolsParams) (*ListToolsResult, error) {
|
||||
return standardCall[ListToolsResult](ctx, c.conn, "tools/list", params)
|
||||
}
|
||||
|
||||
// CallTool calls the tool with the given name and arguments.
|
||||
|
|
|
|||
|
|
@ -97,11 +97,15 @@ var declarations = config{
|
|||
Fields: config{"Params": {Name: "ListToolsParams"}},
|
||||
},
|
||||
"ListToolsResult": {},
|
||||
"Prompt": {},
|
||||
"PromptMessage": {},
|
||||
"PromptArgument": {},
|
||||
"ProgressToken": {Name: "-", Substitute: "any"}, // null|number|string
|
||||
"RequestId": {Name: "-", Substitute: "any"}, // null|number|string
|
||||
"PingRequest": {
|
||||
Name: "-",
|
||||
Fields: config{"Params": {Name: "PingParams"}},
|
||||
},
|
||||
"Prompt": {},
|
||||
"PromptMessage": {},
|
||||
"PromptArgument": {},
|
||||
"ProgressToken": {Name: "-", Substitute: "any"}, // null|number|string
|
||||
"RequestId": {Name: "-", Substitute: "any"}, // null|number|string
|
||||
"ReadResourceRequest": {
|
||||
Name: "-",
|
||||
Fields: config{"Params": {Name: "ReadResourceParams"}},
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ type hiParams struct {
|
|||
}
|
||||
|
||||
func sayHi(ctx context.Context, cc *ServerConnection, v hiParams) ([]*Content, error) {
|
||||
if err := cc.Ping(ctx); err != nil {
|
||||
if err := cc.Ping(ctx, nil); err != nil {
|
||||
return nil, fmt.Errorf("ping failed: %v", err)
|
||||
}
|
||||
return []*Content{NewTextContent("hi " + v.Name)}, nil
|
||||
|
|
@ -89,11 +89,11 @@ func TestEndToEnd(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := c.Ping(ctx); err != nil {
|
||||
if err := c.Ping(ctx, nil); err != nil {
|
||||
t.Fatalf("ping failed: %v", err)
|
||||
}
|
||||
t.Run("prompts", func(t *testing.T) {
|
||||
gotPrompts, err := c.ListPrompts(ctx)
|
||||
res, err := c.ListPrompts(ctx, nil)
|
||||
if err != nil {
|
||||
t.Errorf("prompts/list failed: %v", err)
|
||||
}
|
||||
|
|
@ -105,11 +105,11 @@ func TestEndToEnd(t *testing.T) {
|
|||
},
|
||||
{Name: "fail"},
|
||||
}
|
||||
if diff := cmp.Diff(wantPrompts, gotPrompts); diff != "" {
|
||||
if diff := cmp.Diff(wantPrompts, res.Prompts); diff != "" {
|
||||
t.Fatalf("prompts/list mismatch (-want +got):\n%s", diff)
|
||||
}
|
||||
|
||||
gotReview, err := c.GetPrompt(ctx, "code_review", map[string]string{"Code": "1+1"})
|
||||
gotReview, err := c.GetPrompt(ctx, &GetPromptParams{Name: "code_review", Arguments: map[string]string{"Code": "1+1"}})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
@ -124,13 +124,13 @@ func TestEndToEnd(t *testing.T) {
|
|||
t.Errorf("prompts/get 'code_review' mismatch (-want +got):\n%s", diff)
|
||||
}
|
||||
|
||||
if _, err := c.GetPrompt(ctx, "fail", map[string]string{}); err == nil || !strings.Contains(err.Error(), failure.Error()) {
|
||||
if _, err := c.GetPrompt(ctx, &GetPromptParams{Name: "fail"}); err == nil || !strings.Contains(err.Error(), failure.Error()) {
|
||||
t.Errorf("fail returned unexpected error: got %v, want containing %v", err, failure)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("tools", func(t *testing.T) {
|
||||
gotTools, err := c.ListTools(ctx)
|
||||
res, err := c.ListTools(ctx, nil)
|
||||
if err != nil {
|
||||
t.Errorf("tools/list failed: %v", err)
|
||||
}
|
||||
|
|
@ -156,7 +156,7 @@ func TestEndToEnd(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
if diff := cmp.Diff(wantTools, gotTools, cmpopts.IgnoreUnexported(jsonschema.Schema{})); diff != "" {
|
||||
if diff := cmp.Diff(wantTools, res.Tools, cmpopts.IgnoreUnexported(jsonschema.Schema{})); diff != "" {
|
||||
t.Fatalf("tools/list mismatch (-want +got):\n%s", diff)
|
||||
}
|
||||
|
||||
|
|
@ -350,7 +350,7 @@ func TestBatching(t *testing.T) {
|
|||
errs := make(chan error, batchSize)
|
||||
for i := range batchSize {
|
||||
go func() {
|
||||
_, err := c.ListTools(ctx)
|
||||
_, err := c.ListTools(ctx, nil)
|
||||
errs <- err
|
||||
}()
|
||||
time.Sleep(2 * time.Millisecond)
|
||||
|
|
|
|||
|
|
@ -170,6 +170,16 @@ type ListToolsResult struct {
|
|||
Tools []*Tool `json:"tools"`
|
||||
}
|
||||
|
||||
type PingParams struct {
|
||||
Meta struct {
|
||||
// If specified, the caller is requesting out-of-band progress notifications for
|
||||
// this request (as represented by notifications/progress). The value of this
|
||||
// parameter is an opaque token that will be attached to any subsequent
|
||||
// notifications. The receiver is not obligated to provide these notifications.
|
||||
ProgressToken any `json:"progressToken,omitempty"`
|
||||
} `json:"_meta,omitempty"`
|
||||
}
|
||||
|
||||
// A prompt or prompt template that the server offers.
|
||||
type Prompt struct {
|
||||
// A list of arguments to use for templating the prompt.
|
||||
|
|
|
|||
|
|
@ -303,7 +303,7 @@ type ServerConnection struct {
|
|||
}
|
||||
|
||||
// Ping makes an MCP "ping" request to the client.
|
||||
func (cc *ServerConnection) Ping(ctx context.Context) error {
|
||||
func (cc *ServerConnection) Ping(ctx context.Context, _ *PingParams) error {
|
||||
return call(ctx, cc.conn, "ping", nil, nil)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ func TestSSEServer(t *testing.T) {
|
|||
if err := c.Start(ctx); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := c.Ping(ctx); err != nil {
|
||||
if err := c.Ping(ctx, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
cc := <-conns
|
||||
|
|
|
|||
Loading…
Reference in a new issue