Use Mittr from an AI agent (MCP)
Mittr speaks the Model Context Protocol (MCP). Any MCP-compatible agent (Claude, Claude Code, Cursor, OpenAI Agents, Google ADK, LangChain, CrewAI) can call Mittr as a set of tools to dispatch events for reliable delivery and inspect what happened.
The point: agents are good at deciding what to do, but firing an HTTP call and hoping it lands is fragile. When an agent dispatches an event through Mittr, it inherits the whole delivery pipeline (retries with backoff, dead-letter, and a full audit trail), so the action actually lands and you can see every attempt.
Endpoint
Section titled “Endpoint”| URL | https://app.mittr.io/mcp |
| Transport | Streamable HTTP |
| Auth | Authorization: Bearer mtr_<your-api-key> |
Create an API key in the dashboard under API keys. The key’s role gates what the tools can do. See Roles below.
| Tool | What it does |
|---|---|
mittr_send_event | Dispatch an event for reliable, retried delivery: by destination URL, or by eventType to fan out to your configured endpoints |
mittr_run_status | Answer “did the actions in this run land?” for one agentRunId: one verdict plus per-action outcomes, already resolved |
mittr_get_event | Fetch one event’s current state and delivery progress |
mittr_list_events | List recent events, optionally filtered by status: investigate without an event ID up front |
mittr_list_attempts | List every delivery attempt for an event (status code, error, latency) |
mittr_replay_event | Re-queue a failed or dead event for another attempt |
mittr_list_endpoints | List your delivery endpoints and their subscribed event types |
mittr_create_endpoint | Create a delivery endpoint (a URL that receives events). Private/internal URLs are rejected |
Tools are annotated so MCP hosts can tell reads from writes. The read
tools (get, list_*) carry a read-only hint, the writes
(send, replay, create_endpoint) are marked additive (never
destructive). With these, an agent can discover, send, inspect,
replay, and even set up its own endpoint: the full loop without
leaving the MCP surface.
Every tool and its arguments carry descriptions, and the server returns
short usage instructions when an agent connects, so a capable agent uses
the surface correctly with little extra prompting. For instance payload
is described as a JSON object, so agents send the event body directly
rather than a JSON-encoded string.
Connect
Section titled “Connect”Claude Code
Section titled “Claude Code”Claude Code supports remote HTTP MCP servers directly:
claude mcp add --transport http mittr https://app.mittr.io/mcp \ --header "Authorization: Bearer mtr_your_key"Claude Desktop, Cursor, and config-file clients
Section titled “Claude Desktop, Cursor, and config-file clients”Clients configured through a JSON file connect via the mcp-remote
bridge:
{ "mcpServers": { "mittr": { "command": "npx", "args": [ "mcp-remote", "https://app.mittr.io/mcp", "--header", "Authorization: Bearer ${MITTR_API_KEY}" ], "env": { "MITTR_API_KEY": "mtr_your_key" } } }}Newer clients can connect to a remote Streamable-HTTP server directly
(URL plus headers) without the bridge. Check your client’s MCP docs,
and if it supports remote servers, point it at the URL above with the
Authorization header.
From your own code
Section titled “From your own code”Building an agent programmatically rather than in an interactive client? Anthropic’s Messages API can connect to Mittr’s MCP server for you. Pass the URL and your Mittr key, and Claude discovers and calls the tools itself. No per-tool wiring.
import Anthropic from "@anthropic-ai/sdk";
const claude = new Anthropic(); // reads ANTHROPIC_API_KEY
const message = await claude.beta.messages.create({ model: "claude-opus-4-8", max_tokens: 1024, betas: ["mcp-client-2025-11-20"], mcp_servers: [{ type: "url", name: "mittr", url: "https://app.mittr.io/mcp", authorization_token: process.env.MITTR_API_KEY, // mtr_... }], tools: [{ type: "mcp_toolset", mcp_server_name: "mittr" }], messages: [{ role: "user", content: "Send an order.created event through Mittr, " + "then tell me if it was queued for delivery.", }],});The same shape in Python:
from anthropic import Anthropicimport os
claude = Anthropic() # reads ANTHROPIC_API_KEY
message = claude.beta.messages.create( model="claude-opus-4-8", max_tokens=1024, betas=["mcp-client-2025-11-20"], mcp_servers=[{ "type": "url", "name": "mittr", "url": "https://app.mittr.io/mcp", "authorization_token": os.environ["MITTR_API_KEY"], # mtr_... }], tools=[{"type": "mcp_toolset", "mcp_server_name": "mittr"}], messages=[{ "role": "user", "content": "Send an order.created event through Mittr, " "then tell me if it was queued for delivery.", }],)Other frameworks (OpenAI Agents SDK, LangChain, CrewAI) reach the same remote MCP server through their own MCP-client integrations. The URL and Bearer auth above don’t change.
Agents talking to other agents (A2A)
Section titled “Agents talking to other agents (A2A)”MCP is how an agent calls Mittr as a tool. When agents delegate tasks to each other, the protocol is Agent2Agent (A2A), and its push notifications are webhooks: the serving agent POSTs task updates to a URL the client registered.
Mittr sits under both. It verifies inbound A2A notifications against the credential the sender presents, and delivers outbound ones with the same retries and audit trail as everything else. See A2A push notifications.
What an agent does with it
Section titled “What an agent does with it”Once connected, the agent calls the tools directly. After taking an
action it needs to notify another system about (say, “order 1234
shipped”), it calls mittr_send_event with a destination (or an
eventType that fans out to your configured endpoints) and a JSON
payload. Mittr queues it, delivers it with retries, and returns the
event ID. The agent can then call mittr_get_event or
mittr_list_attempts to confirm it landed or see why it didn’t, and
mittr_replay_event to retry a failed one.
Correlating an agent run
Section titled “Correlating an agent run”mittr_send_event accepts two optional fields that tie events back to
the run that produced them:
agentRunId: a correlation key shared by every event from one run.agentMetadata: a free-form JSON object (framework, step, tool name, …).
Pass them and every event from a run carries the same handle, so you can trace what an agent dispatched on a given run. Ordinary webhook traffic never sets these.
agentRunId earns its place twice: it is also what makes a replayed
step safe when you have no idempotency key to pass. See
Idempotency below.
Idempotency
Section titled “Idempotency”Agent frameworks re-run pre-interrupt code when a run resumes. Without a
stable key that re-execution is a second real action: the same email
sent twice, the same order placed twice. This is the most common way an
otherwise-correct agent causes damage, so mittr_send_event has three
behaviours rather than one.
Pass idempotencyKey. Repeated calls with the same key are
deduplicated. Use this whenever your framework gives you a step or task
identifier that is stable across a resume.
Or pass agentRunId and omit the key. Mittr derives one from the
run plus the action itself — its destination, eventType and
payload. A replayed step re-executes with identical inputs, derives an
identical key, and does not send twice. This is the recommended default
because it needs nothing from you beyond the run id you should already
be passing for correlation.
Pass neither and retries will send again. With no run to key on, nothing distinguishes a replay from a deliberate repeat, so each call is treated as a new action. The tool still works; it just offers no protection.
One consequence worth knowing: inside a single run, two identical sends
to the same destination with the same payload collapse into one. Within
one run that is almost always a replay. If you genuinely want both, pass
distinct idempotencyKey values.
{ "destination": "https://api.example.com/notify", "payload": { "orderId": "ord_123" }, "agentRunId": "run_8f2a"}When a call is deduplicated, mittr_send_event returns
"status": "duplicate" with the original eventIds. That is a success,
not an error: the action exists, nothing was sent twice, and nothing
needs retrying.
Checking whether a run landed
Section titled “Checking whether a run landed”mittr_run_status takes an agentRunId and returns one verdict:
| Verdict | Meaning |
|---|---|
all_delivered | Every action in the run reached its destination |
in_progress | Nothing has failed, but some actions are still being attempted |
some_failed | At least one action failed or dead-lettered — this needs attention |
partial | Nothing examined had failed, but the run has more actions than one response carries. truncated is true |
none_found | No actions carry that run id, usually a typo’d agentRunId |
Use it instead of listing events and reading attempt records yourself.
One call, and the verdict already accounts for retries in flight, so
there is no judgement left to make about whether a failure was
transient. none_found is deliberately distinct from all_delivered
so a mistyped run id can never read as success, and partial exists for
the same reason: a run too large for one response cannot honestly be
called fully delivered.
The tools honor the same roles as the rest of Mittr, read from your API key:
- Editor or higher:
mittr_send_event,mittr_replay_event,mittr_create_endpoint. - Viewer or higher:
mittr_get_event,mittr_list_events,mittr_list_attempts,mittr_list_endpoints.
A read-only (viewer) key can inspect deliveries but can’t send or replay. Every event an agent dispatches is scoped to your workspace. An agent can never read or touch another tenant’s events.