mcp

package module
v0.2.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 15, 2026 License: MIT Imports: 31 Imported by: 0

README

mcp

MCP discovery and execution for Go applications, with Cobra and service integrations.

Go reference Pipeline Coverage Go toolkit

Part of the phpboyscout Go toolkit. Documentation: mcp.go.phpboyscout.uk.

go get gitlab.com/phpboyscout/go/mcp@latest

Serve a Cobra CLI

import (
    mcpcli "gitlab.com/phpboyscout/go/mcp/cli"
    mcpcobra "gitlab.com/phpboyscout/go/mcp/cobra"
)

root.AddCommand(mcpcli.Command(mcpcli.WithBinding(mcpcobra.WithExposure(isExposed))))

my-tool mcp start serves every exposed command over stdio, my-tool mcp stream over Streamable HTTP under the toolkit's lifecycle, my-tool mcp tools writes the catalogue, and my-tool mcp claude|cursor|vscode enable registers the server with the editor. Each call runs the command as a supervised subprocess of the same binary: exact argv, no shell, one execution slot with a retryable busy, bounded output, and cancellation that stops the command and everything it started (a process group on Unix, a job object on Windows).

Publish progressively

By default a client sees three tools, search_tools, get_tool_details and call_tool, whatever the size of the catalogue; a schema enters the conversation only when it is about to be used. server.WithMode(server.Direct) publishes one native tool per operation instead, for clients that rely on per-tool approval. Both modes share one registry and one policy.

Or build on the library

The root package is framework-free: an immutable operation registry with explicit, always-rechecked authorisation, owned results with six content kinds and exact JSON numbers, caller-safe failures, form and URL confirmations with bounded replay, and authorised resource bundles. The server package adapts it to the official Go SDK over stdio and Streamable HTTP; an HTTP service mounts Handler() behind its own authentication and registers Shutdown and Status with its go/controls controller.

registry, err := mcp.New(operations, mcp.WithPolicy(policy))
host, err := server.New(registry, server.WithIdentity("studio", version))
mux.Handle("/mcp", authenticate(host.Handler()))

Where things are

Package Imports Purpose
mcp go/errors, a JSON Schema compiler Operation model. No SDK, Cobra, HTTP or lifecycle framework (depfootprint_test.go enforces it).
mcp/server modelcontextprotocol/go-sdk Compact and direct publication, resources, interactions, Apps shell, stdio and HTTP.
mcp/grpc google.golang.org/grpc, protobuf, go/authn, go/transit A gRPC service's unary methods as operations, through its own interceptors and authorisation predicate.
mcp/cobra spf13/cobra, spf13/pflag A Cobra tree as operations executed as supervised subprocesses.
mcp/cli go/controls, go/transport The mcp command tree: start, stream, tools, editor helpers.

Development: Go 1.27.1 or later, just ci (tidy, tests, race, lint, strict docs build), just test-sdk-compat for the pinned SDK 1.4.1/1.6.0/1.7.0 fixture matrix. The design record is spec 0001 on the project wiki; go-tool-base's consumer spec is 0201.

Documentation

Overview

Package mcp provides an immutable operation registry, progressive discovery, authorized invocation, owned results and caller-safe failures.

Content constructors snapshot their inputs. NewResult validates the assembled content and structured JSON; mutable accessors return detached copies. Result construction does not authorize resources, decode media or validate a future operation's output schema. New prepares schemas at startup; Registry.Invoke enforces current discovery/execution policy, schema validation and core budgets. Protocol wire budgets belong to the adapter defined by specification 0001.

New requires WithPolicy. AllowRegistered explicitly trusts a filtered local catalogue; service hosts supply identity and authorization through context. Search returns bounded summaries, Inspect returns a detached full definition, and Invoke can dispatch a known operation without prior discovery calls. Handlers complete through Finish or request form/URL input through AwaitInput. Verified continuations enforce bounded replay and recovery. The optional server package hosts compact/direct tools and resources; wire interactions remain in progress.

Resources provides explicit read plans, separate visibility/read policy, bounded partial bundles and registered resource/template listing. Adapters share internal request deadlines and conservative sizing without exposing SDK types here.

The root package does not depend on a protocol SDK, CLI or service framework.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func IsOperationName

func IsOperationName(name string) bool

IsOperationName reports whether name is a valid operation identifier: up to 128 ASCII letters, digits, underscores, dots and hyphens.

Types

type AccessKind

type AccessKind string

AccessKind separates discovering an operation from executing it.

const (
	Discover AccessKind = "discover"
	Execute  AccessKind = "execute"
)

Access kinds are the only decisions requested by the registry.

type AccessRequest

type AccessRequest struct {
	Kind      AccessKind
	Operation string
	Arguments json.RawMessage
}

AccessRequest gives policy the operation identity and, for execution, detached validated arguments. Changing this copy cannot change handler arguments.

type Annotations

type Annotations struct {
	Audience     []string   `json:"audience,omitempty"`
	Priority     *float64   `json:"priority,omitempty"`
	LastModified *time.Time `json:"lastModified,omitempty"`
}

Annotations describes intended audiences, importance and modification time. Receiving constructors copy its slice and pointers. These hints grant no access.

func ContentAnnotations

func ContentAnnotations(content Content) Annotations

ContentAnnotations returns detached annotations for a recognized content value, or empty annotations for an unsupported value.

type AudioContent

type AudioContent struct {
	// contains filtered or unexported fields
}

AudioContent owns audio bytes and their declared MIME type.

func Audio

func Audio(data []byte, mimeType string) AudioContent

Audio copies the input bytes without decoding the audio format.

func (AudioContent) Bytes

func (c AudioContent) Bytes() []byte

Bytes returns a detached copy of the audio data.

func (AudioContent) Kind

func (c AudioContent) Kind() ContentKind

func (AudioContent) MIMEType

func (c AudioContent) MIMEType() string

MIMEType returns the declared media type.

type Call

type Call struct {
	// contains filtered or unexported fields
}

Call owns untrusted request data. Only Registry.Invoke validates it against an operation and the host's current authorization policy.

func NewCall

func NewCall(operation string, arguments json.RawMessage, opts ...CallOption) (Call, error)

NewCall checks JSON object syntax and copies arguments. It grants no access.

type CallOption

type CallOption func(*callConfig)

