FounderReply

MCP server

The MCP endpoint, in full

MCP (Model Context Protocol) lets an AI agent enumerate and call tools over a standard wire format. FounderReply exposes its agent at a single endpoint — POST /api/mcp — speaking JSON-RPC 2.0 over one HTTP request and one response.

  • tools/list returns all 60 tools with their JSON Schema
  • One key, one workspace — no tool takes a workspace id
  • Social writes enqueue for approval; the endpoint has no way around that queue

The one surface an fr_live_ key opens — 78 of the 90 /api/v1 routes are session-only

founderreply — mcp$curl -s https://founderreply.com/api/mcp \-H "Authorization: Bearer fr_live_…" \-H "Content-Type: application/json" \-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'{ "jsonrpc": "2.0", "id": 1,"result": { "tools": [{ "name": "create_persona", … },{ "name": "generate_blog_posts", … },{ "name": "draft_reply", … },{ "name": "send_reply", … },{ "name": "browse_page", … },] } }200 · one key, one workspace · writes land in the approval queue

Wire contract

The whole contract, transcribed from source

Endpoint
POST /api/mcp
Protocol
JSON-RPC 2.0 over one HTTP request/response
Methods
tools/list · tools/call
Auth
Authorization: Bearer fr_live_… — missing or revoked → HTTP 401
Scope
The key resolves to one workspace; params never carry a workspace id
Key reach
This endpoint, plus /api/v1/voice/mcpdial/numbers?workspace_id= and /api/v1/voice/mcpdial/numbers/{id}?workspace_id= and /api/v1/voice/mcpdial/numbers/available?workspace_id=&country=&type= and /api/v1/voice/mcpdial/numbers/requirements?workspace_id=&country=&type= and /api/v1/voice/mcpdial/verification/status?workspace_id= and /api/v1/voice/mcpdial/verification/profile?workspace_id= and /api/v1/voice/mcpdial/verification/addresses?workspace_id= and /api/v1/voice/mcpdial/verification/addresses/{id}?workspace_id= and /api/v1/voice/mcpdial/verification/documents?workspace_id= and /api/v1/voice/mcpdial/verification/documents/{id}?workspace_id= and /api/v1/brain and /api/v1/brain/proposalsThe other 78 /api/v1 routes are session-only and never read an Authorization header.
Errors
−32700 parse · −32600 request · −32601 method · −32602 params · −32603 internal — all at HTTP 200
Not shipped
SSE / streamable-HTTP transport: server-push, notifications, sessions
founderreply — mcp — POST /api/mcp
curl -s https://founderreply.com/api/mcp \
  -H "Authorization: Bearer fr_live_…" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
Requesttools/call
{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/call",
  "params": {
    "name": "set_autonomy",
    "arguments": { "action": "reply", "mode": "approve" }
  }
}
Response200 · application/json
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "content": [
      { "type": "text",
        "text": "{\"ok\":true,\"action\":\"reply\",\"mode\":\"approve\"}" }
    ],
    "structuredContent": {
      "ok": true, "action": "reply", "mode": "approve"
    },
    "isError": false
  }
}
Every result carries both a text content block and structuredContent — read whichever your client prefers.

A key is bound to one workspace and the tools take no workspace id, so a key can only ever operate its own. Each key also carries scopes — read, draft, publish, admin — and tools/list shows only the tools they cover. set_autonomy over MCP can only lower a dial: raising one, like approving a queued item, is a human decision made in the dashboard, whatever scopes the key holds. And even a lowered dial changes nothing on this endpoint: send_reply and publish_content enqueue whatever the mode says, so the dial changes what the dashboard and the schedulers do with the queued item, not whether the tool call dispatched.

What this server does not do

  • No SSE or streamable-HTTP transport — no server push, no notifications, no sessions. One request, one response.
  • No workspace switching. A key is minted against one workspace and stays there; there is no parameter to change that.
  • No way around the social approval queue. send_reply and publish_content enqueue and return { ok, queued: true, id } — they do not dispatch, on any plan and for any caller.
  • One exception, in Digital PR and named rather than hidden: send_press_pitch dispatches without a queue stop once a workspace has earned auto-send, and then needs a key with the publish scope. No key can approve a queued item — decide_press_approval only rejects. See the guardrails section for what earning it takes.

Tool registry

Every MCP tool, and what it actually does

The whole registry — 60 tools, in the order tools/list returns them. Nothing below is a roadmap item.

