Documentation
¶
Overview ¶
Package mcpbroker brokers Model Context Protocol (MCP) calls on behalf of a contained island — the execution half of the audited MCP broker (docs/mcp-broker-spec.md). It mirrors the capability broker (internal/capability) exactly: a deny-all default, a host-side curated set of named MCP servers the operator authored, per-island grants of those names, a fixed wire contract, and every call a typed Ledger entry.
A Broker maps a (server, method, params) request to one JSON-RPC call against a granted MCP server. It never constructs a shell command from request data: it execs the operator-curated server program with a fixed argv and speaks JSON-RPC over its stdio. Who may invoke which server (grants) lives in internal/project; this package is only ever reached after a grant check.
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ( // ErrServerNotFound: the named server isn't in the host registry (or the // registry file is absent). Fail closed — same posture as a missing grant. ErrServerNotFound = errors.New("mcp server not found in host registry") // ErrServerUntrusted: the registry file failed its trust checks (not owned // by the daemon user, or group/world-writable), so its contents can't be // trusted to name safe server programs. ErrServerUntrusted = errors.New("mcp server registry failed its trust checks") // ErrMethodNotAllowed: the requested JSON-RPC method is outside the brokered // surface (see AllowedMethods). The lifecycle/handshake methods are driven by // the broker itself and are never callable by a client. ErrMethodNotAllowed = errors.New("mcp method not permitted by the broker") // ErrTimeout: the server didn't complete the call within the wall-clock bound. ErrTimeout = errors.New("mcp call timed out") // ErrProtocol: the server spoke malformed JSON-RPC, closed early, or returned // a JSON-RPC error to a lifecycle/brokered request. ErrProtocol = errors.New("mcp protocol error") )
Sentinel errors let the API layer map broker failures to HTTP status codes without leaking host detail. A tools/call that *ran* and returned an MCP application error (isError:true) is NOT one of these — it returns a Result with IsError set and a nil error; only transport/protocol failures error.
var AllowedMethods = map[string]bool{ "tools/list": true, "tools/call": true, "resources/list": true, "resources/read": true, "prompts/list": true, "prompts/get": true, }
AllowedMethods is the brokered JSON-RPC surface: discovery + invocation, never the lifecycle/handshake methods (initialize, notifications/*), which the broker owns. Keeping this a fixed allow-list is what makes the Ledger tractable — every entry names a published, bounded operation, exactly the argument that rejected a general command broker for capabilities.
Functions ¶
func MethodAllowed ¶
MethodAllowed reports whether method is in the brokered surface.
func ValidateServerName ¶
ValidateServerName checks a registry server name — the handle a grant and a call address. It must be a single safe token: 1–64 chars, no path separators or traversal, no whitespace or control characters. (Server commands can be anything the operator curates; the *name* stays a clean identifier.)
Types ¶
type Broker ¶
Broker maps a Request to one JSON-RPC call against a granted, host-curated MCP server. Implementations MUST never build a shell command from request data: exec the operator-authored server program with a fixed argv and speak JSON-RPC over stdio. Name identifies the transport for the Ledger ("stdio").
type Registry ¶
type Registry struct {
Path string
}
Registry is the host-side catalogue of curated MCP servers. It is read fresh on every lookup (like the capability script adapter Lstats its target each call), so an operator editing servers.toml takes effect with no daemon restart. Path is the servers.toml location.
func DefaultRegistry ¶
DefaultRegistry returns the registry at ~/.dejima/mcp/servers.toml.
func (*Registry) List ¶
func (r *Registry) List() ([]ServerSpec, error)
List returns every curated server, or an empty slice when no registry exists yet (deny-all: nothing to invoke). A present-but-untrusted registry is an error — fail closed rather than trust a file some other account could edit.
func (*Registry) Lookup ¶
func (r *Registry) Lookup(name string) (ServerSpec, error)
Lookup returns the spec for name, or ErrServerNotFound. The name is matched exactly against the curated set; a server present in the registry but not yet granted to the island is still rejected upstream (deny-all grant check).
type Request ¶
type Request struct {
Island string
Agent string
Server string
Method string
Params json.RawMessage
}
Request is one brokered MCP call. The island/agent are carried for the Ledger and the server's minimal environment; Server names a granted registry entry; Method is a member of AllowedMethods; Params is the JSON-RPC params object (may be nil). Nothing here reaches a shell.
type Result ¶
type Result struct {
Output json.RawMessage
IsError bool
}
Result is the outcome of a brokered call that completed the JSON-RPC round-trip. Output is the raw JSON-RPC `result` value (bounded). IsError reports whether a tools/call result carried `isError: true` — an application-level failure that still completed the protocol, mirroring how the capability adapter treats a non-zero exit code: the caller's concern, not a broker error.
type ServerSpec ¶
type ServerSpec struct {
// Name is the handle a grant and a call address. Validated as a single safe
// token (see ValidateServerName) — no separators, bounded length.
Name string `toml:"name"`
// Transport is the MCP transport. Only "stdio" in V1 (the dominant transport,
// and the one with no network surface — the broker spawns the program and
// speaks JSON-RPC over its pipes). Empty defaults to "stdio".
Transport string `toml:"transport,omitempty"`
// Command is the server program. The operator vouches for it by listing it in
// the trust-checked registry; the broker execs it with a fixed argv and never
// through a shell.
Command string `toml:"command"`
// Args is the fixed argv passed to Command. Never interpolated with request
// data — request params travel as JSON-RPC on stdin.
Args []string `toml:"args,omitempty"`
// Env is an explicit "K=V" passthrough (e.g. an API key the server needs).
// Only these — plus a minimal PATH and the island identity — reach the
// process; the daemon's own environment is never inherited.
Env []string `toml:"env,omitempty"`
}
ServerSpec is one operator-curated MCP server the broker may invoke. The set of specs — authored host-side in ~/.dejima/mcp/servers.toml, which the island cannot write — is the security boundary, exactly like the capability broker's ~/.dejima/capabilities/ scripts dir: the island can only invoke a server the user already chose to expose, and only one explicitly granted to it.
type StdioBroker ¶
type StdioBroker struct {
Registry *Registry
Timeout time.Duration // 0 → defaultCallTimeout
MaxOutput int64 // 0 → defaultMaxOutput
}
StdioBroker invokes stdio MCP servers named in a host-side Registry. It is the V1 broker; a future transport (e.g. HTTP/SSE) is a sibling implementation selected the same way, never a generalization of this one.
func (*StdioBroker) Call ¶
Call resolves the named server in the registry (deny-closed if absent or the registry is untrusted), enforces the brokered method surface, and performs one JSON-RPC round-trip bounded by the timeout and output cap. The grant check (deny-all) happens upstream in the API layer; this is only ever reached after it passes.
func (*StdioBroker) Name ¶
func (b *StdioBroker) Name() string