Skip to content

Commit e1b1cd0

Browse files
mcp: implement completion (#55)
This CL implements a completion handler for the server and a complete method for the client. Fixes: #12 <!-- Provide a brief summary of your changes --> ## Motivation and Context <!-- Why is this change needed? What problem does it solve? --> This adds support for completion. ## How Has This Been Tested? <!-- Have you tested this in a real application? Which scenarios were tested? --> Added tests and an example. ## Breaking Changes <!-- Will users need to update their code or configurations? --> N/A ## Types of changes <!-- What types of changes does your code introduce? Put an `x` in all the boxes that apply: --> - [ ] Bug fix (non-breaking change which fixes an issue) - [x] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [ ] Documentation update ## Checklist <!-- Go over all the following points, and put an `x` in all the boxes that apply. --> - [x] I have read the [MCP Documentation](https://modelcontextprotocol.io) - [x] My code follows the repository's style guidelines - [x] New and existing tests pass locally - [x] I have added appropriate error handling - [x] I have added or updated documentation as needed ## Additional context <!-- Add any other context, implementation notes, or design decisions -->
1 parent 92b6983 commit e1b1cd0

File tree

6 files changed

+579
-5
lines changed

6 files changed

+579
-5
lines changed

examples/completion/main.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Copyright 2025 The Go MCP SDK Authors. All rights reserved.
2+
// Use of this source code is governed by an MIT-style
3+
// license that can be found in the LICENSE file.
4+
5+
package main
6+
7+
import (
8+
"context"
9+
"fmt"
10+
"log"
11+
12+
"github.com/modelcontextprotocol/go-sdk/mcp"
13+
)
14+
15+
// This example demonstrates the minimal code to declare and assign
16+
// a CompletionHandler to an MCP Server's options.
17+
func main() {
18+
// Define your custom CompletionHandler logic.
19+
myCompletionHandler := func(_ context.Context, _ *mcp.ServerSession, params *mcp.CompleteParams) (*mcp.CompleteResult, error) {
20+
// In a real application, you'd implement actual completion logic here.
21+
// For this example, we return a fixed set of suggestions.
22+
var suggestions []string
23+
switch params.Ref.Type {
24+
case "ref/prompt":
25+
suggestions = []string{"suggestion1", "suggestion2", "suggestion3"}
26+
case "ref/resource":
27+
suggestions = []string{"suggestion4", "suggestion5", "suggestion6"}
28+
default:
29+
return nil, fmt.Errorf("unrecognized content type %s", params.Ref.Type)
30+
}
31+
32+
return &mcp.CompleteResult{
33+
Completion: mcp.CompletionResultDetails{
34+
HasMore: false,
35+
Total: len(suggestions),
36+
Values: suggestions,
37+
},
38+
}, nil
39+
}
40+
41+
// Create the MCP Server instance and assign the handler.
42+
// No server running, just showing the configuration.
43+
_ = mcp.NewServer("myServer", "v1.0.0", &mcp.ServerOptions{
44+
CompletionHandler: myCompletionHandler,
45+
})
46+
47+
log.Println("MCP Server instance created with a CompletionHandler assigned (but not running).")
48+
log.Println("This example demonstrates configuration, not live interaction.")
49+
}

mcp/client.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,7 @@ func (c *Client) AddReceivingMiddleware(middleware ...Middleware[*ClientSession]
257257

258258
// clientMethodInfos maps from the RPC method name to serverMethodInfos.
259259
var clientMethodInfos = map[string]methodInfo{
260+
methodComplete: newMethodInfo(sessionMethod((*ClientSession).Complete)),
260261
methodPing: newMethodInfo(sessionMethod((*ClientSession).ping)),
261262
methodListRoots: newMethodInfo(clientMethod((*Client).listRoots)),
262263
methodCreateMessage: newMethodInfo(clientMethod((*Client).createMessage)),
@@ -352,6 +353,10 @@ func (cs *ClientSession) ReadResource(ctx context.Context, params *ReadResourceP
352353
return handleSend[*ReadResourceResult](ctx, cs, methodReadResource, orZero[Params](params))
353354
}
354355

356+
func (cs *ClientSession) Complete(ctx context.Context, params *CompleteParams) (*CompleteResult, error) {
357+
return handleSend[*CompleteResult](ctx, cs, methodComplete, orZero[Params](params))
358+
}
359+
355360
func (c *Client) callToolChangedHandler(ctx context.Context, s *ClientSession, params *ToolListChangedParams) (Result, error) {
356361
return callNotificationHandler(ctx, c.opts.ToolListChangedHandler, s, params)
357362
}

mcp/protocol.go

Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ package mcp
1212

1313
import (
1414
"encoding/json"
15+
"fmt"
1516

1617
"github.com/modelcontextprotocol/go-sdk/jsonschema"
1718
)
@@ -133,6 +134,93 @@ type ClientCapabilities struct {
133134
Elicitation *ElicitationCapabilities `json:"elicitation,omitempty"`
134135
}
135136

137+
type CompleteParamsArgument struct {
138+
// The name of the argument
139+
Name string `json:"name"`
140+
// The value of the argument to use for completion matching.
141+
Value string `json:"value"`
142+
}
143+
144+
// CompleteContext represents additional, optional context for completions.
145+
type CompleteContext struct {
146+
// Previously-resolved variables in a URI template or prompt.
147+
Arguments map[string]string `json:"arguments,omitempty"`
148+
}
149+
150+
// CompleteReference represents a completion reference type (ref/prompt ref/resource).
151+
// The Type field determines which other fields are relevant.
152+
type CompleteReference struct {
153+
Type string `json:"type"`
154+
// Name is relevant when Type is "ref/prompt".
155+
Name string `json:"name,omitempty"`
156+
// URI is relevant when Type is "ref/resource".
157+
URI string `json:"uri,omitempty"`
158+
}
159+
160+
func (r *CompleteReference) UnmarshalJSON(data []byte) error {
161+
type wireCompleteReference CompleteReference // for naive unmarshaling
162+
var r2 wireCompleteReference
163+
if err := json.Unmarshal(data, &r2); err != nil {
164+
return err
165+
}
166+
switch r2.Type {
167+
case "ref/prompt", "ref/resource":
168+
if r2.Type == "ref/prompt" && r2.URI != "" {
169+
return fmt.Errorf("reference of type %q must not have a URI set", r2.Type)
170+
}
171+
if r2.Type == "ref/resource" && r2.Name != "" {
172+
return fmt.Errorf("reference of type %q must not have a Name set", r2.Type)
173+
}
174+
default:
175+
return fmt.Errorf("unrecognized content type %q", r2.Type)
176+
}
177+
*r = CompleteReference(r2)
178+
return nil
179+
}
180+
181+
func (r *CompleteReference) MarshalJSON() ([]byte, error) {
182+
// Validation for marshalling: ensure consistency before converting to JSON.
183+
switch r.Type {
184+
case "ref/prompt":
185+
if r.URI != "" {
186+
return nil, fmt.Errorf("reference of type %q must not have a URI set for marshalling", r.Type)
187+
}
188+
case "ref/resource":
189+
if r.Name != "" {
190+
return nil, fmt.Errorf("reference of type %q must not have a Name set for marshalling", r.Type)
191+
}
192+
default:
193+
return nil, fmt.Errorf("unrecognized reference type %q for marshalling", r.Type)
194+
}
195+
196+
type wireReference CompleteReference
197+
return json.Marshal(wireReference(*r))
198+
}
199+
200+
type CompleteParams struct {
201+
// This property is reserved by the protocol to allow clients and servers to
202+
// attach additional metadata to their responses.
203+
Meta `json:"_meta,omitempty"`
204+
// The argument's information
205+
Argument CompleteParamsArgument `json:"argument"`
206+
Context *CompleteContext `json:"context,omitempty"`
207+
Ref *CompleteReference `json:"ref"`
208+
}
209+
210+
type CompletionResultDetails struct {
211+
HasMore bool `json:"hasMore,omitempty"`
212+
Total int `json:"total,omitempty"`
213+
Values []string `json:"values"`
214+
}
215+
216+
// The server's response to a completion/complete request
217+
type CompleteResult struct {
218+
// This property is reserved by the protocol to allow clients and servers to
219+
// attach additional metadata to their responses.
220+
Meta `json:"_meta,omitempty"`
221+
Completion CompletionResultDetails `json:"completion"`
222+
}
223+
136224
type CreateMessageParams struct {
137225
// This property is reserved by the protocol to allow clients and servers to
138226
// attach additional metadata to their responses.
@@ -787,6 +875,9 @@ type implementation struct {
787875
Version string `json:"version"`
788876
}
789877

878+
// Present if the server supports argument autocompletion suggestions.
879+
type completionCapabilities struct{}
880+
790881
// Present if the server supports sending log messages to the client.
791882
type loggingCapabilities struct{}
792883

@@ -809,7 +900,7 @@ type resourceCapabilities struct {
809900
// additional capabilities.
810901
type serverCapabilities struct {
811902
// Present if the server supports argument autocompletion suggestions.
812-
Completions struct{} `json:"completions,omitempty"`
903+
Completions *completionCapabilities `json:"completions,omitempty"`
813904
// Experimental, non-standard capabilities that the server supports.
814905
Experimental map[string]struct{} `json:"experimental,omitempty"`
815906
// Present if the server supports sending log messages to the client.

0 commit comments

Comments
 (0)