Calco

MCP / AI agents

The service exposes a Model Context Protocol (MCP) server at /mcp. AI agents — Claude Code, Cursor, in-house agent SDKs — and AI web chats such as claude.ai and ChatGPT can connect to it and render documents directly from a conversation, without any custom integration code.

Every tool call is scoped to the caller's organization and authenticated by either an API key or an OAuth 2.0 access token. The agent never needs to know which org it belongs to; that is resolved from the credential.

The three tools

The MCP server exposes three tools in sequence:

ToolWhat it does
list_templatesReturns the templates available in the caller's organization (name, hash, description).
get_template_schemaTakes a template hash and returns the expected data fields, so the agent knows what JSON to build.
render_documentRenders a template with supplied data in the requested format and returns a short-lived download URL (not the file inline).

A typical agent flow:

  1. Call list_templates to find the right template.
  2. Call get_template_schema with the chosen hash to understand the data shape.
  3. Collect or build the data, then call render_document.
  4. Return the download URL to the user — it expires after 15 minutes by default (MCP_RENDER_URL_TTL).

Output formats

render_document accepts the same format values as the HTTP API:

formatWhat you get
pdf (default)Print-ready PDF
htmlSelf-contained HTML (inline SVG pages)
docxFilled-in Word document
xlsxFilled-in spreadsheet
jpgRasterised JPEG pages
webpRasterised WebP pages (lossless)
originalSource file with data substituted

csv is not supported and will be rejected.

For jpg and webp, a multi-page document returns a ZIP archive containing pages/page-001.jpg, pages/page-002.jpg, … Single-page renders return the bare image URL.

Connecting a developer tool (API key)

Agents running locally — Claude Code, Cursor, MCP-compatible SDKs — authenticate with an API key. Generate one under Account → API Keys (dc_live_…).

Claude Code (CLI):

bash
claude mcp add --transport http https://<your-host>/mcp \
  --header "Authorization: Bearer dc_live_<your-key>"

Generic JSON config (works with Cursor, most agent SDKs, and mcp.json):

json
{
  "mcpServers": {
    "calco": {
      "type": "http",
      "url": "https://<your-host>/mcp",
      "headers": {
        "Authorization": "Bearer dc_live_<your-key>"
      }
    }
  }
}

Replace <your-host> with your deployment URL and <your-key> with the key you generated. The server uses the Streamable HTTP transport (POST /mcp).

Connecting a web chat (OAuth)

claude.ai, ChatGPT, and other MCP-capable web chats can connect via OAuth instead of an API key. The chat walks you through a sign-in using your organization's identity provider — no manual token handling needed.

To add the connector:

  1. In claude.ai, open Settings → Integrations and choose Add a custom connector.
  2. Paste the URL: https://<your-host>/mcp.
  3. Complete the OAuth sign-in flow that appears. The connector will be linked to your account and organization.

ChatGPT's equivalent is found under Settings → Connected apps (Developer Mode).

An administrator must pre-register the chat's OAuth client on the organization's identity provider (Ory or another OIDC issuer) before users can connect. Each client needs its redirect URI allowlisted and its access tokens configured to carry the /mcp URL as the token audience (MCP_RESOURCE_URL). For claude.ai the redirect URI is https://claude.ai/api/mcp/auth_callback; for ChatGPT, use the redirect URI from OpenAI's connector documentation. This is a one-time setup per workspace.

Authentication summary

All requests to /mcp are authenticated. There are two supported methods:

  • API key (Authorization: Bearer dc_live_…) — for developer tools, CI pipelines, and in-house agents. Manage keys in the account area.
  • OAuth 2.0 access token — for web-chat connectors. Tokens are validated against the OIDC issuer configured via OIDC_ISSUER_URL; opaque tokens are validated via RFC 7662 introspection when OIDC_INTROSPECTION_URL is set.

Either way, every tool call operates within the caller's single organization. No tool argument ever carries an org identifier — it is always resolved from the credential.