Embed Protobox in Your Product
Give each of your end-users a scoped, revocable MCP endpoint — mint sessions server-side, let their agents connect their own accounts.
You run a product whose users bring their own AI agents (Claude Desktop, Claude Code, custom MCP clients). Protobox lets you hand each user a personal MCP endpoint that is scoped to a toolset you choose and to that user's own connected accounts — without you building any OAuth, token storage, or MCP plumbing.
Concepts
| Concept | What it is |
|---|---|
| Workspace | Yours. Holds your API key, toolsets, and billing. |
| Toolset | The set of integration actions your users' agents may reach. |
| Session | One end-user's scoped MCP credential: { userId, toolsetSlug } → a URL + bearer token. |
| Connection | That user's own account login (their GitLab, their Gmail) — connected by them, stored and refreshed by Protobox. |
1. Mint a session server-side
Mint one session per logged-in user, from your backend only:
import { ProtoboxSDK } from '@protoboxai/sdk';
const protobox = new ProtoboxSDK({ apiKey: process.env.PROTOBOX_API_KEY! });
const session = await protobox.sessions.create({
userId: 'user_123', // YOUR user id — the session is hard-bound to it
toolsetSlug: 'support', // optional: restrict to one toolset
});
// session.mcpUrl → https://<your-ws>.protobox.app/mcp/s/<sessionId>
// session.token → shown ONCE. Store it encrypted server-side; it cannot be
// retrieved again (only a hash is stored).Hand the user's agent the URL plus the token as a bearer header.
Claude Desktop (claude_desktop_config.json):
{
"mcpServers": {
"yourproduct-tools": {
"command": "npx",
"args": [
"mcp-remote", "https://<your-ws>.protobox.app/mcp/s/<sessionId>",
"--header", "Authorization: Bearer <session-token>"
]
}
}
}Claude Code:
claude mcp add --transport http yourproduct-tools \
https://<your-ws>.protobox.app/mcp/s/<sessionId> \
--header "Authorization: Bearer <session-token>"Any MCP client (Streamable HTTP):
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
const transport = new StreamableHTTPClientTransport(new URL(session.mcpUrl), {
requestInit: { headers: { Authorization: `Bearer ${session.token}` } },
});
const client = new Client({ name: 'yourproduct', version: '1.0.0' }, { capabilities: {} });
await client.connect(transport);The session exposes exactly three meta-tools — search_actions,
get_action_schema, execute_action — never your workspace's admin tools.
The toolset scopes which integration actions those meta-tools may reach.
2. The auth_required contract
When the agent calls execute_action for an integration the user hasn't
connected yet, the tool call succeeds and returns a structured payload
instead of a result:
{
"status": "auth_required",
"integration": "gitlab",
"message": "Connect gitlab to use this action.",
"connectUrl": "https://app.protobox.ai/connect/gitlab?method=managed&userId=user_123"
}The connectUrl is a hosted connect page already carrying the session's
bound user id — the agent (or your UI) surfaces the link, the user consents
and logs into their own account, and the agent simply retries the action.
Nothing to build on your side beyond showing the link.
3. Lifecycle & safety
-
Token shown once. Only a hash is stored;
get/listnever return it. Lost token → revoke and mint a new session. -
Revoke on sign-out/offboarding:
const sessions = await protobox.sessions.list({ search: 'user_123' }); await Promise.all(sessions.map((s) => protobox.sessions.revoke(s.id)));A revoked session's MCP endpoint immediately returns
401. -
Observability: every search/execute/connection event is logged for 90 days —
protobox.sessions.listEvents(id)returns{ items, nextCursor }(newest first; passnextCursorback ascursorto page).protobox.sessions.get(id)includes an aggregatesummary. -
Impersonation is ignored by design. The caller identity is hard-bound to the session's
userIdat mint time; identity headers sent by the agent are discarded. One user's session can never read another user's connections.
4. Security notes
- Treat session tokens as per-user secrets: mint server-side only, store encrypted, never log them, never ship them in frontend bundles.
- Your workspace API key stays on your backend — it can mint/revoke ALL sessions; the session token can only act as its one user.
- Scope sessions with a
toolsetSlug— least privilege for what the agent can even discover, not just execute.
Worked example
A complete ~100-line Express backend implementing this page (login stub → mint
→ agent config → revoke) lives in the repo:
examples/partner-embed.