FounderReply MCP tools, grouped by area, with the purpose of each tool
ToolWhat it does
Persona & strategy · 3
create_personaGenerate and persist a brand persona / content strategy from a company-focus brief, and update the workspace brand voice.
bootstrap_focusInfer that brief from a connected account’s own recent posts instead of typing it.
get_personaThe workspace’s latest persona, or null if none exists yet.
Content · 12
generate_content_planBuild a rolling calendar of planned posts from the persona over the next horizonDays.
plan_news_postsFind recent news in the brand’s field and schedule one planned post per item on the news template.
generate_blog_postsResearch SEO topics and generate finished, ready-to-publish articles in the brand voice.
list_blog_postsGenerated articles with bodies omitted, optionally filtered by status.
get_blog_postOne article by id, including its full markdown body.
list_syndication_targetsThe workspace’s connected blog syndication platforms (Dev.to, Hashnode, Medium, Ghost) and whether each is enabled.
connect_syndication_targetConnect (or update) one platform’s API credentials for cross-posting published articles. Credentials are encrypted at rest.
disconnect_syndication_targetDisconnect a syndication platform, deleting its stored credentials.
get_post_syndicationsPer-platform syndication state — pending, synced, or failed, with the external URL — for one article.
syndicate_blog_postCross-post an already-published article to every connected target now, with a canonical URL back to its home on your own site.
list_templatesThe available post formats — news, release, personal-update, tip, story, question, announcement.
list_scheduled_postsScheduled posts, optionally filtered by status.
Autonomy & analytics · 2
set_autonomyLower the mode (auto → approve → off) for an action type. A key can only make a dial stricter; raising one is done in the dashboard. Needs the admin scope.
get_analyticsEngagement overview over a trailing window, with a per-content-pillar rollup.
Growth · 2
find_growth_opportunitiesDiscover public conversations the brand could add value to, and persist them.
list_opportunitiesEngagement opportunities, optionally filtered by status.
Engagement — capability-gated per platform · 6
list_messagesInbound DMs on one platform, normalised to { id, origin, sender, content, ts, threadId }.
list_mentionsRecent comments and mentions on the brand.
list_own_postsThe brand’s own recent posts, for persona and context.
draft_replyDraft a reply in brand voice with cross-platform memory recall. Never sends.
send_replyEnqueue a reply to the human approval queue. Does not dispatch.
publish_contentEnqueue an original post to the human approval queue. Does not publish.
SEO · 10
run_seo_auditFetch each page rendered, score it on discrete metrics plus PageSpeed Insights, and reconcile the issue register.
get_seo_overviewSite and page counts, average page score, open issues by severity, keyword coverage, average SERP position.
list_seo_issuesOpen on-page issues across the workspace: error → warn → info.
track_keywordAdd or update a tracked keyword so its SERP position is sampled over time.
get_keyword_rankingsSample current SERP positions and return the latest known position per keyword.
sync_search_consoleIngest Search Console’s authoritative impressions, clicks and average position.
add_seo_siteRegister a website for SEO tracking.
generate_blog_from_seo_gapsFind tracked keywords outside the top 10, read who outranks you, and write against the gap.
generate_conquest_postsMine a competitor’s surface and generate posts that capture the traffic it ranks for.
refresh_stale_blog_postsRedraft published articles in place — same slug, honest updated_at, IndexNow ping when configured.
Browser · 6
browse_pageRead any page as markdown by driving a real browser. The cheapest read.
extract_from_pagePull structured fields out of a page — pricing, contact details, a product list.
screenshot_pageCapture a page as a base64 image. Rides a stored session, so it can shoot logged-in pages.
list_browser_connectionsWhich sites this workspace has a usable sign-in for, and which are still waiting on the user.
connect_browser_accountMint a one-time connect_url to hand the user. Never asks anyone to type a password to the agent.
run_on_pageDrive a goal in a real browser until a success condition holds. Not a posting path — those go through approvals.
Digital PR — journalist outreach · 7
discover_press_contactsFind journalist and outlet contacts by searching with a real browser plus a semantic classifier — reading only the pages a publication put up for pitching, never a personal profile. Saves them as leads; makes no external contact.
generate_press_pitchesResearch sourced, newsworthy angles about the workspace and draft them. Every citation is checked against what was actually scraped, never invented. Makes no external contact.
list_press_pitchesThe generated pitch angles for the workspace.
send_press_pitchPersonalise a pitch for one or more journalist leads and queue each send to the press approval queue. Does not dispatch directly by default — a workspace that has earned auto-send sends immediately, and the response says which happened.
get_press_campaign_statusOne campaign’s coverage status, reply disposition, coverage URL and running conversation summary.
list_press_approvalsPending press approvals awaiting human review — both initial drafts and drafted replies to a journalist’s response.
decide_press_approvalReject a pending press approval. Approving sends the email, so it is a human decision made in the dashboard — over MCP, approve returns an error with the link.
Phone numbers & verification — owner/admin key · 12
list_phone_numbersThe workspace’s numbers — live, in carrier review or suspended — with credits per month, plus recent approvals and rejections.
search_available_numbersNumbers you can buy in a country, the monthly price, and what the carrier still needs. Buys nothing.
buy_phone_numberBuy one. Spends credits; idempotent on the key you send. Where the carrier verifies, it is reserved until approved, and refunded if not.
release_phone_numberGive a number back. Irreversible; needs confirm: true.
get_number_requirementsWhat a country’s carriers verify — fields, address rule, documents — and where the workspace stands.
get_verification_statusCarrier review per country: draft, in review, approved or rejected with the reason.
get_verification_detailsThe profile, addresses and documents on file. Files are never returned.
save_verification_profileWho is behind the numbers — a business or an individual — and the legal fields.
save_verification_addressAn address for verification, one per country.
delete_verification_addressRemove a saved address.
upload_verification_documentUpload a PDF, JPG or PNG (base64, up to 5 MB), checked to be what it says before it is sent.
delete_verification_documentRemove an uploaded document.