CallOption supplies host facilities or still-untrusted continuation data.

func WithInputSupport

func WithInputSupport(kinds ...InputKind) CallOption

WithInputSupport explicitly declares the modes the host can present. It does not grant authorization. Repeating the option or a mode is invalid.

func WithProgressSink

func WithProgressSink(sink func(context.Context, Progress) error) CallOption

WithProgressSink supplies advisory progress delivery for this invocation only.

func WithResume

func WithResume(continuation string, response InputResponse) CallOption

WithResume snapshots a token and untrusted response. It cannot create a verified Resume.

type Content

type Content interface {
	Kind() ContentKind
	// contains filtered or unexported methods
}

Content is an owned value created by this package. NewResult also validates concrete types: embedding a Content in an external type does not make it valid.

func WithContentAnnotations

func WithContentAnnotations(content Content, annotations Annotations) (Content, error)

WithContentAnnotations returns a new content value with copied annotations.

func WithContentMetadata

func WithContentMetadata(content Content, metadata Metadata) (Content, error)

WithContentMetadata returns an owned value of the same concrete kind with additional metadata. Duplicate keys fail instead of replacing existing values.

type ContentKind

type ContentKind string

ContentKind identifies a supported application content variant.

const (
	KindText         ContentKind = "text"
	KindImage        ContentKind = "image"
	KindAudio        ContentKind = "audio"
	KindResourceLink ContentKind = "resource_link"
	KindEmbeddedText ContentKind = "embedded_text"
	KindEmbeddedBlob ContentKind = "embedded_blob"
)

Content kinds are independent of any protocol SDK representation.

type Definition

type Definition struct {
	Name         string          `json:"name"`
	Title        string          `json:"title,omitempty"`
	Summary      string          `json:"summary"`
	Description  string          `json:"description,omitempty"`
	Group        string          `json:"group,omitempty"`
	Source       string          `json:"source,omitempty"`
	Examples     []string        `json:"examples,omitempty"`
	InputSchema  json.RawMessage `json:"inputSchema"`
	OutputSchema json.RawMessage `json:"outputSchema,omitempty"`
	Hints        Hints           `json:"hints"`
	Metadata     Metadata        `json:"-"`
}

Definition describes an operation. New snapshots its mutable fields; Inspect returns detached copies. Title is a display name for clients that show one; Name stays the identifier. Metadata and hints never confer execution permission.

func (Definition) Clone

func (d Definition) Clone() Definition

Clone returns a detached copy: every slice and hint pointer is copied, so editing the result cannot change the definition it came from. Producers that hand definitions out, such as the Cobra binding, use it.

type EmbeddedBlobContent

type EmbeddedBlobContent struct {
	// contains filtered or unexported fields
}

EmbeddedBlobContent owns binary content with its resource identity.

func EmbeddedBlob

func EmbeddedBlob(ref ResourceRef, data []byte) EmbeddedBlobContent

EmbeddedBlob copies data; nil is an intentional zero-length binary payload.

func (EmbeddedBlobContent) Bytes

func (c EmbeddedBlobContent) Bytes() []byte

Bytes returns a detached copy of the embedded bytes.

func (EmbeddedBlobContent) Kind

func (c EmbeddedBlobContent) Kind() ContentKind

func (EmbeddedBlobContent) ResourceRef

func (c EmbeddedBlobContent) ResourceRef() ResourceRef

ResourceRef returns the immutable resource reference.

type EmbeddedTextContent

type EmbeddedTextContent struct {
	// contains filtered or unexported fields
}

EmbeddedTextContent carries text with its resource identity.

func EmbeddedText

func EmbeddedText(ref ResourceRef, text string) EmbeddedTextContent

EmbeddedText constructs text resource content without authorizing its identity.

func (EmbeddedTextContent) Kind

func (c EmbeddedTextContent) Kind() ContentKind

func (EmbeddedTextContent) ResourceRef

func (c EmbeddedTextContent) ResourceRef() ResourceRef

ResourceRef returns the immutable resource reference.

func (EmbeddedTextContent) Text

func (c EmbeddedTextContent) Text() string

Text returns the embedded text.

type Failure

type Failure struct {
	// contains filtered or unexported fields
}

Failure exposes a safe message while retaining the cause for host diagnostics. Neither Error nor its public accessors include the private cause.

func NewFailure

func NewFailure(code FailureCode, message string, cause error) *Failure

NewFailure constructs a failure from an explicitly caller-safe message. The cause remains available to errors.Is/As through the estate error chain.

Example
package main

import (
	"errors"
	"fmt"

	mcp "gitlab.com/phpboyscout/go/mcp"
)

func main() {
	cause := errors.New("private storage diagnostic")
	failure := mcp.NewFailure(mcp.FailureReadFailed, "Preview temporarily unavailable", cause)
	fmt.Println(failure.Code(), failure.Message(), failure.Retryable())
	fmt.Println(errors.Is(failure, cause))
}
Output:
read_failed Preview temporarily unavailable true
true

func (*Failure) Code

func (f *Failure) Code() FailureCode

Code returns the stable failure code.

func (*Failure) Error

func (f *Failure) Error() string

Error returns only the caller-safe message.

func (*Failure) ErrorKind

func (f *Failure) ErrorKind() string

ErrorKind supplies the estate errors module's stable identity contract.

func (*Failure) Message

func (f *Failure) Message() string

Message returns the caller-safe message.

func (*Failure) Retryable

func (f *Failure) Retryable() bool

Retryable indicates whether a caller may explicitly retry. It never authorizes an adapter to repeat an operation automatically.

func (*Failure) Unwrap

func (f *Failure) Unwrap() error

Unwrap exposes the private cause to host diagnostics, never to wire output.

type FailureCode

type FailureCode string

FailureCode identifies a caller-safe failure independently of its private cause.

