Documentation
¶
Overview ¶
Package mcpapps is the MCP Apps host bridge: the frame-level half of a terminal or embedded host that renders an MCP App and answers the calls that App makes back through its postMessage channel.
It lives in pkg/ rather than a guarded surface because it expresses no permission. A view-initiated tools/call passes a Policy this package only holds an interface for; http/mcpverb compiles a guardfile into one. A Host with no Policy forwards nothing, so an undeclared widget reaches no upstream. See docs/mcpapps.md.
Index ¶
Constants ¶
const ( MethodInitialize = "ui/initialize" MethodInitialized = "ui/notifications/initialized" MethodToolResult = "ui/notifications/tool-result" MethodSizeChanged = "ui/notifications/size-changed" MethodOpenLink = "ui/open-link" MethodDownloadFile = "ui/download-file" MethodToolsCall = "tools/call" MethodToolsList = "tools/list" MethodResourcesRead = "resources/read" MethodResourcesList = "resources/list" MethodProgress = "notifications/progress" )
The frame methods this host answers. A view sends the ui/* ones plus ordinary MCP; every other method gets a MethodNotFound reply rather than silence.
const ( CodeMethodNotFound = -32601 CodeInvalidParams = -32602 CodePolicyDenied = -32001 CodeUpstreamFailed = -32002 )
JSON-RPC codes this host returns. PolicyDenied is in the implementation- defined range and mirrors umbra's exitcode taxonomy.
const ProtocolVersion = "2026-01-26"
ProtocolVersion is the MCP Apps version this host speaks, read from `LATEST_PROTOCOL_VERSION` in @modelcontextprotocol/ext-apps spec.types.d.ts.
Variables ¶
This section is empty.
Functions ¶
func CSP ¶
func CSP(s CSPSources) string
CSP builds the policy for one view. An undeclared family falls back to the spec's own default, so a missing declaration refuses rather than opens.
Types ¶
type CSPSources ¶
type CSPSources struct {
// Resource feeds script-src, style-src, img-src, font-src, and media-src.
Resource []string
// Connect feeds connect-src and is what `can connect` declares. The other
// three families have no guardfile verb yet.
Connect []string
// Frame feeds frame-src, and BaseURI feeds base-uri.
Frame []string
BaseURI []string
// Report names a collector path for violation reports. It is umbra's
// addition rather than the spec's, and it grants nothing.
Report string
}
CSPSources are the domains a view declared, one field per directive family the spec's `csp` object carries. See docs/mcpapps.md.
func (CSPSources) Declared ¶
func (s CSPSources) Declared() bool
Declared reports whether the view named any domain. None of them selects the spec's omitted-`ui.csp` case, which is the tighter of the two.
type DownloadItem ¶
type DownloadItem struct {
URI string
MIMEType string
// Raw is the item as the view sent it, so a handler saving inline bytes
// reads them without this package modelling every content shape.
Raw json.RawMessage
}
DownloadItem is one entry of a ui/download-file request, a link the host fetches or an inline resource. URI addresses both, and is what is gated.
type Frame ¶
type Frame struct {
JSONRPC string `json:"jsonrpc"`
ID json.RawMessage `json:"id,omitempty"`
Method string `json:"method,omitempty"`
Params json.RawMessage `json:"params,omitempty"`
}
Frame is one inbound JSON-RPC message from the view. ID is raw because a JSON-RPC id is a string or a number and this host only echoes it back.
type Host ¶
type Host struct {
// Info identifies this host to the view during ui/initialize.
Info Implementation
// Context is sent as `hostContext`. Omitting it entirely leaves the view's
// SDK never-ready, so Handle substitutes a minimal one.
Context HostContext
// Instantiating is the tools/call result that created this view, pushed as
// ui/notifications/tool-result when the view says it is initialized.
Instantiating any
// Session is the upstream a permitted call reaches. A nil Session refuses
// every proxied frame rather than dropping it.
Session Session
// Policy gates every view-initiated call. A nil Policy permits none, which
// is what makes an undeclared widget inert.
Policy Policy
// Emit posts an unsolicited frame to the view. The SDK calls it from its own
// goroutine, so it must be safe concurrently. nil drops them.
Emit func(Reply)
// OpenLink opens a URL the policy permitted. nil leaves `openLinks`
// undeclared, so a view learns rather than asking for what never happens.
OpenLink func(ctx context.Context, url string) error
// SaveFile hands permitted contents to the viewer. nil leaves
// `downloadFile` undeclared, for the same reason.
SaveFile func(ctx context.Context, items []DownloadItem) error
// contains filtered or unexported fields
}
Host answers one view's frames. It holds no transport: a caller reads a postMessage frame from wherever it arrives and hands the bytes to Handle.
func (*Host) Handle ¶
Handle answers one frame from the view, never returning a Go error. Every request yields exactly one reply, a notification only what it triggers.
func (*Host) HandleFrame ¶
HandleFrame is Handle over an already-decoded frame.
func (*Host) HandleProgress ¶
HandleProgress forwards one upstream progress notification to the view under its own token. Wire it as mcpclient.Options.OnProgress.
type HostContext ¶
HostContext is the environment the view renders against. A free map, because the spec's McpUiHostContext carries an index signature.
type Implementation ¶
Implementation names a party to the handshake, matching MCP's own shape.
type Policy ¶
type Policy interface {
// Tools is the surface the view may see and call: deny by absence, the
// same rule the CLI leaves follow. See docs/mcpapps.md.
Tools() []mcpclient.Tool
// CheckToolCall reports why this view-initiated call is refused, or nil. It
// runs after Tools membership, so it guards arguments rather than names.
CheckToolCall(tool string, args map[string]any) error
// CheckResourceRead reports why this view-initiated read is refused, or nil.
CheckResourceRead(uri string) error
// CheckOpenLink reports why opening this URL for the view is refused, or
// nil. Opening a URL an untrusted view chose is its own grant.
CheckOpenLink(url string) error
// CheckSaveFile reports why handing this resource to the viewer to save is
// refused, or nil. It gates the URI of a link and of an inline resource.
CheckSaveFile(uri string) error
}
Policy decides what a view may reach. This package holds the interface and no rules: the guardfile is the policy, compiled above this by http/mcpverb.
type RPCError ¶
type RPCError struct {
Code int `json:"code"`
Message string `json:"message"`
Data any `json:"data,omitempty"`
}
RPCError is the error member of a reply.
type Reply ¶
type Reply struct {
// contains filtered or unexported fields
}
Reply is one outbound frame, carrying a result or an error and never both. Unexported members, because postMessage keeps an empty one. docs/mcpapps.md.
func Failure ¶
Failure answers a request with an error, which is what a refused call gets: the view learns rather than waiting on a reply that never arrives.
func (Reply) MarshalJSON ¶
MarshalJSON emits exactly one of result, error, or method+params.
type Session ¶
type Session interface {
Call(ctx context.Context, c mcpclient.Call) (mcpclient.Result, error)
ReadResource(ctx context.Context, uri string) (*mcp.ReadResourceResult, error)
ListResources(ctx context.Context) ([]mcpclient.Resource, error)
}
Session is the upstream this host proxies to: the subset of *mcpclient.Session a view can reach, which that type already satisfies.