"MCP exposure from the Vox language (SSOT)"

MCP exposure from the Vox language (SSOT)

This page is the contributor SSOT for what “put @mcp.tool on Vox code and it is exposed via MCP” means in this repository today, how that intersects WebSocket and VoxDb, and what roadmap options exist to reduce manual wiring.

Claim policy (read this first)

StatementTrue today?Notes
@mcp.tool on .vox source causes the compiler to emit an MCP-capable stdio JSON-RPC server for that generated crateYesSee Generated app path.
The same decorator automatically registers tools into the shipped vox-mcp binary every editor usesNovox-mcp uses a separate YAML registry and hand-wired Rust; see First-party vox-mcp path.
@mcp.resource is implemented in the core lexer/parser/codegenYes@mcp.resource: nullary fn, exact URI match; resources/list + resources/read in generated mcp_server.rs.

If marketing or tutorials imply a single global “drop a decorator and Cursor sees it,” that is not accurate until the Roadmap: delivering the zero-wiring promise items land.

Two MCP surfaces (do not conflate them)

Generated app path (Vox → compiler)

Flow: .vox module with @mcp.tool → HIR mcp_toolsemit_mcp_server writes src/mcp_server.rs when the module is non-empty (emit/mod.rs).

Wire: JSON-RPC 2.0 over stdio (initialize, tools/list, tools/call). Tool name is the Vox function name; the decorator string is the description.

Scaling: O(n) in the number of decorated functions inside one emitted crate; dispatch is a generated match. No central repo-wide registry file is updated.

Limits today:

  • inputSchema is derived from a small type map (strings, integers, floats, bools); other types fall back to string-ish behavior in the generator.
  • Return values are serialized with serde_json::to_value with coarse error surfaces.
  • This path is orthogonal to Turso/VoxDb unless the generated lib already implements DB-backed fns and the MCP entrypoint calls into that same Rust API.

First-party vox-mcp path

Flow: Unified operation rows in contracts/operations/catalog.v1.yaml project to MCP registry output contracts/mcp/tool-registry.canonical.yaml via vox ci operations-sync --target mcp --write; Rust then consumes this through vox-mcp-registryTOOL_REGISTRY. The same catalog projects transport-independent capability ids / planner metadata to contracts/capability/capability-registry.yaml via --target capability --write (see Capability registry SSOT); agents can call MCP tool vox_capability_model_manifest for the merged JSON view. Per-tool behavior lives in crates/vox-orchestrator/src/mcp_tools/tools/dispatch.rs, JSON Schema in input_schemas.rs, params in params.rs.

Wire: RMCP stdio server; optional HTTP + WebSocket gateway ([`docs/src/reference/cli.md)).

Scaling: First-party registry identity is one catalog row per operation (MCP + CLI + capability YAML are generated); implementation cost is still dispatch + schema + handler code per tool in Rust.

VoxDb: Many vox-mcp tools receive ServerState and talk to Turso / Codex through orchestrator and DB facades. That is not produced by @mcp.tool on user .vox files; it is Rust-native integration.

How MCP fits next to WebSocket and HTTP

Use the right framing for the latency and session model:

Transport (Vox ecosystem)Typical useRelationship to MCP
MCP stdio (generated mcp_server.rs or vox-mcp)Host process spawns server; request/response tool callsCanonical for “model calls a tool” across editors.
MCP-over-HTTP/WS (vox-mcp gateway)Remote/mobile clients, same tool catalog as RMCPSame tool names/schemas as stdio; different transport. See MCP HTTP gateway contract.
OpenClaw WebSocket (vox-skills)Gateway events, subscriptions, upstream skill catalogInterop, not a replacement for MCP tool naming; bridged via openclaw_tools.rs.
SSE / long-lived app streamsIncremental UX, executor outputPrefer stream-native protocols; do not force MCP tool calls per chunk.

Creative SSOT pattern: Treat tool name + JSON Schema as the stable contract. HTTP and WebSocket gateways should reuse that contract (they already converge on tools/list shapes) instead of inventing parallel per-endpoint JSON.

How VoxDb fits

Today:

  • User Vox apps: @table / @query / @mutation codegen lives in the same crate as @mcp.tool fns; MCP exposure is “call Rust that may call DB,” not “MCP reads the schema catalog directly.”
  • vox-mcp: DB is attached to process state (orchestrator + optional Codex); tools like vox_db_* are explicit Rust implementations.

Creative directions (roadmap-friendly):

  1. Manifest table or JSON artifact: Emit a versioned mcp_surface.json (or reuse app_contract.json with an mcp_tools section) from the compiler so CI can diff “what MCP this package exports” without running the binary.
  2. Read models via resources: When @mcp.resource exists, resources could expose schema snapshots or Codex digest for RAG-style hosts—still read-optimized, not a substitute for transactional @mutation.
  3. Optional registration: A future vox-mcp plugin mode could merge manifests from discovered workspace packages into a dynamic tools/list for power users; policy and auth would need to be stricter than static YAML.

Agent-to-agent (A2A) and orchestration

  • Mesh/DB/local bus carry A2A payloads; they are not MCP-framed on the wire.
  • MCP exposes operator/LLM controls such as a2a_send / a2a_inbox (crates/vox-orchestrator/src/mcp_tools/a2a.rs); see [`docs/src/reference/cli.md).
  • Creative: For selected A2AMessageTypes, define JSON sub-schemas shared with MCP tool inputSchema so the same validation runs at message ingress and at tool boundaries—SSOT = schema, transport stays native.

When not to use MCP (even if it is trendy)

  • High-frequency internal queues (orchestrator dispatch, Populi relay): keep domain binary/HTTP semantics and idempotency keys.
  • Large streaming pipelines: WebSocket/SSE/DeI-style lines beat per-chunk tool calls.
  • Security-sensitive execution: MCP host allowlists are coarse; mesh workers need leases, authz, and attestation (see Populi remote execution ADRs).

Roadmap: delivering the “no custom wiring” promise

These are design options, not all committed work. Pick based on product boundary (user apps vs monorepo vox-mcp).

  1. App contract SSOT (shipped): app_contract.json schema_version 2 includes mcp_tools and mcp_resources (names, descriptions, signatures) for workspace tooling and docs generation (app_contract.rs).
  2. Richer schemas from HIR (partial): Generated inputSchema now maps list[T], tuples, and core scalars; extend for structs, enums, and optional fields.
  3. Merge manifests across packages: Workspace build produces a union of MCP surfaces from multiple packages for discovery.
  4. Reduce triple-write in vox-mcp: CI guard: yaml_registry_tools_have_dispatch_match_arms (dispatch.rs); optional codegen for stubs/schemas from tool-registry.canonical.yaml.
  5. Optional host integration: Subprocess or dynamic load so vox-mcp can attach user MCP servers with namespaced tool IDs without hand-editing YAML.
  6. WebSocket parity tests: Contract tests that tools/list over stdio and over the HTTP gateway match for the same server build.