Documentation
¶
Overview ¶
Package mcp provides Scope helpers around the Model Context Protocol (https://modelcontextprotocol.io/).
Use the official Go SDK package (github.com/modelcontextprotocol/go-sdk/mcp) for protocol clients, servers, sessions, and transports. The Scope package keeps the small adapters needed around those SDK primitives: context metadata, reverse-capability helpers, tool.Tool wrapping, tool registration and prompt conversion.
Client and server spans record error classifications without raw error messages. Callers still receive the complete protocol error details. Remote IsError results use core/tool.Failure to preserve every content part and structured detail. Register projects that same failure value back into the MCP result without flattening it to an error string. MCP does not encode refusal separately: remote IsError maps to FailureKindFailed, which does not imply that execution began. Unknown local outcomes and authorization errors become generic protocol errors, never model-visible internal diagnostics or definite Tool results. Input validation remains public Tool error feedback.
Naming ¶
The package shares its name with the official Go SDK (github.com/modelcontextprotocol/go-sdk/mcp). Consumers will normally import it as:
import (
scopemcp "github.com/Tangerg/scope/mcp"
sdkmcp "github.com/modelcontextprotocol/go-sdk/mcp"
)
Inside this package the SDK is imported under the alias sdkmcp.
Index ¶
- Variables
- func AnnotatedReadOnlyConcurrencyPolicy(_, _ string, annotations sdkmcp.ToolAnnotations, _ toolcontract.Invocation) (key string, concurrent bool)
- func DiscoverTools(ctx context.Context, sources []ToolSource, config ToolDiscoveryConfig) ([]toolcontract.Tool, error)
- func Elicit(ctx context.Context, params sdkmcp.ElicitParams) (*sdkmcp.ElicitResult, error)
- func PromptMessagesToChat(messages []*sdkmcp.PromptMessage) ([]chat.Message, error)
- func Register(server *sdkmcp.Server, tools ...toolcontract.Tool) error
- func ReportProgress(ctx context.Context, progress float64, total *float64, message string) error
- func RequestMetaFromContext(ctx context.Context) sdkmcp.Meta
- func WithRequestMeta(ctx context.Context, meta sdkmcp.Meta) context.Context
- type PublicToolNameFunc
- type RequestMetaFunc
- type ToolConcurrencyPolicy
- type ToolDiscoveryConfig
- type ToolSource
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( ErrNilServer = errors.New("mcp: server must not be nil") ErrNilSession = errors.New("mcp: session must not be nil") )
var ErrNoServerSession = errors.New("mcp: no active MCP server session on context")
ErrNoServerSession reports a reverse call made outside an MCP tool invocation.
Functions ¶
func AnnotatedReadOnlyConcurrencyPolicy ¶
func AnnotatedReadOnlyConcurrencyPolicy(_, _ string, annotations sdkmcp.ToolAnnotations, _ toolcontract.Invocation) (key string, concurrent bool)
AnnotatedReadOnlyConcurrencyPolicy opts explicitly read-only MCP tools into conflict-free concurrent execution. Missing, false, or contradictory annotations remain exclusive.
This is only scheduling advice: it neither authorizes a call nor bypasses a caller's approval policy. MCP annotations are untrusted hints, so callers should use this policy only for servers whose descriptors they are willing to trust for execution ordering.
func DiscoverTools ¶
func DiscoverTools(ctx context.Context, sources []ToolSource, config ToolDiscoveryConfig) ([]toolcontract.Tool, error)
DiscoverTools reads each live session's current catalog and projects every remote descriptor into a Scope tool. It does not cache or own the sessions.
Example ¶
package main
import (
"context"
"fmt"
"github.com/Tangerg/scope/mcp"
)
func main() {
tools, err := mcp.DiscoverTools(context.Background(), nil, mcp.ToolDiscoveryConfig{})
if err != nil {
panic(err)
}
fmt.Println(len(tools))
}
Output: 0
func Elicit ¶
func Elicit(ctx context.Context, params sdkmcp.ElicitParams) (*sdkmcp.ElicitResult, error)
Elicit asks the connected client to surface a structured prompt to the end user and returns their response. Useful when a tool needs runtime clarification it could not have asked for at schema-design time (auth confirmation, ambiguous filename, ...).
Returns ErrNoServerSession when called outside an MCP dispatch. Underlying RPC errors propagate as-is.
Example — structured response:
res, err := mcp.Elicit(ctx, sdkmcp.ElicitParams{
Message: "Choose a deployment target",
RequestedSchema: map[string]any{
"type": "object",
"properties": map[string]any{
"env": map[string]any{
"type": "string",
"enum": []string{"staging", "prod"},
},
},
"required": []string{"env"},
},
})
if err != nil { return "", err }
if res.Action != "accept" { return "user canceled", nil }
env, _ := res.Content["env"].(string)
func PromptMessagesToChat ¶
func PromptMessagesToChat(messages []*sdkmcp.PromptMessage) ([]chat.Message, error)
PromptMessagesToChat converts MCP prompt messages into Core chat messages. Text, image, audio, resource-link, and embedded-resource content retain their semantic shape; malformed or unsupported content returns an error instead of disappearing from the prompt.
func Register ¶
func Register(server *sdkmcp.Server, tools ...toolcontract.Tool) error
Register installs every tool.Tool in tools onto server using the low-level [(*sdkmcp.Server).AddTool] API.
Registration is all-or-nothing: definitions are snapshotted, duplicate names within the batch are rejected, and every tool is built before any is added. A bad entry mid-list therefore never leaves the server half-registered, and handlers use the same identity the server advertised even when a Tool implementation is mutable. Structured details are handed to the SDK as raw JSON, preserving numeric precision and the distinction between explicit null and absent details.
The generic sdkmcp.AddTool[In, Out] form is deliberately avoided: tools already supply a hand-authored JSON schema, and the generic API would otherwise reflect over a Go In type and overwrite it.
func ReportProgress ¶
ReportProgress sends a progress notification back to the client. progress should increase monotonically; total is optional and may be left nil when the work size is unknown. message is a free-form human-readable status string.
The originating client must have included a progressToken in its tools/call request — otherwise this helper returns nil without sending a notification (the spec mandates that servers only emit progress when explicitly opted in). Errors propagate from the underlying *sdkmcp.ServerSession.NotifyProgress.
Example:
func (t *longTool) Call(ctx context.Context, invocation tool.Invocation) (chat.ToolOutput, error) {
for i := range 100 {
// ... work ...
_ = mcp.ReportProgress(ctx, float64(i+1), new(100.0),
fmt.Sprintf("processed %d/100", i+1))
}
return "done", nil
}
func RequestMetaFromContext ¶
RequestMetaFromContext returns a shallow copy of metadata stored by WithRequestMeta, or nil. The returned nested values must remain immutable. Its signature matches RequestMetaFunc:
config := mcp.ToolDiscoveryConfig{RequestMeta: mcp.RequestMetaFromContext}
func WithRequestMeta ¶
WithRequestMeta copies the top-level map so its keys may be reused or changed by the caller. Nested maps, slices, and other reference values remain shared; callers must keep them immutable while this context or its derived contexts may be read.
Types ¶
type PublicToolNameFunc ¶
PublicToolNameFunc maps a remote tool identity to the name a model sees. Remote servers choose names independently, so two sources can collide or emit characters providers reject; projecting the name here keeps that negotiation out of the tool contract and lets a host resolve collisions its own way.
type RequestMetaFunc ¶
RequestMetaFunc resolves per-call MCP metadata from the context rather than from a fixed value, so a caller can forward request-scoped identity such as a trace or tenant without rebuilding the tool for every call.
type ToolConcurrencyPolicy ¶
type ToolConcurrencyPolicy func( sourceName, remoteName string, annotations sdkmcp.ToolAnnotations, invocation toolcontract.Invocation, ) (key string, concurrent bool)
ToolConcurrencyPolicy decides whether one remote tool call may overlap other calls from the same model response. A false result keeps the call exclusive; a true result with an empty key declares no known conflict, while equal non-empty keys serialize.
The callback receives the source and remote tool names, an isolated copy of the remote annotations, and a schema-validated invocation. It must be deterministic, side-effect-free, and safe for concurrent use because a durable resume may plan queued calls again and callers may inspect the capability from multiple goroutines. It must not capture a Tool, session, or execution backend; schedulers retain the declaration independently of the remote tool's execution lifetime.
type ToolDiscoveryConfig ¶
type ToolDiscoveryConfig struct {
// PublicName maps each remote tool identity to its public name. Nil
// uses the package default, "<sourceName>_<remoteName>" sanitized to the
// function-name charset accepted by model providers.
PublicName PublicToolNameFunc
// RequestMeta is applied to every tool produced. Nil forwards no metadata on
// tool calls.
RequestMeta RequestMetaFunc
// ConcurrencyPolicy opts remote tools into a caller-owned scheduling policy. Nil
// keeps every MCP call exclusive because protocol descriptors do not provide
// a trustworthy resource-conflict contract. Callers retain ownership of
// execution and result ordering. [AnnotatedReadOnlyConcurrencyPolicy] is the
// conservative ready-made policy for trusted descriptors that declare
// readOnlyHint=true.
ConcurrencyPolicy ToolConcurrencyPolicy
}
ToolDiscoveryConfig controls the boundary projection performed by DiscoverTools.
type ToolSource ¶
type ToolSource struct {
// Name identifies the upstream server in tool prefixes and error
// messages. Empty is allowed but discouraged when more than one
// source is in play.
Name string
// Session is a live, initialized client session. The wrapper does not own
// the session; callers are responsible for closing it.
Session *sdkmcp.ClientSession
}
ToolSource binds an initialized MCP client session to a logical name used to deconflict tools across multiple servers.