Use Axiom from any MCP client (hosted MCP server)
Add Axiom's hosted MCP server in any MCP client — sign in with OAuth or paste an API key — and search the catalog, inspect schemas, read a node's source, invoke nodes and flows, and pin favorites as typed tools, without installing the CLI.
View as MarkdownAxiom ships a hosted MCP server (Model Context Protocol) so an external agent or user can use Axiom without installing anything. Add the server in any MCP client, sign in with OAuth or an Axiom API key, and your agent can search the catalog, inspect a node or flow's schema, read a node's source code to verify what it does, invoke it synchronously, and pin favorites that show up as native typed tools — all over the gateway, scoped to your tenant.
New here? Start with Quickstart: connect your agent (MCP) — the five-minute path from a URL to a real tool call. This page is the full reference behind it.
This is a consume-only surface. It does not author: you cannot create,
compose, push, or publish from the MCP server. The axiom CLI stays the
fully-featured authoring tool (see Author with Claude Code);
the MCP server is how an agent uses what has been published.
What it is
- Hosted and zero-install. The server runs in the Axiom platform behind the gateway; your MCP client connects to a URL, not a local process. No CLI, no Docker, no SDK in your agent's code.
- Consume-only. Search, inspect, read source, invoke, and pin. No authoring lifecycle.
- Authenticated and tenant-scoped. Your credential — OAuth-issued or an API key you created — authenticates through the same gateway every other Axiom client uses (see API keys). Every action is scoped to your tenant: you see public catalog items, your own private items, and items you've been granted an entitlement to — never another tenant's private data.
- Typed. Pinned nodes and flows surface as first-class MCP tools with a derived input schema, so your agent calls them with structured arguments instead of guessing JSON shapes.
Connect with OAuth (no API key)
If your MCP client supports remote servers with OAuth — Claude's connector directory, and a growing number of others — you do not need an API key at all. Give the client the server URL:
https://api.axiomide.com/mcpThe client discovers everything else and walks you through sign-in:
- It reads Axiom's OAuth metadata (advertised on the
/mcpendpoint itself, per RFC 9728) to find the authorization server. - It registers itself automatically (RFC 7591 dynamic client registration) — there is nothing to create in the Axiom console first.
- Your browser opens an Axiom consent screen naming the application and what it will be able to do. Sign in with GitHub, Google, or email and password, then approve.
- The client receives a token and connects. The whole exchange uses authorization code + PKCE (S256); no secret is ever pasted anywhere.
What you are granting: the same access the axiom CLI has — the connected
client acts as you, within your tenant. It can search the catalog, read schemas
and source, invoke nodes and flows (including with your secrets), and manage
your pins. It cannot see another tenant's data.
The token appears in Console → API Keys like any other session, so revoking it is the same as revoking a CLI session — delete it there and the connection stops working immediately. Tokens renew automatically while you keep using the connection; if a connection sits unused for two weeks it expires and the client will ask you to approve again.
Axiom does not review or verify applications that register. The consent screen tells you which application is asking — only approve one you started yourself from a client you trust. How your data is handled is covered in the privacy policy.
Add the Axiom MCP server with an API key
For a client that does not do OAuth (or when you want a key you manage yourself), authenticate with an Axiom API key — create one in Console → API Keys (see Create and manage API keys).
Then add the server in a single step. The only edit you make is replacing
YOUR_AXIOM_API_KEY with your key — everything else is ready to paste as-is.
Claude Code — run one command:
claude mcp add --transport http axiom https://api.axiomide.com/mcp \
--header "Authorization: Bearer YOUR_AXIOM_API_KEY"Claude Desktop, Cursor, or any client with an mcpServers config file —
paste this block:
{
"mcpServers": {
"axiom": {
"type": "http",
"url": "https://api.axiomide.com/mcp",
"headers": {
"Authorization": "Bearer YOUR_AXIOM_API_KEY"
}
}
}
}That's it — reload your client and the Axiom tools below appear. Under the hood
the server speaks the MCP Streamable HTTP transport at the /mcp path on the
gateway; the gateway validates your credential (the same JWT/API-key authorizer
the HTTP API uses) and stamps the authoritative tenant identity, so you only
ever send the Authorization header — the server never trusts a tenant the
client supplies. An OAuth connection ends up holding exactly the same kind of
credential, which is why both routes behave identically from here on.
The tools
Once connected, tools/list advertises the consume surface:
axiom_search— search the catalog for nodes and flows, lexical and semantic, tenant-scoped (public + your own + what you're entitled to). Results carry the invocable id (node_idfor nodes,graph_idfor flows) so they pipe straight into inspect or invoke.axiom_inspect— get the compiled input/output JSON Schema for a node or a flow (the schema a typed invoke payload must satisfy). A flow may be given by its graph id or by its name, a node by its id or by its ref — see Naming a flow and Naming a node below.axiom_get_source— get a node's handler source code plus a pointer to its full repository (source_url, pinned to the exact published commit).axiom_inspecttells you a node's input/output shape;axiom_get_sourcetells you what it actually does, so you can verify a node before invoking it. The snippet is the handler body;source_urlis the escape hatch for reading code the handler calls into. For an Instance node the source is the inherited generic implementation, andgeneric_packagelabels its origin. Takes the same node ref asaxiom_inspect.axiom_invoke— synchronously invoke a published node or a compiled flow, resolved by id, name/ref, or a pinned name. This wraps the existing invoke endpoints — it does not create a new invoke path.axiom_pin/axiom_unpin— pin a node or a flow as a favorite (one pin targets one node or one flow). Pins live in a shared store: a pin you make from the MCP server is also visible toaxiom list-my-toolsin the CLI, and vice versa.axiom_list_my_tools— list your pinned favorites.tool_kindfilters tonodeorflow; omit it for both. An unrecognized value is an error.axiom_propose— propose a package, node, or flow the catalog doesn't have yet. Reach for it the moment a task needs an artifactaxiom_searchcan't find: your proposal is high-signal demand because you hit the gap doing real work. It is propose-only — an agent can request a missing artifact, but filing product bug reports and feature requests stays with the human (the CLI'saxiom feedbackand the editor's feedback dialog), because those need human repro judgment.
How to name a target, and what an invoke can answer besides a result, are covered in the sections below.
Naming a flow
axiom_invoke and axiom_inspect both accept a flow's name wherever they
accept a graph id:
{"kind": "flow", "target": "christiangeorgelucas/cron-explainer-card"}The name is the flow's fully-qualified identity — <handle>/<flow-name> — and
it always resolves to that flow's current published graph. Add @<version>
(…/cron-explainer-card@1.2.0) to pin an exact published version.
Prefer the name. A graph id identifies one published version, so an id you copied out of an earlier answer can go stale the moment the author republishes, and invoking a stale id fails at run time. A name cannot go stale.
Naming a node
axiom_invoke, axiom_inspect and axiom_get_source all accept a node's
ref — the same <handle>/<package>/<Node> form axiom invoke,
axiom inspect node and axiom source node take on the CLI:
{"kind": "node", "target": "christiangeorgelucas/geo-tools/Haversine"}Omit the version and you get the newest published version of that package.
Add @<version> (…/geo-tools/Haversine@0.3.1) to pin an exact one. Node ids
(ULIDs) and the fully-versioned {owner}/{pkg}/{version}/{node} form still work
unchanged.
Prefer the ref without a version, for the same reason you prefer a flow's name: a version you pinned keeps running forever, silently, after the author ships a fix.
You rarely need to pass kind: a target that names itself is self-identifying —
a flow name has two slash-separated segments, a node ref has three — so pasting
either straight out of axiom_search works.
Streaming targets are refused, not truncated
A flow compiled with pipeline_mode: true, or a pipeline node, emits a
stream of frames rather than one result. This server is synchronous
request/response and has nowhere to put frames 2..n, so invoking one returns a
not-callable result with the reason pipeline_flow or pipeline_node — and
names the surface that can receive them (axiom flow run --stream,
axiom invoke --input-stream).
It refuses rather than returning the first frame, because a partial answer that looks complete is worse than no answer: the unary endpoint would return one aggregated result and discard the rest with nothing to say so.
Telling a paused run from a slow one
When an invoke comes back without a result, the reason says which of two different things happened:
hitl_target— the flow paused for human approval and cannot finish without it. Relay the ask, with theexecution_idin the payload; a human resumes it from the console.exceeds_sync_timeout— the flow is still running. This is not a failure and needs no human. The payload carries theexecution_id; fetch the result withaxiom executions get <execution_id>, or simply invoke again — a cold flow is slow on its first run while each node's sidecar scales from zero, and the next run of the same flow is typically much faster.
Every not-callable payload carries the execution_id (and graph_id /
node_ref), so an agent can always name the run it is talking about.
Knowing a run was mocked
axiom_invoke returns the ingress response as-is, which includes
mocked_nodes (ADR-176) when the flow's artifact serves one or more nodes from
authoring fixtures. A response carrying it is not proof of live
behaviour — treat a non-empty mocked_nodes exactly as the CLI's
▲ MOCKED RUN banner: the run exercised the graph, not the world.
Which tools change things
Every tool is annotated with the MCP spec's behavioural hints, so a client knows before it calls whether a tool merely reads or changes something:
- Read-only —
axiom_search,axiom_inspect,axiom_get_source,axiom_list_my_tools. Safe to call freely; they change nothing. - Writes, not destructive —
axiom_invoke,axiom_pin,axiom_propose.axiom_invokeis additionally marked open-world: it runs published code that may reach external systems, so a well-behaved client treats it as consequential. Pinned typed tools carry the same profile, because each one is anaxiom_invokewith the target already bound. - Destructive —
axiom_unpinalone. It removes a stored pin (and with it the typed tool that pin was producing).
Pinned tools become typed tools
When you pin a node or a flow, it does not just appear in a list — it shows up
on tools/list as a first-class MCP tool with a derived inputSchema
compiled from the target's proto definition. Your agent can then call it
directly with structured arguments, exactly like a native function. Unpin it and
the tool disappears. (A pinned node's schema comes from its compiled input JSON
Schema; a pinned flow's comes from its on-demand OpenAPI spec.)
Current limitations
The hosted MCP server is synchronous only today. Know these before you rely on it:
- Sync-only, ~30s.
axiom_invokewaits for a synchronous result and has a roughly 30-second budget. There is no asyncget_result, no HITL resume, norecommend, and nocancelyet — those are planned but not available today. - A target that can't finish synchronously tells you so — it never hangs or
silently pauses. If you invoke something that pauses for human approval, that
streams, or that outlasts the sync budget,
axiom_invokereturns a clear, explicit not-callable result with a machine-readable reason (hitl_target,exceeds_sync_timeout,pipeline_flow,pipeline_nodeorgrant_required) and theexecution_id. It does not return a bare accepted ack and it does not hang your agent — that is a hard guarantee, not best-effort. The reasons are distinguished from one another, too: see Telling a paused run from a slow one above. - A missing secret grant is a relayable ask. An invoke refused for secret
authorization returns reason
grant_requiredcarrying the ingress's machine-readablemissing[]verbatim — every unsatisfied(node, slot)with its typed reason, the human action that fixes it, and a console deep link. Granting is human-only by design; relaying the exact ask is what you can do. - No authoring. You cannot create, compose, push, or publish from the MCP
server. To author, use the
axiomCLI (see Author with Claude Code). - Tenant-scoped. You see only public catalog items, your own, and what you are entitled to — the same boundary as the HTTP API (see Sandboxing and tenancy).
Next steps
- Call a flow the classic way — Invoke a flow via API.
- Author and publish nodes and flows with the CLI — Author with Claude Code.
- The HTTP API the MCP server wraps — HTTP API reference.