Skip to main content
The MCP gateway is a Model Context Protocol server that lets an AI agent drive the platform programmatically. It speaks JSON-RPC 2.0 over a single endpoint, POST /mcp, and exposes the same analytics, flow, connection and configuration capabilities you reach through the admin UI as agent-callable tools — gated by exactly the same permissions. It sits alongside the public Chat API but serves a completely different audience: the Chat API is the browser-facing widget surface, the MCP gateway is the server-side agent surface. Authentication, scoping and rate-limit budgets differ accordingly.

When to use it

Use the MCP gateway when an autonomous agent (or any LLM tool-calling client) needs to read your analytics, inspect flows, or check connections on a caller’s behalf — for example, an assistant that answers “how many conversions did we get last week?” by calling analytics.goal_summary, or one that creates a goal and records a server-side conversion. For a fixed integration that just records deferred conversions or triggers flows from your own backend, prefer the Engine API — it uses a deploy-wide token and a flat REST surface, not the agent-oriented JSON-RPC tool protocol.

Endpoint

POST /mcp HTTP/1.1
Host: flow.example.com
Authorization: Bearer cfp_…
MCP-Protocol-Version: 2025-06-18
Content-Type: application/json
The endpoint is stateless and bearer-only — it never inherits the session, form login or CSRF rules of the interactive admin firewall. One HTTP request carries exactly one JSON-RPC request (batch arrays are rejected).

Authentication

The gateway authenticates with a Personal Access Token (PAT) presented as a bearer credential:
Authorization: Bearer cfp_xxxxxxxxxxxxxxxxxxxxxxxx
Tokens are minted from Account → Personal access tokens (/admin/account/tokens) — see Your account & security › Personal access tokens. A token is shown once in plaintext at creation; copy it then. It acts as you: the call inherits your role and is pinned to your workspace.
A token grants access as the issuing user. Treat it like a password, give each agent its own narrowly-scoped token, and revoke it the moment it leaks.
A request with a missing or invalid token never reaches a method handler — the firewall returns a clean 401, and a request bound to a deactivated user is rejected before dispatch.

Scopes

When you create the token, grant it only the MCP scopes the agent needs. The vocabulary is:
ScopeLabelGrants
mcpMCP: full accessEvery MCP capability below (root scope).
mcp:analytics:readAnalytics: readRead reports, datasets, goals, funnels and telemetry.
mcp:analytics:writeAnalytics: writeCreate and update goals; record conversions.
mcp:flows:readFlows: readList and read flows.
mcp:connections:readConnections: readList connections and their metadata.
mcp:connections:manageConnections: manageRun live connection tests.
mcp:history:readHistory: readRead execution and run history.
mcp:config:readConfig: readRead non-secret configuration values.
Scope resolution is table-driven and fails closed: an unrecognised scope grants nothing. Holding mcp implies every scope; a group root implies its leaves — mcp:analytics implies both mcp:analytics:read and mcp:analytics:write, mcp:connections implies both connection scopes.
Prefer leaf scopes (mcp:analytics:read) over the root mcp so a leaked token can do as little as possible.

Authorization model

Every tool call is gated by three independent layers, all of which must pass. Effective access is the intersection:
effective access = user ACL  ∩  token scope  ∩  tenant (RLS)
  1. User ACL — your role must grant the tool’s required ACL resource (e.g. comerix.insights.analytics). This is the same check the admin UI uses, so the gateway can never do more than you can do in the UI.
  2. Token scope — the presented token’s scopes must imply the tool’s required scope (e.g. mcp:analytics:read). A token scoped below your role is the tighter bound.
  3. Tenant isolation — every read and write is scoped to your workspace (the token’s owning user’s tenant), enforced at the database layer by Postgres row-level security. The tenant is derived from the token and is never read from the request body, so a token cannot reach another workspace.
tools/list applies layers 1 and 2 as a filter: a tool you cannot call is omitted from the listing entirely, so an agent never discovers a capability it cannot use.

Protocol version negotiation

The server speaks these protocol revisions, newest first:
Revision
2025-06-18Latest (default).
2025-03-26Supported.
Send the revision you want in the MCP-Protocol-Version request header. If it is supported it is honoured and echoed back on the response; otherwise the server falls back to its latest (2025-06-18) and returns that in the response header so the client can decide whether to proceed. The same negotiation runs for the protocolVersion field of the initialize request body. Every response carries the negotiated value in the MCP-Protocol-Version header.

The JSON-RPC envelope

Requests and responses follow JSON-RPC 2.0. Request:
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": { "name": "analytics.goal_summary", "arguments": {} }
}
Success result:
{ "jsonrpc": "2.0", "id": 1, "result": { /* method-specific */ } }
Error:
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": { "code": -32002, "message": "…", "data": { /* optional */ } }
}
Notes on framing:
  • jsonrpc must be the string "2.0", and method a non-empty string.
  • params, when present, must be an object (not an array).
  • Batch payloads (a top-level JSON array) are rejected with -32600 Invalid request.
  • A request with no id is a notification: it expects no response and the server replies with an empty 202 Accepted. A request carrying an id (string, number, or null) always gets a JSON-RPC response with HTTP 200.
  • Framing and authorization failures are returned as a JSON-RPC error body (HTTP 200), not as an HTTP error status — read the error.code to branch.

Standard methods

MethodPurpose
initializeNegotiate the protocol revision and read server capabilities + identity.
pingLiveness probe; returns an empty result.
tools/listList the tools the caller is permitted to call (filtered by ACL + scope).
tools/callInvoke one tool by name with an arguments object.
resources/listList the read-only resources the caller may read.
resources/readRead one resource by URI.

initialize

Returns the negotiated protocolVersion, the advertised capabilities, and serverInfo:
{
  "protocolVersion": "2025-06-18",
  "capabilities": {
    "tools":     { "listChanged": false },
    "resources": { "listChanged": false, "subscribe": false }
  },
  "serverInfo": { "name": "comerix-flow-mcp", "version": "1.0.0" }
}
Tool and resource lists are stable within a session (listChanged: false), and resource subscriptions are not offered.

tools/call

params.name is the tool name; params.arguments is the validated arguments object. The arguments are validated against the tool’s inputSchema (JSON Schema, draft 2020-12) before the call runs. A business failure inside a tool (e.g. “Flow not found”, “Invalid report definition”, “Unknown or inactive goal”) is not a JSON-RPC error — it comes back as a normal result whose isError is true:
{
  "content": [{ "type": "text", "text": "Flow not found." }],
  "isError": true
}
A successful result carries a text block plus, for JSON-returning tools, a structuredContent mirror of the same data:
{
  "content": [{ "type": "text", "text": "{\"flows\":[…]}" }],
  "isError": false,
  "structuredContent": { "flows": [ /* … */ ] }
}
Only protocol and authorization problems (bad framing, denied scope/ACL, unknown tool) surface as JSON-RPC errors.

Available tools

Tools are contributed by their owning module. The table below lists the full catalogue, grouped by module, with each tool’s read/write classification. Read tools (readOnlyHint) never mutate state; write tools (destructiveHint) may create, change or remove data. Tools marked external (openWorldHint) reach an outside system. Each tool requires both the listed scope and the corresponding role permission.

Analytics tools (Insights)

