API v1 · Beta
MCP developer clients
Integration candidate, not publicly deployed: the optional POST /mcp endpoint is disabled by default. Use only an explicitly enabled test service and a key whose signed policy permits MCP. Existing JSON access does not grant MCP access.
Supported clients and tools
The adapter supports MCP 2026-07-28 using stateless Streamable HTTP, tested with official Rust and Python clients. Older initialize/session clients, browser Origins, GET event streams, tasks and subscriptions are unsupported. Configure a modern developer client with the endpoint and its Bearer key; let its SDK supply protocol metadata.
Currently tools/list advertises twelve tools: price, implied volatility, Greeks and analytics (each single and batch), regime, and the three model/cost utilities. Follow any opaque nextCursor until absent. Discovery and listing require authentication and bounded utility admission but charge no CUs. All nine existing calculations share the HTTP operation semantics, policy and charges. Regime has no batch form. The existing HTTP cost utilities and public model catalog remain separate.
| Client | Version and evidence | Scope |
|---|---|---|
| Official Python MCP SDK | mcp 2.3.0, httpx2 2.16.0; local Python 3.15.1 and Linux CI; hash lock installs/imports on Python 3.11.2 | All twelve tools over native Streamable HTTP, output-schema validation, partial batches and typed/protocol refusals; public example below tested against a protected local service |
| Official Rust MCP SDK | rmcp 3.8.0 | All twelve tools over the native listener, quote/charge parity, partial batches and typed/protocol refusals |
| Hosted assistants, desktop apps and browser clients | Not qualified | No generic client compatibility claim; hosted authorization is separate work |
| Tool names | Result | Commercial cost |
|---|---|---|
pricing_models | Compiled model capabilities, independent of your entitlement | Zero |
cost_schedule, cost_quote | Effective account schedule and conditional quote | Zero |
price, price_batch | Price with model/engine identity | Required max_cu |
implied_volatility, implied_volatility_batch | Solved volatility and diagnostics | Required max_cu |
greeks, greeks_batch, analytics, analytics_batch | All ten Greeks or an error on this pin; analytics also returns price | Required max_cu |
regime | Applicability, scores and inference provenance; no batch tool | Required max_cu |
Configure and run the Python MCP client
Use Python 3.11 or newer and an operator-provided test endpoint with MCP enabled, its hostname allowed and your key authorized for the MCP representation and requested operations. Scoped keys currently require operator-created accounts; the self-service key screen does not grant MCP access. Use HTTPS for remote services; the example permits HTTP only on loopback.
In Bash or Zsh, install the tested direct versions and replace the loopback origin with your enabled service. CI uses a full hash-locked dependency graph. This setup sends no API requests.
python3 -m venv .venv-mcp
. .venv-mcp/bin/activate
python -m pip install 'mcp==2.3.0' 'httpx2==2.16.0'
export MORPHIQ_API_BASE_URL='http://127.0.0.1:8080'Save mcp_cost_aware.py locally, or copy the complete source below. The script reads MORPHIQ_API_KEY from your secret-managed environment, or prompts with hidden input. Keep the key out of source, prompts sent to an assistant, tool arguments and logs. Never paste it into a URL. For the cURL examples, supply the same environment variable from your secret manager and avoid shell tracing.
Complete Python example
"""Synthetic MCP walkthrough. Utilities only unless --execute is supplied."""
import argparse
import asyncio
import getpass
import json
import os
import re
import sys
from urllib.parse import urlsplit
import httpx2
from mcp import Client
from mcp.client.streamable_http import streamable_http_client
def ceiling(value: str) -> str:
if not re.fullmatch(r"0|[1-9][0-9]{0,19}", value) or int(value) > 2**64 - 1:
raise argparse.ArgumentTypeError("max-cu must be a canonical decimal u64")
return value
async def run(base_url: str, key: str, batch: bool, max_cu: str | None) -> dict:
endpoint = base_url.rstrip("/") + "/mcp"
parsed = urlsplit(endpoint)
local = parsed.scheme == "http" and parsed.hostname in ("127.0.0.1", "localhost", "::1")
if (not (parsed.scheme == "https" or local) or not parsed.hostname
or parsed.username or parsed.password or parsed.query or parsed.fragment
or parsed.path != "/mcp"):
raise ValueError("use an HTTPS service origin, or HTTP loopback for local testing")
option = {
"exercise_style": "european", "pricing_model": "auto", "option_type": "call",
"spot": 100, "strike": 100, "time_to_expiry_years": 1,
"risk_free_rate": 0.05, "dividend_yield": 0, "volatility": 0.2,
}
operation = "price_batch" if batch else "price"
payload = {"requests": [option, {**option, "strike": 105}]} if batch else option
# No proxy inheritance, redirects or retry policy. Credentials stay in headers.
async with httpx2.AsyncClient(
headers={"Authorization": f"Bearer {key}"}, trust_env=False,
follow_redirects=False, timeout=15,
) as http:
async with Client(
streamable_http_client(endpoint, http_client=http),
mode="2026-07-28", read_timeout_seconds=15, cache=None,
) as client:
tools, cursor = [], None
while True:
page = await client.list_tools(cursor=cursor)
tools.extend(tool.name for tool in page.tools)
cursor = page.next_cursor
if cursor is None:
break
report = {"tools": tools}
for label, name, arguments in [
("catalog", "pricing_models", {}),
# Schedule filters use billing operations; batches share price rates.
("schedule", "cost_schedule", {"operation": "price"}),
("quote", "cost_quote", {"request": {"operation": operation, "request": payload}}),
]:
reply = await client.call_tool(name, arguments)
report[label] = reply.structured_content
if reply.is_error:
return report # A refused utility never triggers execution.
# Explicit caller ceiling, never inferred or raised from the quote.
if max_cu is not None:
reply = await client.call_tool(operation, {"request": payload, "max_cu": max_cu})
report["execution"] = reply.structured_content
return report
def main() -> None:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--batch", action="store_true", help="use two synthetic options")
parser.add_argument("--execute", action="store_true", help="submit one billable call after the utilities")
parser.add_argument("--max-cu", type=ceiling, help="explicit ceiling for the whole execution")
args = parser.parse_args()
if args.execute != (args.max_cu is not None):
parser.error("--execute and --max-cu must be supplied together")
base_url = os.environ.get("MORPHIQ_API_BASE_URL")
if not base_url:
parser.error("set MORPHIQ_API_BASE_URL to your enabled test service origin")
key = os.environ.get("MORPHIQ_API_KEY") or getpass.getpass("MCP API key (hidden): ")
if not key:
parser.error("an MCP-authorized key is required")
try:
report = asyncio.run(run(base_url, key, args.batch, args.max_cu))
except Exception:
# Do not print credentials, request headers or exception payloads.
print("No complete response. Check service/client configuration; any execution outcome may be uncertain. No retry was attempted.", file=sys.stderr)
raise SystemExit(1) from None
print(json.dumps(report, indent=2))
if any(isinstance(value, dict) and value.get("status") == "error" for value in report.values()):
raise SystemExit(2) # Structured service refusal was printed with its receipt.
if __name__ == "__main__":
main()
# Discover models, inspect the schedule and quote. No calculation.
python mcp_cost_aware.py
# One price call, at most 1 CU.
python mcp_cost_aware.py --execute --max-cu 1
# Inspect and quote two contracts; no calculation.
python mcp_cost_aware.py --batch
# One two-contract batch, at most 2 CUs for the entire batch.
python mcp_cost_aware.py --batch --execute --max-cu 2
# With a positive effective quote, returns cost_limit_exceeded and zero charge.
python mcp_cost_aware.py --execute --max-cu 0Each run follows every discovery page, calls the catalog, filtered schedule and quote, then stops unless you supplied --execute with --max-cu. Execution makes exactly one calculation call; a batch ceiling covers both items. Your effective prices may exceed these example caps. Inspect the quote, then choose your own ceiling explicitly. The script never derives a higher ceiling, retries, falls back to another protocol or splits a batch. Re-running any execution command may charge again.
Output contains tools, catalog, schedule, quote and, only when requested, execution. Inspect quote.response.quote.total_fcu and the execution receipt, including request_id, fcu_quoted, fcu_charged, policy/schedule identity and engine/model provenance. A service refusal exits with code 2 and preserves its structured response. A connection/protocol failure exits with code 1; any submitted execution may have been charged.
The MorphIQ Python SDK is the separate HTTP client; it does not need an MCP runtime dependency. Its cost utilities and execution ceilings are tracked in SDK PR #41, currently pending merge/release. This MCP candidate incorporates Risk adoption !180, including QdFp/cash model discovery and independently available Greeks. Check the deployed API and SDK schema before rollout.
Inspect capabilities and costs
All MCP calls require the authorized key. pricing_models returns the same account-independent compiled catalog as public HTTP discovery; it does not grant entitlement. cost_schedule returns your effective schedule, optionally filtered by operation and versioned billing model. Those billing IDs may differ from numerical model selectors. Schedule operation filters use billing names such as price; the quotation union uses price_batch for a batch, whose items share the price rates. Filters preserve schedule identity; there is no schedule/key endpoint.
cost_quote accepts the existing operation/request union: price, implied_volatility, greeks, analytics, their _batch variants, and regime. It performs bounded validation/resolution but no numerical calculation, fund reservation or compute-pool admission. Cost metadata reports fcu_charged: "0", plus the pinned policy and schedule. The returned total is the estimate for a later execution, not a charge for the quote.
Set MORPHIQ_API_BASE_URL and MORPHIQ_API_KEY as below. These complete requests inspect models, filter the schedule, and quote a synthetic two-contract batch:
pricing_models
curl --fail-with-body "$MORPHIQ_API_BASE_URL/mcp" \
--header "Authorization: Bearer $MORPHIQ_API_KEY" \
--header 'Content-Type: application/json' \
--header 'Accept: application/json, text/event-stream' \
--header 'MCP-Protocol-Version: 2026-07-28' \
--header 'Mcp-Method: tools/call' \
--header 'Mcp-Name: pricing_models' \
--data '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "pricing_models",
"arguments": {},
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientInfo": {
"name": "example",
"version": "1"
},
"io.modelcontextprotocol/clientCapabilities": {}
}
}
}'cost_schedule
curl --fail-with-body "$MORPHIQ_API_BASE_URL/mcp" \
--header "Authorization: Bearer $MORPHIQ_API_KEY" \
--header 'Content-Type: application/json' \
--header 'Accept: application/json, text/event-stream' \
--header 'MCP-Protocol-Version: 2026-07-28' \
--header 'Mcp-Method: tools/call' \
--header 'Mcp-Name: cost_schedule' \
--data '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "cost_schedule",
"arguments": {
"operation": "price",
"model": "black_scholes_merton/1"
},
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientInfo": {
"name": "example",
"version": "1"
},
"io.modelcontextprotocol/clientCapabilities": {}
}
}
}'cost_quote
curl --fail-with-body "$MORPHIQ_API_BASE_URL/mcp" \
--header "Authorization: Bearer $MORPHIQ_API_KEY" \
--header 'Content-Type: application/json' \
--header 'Accept: application/json, text/event-stream' \
--header 'MCP-Protocol-Version: 2026-07-28' \
--header 'Mcp-Method: tools/call' \
--header 'Mcp-Name: cost_quote' \
--data '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "cost_quote",
"arguments": {
"request": {
"operation": "price_batch",
"request": {
"requests": [
{
"exercise_style": "european",
"pricing_model": "auto",
"option_type": "call",
"spot": 100,
"strike": 100,
"time_to_expiry_years": 1,
"risk_free_rate": 0.05,
"dividend_yield": 0,
"volatility": 0.2
},
{
"exercise_style": "european",
"pricing_model": "auto",
"option_type": "call",
"spot": 100,
"strike": 100,
"time_to_expiry_years": 1,
"risk_free_rate": 0.05,
"dividend_yield": 0,
"volatility": 0.2
}
]
}
}
},
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientInfo": {
"name": "example",
"version": "1"
},
"io.modelcontextprotocol/clientCapabilities": {}
}
}
}'Utilities omit max_cu, consume no CUs, and still obey shared account concurrency and bounded utility-rate/worker limits. Replies are private and non-cacheable. A quote can succeed without funded execution capacity, but it must pass the target operation's entitlement, rollout and input limits. Oversized or invalid batches fail as a whole; no automatic chunking or execution follows.
Make a bounded price call
Set MORPHIQ_API_BASE_URL to your enabled test service and MORPHIQ_API_KEY to its authorized key. This synthetic European call consumes CUs on successful execution. A max_cu of "1" permits at most one CU; a more expensive policy quote is refused before execution.
curl --fail-with-body "$MORPHIQ_API_BASE_URL/mcp" \
--header "Authorization: Bearer $MORPHIQ_API_KEY" \
--header 'Content-Type: application/json' \
--header 'Accept: application/json, text/event-stream' \
--header 'MCP-Protocol-Version: 2026-07-28' \
--header 'Mcp-Method: tools/call' \
--header 'Mcp-Name: price' \
--data '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "price",
"arguments": {
"request": {
"exercise_style": "european",
"pricing_model": "auto",
"option_type": "call",
"spot": 100,
"strike": 100,
"time_to_expiry_years": 1,
"risk_free_rate": 0.05,
"dividend_yield": 0,
"volatility": 0.2
},
"max_cu": "1"
},
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientInfo": {
"name": "example",
"version": "1"
},
"io.modelcontextprotocol/clientCapabilities": {}
}
}
}'The request uses the canonical price request: volatility is annualized, time is in years and prices use the spot/strike currency. MCP returns structuredContent with status and response; the latter contains the normal result and metadata. Numerical prices and Greeks remain JSON numbers. Unsigned 64-bit quantities, including quoted/charged CUs, are exact decimal strings.
Other calculations and batches
These complete examples use synthetic, caller-supplied inputs and a per-call ceiling of "100" CUs. A more expensive effective quote is refused. Quote your request first when needed; these examples do not fetch market data, manage portfolios or place orders.
implied_volatility solves annualized volatility from market_price. greeks uses supplied volatility; sensitivities use the units in the model guide. analytics combines price and Greeks and, when market_price is supplied, returns solve provenance. Resolved Greeks retain their values, including zero. Unavailable quantities are omitted with typed reasons in greeks.unavailable; a valid price or solved IV is preserved. A successful batch may contain both successful items and explicit item errors.
Batch tools accept requests in input order and return indexed item outcomes. A successful tool result can contain failed items: inspect every item. Invalid envelopes or unresolved inputs can reject the whole batch before charging. Numerical failures may remain item errors alongside successful neighbors. The single receipt and spending ceiling apply to the whole batch; no automatic splitting occurs.
regime takes at least 512 positive prices, oldest first. Every supplied value is validated; the latest 512 form the public window and the latest 507 feed inference. Inspect consumed ranges, applicability, per-head scores and model provenance. Scores are not a joint probability distribution; no sampling interval is inferred. See the regime guide for input and output semantics.
analytics — complete request
curl --fail-with-body "$MORPHIQ_API_BASE_URL/mcp" \
--header "Authorization: Bearer $MORPHIQ_API_KEY" \
--header 'Content-Type: application/json' \
--header 'Accept: application/json, text/event-stream' \
--header 'MCP-Protocol-Version: 2026-07-28' \
--header 'Mcp-Method: tools/call' \
--header 'Mcp-Name: analytics' \
--data '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "analytics",
"arguments": {
"request": {
"exercise_style": "european",
"pricing_model": "auto",
"option_type": "call",
"spot": 100,
"strike": 100,
"time_to_expiry_years": 1,
"risk_free_rate": 0.05,
"dividend_yield": 0,
"volatility": 0.2,
"market_price": 10.450583572185565
},
"max_cu": "100"
},
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientInfo": {
"name": "example",
"version": "1"
},
"io.modelcontextprotocol/clientCapabilities": {}
}
}
}'analytics_batch — complete request
curl --fail-with-body "$MORPHIQ_API_BASE_URL/mcp" \
--header "Authorization: Bearer $MORPHIQ_API_KEY" \
--header 'Content-Type: application/json' \
--header 'Accept: application/json, text/event-stream' \
--header 'MCP-Protocol-Version: 2026-07-28' \
--header 'Mcp-Method: tools/call' \
--header 'Mcp-Name: analytics_batch' \
--data '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "analytics_batch",
"arguments": {
"request": {
"requests": [
{
"exercise_style": "european",
"pricing_model": "auto",
"option_type": "call",
"spot": 100,
"strike": 100,
"time_to_expiry_years": 1,
"risk_free_rate": 0.05,
"dividend_yield": 0,
"volatility": 0.2,
"market_price": 10.450583572185565
},
{
"exercise_style": "european",
"pricing_model": "auto",
"option_type": "call",
"spot": 100,
"strike": 100,
"time_to_expiry_years": 1,
"risk_free_rate": 0.05,
"dividend_yield": 0,
"volatility": 0.2,
"market_price": 10.450583572185565
}
]
},
"max_cu": "100"
},
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientInfo": {
"name": "example",
"version": "1"
},
"io.modelcontextprotocol/clientCapabilities": {}
}
}
}'greeks — complete request
curl --fail-with-body "$MORPHIQ_API_BASE_URL/mcp" \
--header "Authorization: Bearer $MORPHIQ_API_KEY" \
--header 'Content-Type: application/json' \
--header 'Accept: application/json, text/event-stream' \
--header 'MCP-Protocol-Version: 2026-07-28' \
--header 'Mcp-Method: tools/call' \
--header 'Mcp-Name: greeks' \
--data '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "greeks",
"arguments": {
"request": {
"exercise_style": "european",
"pricing_model": "auto",
"option_type": "call",
"spot": 100,
"strike": 100,
"time_to_expiry_years": 1,
"risk_free_rate": 0.05,
"dividend_yield": 0,
"volatility": 0.2
},
"max_cu": "100"
},
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientInfo": {
"name": "example",
"version": "1"
},
"io.modelcontextprotocol/clientCapabilities": {}
}
}
}'greeks_batch — complete request
curl --fail-with-body "$MORPHIQ_API_BASE_URL/mcp" \
--header "Authorization: Bearer $MORPHIQ_API_KEY" \
--header 'Content-Type: application/json' \
--header 'Accept: application/json, text/event-stream' \
--header 'MCP-Protocol-Version: 2026-07-28' \
--header 'Mcp-Method: tools/call' \
--header 'Mcp-Name: greeks_batch' \
--data '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "greeks_batch",
"arguments": {
"request": {
"requests": [
{
"exercise_style": "european",
"pricing_model": "auto",
"option_type": "call",
"spot": 100,
"strike": 100,
"time_to_expiry_years": 1,
"risk_free_rate": 0.05,
"dividend_yield": 0,
"volatility": 0.2
},
{
"exercise_style": "european",
"pricing_model": "auto",
"option_type": "call",
"spot": 100,
"strike": 100,
"time_to_expiry_years": 1,
"risk_free_rate": 0.05,
"dividend_yield": 0,
"volatility": 0.2
}
]
},
"max_cu": "100"
},
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientInfo": {
"name": "example",
"version": "1"
},
"io.modelcontextprotocol/clientCapabilities": {}
}
}
}'implied_volatility — complete request
curl --fail-with-body "$MORPHIQ_API_BASE_URL/mcp" \
--header "Authorization: Bearer $MORPHIQ_API_KEY" \
--header 'Content-Type: application/json' \
--header 'Accept: application/json, text/event-stream' \
--header 'MCP-Protocol-Version: 2026-07-28' \
--header 'Mcp-Method: tools/call' \
--header 'Mcp-Name: implied_volatility' \
--data '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "implied_volatility",
"arguments": {
"request": {
"exercise_style": "european",
"pricing_model": "auto",
"option_type": "call",
"spot": 100,
"strike": 100,
"time_to_expiry_years": 1,
"risk_free_rate": 0.05,
"dividend_yield": 0,
"market_price": 10.450583572185565
},
"max_cu": "100"
},
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientInfo": {
"name": "example",
"version": "1"
},
"io.modelcontextprotocol/clientCapabilities": {}
}
}
}'implied_volatility_batch — complete request
curl --fail-with-body "$MORPHIQ_API_BASE_URL/mcp" \
--header "Authorization: Bearer $MORPHIQ_API_KEY" \
--header 'Content-Type: application/json' \
--header 'Accept: application/json, text/event-stream' \
--header 'MCP-Protocol-Version: 2026-07-28' \
--header 'Mcp-Method: tools/call' \
--header 'Mcp-Name: implied_volatility_batch' \
--data '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "implied_volatility_batch",
"arguments": {
"request": {
"requests": [
{
"exercise_style": "european",
"pricing_model": "auto",
"option_type": "call",
"spot": 100,
"strike": 100,
"time_to_expiry_years": 1,
"risk_free_rate": 0.05,
"dividend_yield": 0,
"market_price": 10.450583572185565
},
{
"exercise_style": "european",
"pricing_model": "auto",
"option_type": "call",
"spot": 100,
"strike": 100,
"time_to_expiry_years": 1,
"risk_free_rate": 0.05,
"dividend_yield": 0,
"market_price": 10.450583572185565
}
]
},
"max_cu": "100"
},
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientInfo": {
"name": "example",
"version": "1"
},
"io.modelcontextprotocol/clientCapabilities": {}
}
}
}'price_batch — complete request
curl --fail-with-body "$MORPHIQ_API_BASE_URL/mcp" \
--header "Authorization: Bearer $MORPHIQ_API_KEY" \
--header 'Content-Type: application/json' \
--header 'Accept: application/json, text/event-stream' \
--header 'MCP-Protocol-Version: 2026-07-28' \
--header 'Mcp-Method: tools/call' \
--header 'Mcp-Name: price_batch' \
--data '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "price_batch",
"arguments": {
"request": {
"requests": [
{
"exercise_style": "european",
"pricing_model": "auto",
"option_type": "call",
"spot": 100,
"strike": 100,
"time_to_expiry_years": 1,
"risk_free_rate": 0.05,
"dividend_yield": 0,
"volatility": 0.2
},
{
"exercise_style": "european",
"pricing_model": "auto",
"option_type": "call",
"spot": 100,
"strike": 100,
"time_to_expiry_years": 1,
"risk_free_rate": 0.05,
"dividend_yield": 0,
"volatility": 0.2
}
]
},
"max_cu": "100"
},
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientInfo": {
"name": "example",
"version": "1"
},
"io.modelcontextprotocol/clientCapabilities": {}
}
}
}'regime — complete request
curl --fail-with-body "$MORPHIQ_API_BASE_URL/mcp" \
--header "Authorization: Bearer $MORPHIQ_API_KEY" \
--header 'Content-Type: application/json' \
--header 'Accept: application/json, text/event-stream' \
--header 'MCP-Protocol-Version: 2026-07-28' \
--header 'Mcp-Method: tools/call' \
--header 'Mcp-Name: regime' \
--data '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "regime",
"arguments": {
"request": {
"prices": [
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100
]
},
"max_cu": "100"
},
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientInfo": {
"name": "example",
"version": "1"
},
"io.modelcontextprotocol/clientCapabilities": {}
}
}
}'Costs, errors and retries
max_cu is required on billable tools and applies to the whole call; it is not a conversation-wide budget. Use a canonical decimal string from "0" through "18446744073709551615"; numbers, signs, leading zeroes and overflow are invalid. Repeated successful calls charge again, even when you reuse the same JSON-RPC request ID; it is not an idempotency key. A quote is not a reservation or price lock. Execution obtains a fresh quote; if it exceeds your ceiling, execution is refused with zero charge. Other authentication/funding refusals retain their normal ordering. Never silently raise the ceiling.
Service failures set isError=true and return status: "error", http_status and the original service error/receipt under response. Protocol errors remain JSON-RPC errors; authentication and early transport refusals can be HTTP errors before a tool result exists. Inspect both HTTP and MCP outcomes. The x-request-id header matches the structured service receipt.
A timeout, disconnected client or service-process failure does not prove zero charge. Preserve any known receipt and do not automatically retry uncertain outcomes. A result that cannot be delivered may still have been charged; missing charge evidence is unknown, never zero.
For a positive quote with a zero ceiling, the execution result contains this tested excerpt. The full response also carries its request identity, quote and policy/schedule evidence. HTTP can be 200 for a valid MCP tool response even when its structured http_status is 409 and isError is true.
{
"status": "error",
"http_status": 409,
"response": {
"error": {
"code": "cost_limit_exceeded"
},
"metadata": {
"fcu_charged": "0"
}
}
}Partial batch success and partial Greeks are different. This build can return successful batch items alongside typed item errors, but it does not return partially available Greeks within an item. Never replace an absent or unsupported sensitivity with zero; only interpret partial-Greek availability fields when the served contract actually introduces them.
Limits
Single pricing calculations, catalog and schedule calls accept at most 8 KiB per request and 1,024 JSON nodes including keys. Regime accepts 32 KiB and 32,768 nodes; batch calculations accept 1 MiB and 131,072 nodes. Regime and batch strings/keys are limited to 1,024 UTF-8 bytes. All profiles include MCP framing, have depth 16, and are narrowed by account policy. Single/utility tool values are bounded to 16 KiB and complete responses to 128 KiB. Batch tool values are bounded to 1 MiB and complete responses to 8 MiB. Oversized output fails explicitly with available charge evidence; results are never silently truncated. cost_quote alone accepts up to 1 MiB + 8 KiB, 131,072 JSON nodes and 1,024 UTF-8 bytes per string/key, still at depth 16 and narrowed by policy. Canonical operation byte/cardinality limits also apply inside the quote. The current account batch limits and compute deadlines apply unchanged; the proposed batch/deadline upgrade is not activated by MCP. Normal account concurrency, rate, compute and network deadlines apply across transports. POST is the only supported method; a disallowed Host or any Origin header is refused.