Mosaic

MCP Server

Connect an AI agent to Mosaic's code-mode MCP server with WorkOS OAuth.

Mosaic exposes a remote Model Context Protocol server for staff automation: an AI agent connects with OAuth, inspects the reviewed function catalog, and runs small TypeScript programs against a typed mosaic.* facade over the admin API.

Connecting

Point any MCP client that supports streamable HTTP + OAuth at:

https://mosaic.nicolaischmid.com/mcp

For example, with the Claude Code CLI:

claude mcp add --transport http mosaic https://mosaic.nicolaischmid.com/mcp

The endpoint is generated from the deployment's canonical app origin. On Vercel production that origin comes from VERCEL_PROJECT_PRODUCTION_URL, so the displayed URL follows the production domain configured for the project.

Authentication is standard OAuth 2.1 (PKCE, dynamic client registration) against WorkOS AuthKit:

  1. An unauthenticated request receives a WWW-Authenticate: Bearer challenge pointing at /.well-known/oauth-protected-resource/mcp.
  2. That document names the WorkOS authorization server; your client registers and runs the browser sign-in flow there.
  3. The resulting access token is sent as Authorization: Bearer … on every MCP request.

You sign in with your normal Mosaic staff account. Every call is authorized against your WorkOS organization membership — a token without staff access to an organizer cannot read or change that organizer's data.

WorkOS Connect binds each OAuth authorization to one organization and includes that selection as org_id in the access token. If you join or switch organizations after connecting an MCP client, reconnect it so WorkOS can issue a token for the selected organization. Organizer bootstrap fails closed when the token has no organization access; Mosaic never accepts a tenant id from tool arguments.

Scopes

Two Mosaic-side scopes gate the catalog by risk level:

ScopeGrantsHow it is assigned
readread-risk functions (all inspection queries)Default for every authenticated caller
admineverything, including write and dangerous functionsYour canonical WorkOS token identifier (issuer + subject, e.g. https://project.authkit.app|user_01ABC…) has a row in the mcpAdmins Convex table

The default is fail-closed: unless the operator creates an mcpAdmins row for your exact canonical token identifier, the connection is read-only and mutations are rejected before dispatch. The grant is bound to the authenticated principal (not the bearer token), so OAuth token refresh never changes your scope mid-session. refunds:create is the only dangerous function — it unwinds sold tickets.

The three tools

The server exposes exactly three tools:

  • docs() — returns the code-mode guide with the full facade reference.
  • search({ query }) — natural-language function discovery (recommended), including risk levels and example arguments.
  • search({ code }) — advanced filtering with a local catalog array.
  • execute({ code }) — runs code with the mosaic facade in scope; facade calls dispatch to reviewed Convex functions.

Pass exactly one of query or code to search:

// search: recommended natural-language discovery
search({ query: "create event ticket offer capacity" });

For advanced search code and execute, submit a TypeScript statement body (no function wrapper), e.g.:

// search: what can I call about orders?
return catalog.filter((fn) => fn.name.startsWith("orders:"));
// execute: sales snapshot for an event
const orders = await mosaic.orders.list({ eventId: "..." });
const paid = orders.filter((order) => order.state === "paid");
return { paid: paid.length, total: orders.length };
// execute (admin scope): place a press hold on a pool
return await mosaic.program.createHold({
  idempotencyKey: "3f8e7d1c-...-fresh-uuid",
  poolId: "...",
  qty: 10,
  label: "press allocation",
});

Every write command takes an idempotencyKey: use a fresh UUID per logical command; retrying with the same key returns the recorded result instead of executing twice.

Sandbox and limits

Submitted code never runs in a JavaScript VM. It is parsed with the TypeScript compiler and interpreted by a whitelisting AST walker:

  • allowed: const bindings, return, await, literals, arrow callbacks, property reads, read-only array/string helpers, mosaic.* calls
  • blocked: loops, assignments, eval/Function/import, Node globals, prototype access, network and filesystem
  • budgets: 16,000 code characters, 10,000 evaluation steps, 15 s wall clock, at most 20 facade calls per execution, 64,000-character bounded output
  • rate limit: 60 requests per minute per user

Every search/execute call is audited with your WorkOS identity, the SHA-256 and length of the submitted natural-language query or code, duration, and outcome — never the query or code text itself. Admin commands additionally record the standard command audit trail.

On this page