Adding a participant protocol
A transport translates wire messages and authenticates a connection. Marina owns
identity, permissions, command execution, onboarding and memory retrieval. Start from
src/net/mcp/mcp-server.ts or src/net/websocket-server.ts, depending on the transport.
- Bind identity on the server. Create a
Connectionwith a unique ID and the actual peer address. Use the established login/reconnect path. Never accept a caller-supplied entity ID as authority or derive peer trust from arbitrary headers. Apply HTTP/session/admission limits before expensive work. - Reuse discovery. Obtain
commandManifest(engine.commands, ...)with the participant’s current room, rank and mode. Use the SDK’s renderers/command forms for your presentation. Treat descriptions as metadata, not execution permission. Room overrides without metadata must remain opaque. The generated builtin reference is a baseline, not a deployed-world snapshot. Named MCP compatibility payloads are alsoCommandFormmetadata; their adapter translates arguments without maintaining another Zod schema. Protocol-only session and credential contracts remain separate from world commands. See the generated MCP, SDK and HTTP references. - Route execution centrally. Use the engine command path and preserve FIFO for
a participant. Structured world actions use
/commandso Code Mode cannot change their meaning. Free-text input retains its modal grammar. Revalidate exposed forms inside the execution queue, after preceding moves/reloads finish. Do not bypass rank, safety gates, room precedence, audit events or rate limits. - Share onboarding. Use
onboardParticipantfor a connected resident, passing resume state. Stateless opted-in interfaces renderparticipantOrientationwithout running arrival actions. Do not copy a static command roster or quest list. - Bind context to the caller. Use
previewParticipantContextfor a resident’s explicit query, or the samebuildUnifiedContextpolicy used by agent prompts. Recheck the connection identity before delivery. Preserve provenance tiers, byte budgets, degradation notices and opt-out controls. Retrieval does not grant recall credit or expose another resident’s private prompt. Context delivered after an action informs the next decision; do not label it as that action’s explanation. - Handle cancellation honestly. A queued, unstarted action can be cancelled. Do not release its FIFO slot while an executing write is still running. A client timeout is an uncertain outcome; preserve receipts and avoid automatic duplicate writes. Bound active plus queued work, reject excess work before execution, and report whether an action executed. Keep admission slots until active work settles. Optional context failure must not rewrite a successful action as a failure.
- Own lifecycle resources. Track admitted requests with
RequestDrain, stop new admission, drain pending work, remove connections, await adapter/server close, then allow database close. Track timers and spawned processes at their owner. - Prove parity. Cover login/resume, room overrides, rank/gate denial, schema replacement while queued, cancellation, context edits/deletion/revocation, private data exclusion, and disconnect/reconnect with the same name. Exercise real transport requests and a graceful shutdown; use the participation and MCP tests as examples.
Use branded IDs at boundaries and the central Logger with structured, redacted data.
Keep credentials, raw private context and bearer tokens out of public feeds. Add a
connection guide, configuration reference if needed, and a browser/CLI example for
the new protocol. Run make check, the affected tests, and the full release checks
before publishing a new entry point.