ToolTypeScopePurpose
analytics.list_datasetsreadmcp:analytics:readList reporting datasets with their dimensions, measures and filters.
analytics.run_reportreadmcp:analytics:readRun an ad-hoc report definition and return columns + rows. mode caps rows: preview=200, view=500 (default), export=5000.
analytics.list_reportsreadmcp:analytics:readList saved reports; optionally only pinned or only scheduled.
analytics.get_reportreadmcp:analytics:readReturn a saved report definition by report_id.
analytics.suggest_filter_valuesreadmcp:analytics:readSuggest distinct values for a filterable field in a dataset.
analytics.goal_summaryreadmcp:analytics:readSummarise goal completions and value over a date range; set breakdown for per-goal and daily series.
analytics.engagement_summaryreadmcp:analytics:readSummarise conversation/message engagement over a date range, with a daily series.
analytics.funnelreadmcp:analytics:readReturn step-by-step reach counts for a flow_id over a date range.
analytics.top_customersreadmcp:analytics:readList the customers with the most conversions (limit ≤ 50).
analytics.list_telemetryreadmcp:analytics:readList recent raw telemetry events over a date range, optionally filtered by name (limit ≤ 100).
analytics.export_report_csvreadmcp:analytics:readRun a report definition at export scale and return the result as CSV text.
analytics.create_goalwritemcp:analytics:writeCreate a conversion/engagement goal. Idempotent.
analytics.update_goalwritemcp:analytics:writeUpdate an existing goal by goal_id.
analytics.change_goal_statuswritemcp:analytics:writeActivate, pause or archive a goal (status: active / paused / archived).
analytics.record_conversionwrite, externalmcp:analytics:writeRecord a server-side conversion against a goal; idempotent on external_ref.
Date-range tools accept from / to as YYYY-MM-DD and default to the last 30 days (today inclusive). analytics.list_telemetry requires the comerix.insights.telemetry permission; the goal-writing tools require comerix.insights.goals.manage; all other analytics tools require comerix.insights.analytics.

Flow tools (Flow Studio)

ToolTypeScopePurpose
flows.list_flowsreadmcp:flows:readList the workspace’s flows with status and metadata.
flows.get_flowreadmcp:flows:readReturn a single flow, including its definition, by flow_id.
Both flow tools require the comerix.flows.view permission.

Connection tools (Flow Engine)

ToolTypeScopePurpose
connections.list_connectionsreadmcp:connections:readList workspace connections (metadata only — never credentials), optionally filtered by provider_key / status.
connections.get_connection_metadatareadmcp:connections:readReturn non-secret metadata for one connection_id, or for every connection when none is given.
connections.test_connectionexternalmcp:connections:managePerform a live connectivity check against the external provider for one connection_id.
Connection reads require comerix.connections.view; connections.test_connection requires comerix.connections.manage. Stored credentials are never serialised by these tools.

Configuration tools (Config)

ToolTypeScopePurpose
config.listreadmcp:config:readList the configuration fields readable over the API (non-secret only), with their kind and label.
config.getreadmcp:config:readRead one non-secret configuration value by path, optionally at a scope (global, organization:<uuid>, tenant:<uuid>; defaults to the caller’s own scope).
Both require the comerix.config permission, and results are further filtered by the per-section view ACL (comerix.config.<section>.view). Only fields a module declares api_readable are exposed; secret (encrypted or sensitive) values can never be read, and a non-superadmin may only target their own workspace scope. The payloads and rules are identical to the REST surface — see the Configuration read API.

Idempotency

Write tools support safe retries via an Idempotency-Key request header. When you set the header and call a tool that mutates state or claims idempotency (analytics.create_goal, analytics.update_goal, analytics.change_goal_status, analytics.record_conversion), the gateway caches the successful result and replays it for a repeated call instead of performing the side effect again.
POST /mcp HTTP/1.1
Authorization: Bearer cfp_…
Idempotency-Key: create-goal-2026-06-07-purchase
Content-Type: application/json
Details:
  • The cached entry is bound to tenant + calling user + tool name + key + a canonical fingerprint of the arguments. Reusing a key with different arguments (or by a different user) does not replay a stale result — it runs fresh.
  • Only non-error results are cached. A failed call is not stored, so a retry re-attempts the operation.
  • Entries are held for 24 hours.
  • The header is ignored for read-only tools (there is nothing to make idempotent) and when no key is supplied.
