Documentation
¶
Overview ¶
Package mcp serves an app's tools to AI assistants over the Model Context Protocol, at /mcp, with Streamable HTTP. Tools are Go functions with typed arguments and results; with plugins/oidc, users authorize each assistant on the app's own consent screen, and tools run as that user.
server := mcp.New(mcp.Options{
Name: "Shelf",
Tools: []mcp.Tool{mcp.NewTool("list_links", "List the user's links.", listLinks, mcp.ReadOnly())},
OAuth: provider,
SignIn: func(ctx *kit.Ctx, t *oidc.AccessToken) error { ... },
})
app, err := ternApp(kit.WithPlugins(acc, provider, server))
It serves protocol version 2026-07-28, which is stateless, and 2025-11-25, 2025-06-18 and 2025-03-26, which start with initialize, on the same endpoint, without sessions. See docs/mcp-server.md and ADR 0023.
Index ¶
Constants ¶
const Modern = "2026-07-28"
Modern is the stateless protocol version: every request carries its version, and there's no initialize.
Variables ¶
var Versions = []string{Modern, "2025-11-25", "2025-06-18", "2025-03-26"}
Versions are the protocol versions served, newest first.
Functions ¶
This section is empty.
Types ¶
type Options ¶
type Options struct {
// Path is the endpoint; the default is "/mcp".
Path string
// Name and Version identify the server to clients; the default name is
// "tern". Title is a display name, such as "Shelf".
Name, Version, Title string
// Instructions tell the assistant's model how to use the tools, such
// as "Links are a user's reading list. Save one when the user asks to
// read something later."
Instructions string
Tools []Tool
// OAuth is the app's OpenID Connect provider. Requests then need an
// access token issued for this server (its Resource), and SignIn makes
// the token's user the request's.
OAuth *oidc.Plugin
// Resource is the server's canonical URL, which tokens must be issued
// for. The default is the provider's issuer origin and Path, such as
// "https://example.com/mcp".
Resource string
// Scopes every request needs, such as "mcp". Tools can need more.
Scopes []string
// SignIn makes the token's subject the signed-in user of the request,
// such as with accounts' ActAs. An error refuses the request with 401.
SignIn func(ctx *kit.Ctx, token *oidc.AccessToken) error
// Authorize checks requests without OAuth, such as an API key in a
// header. An error from kit.Error refuses the request with its status.
Authorize func(ctx *kit.Ctx) error
// AllowedOrigins are browser origins that may call the server, such as
// "https://inspector.example.com". Requests from browsers on other
// origins are refused (DNS rebinding protection); clients that aren't
// browsers send no Origin.
AllowedOrigins []string
}
Options configure the server.
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
Server is the MCP server, a kit.Plugin.
type Tool ¶
type Tool struct {
// contains filtered or unexported fields
}
Tool is a function an assistant can call. Make one with NewTool.
func NewTool ¶
func NewTool[In, Out any](name, description string, fn func(*kit.Ctx, In) (Out, error), opts ...ToolOption) Tool
NewTool makes a tool of fn. In is the arguments, a struct: its json names, `description` tags and validate rules become the input schema, and the rules are checked before fn runs, as for a typed endpoint. Out is the result, sent as JSON. fn gets the request's Ctx, with the user the token belongs to signed in, so it can use the app's own checks:
mcp.NewTool("save_link", "Save a link to read later.",
func(ctx *kit.Ctx, in NewLink) (shelf.Link, error) {
user, err := shelf.Accounts.Require(ctx)
if err != nil {
return shelf.Link{}, err
}
return shelf.Add(ctx, user.ID, in.URL, in.Title)
}, mcp.Additive())
Errors from fn are shown to the assistant, so it can correct itself: those from kit.Error, kit.NotFound and failed validation with their message, others as "Internal Error" (and logged).
type ToolOption ¶
type ToolOption func(*Tool)
ToolOption describes a tool further.
func Additive ¶
func Additive() ToolOption
Additive marks a tool that only adds, such as saving a new link.
func Destructive ¶
func Destructive() ToolOption
Destructive marks a tool that deletes or overwrites, so assistants ask before calling it. Tools that aren't ReadOnly are assumed destructive unless marked Additive.
func Idempotent ¶
func Idempotent() ToolOption
Idempotent marks a tool that does nothing more when called again with the same arguments, such as marking something read.
func ReadOnly ¶
func ReadOnly() ToolOption
ReadOnly marks a tool that changes nothing, such as a search, so assistants may call it without asking the user first.
func Scopes ¶
func Scopes(scopes ...string) ToolOption
Scopes are the OAuth scopes a token needs to call the tool. A token without them gets 403 with the scopes to ask the user for.
func Title ¶
func Title(title string) ToolOption
Title is the tool's name for people, such as "Save a link".