const (
	FailureUnavailable          FailureCode = "unavailable"
	FailureInvalidArguments     FailureCode = "invalid_arguments"
	FailureBusy                 FailureCode = "busy"
	FailureTimeout              FailureCode = "timeout"
	FailureCancelled            FailureCode = "cancelled"
	FailureConfirmationRequired FailureCode = "confirmation_required"
	FailureInteractionDeclined  FailureCode = "interaction_declined"
	FailureInteractionCancelled FailureCode = "interaction_cancelled"
	FailureInteractionLimit     FailureCode = "interaction_limit"
	FailureContinuationInvalid  FailureCode = "continuation_invalid"
	FailureContinuationStale    FailureCode = "continuation_stale"
	FailureInvalidResult        FailureCode = "invalid_result"
	FailureResultTooLarge       FailureCode = "result_too_large"
	FailureCommandFailed        FailureCode = "command_failed"
	FailureCleanupFailed        FailureCode = "cleanup_failed"
	FailureReadFailed           FailureCode = "read_failed"
	FailureInternal             FailureCode = "internal"
)

Failure codes are stable application contracts, not JSON-RPC error numbers.

type FormDescription

type FormDescription struct {
	Message string
	Schema  json.RawMessage
}

FormDescription exposes only the public, detached prompt.

type Handler

type Handler func(context.Context, *Invocation) (Outcome, error)

Handler receives module-validated invocation data after current policy passes. A non-nil error is authoritative; valid accompanying results retain diagnostics.

type Hints

type Hints struct {
	ReadOnly    *bool `json:"readOnly,omitempty"`
	Destructive *bool `json:"destructive,omitempty"`
	Idempotent  *bool `json:"idempotent,omitempty"`
	OpenWorld   *bool `json:"openWorld,omitempty"`
}

Hints are optional behavioral annotations. Nil preserves an unspecified hint.

type ImageContent

type ImageContent struct {
	// contains filtered or unexported fields
}

ImageContent owns image bytes and their MIME declaration.

func Image

func Image(data []byte, mimeType string) ImageContent

Image copies data without decoding it. NewResult checks the MIME declaration.

func (ImageContent) Bytes

func (c ImageContent) Bytes() []byte

Bytes returns a detached copy of the image data.

func (ImageContent) Kind

func (c ImageContent) Kind() ContentKind

func (ImageContent) MIMEType

func (c ImageContent) MIMEType() string

MIMEType returns the declared media type.

type InputAction

type InputAction string

InputAction describes the user's explicit response.

const (
	Accept  InputAction = "accept"
	Decline InputAction = "decline"
	Cancel  InputAction = "cancel"
)

Accepted response actions. Accept alone is not boolean confirmation.

type InputKind

type InputKind string

InputKind identifies a host-supported interaction mode.

const (
	FormInput InputKind = "form"
	URLInput  InputKind = "url"
)

Supported input modes.

type InputOption

type InputOption func(*inputConfig)

InputOption configures an owned prompt.

func WithInputExpiry

func WithInputExpiry(expiry time.Time) InputOption

WithInputExpiry shortens the registry lifetime or previous application deadline.

type InputRequired

type InputRequired struct {
	// contains filtered or unexported fields
}

InputRequired owns a prompt and private application state. The zero value is invalid.

func NewFormInput

func NewFormInput(message string, schema, state json.RawMessage, opts ...InputOption) (InputRequired, error)

NewFormInput checks the supported flat form profile and snapshots schema/state. Defaults remain schema data; they are never inserted into answers.

func NewURLInput

func NewURLInput(message, targetURL string, state json.RawMessage, opts ...InputOption) (InputRequired, error)

NewURLInput requires absolute HTTPS without credentials. It never visits the URL. Acceptance means navigation consent; the handler must verify its external flow.

func (InputRequired) Form

func (i InputRequired) Form() (FormDescription, bool)

Form returns a detached description when this is a form.

func (InputRequired) Kind

func (i InputRequired) Kind() InputKind

Kind returns the requested interaction mode.

func (InputRequired) URL

func (i InputRequired) URL() (URLDescription, bool)

URL returns a description when this is a URL request.

type InputResponse

type InputResponse struct {
	// contains filtered or unexported fields
}

InputResponse owns an untrusted response; only Invoke verifies its prompt binding.

func NewInputResponse

func NewInputResponse(action InputAction, answers json.RawMessage) (InputResponse, error)

NewInputResponse accepts object answers only for Accept. A URL acceptance, decline or cancellation carries nil answers, not a fabricated empty form.

type Invocation

type Invocation struct {
	// contains filtered or unexported fields
}

Invocation contains arguments validated and authorized by the registry. Application code receives it through Handler, rather than constructing it.

func (*Invocation) Arguments

func (i *Invocation) Arguments() json.RawMessage

Arguments returns detached, validated JSON without inserting schema defaults.

func (*Invocation) Progress

func (i *Invocation) Progress(ctx context.Context, progress Progress)

Progress delivers an advisory snapshot during this request. Invalid updates or sink failures do not alter the handler outcome. Sink callbacks must obey context.

func (*Invocation) Resume

func (i *Invocation) Resume() (Resume, bool)

Resume reports whether this invocation answers a verified prompt.

func (*Invocation) Supports

func (i *Invocation) Supports(kind InputKind) bool

Supports reports the host-declared interaction modes for this call.

type Limits

type Limits struct {
	ArgumentBytes, DefinitionBytes, MetadataBytes                 int
	ResultBytes, InlineBytes, ContentBlocks                       int
	FormSchemaBytes, ContinuationStateBytes, AnswerBytes          int
	ContinuationTokenBytes, ContinuationChains, ContinuationBytes int
	CursorBytes                                                   int
	InteractionRounds                                             int
	ConfirmationTTL                                               time.Duration
}

Limits bounds registry data. Zero fields select defaults, negatives fail, and increasing one field never implicitly increases a related budget.

type Metadata

type Metadata struct {
	// contains filtered or unexported fields
}

Metadata is owned, namespaced JSON. Its zero value means no metadata. Values returns fully qualified keys, including their namespace.

func ContentMetadata

func ContentMetadata(content Content) Metadata

ContentMetadata returns metadata for a recognized content value, or empty metadata for an unsupported value. Values detaches all mutable storage.

func NewMetadata

func NewMetadata(namespace string, values map[string]json.RawMessage) (Metadata, error)

NewMetadata snapshots local names and raw JSON under a DNS namespace. Generic metadata cannot override protocol or module routing keys. Per-location byte budgets belong to the configured invocation/adapter, not this constructor.

func (Metadata) Values

func (m Metadata) Values() map[string]json.RawMessage

Values returns a detached map, including detached raw JSON values.

type Operation

type Operation struct {
	Definition Definition
	Handle     Handler
}

Operation binds an immutable description to application code. A handler's application state and concurrent access remain the host's responsibility.

type Option

type Option func(*registryConfig)

Option configures a registry at construction.

func WithLimits

func WithLimits(limits Limits) Option

WithLimits overrides positive fields of the default limits. Repetition fails.

func WithPolicy

func WithPolicy(policy Policy) Option

WithPolicy selects the required host policy. Repeated policy options fail.

type Outcome

type Outcome struct {
	// contains filtered or unexported fields
}

Outcome is an explicit handler result. The zero value is not successful output.

func AwaitInput

func AwaitInput(input InputRequired) Outcome

AwaitInput requests a prompt. It cannot be combined with a handler error.

func Finish

func Finish(result Result) Outcome

Finish marks a handler result complete. The gateway still checks construction, the operation's output schema and applicable result budgets.

type PendingInput

type PendingInput struct {
	// contains filtered or unexported fields
}

PendingInput contains the validated prompt and its opaque, expiring token.

func (PendingInput) Continuation

func (p PendingInput) Continuation() string

Continuation returns the opaque token. It must not be logged or shared across users.

func (PendingInput) ExpiresAt

func (p PendingInput) ExpiresAt() time.Time

ExpiresAt returns this prompt's fixed expiry.

func (PendingInput) Request

func (p PendingInput) Request() InputRequired

Request returns the owned request. Its descriptions detach mutable data.

type Policy

type Policy struct {
	Authorize func(context.Context, AccessRequest) error
	ScopeKey  func(context.Context) (string, error)
}

Policy supplies host authorization and pagination scope. Both callbacks are required and must support concurrent calls. ScopeKey identifies the effective principal and policy revision; it must be nonempty and contain no credentials.

func AllowRegistered

func AllowRegistered() Policy

AllowRegistered explicitly trusts a filtered local catalogue. It is intended for local stdio hosts, not as an HTTP authentication strategy.

type Presentation

type Presentation struct {
	// contains filtered or unexported fields
}

Presentation owns view data. The host's Apps configuration must approve the view before delivery; this value alone grants no access or execution rights.

func NewPresentation

func NewPresentation(spec PresentationSpec) (Presentation, error)

NewPresentation validates and snapshots a view description. It does not fetch an Apps shell or validate against the host's approved view set.

Example
package main

import (
	"encoding/json"
	"fmt"

	mcp "gitlab.com/phpboyscout/go/mcp"
)

func main() {
	presentation, err := mcp.NewPresentation(mcp.PresentationSpec{View: "candidate-gallery", Data: json.RawMessage(`{"selected":3}`)})
	if err != nil {
		panic(err)
	}
	result, err := mcp.NewResult([]mcp.Content{mcp.Text("Selected candidate 3")}, mcp.WithPresentation(presentation))
	if err != nil {
		panic(err)
	}
	fmt.Println(string(result.Metadata().Values()["go.phpboyscout.uk/mcp.presentation"]))
}
Output:
{"view":"candidate-gallery","data":{"selected":3}}

func (Presentation) Description

func (p Presentation) Description() PresentationSpec

Description returns the view description with detached JSON data.

type PresentationSpec

type PresentationSpec struct {
	View string          `json:"view"`
	Data json.RawMessage `json:"data"`
}

PresentationSpec selects an application view and its JSON data. Data must be a JSON value; use explicit null when the view does not need data.

type Progress

type Progress struct {
	Completed float64
	Total     *float64
	Message   string
}

Progress is a per-call snapshot. Completed must be finite and nondecreasing; Total, when supplied, must be finite and at least Completed.

type Registry

type Registry struct {
	// contains filtered or unexported fields
}

Registry owns an immutable operation catalogue. Request authorization remains current; changing descriptions requires constructing a new registry.

func New

func New(operations []Operation, opts ...Option) (*Registry, error)

New snapshots a catalogue and its required host policy before serving it.

Example
package main

import (
	"context"
	"encoding/json"
	"fmt"

	mcp "gitlab.com/phpboyscout/go/mcp"
)

func main() {
	registry, err := mcp.New([]mcp.Operation{{
		Definition: mcp.Definition{Name: "project.status", Summary: "Inspect project status", Group: "projects", InputSchema: json.RawMessage(`{"type":"object","properties":{"id":{"type":"integer"}},"required":["id"],"additionalProperties":false}`), OutputSchema: json.RawMessage(`{"type":"object","properties":{"ready":{"type":"boolean"}},"required":["ready"]}`)},
		Handle: func(_ context.Context, invocation *mcp.Invocation) (mcp.Outcome, error) {
			var args struct {
				ID uint64 `json:"id"`
			}
			if err := json.Unmarshal(invocation.Arguments(), &args); err != nil {
				return mcp.Outcome{}, mcp.NewFailure(mcp.FailureInvalidArguments, "Invalid project ID", err)
			}
			result, err := mcp.JSONResult(map[string]bool{"ready": args.ID != 0}, mcp.Text("Project status inspected"))
			return mcp.Finish(result), err
		},
	}}, mcp.WithPolicy(mcp.AllowRegistered()))
	if err != nil {
		panic(err)
	}
	ctx := context.Background()
	page, err := registry.Search(ctx, mcp.SearchRequest{Query: "status"})
	if err != nil {
		panic(err)
	}
	fmt.Println(page.Operations[0].Name)
	call, err := mcp.NewCall("project.status", json.RawMessage(`{"id":9007199254740993}`))
	if err != nil {
		panic(err)
	}
	reply, err := registry.Invoke(ctx, call)
	if err != nil {
		panic(err)
	}
	result, _ := reply.Result()
	raw, _ := result.Structured()
	fmt.Println(string(raw))
}
Output:
project.status
{"ready":true}

func (*Registry) Inspect

func (r *Registry) Inspect(ctx context.Context, name string) (Definition, error)

Inspect returns an authorized, detached definition. Unknown and inaccessible names return the same caller-safe unavailable failure.

func (*Registry) Invoke

func (r *Registry) Invoke(ctx context.Context, call Call) (Reply, error)

Invoke authorizes discovery, validates arguments and authorizes execution before dispatch. It validates success and optional failure diagnostics alike.

