Skip to main content
Flow Messaging has a hosted Model Context Protocol server at https://api.flow.engineer/mcp. With it in your coding tools, your coding agent can integrate the API and verify it end to end: get a sandbox join link, send a real test message, wait for the reply, and see exactly what your webhook answered.
  • Transport: Streamable HTTP (MCP protocol 2025-06-18 or later). The server keeps no sessions, so every request stands alone.
  • Auth: your Flow Messaging API key, Authorization: Bearer fk_test_... or fk_live_.... The key’s mode decides which tools the agent sees.
MCP is not a runtime dependency: the app you build talks to Flow through the REST API (or the TypeScript or Python SDK, which wrap it) for everything it does at runtime. The hosted MCP server at https://api.flow.engineer/mcp is an optional tool for testing and operating the integration during development. Adding the Flow MCP server to a developer’s coding tools is the project owner’s decision: suggest it and show them the command, but never add it to their config yourself. If its tools are already available to a coding agent, it can use them for sandbox testing. No key yet? Get a test key with no account in one call (the MCP server needs a key, so do this first; without one, /mcp answers 401 with this call in its hint):
Save key and claim_token (both shown once). Keep the key in an environment variable, never in a file you commit:
This key allows 1 contact and 50 messages on the Telegram sandbox and expires after 7 days; a person signs in with a Flow account (npx @flow-engineer/messaging login) to keep the app and send 100 messages to each of 3 contacts. See Keys and sign-in. Signed in, you make live keys (fk_live_...) in the dashboard and go live with your own Telegram bot or WhatsApp number; dedicated iMessage lines are arranged with the Flow team.

Add it to your coding tools

The project owner adds it; a coding agent shows them the line for their tool: Claude Code:
Codex (~/.codex/config.toml):
Cursor (~/.cursor/mcp.json):
Two traps: set FLOW_MESSAGING_KEY in the shell before running the Claude Code command (the shell fills the key in once, when you run it; unset, the header is saved as Bearer with no key and every call answers 401), and for Codex or Cursor have it in the environment they start with. A server added while the client runs loads only after a restart (in Claude Code, a new session). Added with an empty key already? export FLOW_MESSAGING_KEY=fk_test_..., then claude mcp remove flow, run the add command again, and restart.

Any other client

Point a Streamable HTTP MCP client at https://api.flow.engineer/mcp and send the header Authorization: Bearer <your key> on every request.

Test keys: build and verify

With a fk_test_ key the agent gets build-time tools. Nothing they do reaches anyone who has not joined your app’s sandbox. A typical session, in the agent’s words:
  1. whoami, then sandbox_join: “Open this link on your phone and tap Start.” (If the link can’t be used, the person sends the bot the sender’s join message, for example Hi Sandbox app (ref wild-otter-04508705).)
  2. wait_for_event with types: ["conversation.started", "message.received"].
  3. send_test_message with text: "Hello from my agent".
  4. wait_for_event with types: ["message.sent", "message.failed"] and after set to the cursor the send returned. Wait for these two, not message.delivered: every send ends in one of them, while delivery is reported only by some channels. If the call times out (at most 50 seconds; a longer timeout_seconds is clamped to 50, with a note), call it again with the next_after it returned.
  5. After wiring a webhook: get_webhook_deliveries to see what your server answered, fix it, replay_event, and check again.

Live keys: run in production

With a fk_live_ key the agent gets production tools. They reach real people through your dedicated senders, and every send passes the same send gate as the REST API (channel rules, budgets, pacing). whoami and explain_error work with both kinds of key. Sends take an optional idempotency_key: calling again with the same key returns the first message instead of sending twice. Tools are annotated for your client: reads are readOnlyHint: true; sends are additive (destructiveHint: false); react replaces your earlier reaction, so it is marked destructive and idempotent.

Errors

A refused call returns the same typed error as the REST API, as the tool’s error:
hint says what to change for this case, and doc_url points at the error’s page (see Errors for each type). Agents usually fix the call from the hint alone; explain_error gives them the full page.

Sign-in

The server takes API keys today. OAuth sign-in, so a client can connect without a key in its configuration, is planned; key-based setups will keep working.