Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.getcitable.com/llms.txt

Use this file to discover all available pages before exploring further.

Every MCP session is scoped to one brand and one user. The brand controls what data the session sees and what writes it can make; the user is recorded on every action for audit. Neither is ever passed as a tool input — both are resolved from the transport layer.

Auth context shape

When the server accepts your connection, it resolves a context that looks like:
interface AuthContext {
  brandId: number;     // brand this session reads + writes for
  userId: number;      // user behind the call (audit trail)
  apiKeyId: number | null;  // the API key id, if HTTP-authenticated
  source: string;      // 'stdio:env' | 'http:api_key'
}
The brandId is the most important field — every read filters by it, every write rejects cross-brand IDs against it.

Transport options

stdio (local clients)

Used by Claude Desktop, Cursor, and other local MCP clients. Brand and user come from environment variables you set in your client config:
CITABLE_BRAND_ID=123
CITABLE_USER_ID=456
The user must be an active member of the brand. The check runs at connection time, so a misconfigured env throws immediately rather than failing later on a tool call.

Streamable HTTP (remote agents)

Used by hosted agents and remote integrations. Auth is an API key in the Authorization header:
Authorization: Bearer <api_key>
The key maps to a stored (brand, user, api_key) tuple. The resolved API key id is recorded on the auth context so every write is traceable back to a specific key.

Brand scoping

Every read query filters by your auth context’s brandId at the database layer. Every write tool that accepts an ID looks up that ID and rejects with a 403 if it belongs to a different brand. There’s no MCP-side workaround — the same guard applies whether the client is Claude Desktop, a hosted agent, or any other caller. Example: approve_ticket({ ticket_code: "OTHER-001" }) resolves the ticket, sees it belongs to a different brand, and rejects with a 403. The audit log records the failed attempt.

API key lifecycle

Create API keys in the Citable web app under Settings → API Keys. Each key:
  • Belongs to one user (the creator) and one brand
  • Cannot be used to act on any other brand
  • Can be revoked anytime — revoked keys fail auth immediately
  • Records last_used_at on every successful call
Rotate by creating a new key, updating your integration, and revoking the old one. Keys are shown once at creation time and never displayed again. Treat them like any other secret.

Rate limits

Each brand gets a per-hour rate limit. Response headers tell you where you stand:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 47
X-RateLimit-Reset: 1715731200
The default tier gets 100 calls/hour. Higher tiers raise the read limit; write limits stay in place across all tiers as cost protection on the platform side. If you need a higher limit for a specific integration, get in touch from your account.