MCP endpoint
The MCP endpoint lets AI agents and tools that speak the Model Context Protocol (MCP) run your calculators. Each calculator your cobrand can use is a tool, and a call returns the same result as the REST API.
Before you start
- A secret API key (
sk_...). Keep it on the server that runs your agent. - The MCP URL. The Go live page in the portal shows it. It ends in
/mcp.
The endpoint is stateless Streamable HTTP. Every request is a POST with a JSON-RPC 2.0 message, Content-Type: application/json and your key as a bearer token. It supports initialize, tools/list and tools/call. The protocol versions are 2025-06-18, 2025-03-26 and 2024-11-05.
Minimal example
export AZTEC_MCP_URL="<your MCP URL>"
export AZTEC_SECRET_KEY="<your secret key>"
# 1. Start a session and negotiate the protocol version
curl -sS -X POST "$AZTEC_MCP_URL" \
-H "Authorization: Bearer $AZTEC_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18"}}'
# 2. List the calculators your cobrand can use
curl -sS -X POST "$AZTEC_MCP_URL" \
-H "Authorization: Bearer $AZTEC_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}'
# 3. Run one
curl -sS -X POST "$AZTEC_MCP_URL" \
-H "Authorization: Bearer $AZTEC_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"auto-loan-payment","arguments":{"vehiclePrice":30000,"downPayment":3000,"tradeInValue":0,"salesTaxRate":6,"apr":7,"termMonths":60}}}'
In an MCP client, set the URL and an Authorization header with your key, and the client does the rest.
A successful call returns result.content, with a line for the headline figure and the disclaimer, and result.structuredContent. The structured content is the REST calculation response, including engineVersion, plus the locale.
Try a failing call
Each of these fails in a different way. They use the same headers as the minimal example.
An unknown method returns -32601:
curl -sS -X POST "$AZTEC_MCP_URL" \
-H "Authorization: Bearer $AZTEC_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":4,"method":"tools/unknown"}'
# {"jsonrpc":"2.0","id":4,"error":{"code":-32601,"message":"Method not found"}}
An unknown tool name, or a calculator your cobrand can't use, returns -32602:
curl -sS -X POST "$AZTEC_MCP_URL" \
-H "Authorization: Bearer $AZTEC_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":5,"method":"tools/call","params":{"name":"no-such-calculator","arguments":{}}}'
# {"jsonrpc":"2.0","id":5,"error":{"code":-32602,"message":"Unknown tool"}}
A calculation that ran but failed is a tool error. The HTTP status is 200, and the result has isError set to true and no structuredContent. content[0].text is a JSON string with code, message and errors. The values below are placeholders for what you would see:
{"jsonrpc":"2.0","id":3,"result":{"isError":true,"content":[{"type":"text","text":"{\"code\":\"validation_failed\",\"message\":\"<summary>\",\"errors\":[{\"field\":\"<input key>\",\"code\":\"<field code>\",\"message\":\"<text>\"}]}"}]}}
For engine_fault, engine_timeout and engine_overloaded, errors is null. Parse the text as JSON, and branch on code.
Options
- Each tool takes the calculator key as its name. Its
inputSchemaandoutputSchemacome from the calculator's definition. - The tool
argumentsare the calculator's inputs. Inputs you leave out take their defaults, as in the REST API. - Tools are read-only. They carry
readOnlyHintandidempotentHint, and the endpoint saves nothing. - Calls use your cobrand's default locale. Text in the result follows that locale.
- A message with no
idis a notification. The endpoint answers202with no body.
Errors and limits
Three kinds of failure can happen, and each shows up in a different place.
HTTP status. These come before any JSON-RPC message:
| Status | Cause |
|---|---|
| 401 | The key is missing or isn't a valid secret key. The response has WWW-Authenticate: Bearer and no body. |
| 415 | The content type isn't JSON. |
| 413 | The body is over 64 KB. |
| 429 | You went over your limit. The body is a problem document with the code rate_limited, and Retry-After gives the seconds to wait. |
| 503 | The service can't verify the key right now. Retry-After is 10 seconds. |
JSON-RPC errors. The body has an error object with a code:
| Code | Meaning |
|---|---|
-32700 | Parse error. The body isn't JSON. The HTTP status is 400. |
-32600 | Invalid request. The message isn't a valid JSON-RPC 2.0 object. The status is 400, or 413 for a body that's too large. |
-32601 | Method not found. |
-32602 | Invalid params. The tool name is missing or unknown, protocolVersion is missing or has no match. An unknown tool and a tool your cobrand can't use give the same error. |
-32603 | Internal error. The data.correlationId field helps support find the cause. |
Tool errors. A calculation that ran but failed returns HTTP 200 with result.isError set to true. The text of the content is JSON with code, message and, for validation, an errors array. The codes are validation_failed, malformed_json, payload_too_large, engine_fault, engine_timeout and engine_overloaded, with the same meaning as in the REST API. Read the errors and correct the arguments.
| Limit | Value |
|---|---|
| Request body | 64 KB |
| Calculation time | 10 seconds |
| Request rate | 600 requests a minute for each cobrand, shared with the REST API. See Rate limits. |
| Caching | Every response has Cache-Control: no-store. |
Show the disclaimer with every result. The server's initialize instructions say the same.
Related API reference
An MCP call runs the same operation as the REST API: