@kolu/surface-mcp reference
Re-expose any @kolu/surface as an MCP server, so a coding agent drives it with
structured tool calls. The adapter owns the generic parts — the
resources/subscribe lifecycle, the zod → JSON-Schema bridge, stdio discipline —
and leaves the consumer in control of what is exposed.
serveSurfaceAsMcp
const { server, close } = await serveSurfaceAsMcp({
surface,
client: () => client,
expose: {
/* … */
},
});
serveSurfaceAsMcp(opts): Promise<{ server, close }>, imported from the root
@kolu/surface-mcp subpath.
| Option | Meaning |
|---|---|
surface |
the surface spec being projected |
client |
a factory () => client for a live implementation |
expose |
the default-deny allowlist (see below) |
tools? |
hand-authored bespoke tools |
serverInfo? |
MCP server identity |
transport? |
defaults to StdioServerTransport; inject an in-memory half for tests |
The projection
expose is default-deny: nothing crosses to the host until named, and every
key is checked against the surface spec at boot.
| Surface member | Exposed as | URI / wire name |
|---|---|---|
| cell | resource | surface://cells/<k> |
| collection | resource (+ template) | surface://collections/<k> · …/<k>/{id} |
| stream | resource | surface://streams/<k> |
| event | resource | surface://events/<k> |
procedure "<ns>.<verb>" |
tool | <ns>_<verb> (. is illegal in a tool name) |
Resources are readable and subscribable; procedures become callable tools.
Two shapes
- Serve fresh —
clientis adirectLinkover an in-processimplementSurface; the MCP server is the surface’s backend. - Bridge a live surface —
clientdials an already-running served surface over a socket or ssh stdio; the MCP server is a face on an existing server (odu’sodu mcpdials.ci/odu.sock).
Bespoke tools and curation
tools:— hand-authored, call-shaped capabilities (spawn-and-wait, blocking polls). Each is{ description, input: z.object(...), mutates, handler }; thehandler(args, client, signal)composes over the live client and still rides the JSON-Schema bridge and lifecycle.projectSurface(from@kolu/surface/project) is the cleanest curation: project the live surface into an observer-safe second surface — drop dangerous procedures, bound logs, derive verdicts — and serve that.
Other exports
| Export | Role |
|---|---|
toInputSchema(schema?) |
zod → JSON Schema (draft 2020-12), $ref-dereferenced, top-level-object enforced |
resolveExpose(spec, expose) |
the default-deny resolver → { resources, resourceTemplates, tools } |
ExposeMap · BespokeTool · ToolResult · ServeSurfaceAsMcpOptions |
types |
The step-by-step is in How to expose a surface to agents.