Guardrails

The agent gets the same gate you do

An agent holding a key is not a privileged caller. It reaches the product through the controller the dashboard reaches it through, and the queues are the same queues.

A tools/call, in full

Enforced server-side at /api/mcp — not by a client library you could swap out.

Always
Resolve the key to one workspace before any tool runs
Send a social write to the same approval queue the dashboard reads from
Apply the autonomy mode set for that action on that network
Return a JSON-RPC error envelope at HTTP 200 when the protocol fails
Never
Publish because the caller was an agent rather than a person
Touch a workspace the key was not minted against
Send a DM or comment on a third-party thread un-gated unless you raised that dial
Accept a revoked key — the next request is a 401

Press pitches run on a separate queue, and a trust ladder

Journalist outreach has its own review queue — list_press_approvals and decide_press_approval, not the social one — and its own way out of it. A workspace that approves fifteen consecutive pitches without editing them earns auto-send, after which send_press_pitch dispatches directly and returns auto_sent: true. Roughly one in twenty is still sampled back to a human, and a single edit or rejection resets the streak and turns auto-send off again. It is a dial you climb by reviewing, not one a plan grants.

FAQ

What agent developers actually ask.

One: JSON-RPC 2.0 over a single HTTP request and response, at POST /api/mcp. SSE and streamable-HTTP transport are not shipped, which means no server push, no notifications and no sessions — a client that requires them will not connect.
The key does it. An fr_live_ key resolves to exactly one workspace at the edge, and no tool takes a workspace id in its arguments, so there is nothing in a request body that could point a call at someone else’s data.
Not on a social network. send_reply and publish_content enqueue to the human approval queue and say so in their response — they do not dispatch, for any caller. Email is the one place that is not absolute: send_press_pitch normally queues to the separate press approval queue, but a workspace that has approved fifteen consecutive pitches without editing them earns auto-send, after which it dispatches directly (about one in twenty is still sampled back to a human, and any edit or rejection turns auto-send straight back off) — and from then on it needs a key holding the publish scope. No key can approve a queued item: decide_press_approval only rejects; approving happens in the dashboard.
Two layers. A missing or revoked key fails at the transport layer with HTTP 401. Anything that goes wrong inside the protocol — a malformed body, an unknown method, bad params, an internal error — comes back at HTTP 200 with a JSON-RPC error envelope carrying one of −32700, −32600, −32601, −32602 or −32603. A tool the key’s scopes do not cover returns −32001, and a decision only a human may make (approving, raising autonomy) returns −32002; both carry a data object naming the tool.
Against the routes marked bearer in the API reference, and no others: /api/v1/brain, /api/v1/brain/proposals and the phone-number and verification routes under /api/v1/voice/mcpdial try an fr_live_ bearer first and fall back to the session. Every other /api/v1 route authenticates off the signed-in Supabase cookie and never inspects an Authorization header at all, so a key sent there is not rejected on its merits — it is simply not read, and the request fails as unauthenticated. For anything headless, this endpoint is the surface.
Only a key minted by a workspace owner or admin, and only while that person still is one — the same rule as the Phone numbers page. Keys minted before 4 October 2026 do not record who created them and are refused; mint a new one. buy_phone_number spends credits (the first month at once, then rent monthly) and needs an idempotency_key you reuse on retry; release_phone_number is irreversible and needs confirm: true. A refusal such as insufficient_credits or needs_documents comes back as a result with ok: false and the missing items, so the agent can complete the verification and try again.
A real browser on a session you connected yourself. connect_browser_account mints a one-time connect_url you hand to the user, so nobody ever types a password to the agent, and run_on_page is not a posting path — anything that would post goes through approvals like everything else.

Agent-native

Point your agent at one endpoint.

60 tools, one workspace per key, and a queue that does not move because the caller was a model.

Free to start · Approval on by default · No card required