Example (Confirmation)
// The application owns intent identity and effect recovery. This example store
// is process-local; use a durable transaction/reconciliation store in production.
var mu sync.Mutex
completed := map[string]bool{}
effects := 0
handler := func(_ context.Context, invocation *mcp.Invocation) (mcp.Outcome, error) {
	resume, resuming := invocation.Resume()
	if !resuming {
		input, err := mcp.NewFormInput("Apply the prepared change?", json.RawMessage(confirmationSchema), json.RawMessage(`{"intent":"change-123"}`))
		return mcp.AwaitInput(input), err
	}
	var state struct {
		Intent string `json:"intent"`
	}
	if err := json.Unmarshal(resume.State(), &state); err != nil {
		return mcp.Outcome{}, err
	}
	var answers struct {
		Confirmed bool `json:"confirmed"`
	}
	if resume.Action() != mcp.Accept {
		return mcp.Outcome{}, mcp.NewFailure(mcp.FailureInteractionDeclined, "Change was not confirmed", nil)
	}
	if err := json.Unmarshal(resume.Answers(), &answers); err != nil {
		return mcp.Outcome{}, err
	}
	if !answers.Confirmed {
		return mcp.Outcome{}, mcp.NewFailure(mcp.FailureInteractionDeclined, "Change was not confirmed", nil)
	}
	mu.Lock()
	defer mu.Unlock()
	if !completed[state.Intent] {
		if resume.RecoveryOnly() {
			return mcp.Outcome{}, mcp.NewFailure(mcp.FailureCommandFailed, "Reconcile the existing intent before continuing", nil)
		}
		// In production, atomically record the effect with its outcome, or reconcile
		// the external system by intent key after an ambiguous response.
		effects++
		completed[state.Intent] = true
	}
	result, err := mcp.TextResult("Change applied")
	return mcp.Finish(result), err
}
registry, err := mcp.New([]mcp.Operation{{Definition: mcp.Definition{Name: "change.apply", Summary: "Apply a prepared change", InputSchema: json.RawMessage(`{"type":"object"}`)}, Handle: handler}}, mcp.WithPolicy(mcp.AllowRegistered()))
if err != nil {
	panic(err)
}
initial, err := mcp.NewCall("change.apply", json.RawMessage(`{}`), mcp.WithInputSupport(mcp.FormInput))
if err != nil {
	panic(err)
}
reply, err := registry.Invoke(context.Background(), initial)
if err != nil {
	panic(err)
}
pending, _ := reply.Input()
form, _ := pending.Request().Form()
fmt.Println(form.Message)
// This response represents a user explicitly selecting the confirmation field.
response, err := mcp.NewInputResponse(mcp.Accept, json.RawMessage(`{"confirmed":true}`))
if err != nil {
	panic(err)
}
continuation, err := mcp.NewCall("change.apply", json.RawMessage(`{}`), mcp.WithResume(pending.Continuation(), response))
if err != nil {
	panic(err)
}
for range 2 {
	reply, err = registry.Invoke(context.Background(), continuation)
	if err != nil {
		panic(err)
	}
	result, _ := reply.Result()
	fmt.Println(result.Content()[0].(mcp.TextContent).Text())
}
fmt.Println("application effects:", effects)
Output:
Apply the prepared change?
Change applied
Change applied
application effects: 1

func (*Registry) Search

func (r *Registry) Search(ctx context.Context, request SearchRequest) (SearchPage, error)

Search ranks exact identifiers first, then deterministic keyword matches. It reauthorizes each emitted summary and never caches pages across caller scopes.

type Reply

type Reply struct {
	// contains filtered or unexported fields
}

Reply contains a gateway-validated result or pending input. A failure may include valid result diagnostics; the accompanying error is the authoritative failure signal.

func (Reply) Input

func (r Reply) Input() (PendingInput, bool)

Input reports a validated pending interaction, mutually exclusive with Result.

func (Reply) Result

func (r Reply) Result() (Result, bool)

Result reports whether this reply contains a constructed, validated result.

type ResourceBinding

type ResourceBinding struct {
	Definition ResourceDefinition
	Resolve    func(context.Context, ResourceMatch) (ResourceReadPlan, error)
	Read       func(context.Context, ResourceTarget) (ResourcePayload, error)
}

ResourceBinding resolves identities without body I/O, then reads individual authorized targets. Callbacks must honor context and support concurrent calls.

type ResourceData

type ResourceData struct {
	// contains filtered or unexported fields
}

ResourceData owns exactly one text or blob variant. Its zero value is invalid.

func ResourceBlob

func ResourceBlob(data []byte) ResourceData

ResourceBlob snapshots bytes; nil is an intentional empty blob.

func ResourceText

func ResourceText(text string) ResourceData

ResourceText constructs text data, including intentional empty text.

func (ResourceData) Blob

func (d ResourceData) Blob() ([]byte, bool)

Blob returns detached bytes for the blob variant.

func (ResourceData) Text

func (d ResourceData) Text() (string, bool)

Text returns the text variant, preserving an explicit empty value.

type ResourceDefinition

type ResourceDefinition struct {
	Name, Title, Description, MIMEType string
	URI, URITemplate                   string
	Metadata                           Metadata
}

ResourceDefinition describes one registered concrete resource or path template. Exactly one of URI and URITemplate is required; metadata confers no access.

type ResourceIssue

type ResourceIssue struct {
	// contains filtered or unexported fields
}

ResourceIssue describes one visible failure without private authorization data.

func (ResourceIssue) Code

func (i ResourceIssue) Code() string

Code returns a stable resource issue code.

func (ResourceIssue) Message

func (i ResourceIssue) Message() string

Message returns a fixed safe template, never a reader's error string.

func (ResourceIssue) ResourceURI

func (i ResourceIssue) ResourceURI() (string, bool)

ResourceURI returns an identifier only when final policy explicitly allowed it.

func (ResourceIssue) Retryable

func (i ResourceIssue) Retryable() bool

Retryable permits explicit retry; the library never retries automatically.

type ResourceItem

type ResourceItem struct {
	// contains filtered or unexported fields
}

ResourceItem binds a validated payload to the authorized canonical URI.

func (ResourceItem) Data

func (i ResourceItem) Data() ResourceData

Data returns owned data with detached mutable accessors.

func (ResourceItem) MIMEType

func (i ResourceItem) MIMEType() string

MIMEType returns this item's declared type, independent of the bundle's type.