Some tools are idempotent at the domain level regardless of the header: analytics.record_conversion deduplicates on its external_ref argument, so a replay returns the existing completion.

Error codes

Errors use the standard JSON-RPC transport codes plus a small set of application codes:
codeMeaning
-32700Parse error — the body was not valid JSON.
-32600Invalid request — not a JSON-RPC request object, a batch array, or a bad jsonrpc/method/id.
-32601Method not found — unknown JSON-RPC method.
-32602Invalid paramsparams was not an object, or tool arguments failed schema validation.
-32603Internal error — unexpected server fault (details are logged, never leaked).
-32001Tool not found — no provider owns the requested tool name.
-32002Authorization denied — the ACL check or the scope check failed; error.data distinguishes them (resource vs required_scope).
-32003Rate limited — the per-token rate limit was exceeded.
These are returned in the JSON-RPC error object (HTTP 200); the firewall still returns plain HTTP 401 for a missing or invalid bearer token before any JSON-RPC processing. For the platform-wide REST error envelope, see Errors.

Worked example

A full minimal session — initialize, discover tools, then call one. Replace cfp_… with your token and the host with your deployment. 1. Initialize the session and read capabilities:
curl -sS https://flow.example.com/mcp \
  -H "Authorization: Bearer cfp_…" \
  -H "MCP-Protocol-Version: 2025-06-18" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "initialize",
    "params": { "protocolVersion": "2025-06-18" }
  }'
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "protocolVersion": "2025-06-18",
    "capabilities": {
      "tools":     { "listChanged": false },
      "resources": { "listChanged": false, "subscribe": false }
    },
    "serverInfo": { "name": "comerix-flow-mcp", "version": "1.0.0" }
  }
}
2. List the tools your token may call:
curl -sS https://flow.example.com/mcp \
  -H "Authorization: Bearer cfp_…" \
  -H "Content-Type: application/json" \
  -d '{ "jsonrpc": "2.0", "id": 2, "method": "tools/list" }'
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "tools": [
      {
        "name": "analytics.goal_summary",
        "title": "Goal / conversion summary",
        "description": "Summarises goal completions and value over a date range; set breakdown for per-goal and daily series.",
        "inputSchema": { "type": "object", "properties": { /* … */ } },
        "annotations": {
          "readOnlyHint": true, "destructiveHint": false,
          "idempotentHint": true, "openWorldHint": false
        }
      }
    ]
  }
}
3. Call a tool — a goal summary for a custom date range:
curl -sS https://flow.example.com/mcp \
  -H "Authorization: Bearer cfp_…" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 3,
    "method": "tools/call",
    "params": {
      "name": "analytics.goal_summary",
      "arguments": { "from": "2026-05-01", "to": "2026-05-31", "breakdown": true }
    }
  }'
{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {
    "content": [{ "type": "text", "text": "{\"summary\":{…},\"by_goal\":[…],\"timeseries\":[…]}" }],
    "isError": false,
    "structuredContent": {
      "summary":    { /* … */ },
      "by_goal":    [ /* … */ ],
      "timeseries": [ /* … */ ]
    }
  }
}
Read result.structuredContent for the machine-readable payload; the text block mirrors it as JSON for clients that only consume content blocks.

Permissions

The MCP gateway grants no permissions of its own — every tool is gated by the permission of the module that owns it, in addition to the token scope.
Tool groupPermission
Analytics reports, datasets, funnels, engagement, customerscomerix.insights.analytics
analytics.list_telemetrycomerix.insights.telemetry
Goal create/update/status, record conversioncomerix.insights.goals.manage
Flow toolscomerix.flows.view
Connection readscomerix.connections.view
connections.test_connectioncomerix.connections.manage
Configuration toolscomerix.config (+ per-section comerix.config.<section>.view)
The bearer token itself is managed under your account (comerix.account.tokens.manage — see Your account & security).