Search

Search the documentation

Protobox
Use cases

Publish an MCP server

Ship a durable, named MCP endpoint your customers add to Claude, Cursor, or any MCP client — backed by a toolset you curate, guarded by OAuth or API keys.

Scenario: Acme wants a headline feature: "Add Acme to Claude." Every Acme customer gets an MCP endpoint that exposes Acme's actions — search tickets, file a ticket, pull a report — usable from any MCP client their team already runs. No MCP protocol code, no hosting, no token plumbing on Acme's side.

Per-user sessions are ephemeral credentials you mint per conversation. A published server is the opposite: a durable, named endpoint with its own inbound auth, meant to be configured once in someone's client and kept.

1. Curate the toolset it serves

A server serves exactly one toolset — decide the surface first:

const toolset = await protobox.toolsets.create({
  name: 'Acme for AI clients',
  description: 'Search, file, and update Acme tickets.',
  tools: [/* tool ids — e.g. from your registered private connector */],
});

Your own product's actions come from registering your API as a connector; catalog tools can sit in the same toolset.

2. Publish

const server = await protobox.mcpServers.create({
  slug: 'acme',
  name: 'Acme',
  toolsetId: toolset.id,
  preset: 'direct',                        // serve tools flat (default)
  inboundAuth: { mode: 'protobox_oauth' }, // or 'api_key' — see below
});

console.log(server.url);
// e.g. https://<your-workspace>.protobox.app/mcp/srv/acme

That URL is live immediately. preset: 'direct' serves the toolset's tools flat — what most clients expect; 'meta' serves search/execute meta-tools instead, which scales better past ~40 tools.

3. Choose inbound auth

The fully-served option: clients hitting the URL get a standards-compliant MCP OAuth flow, hosted end-to-end. Best for endpoints humans configure in Claude or Cursor — nothing to copy around.

inboundAuth: { mode: 'protobox_oauth' }

For machine callers and simple rollouts: mint named keys, hand them out, revoke per-customer.

const server = await protobox.mcpServers.create({
  slug: 'acme',
  name: 'Acme',
  toolsetId: toolset.id,
  inboundAuth: { mode: 'api_key' },
});

const key = await protobox.mcpServers.keys.create('acme', { label: 'initech-corp' });
// key.key is the plaintext — shown ONCE, hashed at rest.
// Callers present it as `X-API-Key: <key>` or `Authorization: Bearer <key>`.

Operate the keyring per customer:

await protobox.mcpServers.keys.list('acme');            // prefixes + last4, never secrets
await protobox.mcpServers.keys.revoke('acme', key.id);  // offboarding — immediate

Operate it

// Evolve the surface — served live, no client reconfiguration:
await protobox.mcpServers.update('acme', { toolsetId: newToolset.id });

// Kill switch — resolution stops immediately:
await protobox.mcpServers.update('acme', { status: 'disabled' });

// Inventory:
const { items } = await protobox.mcpServers.list({ status: 'active' });

Because the server binds a toolset reference, editing the toolset (adding tools, renaming via overrides) updates what every connected client sees — no re-publish step.

What your customer does

One-time setup in their client, using your onboarding doc:

{
  "mcpServers": {
    "acme": { "url": "https://<workspace>.protobox.app/mcp/srv/acme" }
  }
}

With protobox_oauth, their client walks them through sign-in on first use. With api_key, they add the header with the key you issued.

On the roadmap: serving published servers from your own domain (mcp.acme.com), and federating inbound OAuth to your existing identity provider so sign-in is your login page. Today the endpoint lives under *.protobox.app and OAuth is Protobox-hosted.

Production notes

  • One server per audience. A support server for agents, an admin server for internal ops — separate toolsets, separate auth, separate blast radius.
  • Label keys by customer (label: 'initech-corp') so revocation maps to offboarding without a lookup table.
  • Watch it: executions served through the endpoint appear in the same execution log as everything else.

On this page