MCP Server
Configure Model Context Protocol servers as an Aforo product type — tool registry, per-tool pricing, and session lifecycle.
MCP Server
Best when your product exposes tools over the Model Context Protocol and you want to bill each tool at a different rate. MCP Server is one of the four generally available product types in Aforo. This page covers what to configure in the catalog. The wire-level metering path — how a tools/call becomes a billable event, how gateway plugins detect it, and how the SDK decorators emit it — lives on the MCP Servers protocol guide.
When to use the MCP Server product type
Pick MCP Server when:
- Your product answers MCP
tools/callJSON-RPC requests, and - Different tools cost you different amounts to run (a semantic search vs. a database write vs. an LLM call), and
- You want the invoice line item to say "SmartSearch.query — 1,200 calls" rather than "API — 3,400 requests".
If your product is a normal REST API you also want to sell to AI agents, pick Agentic API instead. If it is a fully autonomous agent that runs long sessions, pick AI Agent. See the Products page for the full type comparison.
Configuring the tool registry
Every MCP Server product carries a tool registry — the list of tools clients can call, stored in the product's tool_registry JSONB column. Two ways to populate it:
Discover from a running MCP server. Aforo calls the server's tools/list JSON-RPC and returns the tools it advertises:
curl -X POST "https://catalog.aforo.ai/api/v1/products/discover?productType=MCP_SERVER" \
-H "Authorization: Bearer $AFORO_API_KEY" \
-H "X-Tenant-Id: $TENANT_ID" \
-H "Content-Type: application/json" \
-d '{ "serverUrl": "https://mcp.example.com" }'
The response includes every tool's name, description, and inputSchema. Save what you want in the product's tool registry — you don't have to bill on every tool the server exposes.
An older endpoint POST /api/v1/products/discover-mcp still works but is deprecated (2026-04-13). New integrations use POST /api/v1/products/discover?productType=MCP_SERVER.
Author it directly. Set type: "MCP_SERVER" on create and pass a toolRegistry object:
curl -X POST https://catalog.aforo.ai/api/v1/products \
-H "Authorization: Bearer $AFORO_API_KEY" \
-H "X-Tenant-Id: $TENANT_ID" \
-H "Content-Type: application/json" \
-d '{
"name": "SmartSearch",
"type": "MCP_SERVER",
"toolRegistry": {
"tools": [
{ "name": "SmartSearch.query", "description": "Semantic search over indexed documents" },
{ "name": "SmartSearch.index", "description": "Index new documents for search" },
{ "name": "SmartSearch.delete", "description": "Remove documents from the index" }
]
},
"sessionConfig": {
"idle_timeout_sec": 3600,
"concurrent_sessions": 100
},
"integrationMode": "DIRECT"
}'
Field notes:
Tool names in the registry must match exactly what your MCP server sends — SmartSearch.query, not smart_search_query. This is the same string the gateway plugin extracts from the JSON-RPC body and the key dimensionPricing uses at billing time.
Per-tool pricing
Aforo rate plans weight individual tools with different multipliers via the plan's dimensionPricing map. The map is a top-level field on the rate plan; keys are tool names, values are multipliers applied to the per-metric base rate.
curl -X POST https://pricing.aforo.ai/api/v1/rate-plans \
-H "Authorization: Bearer $AFORO_API_KEY" \
-H "X-Tenant-Id: $TENANT_ID" \
-H "Content-Type: application/json" \
-d '{
"name": "SmartSearch — Standard",
"pricingModel": "PER_UNIT",
"currency": "USD",
"productIds": ["prod_smartsearch_uuid"],
"dimensionPricing": {
"SmartSearch.query": 1.0,
"SmartSearch.index": 3.0,
"SmartSearch.delete": 0.5
},
"metricConfigs": [{
"metricName": "Tool Invocations",
"model": "PER_UNIT",
"rate": 0.01,
"includedFree": 0
}]
}'
With this plan, a customer who fires 1,000 SmartSearch.query calls and 100 SmartSearch.index calls in a billing period sees two line items:
Per-tool multipliers only fan out into separate line items when the metric config uses model: "PER_UNIT" with includedFree: 0. On FLAT_RATE, INCLUDED_QUOTA, GRADUATED, VOLUME_TIERED, STAIRCASE, or OUTCOME_BASED, the plan bills the aggregate as a single line item at the base rate — fanning per-tool across those models would either triple-count a flat fee or hand each tool its own full allowance. If per-tool matters for you, use PER_UNIT.
Attach billable units that make sense for the metric shape you care about — the shipped MCP templates are MCP Tool Calls, MCP Session Duration, MCP Active Sessions, MCP Connected Agents, MCP Input Tokens, MCP Output Tokens, MCP Errors, and MCP P95 Latency.
Session lifecycle
MCP sessions are long-lived. A single session may fire fifty tool calls, span an hour, and consume thousands of reasoning tokens. Aforo tracks the full lifecycle server-side:
sessionConfig on the product holds the idle-window and concurrency policy — set idle_timeout_sec too low and sessions the customer expected to be a single conversation split into several; set it too high and concurrency reporting under-counts.
The current session list for a customer is available via the storefront BFF at GET /api/v1/portal/mcp/sessions — this is what the customer-facing dashboard reads.
Troubleshooting
What this guide does NOT cover
- On-the-wire metering. How
tools/callrequests get intercepted, how sessions are correlated, how gateway plugins vs. SDK decorators emit the event — that's the MCP Servers protocol guide. - Billable unit definitions. Aggregation types, unit types, filter conditions, custom units — see Billable Units.
- Customer credential lifecycle. How end-customers register agents, rotate
client_id/client_secret, or bind keys to subscriptions — see Customers. - Operator MCP analytics dashboards. Aggregate views by tool, by agent, and by capability live inside the Aforo product console, not on this docs site.
- The MCP protocol itself. Transport specs, tool schemas, and JSON-RPC framing are defined by the Model Context Protocol project; Aforo tracks the spec but doesn't restate it here.