func (ResourceItem) Metadata

func (i ResourceItem) Metadata() Metadata

Metadata returns immutable item metadata.

func (ResourceItem) URI

func (i ResourceItem) URI() string

URI returns the gateway-selected identity; readers cannot substitute it.

type ResourceLimits

type ResourceLimits struct {
	PayloadBytes, ResponseBytes, PlanItems, ContentItems           int
	URIBytes, RepresentationBytes, PageBytes, PageDefault, PageMax int
	IssueDetails, DiagnosticPayloadBytes, DiagnosticEncodedBytes   int
	Timeout                                                        time.Duration
}

ResourceLimits bounds resource planning, admission and reporting. Zero fields select defaults; increasing one field never increases a related field.

type ResourceLinkContent

type ResourceLinkContent struct {
	// contains filtered or unexported fields
}

ResourceLinkContent refers to an application resource without reading it.

func ResourceLink(ref ResourceRef) ResourceLinkContent

ResourceLink retains an immutable reference, validated by NewResult.

func (ResourceLinkContent) Kind

func (c ResourceLinkContent) Kind() ContentKind

func (ResourceLinkContent) ResourceRef

func (c ResourceLinkContent) ResourceRef() ResourceRef

ResourceRef returns the immutable resource reference.

type ResourceMatch

type ResourceMatch struct {
	// contains filtered or unexported fields
}

ResourceMatch contains a requested URI and once-decoded, still-untrusted variables.

func (ResourceMatch) URI

func (m ResourceMatch) URI() string

URI returns the original requested identity, without canonicalizing it implicitly.

func (ResourceMatch) Variables

func (m ResourceMatch) Variables() map[string]string

Variables returns a detached map. Hosts must not decode values a second time.

type ResourceOption

type ResourceOption func(*resourceConfig)

ResourceOption configures resource execution at construction.

func WithResourceLimits

func WithResourceLimits(limits ResourceLimits) ResourceOption

WithResourceLimits overrides positive fields. Negative values and repetition fail.

type ResourcePage

type ResourcePage struct {
	Resources  []ResourceDefinition
	NextCursor string
}

ResourcePage contains detached descriptions authorized for this request.

type ResourcePageRequest

type ResourcePageRequest struct {
	Cursor string
	Limit  int
}

ResourcePageRequest selects one page of registered descriptions, not dynamic assets.

type ResourcePayload

type ResourcePayload struct {
	// contains filtered or unexported fields
}

ResourcePayload is an owned body without a selectable output identity. The gateway binds it to the planned, authorized target before returning an item.

func NewResourcePayload

func NewResourcePayload(data ResourceData, mimeType string, metadata Metadata) (ResourcePayload, error)

NewResourcePayload checks content and the declared MIME type, without decoding codecs or authorizing resources. The gateway applies payload and metadata budgets.

func (ResourcePayload) Data

func (p ResourcePayload) Data() ResourceData

Data returns owned data with detached mutable accessors.

func (ResourcePayload) MIMEType

func (p ResourcePayload) MIMEType() string

MIMEType returns the actual declared type for this body.

func (ResourcePayload) Metadata

func (p ResourcePayload) Metadata() Metadata

Metadata returns immutable metadata; Values detaches its JSON.

type ResourcePolicy

type ResourcePolicy struct {
	Discover func(context.Context, ResourceDefinition) error
	Visible  func(context.Context, ResourceTarget) (ResourceVisibility, error)
	Read     func(context.Context, ResourceTarget) error
	ScopeKey func(context.Context) (string, error)
}

ResourcePolicy authorizes registered descriptions and canonical targets. Return FailureUnavailable to deny discovery/read; operational failures abort the read. ScopeKey is a nonempty principal/authorization-revision key without credentials.

type ResourceReadPlan

type ResourceReadPlan struct {
	// contains filtered or unexported fields
}

ResourceReadPlan owns the requested bundle identity and ordered, unique item targets.

func NewResourceReadPlan

func NewResourceReadPlan(requested ResourceTarget, items []ResourceTarget) (ResourceReadPlan, error)

NewResourceReadPlan rejects unconstructed targets and duplicate canonical URIs, even when their representations differ. An explicitly empty selection is valid.

func (ResourceReadPlan) Items

func (p ResourceReadPlan) Items() []ResourceTarget

Items returns a detached ordered selection.

func (ResourceReadPlan) Requested

func (p ResourceReadPlan) Requested() ResourceTarget

Requested returns the immutable bundle identity.

type ResourceRef

type ResourceRef struct {
	// contains filtered or unexported fields
}

ResourceRef owns a validated resource identity. Construct one with NewResourceRef.

func NewResourceRef

func NewResourceRef(spec ResourceRefSpec) (ResourceRef, error)

NewResourceRef validates a reference without fetching or authorizing it.

func (ResourceRef) Description

func (r ResourceRef) Description() ResourceRefSpec

Description returns the description with detached annotation pointers/slices. Its Metadata remains immutable; Metadata.Values returns detached JSON.

type ResourceRefSpec

type ResourceRefSpec struct {
	URI, Name, Title, Description, MIMEType string
	Metadata                                Metadata
	Annotations                             Annotations
}

ResourceRefSpec describes a reference; NewResourceRef snapshots mutable fields. Metadata and annotations are hints and never confer permission to read the URI.

type ResourceResult

type ResourceResult struct {
	// contains filtered or unexported fields
}

ResourceResult contains a complete or explicitly partial bundle. Items includes a generated warning first for partial results. A non-nil Read error means no bundle.

func (ResourceResult) Issues

func (r ResourceResult) Issues() []ResourceIssue

Issues returns detached, bounded caller-safe details; private causes never escape.

func (ResourceResult) IssuesOmitted

func (r ResourceResult) IssuesOmitted() int

IssuesOmitted counts additional visible failures excluded from detailed reporting.

func (ResourceResult) Items

func (r ResourceResult) Items() []ResourceItem

Items returns a detached ordered collection of owned resource items.

func (ResourceResult) Metadata

func (r ResourceResult) Metadata() Metadata

Metadata returns the owned completeness report shared with the visible warning.

func (ResourceResult) Partial

func (r ResourceResult) Partial() bool

Partial reports omissions from the current caller-visible selection.

type ResourceTarget

type ResourceTarget struct {
	// contains filtered or unexported fields
}

