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:
- An unauthenticated request receives a
WWW-Authenticate: Bearerchallenge pointing at/.well-known/oauth-protected-resource/mcp. - That document names the WorkOS authorization server; your client registers and runs the browser sign-in flow there.
- 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:
| Scope | Grants | How it is assigned |
|---|---|---|
read | read-risk functions (all inspection queries) | Default for every authenticated caller |
admin | everything, including write and dangerous functions | Your 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 localcatalogarray.execute({ code })— runs code with themosaicfacade 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:
constbindings,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.