calc MCP server
Use calc through the Model Context Protocol (MCP) from an AI assistant. The hosted server needs no local installation.
Endpoint
The server uses Streamable HTTP. GET /health needs no credentials.
Authentication
Claude Desktop with WorkOS
After Gmatter enables WorkOS, members connect https://calc-mcp.fly.dev/mcp from Customize > Connectors. Claude discovers the authorization server, prompts for Google sign-in, and refreshes its token automatically. Do not add an API-key header or OAuth client credentials.
Only verified email addresses in Gmatter's configured domains can connect.
calc-mcp validates the access token's signature, issuer, and audience, then reads the user's verified email from the WorkOS Management API (GET /user_management/users/{id}) using the official workos crate. Profiles are cached for five minutes per user.
AuthKit's OIDC /oauth2/userinfo endpoint cannot be used for this. AuthKit issues MCP access tokens with aud set to this server's resource indicator, and userinfo accepts only tokens audienced to AuthKit itself, so it answers 401 for every token calc-mcp can receive.
Gmatter operators
Configure AuthKit before enabling the connector:
- Enable Client ID Metadata Document and Dynamic Client Registration under Connect > Configuration.
- Enable Google social login.
- Register
https://calc-mcp.fly.dev/mcpas a Resource Indicator and set it as the default. - Set
CALC_MCP_OAUTH_ISSUERto the AuthKit issuer,CALC_MCP_OAUTH_ALLOWED_EMAIL_DOMAINSto the comma-separated Gmatter email domains, andCALC_MCP_OAUTH_WORKOS_API_KEYto a WorkOS API key in thecalcproduction deployment. All three must be set together or the server refuses to start.
The API key must belong to the same WorkOS environment as the issuer — a production key cannot read a staging user, and vice versa.
No custom AuthKit JWT template, client ID, or client secret is required when AuthKit supports CIMD/DCR.
API-key clients
Existing integrations send an API key on every request:
| Header | Purpose |
|---|---|
x-api-key |
Authenticates your organization. |
Missing or invalid credentials receive 401 Unauthorized.
Client configuration
API-key clients
Add the hosted server to any client that supports HTTP MCP servers:
{
"mcpServers": {
"calc": {
"type": "http",
"url": "https://calc-mcp.fly.dev/mcp",
"headers": {
"x-api-key": "YOUR_API_KEY"
}
}
}
}
Tools
| Tool | Purpose |
|---|---|
run_calc_script |
Runs JavaScript against calc for one participant. |
describe_calc_tables |
Returns DDL for the participant-scoped sql() tables. |
get_request_shape |
Returns the calculation-request shape. |
search_calc_api |
Searches the calc API surface. |
run_calc_script requires a non-blank participantKey and code. Set
participantKey on each call, so one MCP connection can query different
participants:
// run_calc_script arguments
{
participantKey: 'ag_vend_austin_tx_000',
code: `
const response = await fetch(
'/programs?program_supplier_key=corteva&time_frame=2026',
);
const programs = await response.json();
return programs.length;
`,
}
Scripts can call calc API paths through fetch, and run DuckDB SQL through
sql(). One sql() reads two things, in one database, so a single statement
can join them:
- The flat, participant-scoped calc tables, when the tool call carries
programSupplierKeyandtimeFrame. Calldescribe_calc_tablesfor their DDL. Theprogramstable includes only released programs the session participant is enrolled in. - Any response
fetch()already returned, passed as an argument — it becomesdata,data2, and so on, in argument order.
// run_calc_script arguments
{
participantKey: 'ag_vend_austin_tx_000',
programSupplierKey: 'corteva',
timeFrame: '2026',
code: `
return sql(
'SELECT program_key, program_label FROM programs ORDER BY 1',
);
`,
}
Pass programSupplierKey and timeFrame together or not at all. Omit both for
a script that only reduces fetch() responses. Keep using fetch() for
calculations and /programs/skus.
Scripts cannot access the filesystem, arbitrary network hosts, or host globals. A script cannot override its participant with request headers.
Limits
Each script has a 10-second wall-clock limit, 128 MiB heap limit, and a
50,000-character result limit. Requests may also be rate-limited; honor
Retry-After when the server responds with 429 Too Many Requests.