Skip to content
mittr

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.

URLhttps://app.mittr.io/mcp
TransportStreamable HTTP
AuthAuthorization: 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.

ToolWhat it does
mittr_send_eventDispatch an event for reliable, retried delivery: by destination URL, or by eventType to fan out to your configured endpoints
mittr_run_statusAnswer “did the actions in this run land?” for one agentRunId: one verdict plus per-action outcomes, already resolved
mittr_get_eventFetch one event’s current state and delivery progress
mittr_list_eventsList recent events, optionally filtered by status: investigate without an event ID up front
mittr_list_attemptsList every delivery attempt for an event (status code, error, latency)
mittr_replay_eventRe-queue a failed or dead event for another attempt
mittr_list_endpointsList your delivery endpoints and their subscribed event types
mittr_create_endpointCreate 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.

Claude Code supports remote HTTP MCP servers directly:

Terminal window
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:

claude_desktop_config.json
{
"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.

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.

agent.mjs
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:

agent.py
from anthropic import Anthropic
import 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.

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.

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.

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.

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.

mittr_run_status takes an agentRunId and returns one verdict:

VerdictMeaning
all_deliveredEvery action in the run reached its destination
in_progressNothing has failed, but some actions are still being attempted
some_failedAt least one action failed or dead-lettered — this needs attention
partialNothing examined had failed, but the run has more actions than one response carries. truncated is true
none_foundNo 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.