ResourceTarget owns a canonical identity shared by policy and storage callbacks.

func NewResourceTarget

func NewResourceTarget(spec ResourceTargetSpec) (ResourceTarget, error)

NewResourceTarget snapshots the private JSON, when supplied, and checks identity.

func (ResourceTarget) AuthorizationData

func (t ResourceTarget) AuthorizationData() json.RawMessage

AuthorizationData returns detached private host data, not caller-facing metadata.

func (ResourceTarget) Representation

func (t ResourceTarget) Representation() string

Representation identifies the host's selected representation; empty is the default.

func (ResourceTarget) URI

func (t ResourceTarget) URI() string

URI returns the canonical wire identity.

type ResourceTargetSpec

type ResourceTargetSpec struct {
	URI               string
	Representation    string
	AuthorizationData json.RawMessage
}

ResourceTargetSpec describes an application-canonical identity. AuthorizationData is private host data, never content or permission granted by this constructor.

type ResourceTemplatePage

type ResourceTemplatePage struct {
	Templates  []ResourceDefinition
	NextCursor string
}

ResourceTemplatePage contains detached descriptions of supported path templates.

type ResourceVisibility

type ResourceVisibility struct {
	Visible          bool
	DiscloseIssueURI bool
}

ResourceVisibility separates existence disclosure from permission to read a body.

type Resources

type Resources struct {
	// contains filtered or unexported fields
}

Resources owns immutable explicit bindings; it does not own a listener or jobs.

func NewResources

func NewResources(bindings []ResourceBinding, policy ResourcePolicy, opts ...ResourceOption) (*Resources, error)

NewResources snapshots registrations and requires all resource policy callbacks.

func (*Resources) List

List returns concrete registrations in URI/name order with current discovery policy.

func (*Resources) ListTemplates

func (r *Resources) ListTemplates(ctx context.Context, request ResourcePageRequest) (ResourceTemplatePage, error)

ListTemplates returns templates separately; cursors cannot cross listing methods.

func (*Resources) Read

func (r *Resources) Read(ctx context.Context, uri string) (ResourceResult, error)

Read resolves one explicit binding, authorizes the whole plan before body I/O, and rechecks access before committing an ordered complete or partial bundle.

Example
package main

import (
	"context"
	"errors"
	"fmt"

	mcp "gitlab.com/phpboyscout/go/mcp"
)

func main() {
	requested, err := mcp.NewResourceTarget(mcp.ResourceTargetSpec{URI: "bundle://project/preview"})
	if err != nil {
		panic(err)
	}
	summary, err := mcp.NewResourceTarget(mcp.ResourceTargetSpec{URI: "asset://project/summary"})
	if err != nil {
		panic(err)
	}
	transcript, err := mcp.NewResourceTarget(mcp.ResourceTargetSpec{URI: "asset://project/transcript"})
	if err != nil {
		panic(err)
	}
	plan, err := mcp.NewResourceReadPlan(requested, []mcp.ResourceTarget{summary, transcript})
	if err != nil {
		panic(err)
	}
	// This example deliberately trusts its fixed local catalogue. Service hosts
	// enforce their authenticated principal and current storage policy here.
	policy := mcp.ResourcePolicy{
		Discover: func(context.Context, mcp.ResourceDefinition) error { return nil },
		Visible: func(context.Context, mcp.ResourceTarget) (mcp.ResourceVisibility, error) {
			return mcp.ResourceVisibility{Visible: true}, nil
		},
		Read:     func(context.Context, mcp.ResourceTarget) error { return nil },
		ScopeKey: func(context.Context) (string, error) { return "local-preview", nil },
	}
	binding := mcp.ResourceBinding{
		Definition: mcp.ResourceDefinition{Name: "preview", URI: requested.URI()},
		Resolve:    func(context.Context, mcp.ResourceMatch) (mcp.ResourceReadPlan, error) { return plan, nil },
		Read: func(_ context.Context, target mcp.ResourceTarget) (mcp.ResourcePayload, error) {
			if target.URI() == transcript.URI() {
				return mcp.ResourcePayload{}, errors.New("private storage failure")
			}
			return mcp.NewResourcePayload(mcp.ResourceText("Preview is ready"), "text/plain", mcp.Metadata{})
		},
	}
	resources, err := mcp.NewResources([]mcp.ResourceBinding{binding}, policy)
	if err != nil {
		panic(err)
	}
	result, err := resources.Read(context.Background(), requested.URI())
	if err != nil {
		panic(err)
	}
	fmt.Println("partial:", result.Partial())
	fmt.Println("contents:", len(result.Items())) // The first is the generated warning.
	fmt.Println("survivor:", result.Items()[1].URI())
	fmt.Println("issue:", result.Issues()[0].Code())
}
Output:
partial: true
contents: 2
survivor: asset://project/summary
issue: read_failed

type Result

type Result struct {
	// contains filtered or unexported fields
}

Result owns ordered content and an optional structured JSON value. Its zero value is not a constructed result; NewResult(nil) is an intentional empty one.

func JSONResult

func JSONResult(value any, content ...Content) (Result, error)

JSONResult marshals a Go value once, then validates and owns its JSON. This does not repair numbers already rounded by the caller or add protocol wrapper text.

Example
package main

import (
	"fmt"

	mcp "gitlab.com/phpboyscout/go/mcp"
)

func main() {
	result, err := mcp.JSONResult([]string{"preview", "transcript"}, mcp.Text("Two assets are ready"))
	if err != nil {
		panic(err)
	}
	raw, _ := result.Structured()
	fmt.Println(string(raw))
}
Output:
["preview","transcript"]

func NewResult

func NewResult(content []Content, opts ...ResultOption) (Result, error)

NewResult assembles an owned result. Operation schemas and protocol response budgets are checked by the invocation and adapter layers, not here.

Example
package main

import (
	"encoding/json"
	"fmt"

	mcp "gitlab.com/phpboyscout/go/mcp"
)

func main() {
	result, err := mcp.NewResult([]mcp.Content{mcp.Text("Selected candidate")}, mcp.WithStructured(json.RawMessage(`{"id":9007199254740993}`)))
	if err != nil {
		panic(err)
	}
	raw, present := result.Structured()
	fmt.Println(result.Content()[0].(mcp.TextContent).Text())
	fmt.Println(present, string(raw))
}
Output:
Selected candidate
true {"id":9007199254740993}

