CLAUDE.md@packages/mcp · git:20261001.248307a · 2026-10-01 · sha256 dd0b79c802d7b137
CLAUDE.md@packages/mcp git:20261001.248307aA
Immutable. This exact content never changes and is served at /api/v1/blob/dd0b79c802d7b137.
# mcp ## Purpose Loom's adapter for the standalone `gleam_mcp` library. This package turns untrusted tool listings into `cap/mcp/<server>` Gleam source and translates values between Loom's capability MessagePack wire and the library's JSON vocabulary. Protocol codecs, stdio framing, the client state machine and native process ownership belong to `gleam_mcp`. MCP reaches a model through code mode only: one generated module per server. `codegen.generate` returns source text and a rendered surface at boot. It never compiles code, starts a process, or writes a file. The jailed build compiles only the generated modules the submitted program imports. `client/mcp` owns configuration, client startup, cleanup custody, and routing. ## Key Types - `mcp/codegen.Generated(module_name, source, surface)` is the complete generated artifact. `GenerateError` refuses excessive tool counts, name collisions, excessive rendered surfaces, and sanitizer failures. - `mcp/schema.Plan` is `Typed(parameters, optionals)` or `WholeValue(reason)`. Every required parameter survives as a typed or structured argument; an unusable schema becomes a whole-value argument rather than an omission. - `mcp/name` maps wire names to Gleam identifiers, retaining an injected digest suffix whenever a name changes. Wire names themselves never change. - `mcp/interchange.InterchangeFault` names an unrepresentable value's path. `to_json` converts `core/msgpack.MsgPackValue` directly to `gleam_mcp/json.JsonValue`; `to_msgpack` performs the reverse conversion. - `gleam_mcp/protocol.ToolDescriptor` supplies the generator's tool name, descriptions and raw schemas. The library's JSON type is used directly throughout this adapter; Loom's frozen `core/json` remains independent. ## Relationships - **Depends on**: `gleam_stdlib`; `core` for `core/msgpack`; `gleam_mcp` for protocol descriptors and JSON values. The four local modules perform no I/O. The dependency includes an Erlang runtime, so this package does not claim the portable subset held by `core`, `machine` and `prompt`. - **Depended on by**: `client`, through `client/catalog`'s name checks and `client/mcp`'s generation and capability conversion. Generated source imports `cap/internal/mcp`, `cap/mcp` and `cap/report`, but this package has no dependency on `cap`: those imports are emitted as source text. - **FFI**: none. Native stdio process operations belong to the external library's `gleam_mcp/internal/ffi_port` module. ## Traffic - **Actor messages, commits and registers**: none in this package. - **Wire values**: `interchange` translates the arguments and structured results crossing `client/mcp`'s `mcp.<server>` capability arm. It does not own either wire's transport or framing. - **Generated artifacts**: `codegen.generate` returns source for `cap/mcp/<segment>` plus the surface shown to the model. `client/mcp` retains both. `codemode/build` writes selected modules inside the vendored capability package after seed cloning and before compilation. ## Invariants - **Code-mode authority stays per server.** Generated functions close over the original server and tool names and call `cap/internal/mcp.invoke`. The adapter does not expose a generic model-callable dispatcher. - **Wire names travel verbatim.** Mangling affects Gleam names only. Escaped literals preserve original tool and parameter names; a residual tool-name collision refuses the server. A parameter-label collision degrades that tool to whole-value arguments. - **Server prose remains inert.** Descriptions lose control and direction changing codepoints and are capped. Every generated doc line starts `/// `. `scan_for_at` refuses an attribute outside a string or comment. - **Generation is bounded.** `max_tools` is 256; `max_surface_bytes` is 65,536. A listing exceeding either limit refuses the server. - **Value translation is total.** JSON integers outside `[-2^63, 2^64 - 1]` fail the whole MessagePack conversion. Binary values and non-string map keys cannot become JSON arguments. No wrapping, clamping or guessed encoding is permitted. JSON and MessagePack parser nesting limits remain aligned, and the client separately checks the final capability envelope. - **Loom owns result reduction.** The library retains non-text blocks as `Other(kind, raw)`. `client/mcp.content_block` sends only their kind to `cap/mcp.Other`; raw image, audio and resource payloads do not enter the capability result. Text and structured results retain existing handling. - **Loom owns lifecycle policy.** `client/mcp` uses the library's parked `prepare_owned` clients, publishes every cleanup handle before connecting, and requires explicit native exit and normal actor retirement. Moving these primitives out of the tree does not weaken that custody boundary. - **Client identity is caller-owned.** The external library defaults to `gleam-mcp`; `client/mcp.start_one` explicitly identifies Loom as `loom`. The declared client capabilities remain empty. ## Deep Docs - [README.md](README.md) explains the extraction boundary and local tests. - [MCP architecture](../../docs/architecture/mcp.md) follows configuration, startup, generation, compilation, calls and retirement end to end. - [Code-mode architecture](../../docs/architecture/code-mode.md) describes import vetting and the jailed build that compiles generated modules. - [Capability package](../cap/CLAUDE.md) owns the frozen result vocabulary. - [Client package](../client/CLAUDE.md) owns lifecycle wiring and routing. - [Root CLAUDE.md](../../CLAUDE.md) holds repository rules and the doc graph.