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
-->
This commit is contained in:
Sam Thanawalla 2025-07-01 13:09:15 -04:00 • committed by GitHub
commit e1b1cd0072
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -12,6 +12,7 @@ package mcp
import (
"encoding/json"
"fmt"
"github.com/modelcontextprotocol/go-sdk/jsonschema"
)
@ -133,6 +134,93 @@ type ClientCapabilities struct {
Elicitation *ElicitationCapabilities `json:"elicitation,omitempty"`
}
type CompleteParamsArgument struct {
// The name of the argument
Name string `json:"name"`
// The value of the argument to use for completion matching.
Value string `json:"value"`
}
// CompleteContext represents additional, optional context for completions.
type CompleteContext struct {
// Previously-resolved variables in a URI template or prompt.
Arguments map[string]string `json:"arguments,omitempty"`
}
// CompleteReference represents a completion reference type (ref/prompt ref/resource).
// The Type field determines which other fields are relevant.
type CompleteReference struct {
Type string `json:"type"`
// Name is relevant when Type is "ref/prompt".
Name string `json:"name,omitempty"`
// URI is relevant when Type is "ref/resource".
URI string `json:"uri,omitempty"`
}
func (r *CompleteReference) UnmarshalJSON(data []byte) error {
type wireCompleteReference CompleteReference // for naive unmarshaling
var r2 wireCompleteReference
if err := json.Unmarshal(data, &r2); err != nil {
return err
}
switch r2.Type {
case "ref/prompt", "ref/resource":
if r2.Type == "ref/prompt" && r2.URI != "" {
return fmt.Errorf("reference of type %q must not have a URI set", r2.Type)
}
if r2.Type == "ref/resource" && r2.Name != "" {
return fmt.Errorf("reference of type %q must not have a Name set", r2.Type)
}
default:
return fmt.Errorf("unrecognized content type %q", r2.Type)
}
*r = CompleteReference(r2)
return nil
}
func (r *CompleteReference) MarshalJSON() ([]byte, error) {
// Validation for marshalling: ensure consistency before converting to JSON.
switch r.Type {
case "ref/prompt":
if r.URI != "" {
return nil, fmt.Errorf("reference of type %q must not have a URI set for marshalling", r.Type)
}
case "ref/resource":
if r.Name != "" {
return nil, fmt.Errorf("reference of type %q must not have a Name set for marshalling", r.Type)
}
default:
return nil, fmt.Errorf("unrecognized reference type %q for marshalling", r.Type)
}
type wireReference CompleteReference
return json.Marshal(wireReference(*r))
}
type CompleteParams struct {
// This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses.
Meta `json:"_meta,omitempty"`
// The argument's information
Argument CompleteParamsArgument `json:"argument"`
Context *CompleteContext `json:"context,omitempty"`
Ref *CompleteReference `json:"ref"`
}
type CompletionResultDetails struct {
HasMore bool `json:"hasMore,omitempty"`
Total int `json:"total,omitempty"`
Values []string `json:"values"`
}
// The server's response to a completion/complete request
type CompleteResult struct {
// This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses.
Meta `json:"_meta,omitempty"`
Completion CompletionResultDetails `json:"completion"`
}
type CreateMessageParams struct {
// This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses.
@ -787,6 +875,9 @@ type implementation struct {
Version string `json:"version"`
}
// Present if the server supports argument autocompletion suggestions.
type completionCapabilities struct{}
// Present if the server supports sending log messages to the client.
type loggingCapabilities struct{}
@ -809,7 +900,7 @@ type resourceCapabilities struct {
// additional capabilities.
type serverCapabilities struct {
// Present if the server supports argument autocompletion suggestions.
Completions struct{} `json:"completions,omitempty"`
Completions *completionCapabilities `json:"completions,omitempty"`
// Experimental, non-standard capabilities that the server supports.
Experimental map[string]struct{} `json:"experimental,omitempty"`
// Present if the server supports sending log messages to the client.