func TextResult

func TextResult(text string) (Result, error)

TextResult constructs an unstructured text result, without guessing at JSON.

func (Result) Content

func (r Result) Content() []Content

Content returns a detached slice of immutable content values.

func (Result) Metadata

func (r Result) Metadata() Metadata

Metadata returns the result metadata; Values provides detached access.

func (Result) Structured

func (r Result) Structured() (json.RawMessage, bool)

Structured returns a detached JSON value and whether one was supplied.

type ResultOption

type ResultOption func(*resultConfig)

ResultOption configures result assembly without exposing mutable state.

func WithPresentation

func WithPresentation(presentation Presentation) ResultOption

WithPresentation adds the typed, reserved presentation metadata. Provide useful ordinary content or structured output for clients that cannot render Apps.

func WithResultMetadata

func WithResultMetadata(metadata Metadata) ResultOption

WithResultMetadata adds owned metadata, rejecting duplicate fully qualified keys.

func WithStructured

func WithStructured(value json.RawMessage) ResultOption

WithStructured snapshots JSON immediately, preserving null versus absence.

type Resume

type Resume struct {
	// contains filtered or unexported fields
}

Resume contains only gateway-verified state and answers from the original prompt.

func (Resume) Action

func (r Resume) Action() InputAction

Action returns the user's explicit action.

func (Resume) Answers

func (r Resume) Answers() json.RawMessage

Answers returns detached, canonical answers, or nil for responses without answers.

func (Resume) RecoveryOnly

func (r Resume) RecoveryOnly() bool

RecoveryOnly requires recovery of prior effects and permits Finish only.

func (Resume) Round

func (r Resume) Round() int

Round returns the answered prompt number, starting at one.

func (Resume) State

func (r Resume) State() json.RawMessage

State returns detached application state from the issued prompt.

type SearchPage

type SearchPage struct {
	Operations []Summary `json:"operations"`
	NextCursor string    `json:"nextCursor,omitempty"`
	Revision   string    `json:"revision"`
}

SearchPage is an authorized page with an opaque continuation and catalogue revision.

type SearchRequest

type SearchRequest struct {
	Query, Group, Cursor string
	Limit                int
}

SearchRequest selects a bounded page. Zero Limit uses five, up to twenty. Query matches case-insensitive keywords; an empty query browses by name.

type Summary

type Summary struct {
	Name    string `json:"name"`
	Summary string `json:"summary"`
	Group   string `json:"group,omitempty"`
}

Summary contains discovery text only; schemas and full docs require Inspect.

type TextContent

type TextContent struct {
	// contains filtered or unexported fields
}

TextContent is immutable UTF-8 text, validated when assembled into a Result.

func Text

func Text(value string) TextContent

Text snapshots a text value. An empty string is valid text.

func (TextContent) Kind

func (c TextContent) Kind() ContentKind

func (TextContent) Text

func (c TextContent) Text() string

Text returns the text value.

type URLDescription

type URLDescription struct{ Message, URL string }

URLDescription exposes a host-authorized route, never private application state.

Directories

Path Synopsis
Package cli is the `mcp` command tree a Cobra application mounts to serve itself over MCP: start (stdio), stream (Streamable HTTP under the estate's controls lifecycle), tools (the offline catalogue export) and the claude, cursor and vscode helpers that register the server with an editor.
Package cli is the `mcp` command tree a Cobra application mounts to serve itself over MCP: start (stdio), stream (Streamable HTTP under the estate's controls lifecycle), tools (the offline catalogue export) and the claude, cursor and vscode helpers that register the server with an editor.
Package cobra binds a completed Cobra command tree to MCP operations that run each command as a subprocess of the resolved executable.
Package cobra binds a completed Cobra command tree to MCP operations that run each command as a subprocess of the resolved executable.
Package grpc binds a gRPC service's unary methods to MCP operations without bypassing the authorisation its interceptors enforce (spec 0002).
Package grpc binds a gRPC service's unary methods to MCP operations without bypassing the authorisation its interceptors enforce (spec 0002).
internal
fixturetree
Package fixturetree is the command tree behind the binding test fixture: a real Cobra CLI that reports the argv it parsed, exits with chosen codes, floods output, sleeps, and spawns a grandchild so descendant cleanup can be observed.
Package fixturetree is the command tree behind the binding test fixture: a real Cobra CLI that reports the argv it parsed, exits with chosen codes, floods output, sleeps, and spawns a grandchild so descendant cleanup can be observed.
grpcfixture
Package grpcfixture is the service the gRPC binding's integration tests run: a notes service served on a transport gRPC server behind the transport's auth interceptor and a transit logging interceptor, and the same implementation's unary methods bound as MCP operations behind the estate HTTP chain, under one controls controller.
Package grpcfixture is the service the gRPC binding's integration tests run: a notes service served on a transport gRPC server behind the transport's auth interceptor and a transit logging interceptor, and the same implementation's unary methods bound as MCP operations behind the estate HTTP chain, under one controls controller.
inputprofile
Package inputprofile carries adapter form restrictions before ledger retention.
Package inputprofile carries adapter form restrictions before ledger retention.
progressdiag
Package progressdiag connects private invocation diagnostics to host adapters.
Package progressdiag connects private invocation diagnostics to host adapters.
resourceexec
Package resourceexec shares a resource request's processing deadline and pure wire sizing with module adapters, without exposing SDK types in the root API.
Package resourceexec shares a resource request's processing deadline and pure wire sizing with module adapters, without exposing SDK types in the root API.
servicefixture
Package servicefixture is the HTTP service the service-integration tests run: an application with a route of its own that mounts the MCP handler behind the estate transport and a transit chain, under one controls controller, the way spec 0001 D7 requires of a real service.
Package servicefixture is the HTTP service the service-integration tests run: an application with a route of its own that mounts the MCP handler behind the estate transport and a transit chain, under one controls controller, the way spec 0001 D7 requires of a real service.
serving
Package serving coordinates module adapters without exposing continuation ownership or verified state through the public library API.
Package serving coordinates module adapters without exposing continuation ownership or verified state through the public library API.
Package server hosts an authorized MCP registry through the official Go SDK.
Package server hosts an authorized MCP registry through the official Go SDK.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL