Reference

The MCP server, end to end.

Merge & Tell exposes its whole setup to an agent through one server at https://merge.tel/mcp. This page is everything about it: how to connect from each client, what you are allowing when you sign in, every tool by name, how personal tokens and disconnecting work, and what the refusals mean. If you only want to get going, the start page is three commands and a prompt.

Connecting

The server speaks MCP over streamable HTTP with OAuth 2.1, which means any client that supports remote MCP servers can add it by URL and sign in through a browser tab. No client id to obtain, no secret to paste.

Claude Code

claude mcp add --transport http merge-and-tell https://merge.tel/mcp
claude mcp login merge-and-tell

Optionally install the plugin, which adds a skill that teaches the agent the walkthrough (the protocol, the two rules, how to write a voice from five questions, how to commit a .marketing.yml on a branch):

claude plugin marketplace add jfreal/mergetel
claude plugin install merge-and-tell@mergetel

claude.ai and Claude Desktop

Customize, then Connectors, then Add custom connector. Paste https://merge.tel/mcp as the server URL and connect. A sign-in tab opens. In a chat, turn the connector on with the plus button.

Cursor

{
  "mcpServers": {
    "merge-and-tell": {
      "url": "https://merge.tel/mcp"
    }
  }
}

In .cursor/mcp.json for one project or ~/.cursor/mcp.json for all of them. Approve the sign-in when Cursor asks.

Any other client

The server publishes the two discovery documents the MCP authorization specification requires, so a conforming client needs only the URL:

  • https://merge.tel/.well-known/oauth-protected-resource
  • https://merge.tel/.well-known/oauth-authorization-server

Dynamic client registration is on. Only public clients are supported (PKCE with S256 is required; there is no client secret). Redirect URIs must be HTTPS, or HTTP on localhost. A client that cannot do OAuth at all can send a personal token as a bearer header instead.

The prompt

Once connected, this is the whole instruction:

Set up Merge & Tell for me. Use the merge-and-tell MCP server. Call get_setup_state, then work through each step with me until my first post is queued. When a step needs something only I can do in a browser, give me the link and wait. Never ask me for a password, token, or card. Show me what will publish and ask before publishing anything.

Signing in and scopes

The first call from a new client gets a 401 that names the authorization server. The client opens a browser tab at the consent screen. If you are not signed in to Merge & Tell, you sign in (or sign up) first and come straight back. The screen names the client and lists what it will be able to do. Allow, and the client receives a token good for an hour, plus a refresh token that rotates for thirty days.

An agent asks for three scopes. Each is a separate permission:

read
See repositories, connections, voices, schedule, readiness, drafts and the queue.
configure
Create and change products, readers, voices, repository settings, sets and posting times. Preview drafts, read a site, start a checkout or an OAuth connection.
publish
Queue posts for publishing. Each approval still asks the person first.

A client that asks for no scopes gets all three. Scopes this server does not have are dropped from a request; a request with none it recognises is refused. A token without the scope a tool needs gets a refusal naming the scope, never a silent no-op.

Signing up through an agent does not require a plan first. The consent completes, the agent gets its token, and every tool that needs a plan answers with the checkout link until there is one. What works before paying: everything that reads, and preview_pr, which runs the real generator on a public pull request within the same limits as the logged-out demo.

The checklist

One tool, get_setup_state, returns nine steps in order, each with a status. The agent works the first step that is not done and calls it again. The server decides what is next; the prompt never has to.

done
Nothing to do.
todo
A tool here does it. The step names which.
needs_human
Only a browser can. The step carries the link and what to call once you are back.
blocked
An earlier step first.
unknown
A read failed. The error is attached. It is never shown as todo.
  1. Pick a plan. Browser. The agent hands you the Stripe link.
  2. Install the GitHub App. Browser. The link carries a signed state naming your account; the installation is then bound by the GitHub account that pressed Install (or, on a deployment with a single account, to that account).
  3. Describe the product. The agent reads your site and proposes a one-liner and a description.
  4. Name the reader. Who every post is written for.
  5. Choose a voice. Brand (we) or person (I). Person-voiced copy never auto-publishes.
  6. Connect a social account. Browser: OAuth consent for X, LinkedIn, Mastodon, WordPress.com; an in-app form for Bluesky, Discord, WordPress.
  7. Route repositories to accounts. Social sets, when you have more than one product or a founder account.
  8. Timezone and posting times.
  9. Queue the first post. Preview, generate, show the plan, ask, approve.

The same call returns the three readiness bars and the ranked list of fixes, and every call is logged with each step's status, which is how we know where people get stuck.

Tools

44 tools. Each entry names the scope it needs. Tools marked confirm do nothing unless the agent passes confirm: true, which the skill tells it to do only after asking you. Tools marked hands over a link return a URL for a browser and the agent waits.

Where am I

The checklist and the readiness bars. Every walkthrough starts and ends here.

  • get_setup_statereadThe ordered onboarding checklist with a status per step, the readiness bars and the ranked fixes. Call it first and after every step.
  • get_readinessreadThe three readiness bars (reach, health, proof), the merged-PR funnel and the ranked list of things to fix.
  • wait_forreadLong-poll up to 20 seconds for a plan, a repository, a connection or a pull request to appear while the person is in a browser.

Links for the browser steps

Paying, installing the GitHub App and connecting accounts happen in a browser. These tools mint the link and wait for the result.

  • get_checkout_linkconfigurehands over a linkA Stripe Checkout URL for a plan, monthly or yearly.
  • get_github_install_linkreadhands over a linkThe GitHub App install link, carrying a signed state so the installation lands on this account.
  • begin_social_connectconfigurehands over a linkThe OAuth authorization URL for X, LinkedIn, Mastodon or WordPress.com.
  • get_secret_form_linkreadhands over a linkA link to the in-app form for Bluesky, Discord or WordPress, where the person pastes the credential themselves, plus where in that network to create it.

Reading

What the account has. Safe to call any time.

  • list_reposreadEvery synced repository and whether it is hidden.
  • list_connectionsreadEvery connected social account with status, handle and voice, and which networks this deployment can connect.
  • list_social_setsreadThe named groups of accounts a repository can publish through.
  • list_productsreadThe products the account markets.
  • list_icpsreadThe readers posts are written for.
  • list_voicesreadEvery voice and which is the default.
  • get_posting_settingsreadTimezone, pause state, spacing, link policy and every posting slot.
  • get_activityreadThe last 50 Activity feed rows, including what agents changed.
  • get_queuereadQueued, failed and recently published posts.
  • list_recent_prsreadThe 50 most recently updated pull requests in a repository, live from GitHub.
  • get_repo_configreadBoth halves of a repository’s configuration: the app-owned settings and the committed .marketing.yml.
  • suggest_marketing_ymlreadA proposed .marketing.yml built from the repository’s real labels and directories.
  • get_draftsreadThe drafts generated for a pull request, with their queued posts.
  • get_publish_planreadWhat approving a pull request would do: which drafts go where, in which voice.

Configuring

Products, readers, voices, repositories, sets and the schedule. Saves are idempotent on name where a name exists.

  • derive_briefconfigureRead a public product site and propose the product description and the reader. Saves nothing; rate-limited like the demo.
  • save_productconfigureCreate or update a product by name.
  • save_icpconfigureCreate or update the reader posts are written for, by name.
  • link_repo_icpconfigureAssociate a reader with a repository.
  • save_voiceconfigureCreate or update a voice by name: brand (we) or person (I).
  • derive_voiceconfigureFill a voice in from pasted writing or a public URL, as a background job.
  • set_default_voiceconfigureThe voice unbound accounts and the changelog use.
  • set_connection_voiceconfigureMake one connected account post as one voice.
  • configure_repoconfigureconfirmSave the app-owned half of a repository’s configuration: product, reader, voice, set, networks, mode, style rules. Switching to publish mode needs the confirm flag and the publish scope.
  • set_repo_hiddenconfigureconfirmHide or unhide a repository. A hidden one records nothing on merge.
  • create_social_setconfigureA named group of connected accounts. Pro and above.
  • set_connection_setsconfigureThe whole list of sets one account belongs to.
  • set_repo_social_setconfigureRoute repositories through a set by name.
  • set_default_social_setconfigureThe set a repository with none of its own publishes through.
  • save_posting_settingsconfigureTimezone, spacing and link policy. Only the fields given change.
  • add_posting_slotconfigureA weekly wall-clock time that "add to queue" picks from.
  • delete_posting_slotconfigureRemove one slot.

The first post

Preview freely, generate deliberately, approve only after the person has seen the plan.

  • preview_prconfigureRun the real generator on a pull request and return the drafts. Saves nothing, publishes nothing. Spends a generation on a paid account; works unpaid within the demo limits.
  • generate_prconfigureGenerate and keep drafts on a pull request so they can be edited and approved. Costs one generation.
  • update_draft_textconfigureReplace one draft’s copy before it is queued.
  • approve_prpublishconfirmQueue a pull request’s drafts for publishing: now, at a time, or at the next slot.

Diagnosing

For the month-later question, why did nothing post.

  • verify_connectionconfigureAsk the network who we are through a connection, refreshing the token if needed, and record the outcome.
  • disconnectconfigureconfirmRevoke and remove a connected account.

Every result is JSON with ok and, on failure, the provider's own message, redacted of anything secret-shaped. Text that arrives inside a result (pull request titles and bodies, README contents, website copy) was written by strangers; the tool descriptions say so, and the skill tells the agent to treat it as data.

The server also serves resources: mergetel://setup-state and the operator documentation for .marketing.yml, connections, social sets, the schedule and voices, so an agent writes a config file from the real format rather than from memory.

Personal tokens

For a client that cannot do the OAuth dance, or for a script. On Account, under Connected agents, mint a token with a label and the scopes you choose. It is shown once. It starts with mt_pat_, does not expire, and works until you revoke it.

claude mcp add --transport http merge-and-tell https://merge.tel/mcp --header "Authorization: Bearer mt_pat_…"

Treat it like a password. It is hashed on our side, so a leaked one cannot be recovered from us, only revoked.

Disconnecting an agent

Connected agents on Account lists every client that holds a live token and every personal token, with the scopes, when it was added and when it last called. Disconnect revokes every token that agent holds; its next call gets a 401 and it has to be allowed again. From the client side, claude mcp logout merge-and-tell or the connector's Disconnect does the same through the standard revocation endpoint.

Everything an agent changes lands in the Activity feed on the Social screen with the agent's name ("via Claude Code"), next to the connection events the feed already shows. Disconnecting does not undo what it did.

What the server refuses

  • Credentials. No tool accepts a password, app password, webhook URL, token or card. For Bluesky, Discord and WordPress the tool returns a link to the form in the app; you paste it there. An agent that asks you for one in chat is not following the rules, and the answer is the link.
  • Publishing without a confirm. Approving a pull request, disconnecting an account, hiding a repository and switching a repository to auto-publish mode do nothing without confirm: true. Without it they return what would happen. The skill tells the agent to show you the plan and ask first; the server does not rely on that.
  • Acting outside its scopes. The refusal names the scope.
  • Claiming an installation it cannot prove. The GitHub App install link carries a signed state, but that only says which account minted the link; it is not proof of ownership. An installation is bound when the GitHub user that pressed Install is a sign-in on the account (which also lets it move between accounts), or, on a deployment with exactly one account, to that account. With several accounts and no such sign-in it stays unbound, and the Repositories screen says what to do.

When something refuses

401 on every call
The token expired or was revoked. claude mcp login merge-and-tell again, or reconnect the connector. A refresh token works once. If one is presented a second time, every token from that login is revoked, because a second presenter means the token leaked; two sessions sharing one login will both have to sign in again.
"This token does not have the … scope"
Reconnect and allow the scope, or mint a personal token that has it. Tokens do not gain scopes after the fact.
Every tool says there is no plan
The free plan runs nothing. get_checkout_link hands you the Stripe link; wait_for('entitlement') notices when it lands. preview_pr works meanwhile.
The install landed as "unproven" or "pending"
Unproven: the installation is filed under another account and this one has no GitHub sign-in matching whoever installed. Add GitHub as a sign-in method on Account with that GitHub account, then open the install link again. Pending: GitHub's webhook has not arrived, or it arrived and could not match the installer to any account. Give it a minute; if the repositories never appear, the same fix applies.
Rate limited
Registering clients is limited per address, like signing in. Preview and site reading on an unpaid account share the demo's hourly and daily budgets.
The agent keeps calling wait_for
It is waiting for you. Finish the browser step it linked, or tell it you are stuck. Each call caps at twenty seconds.

Running your own

Merge & Tell is open source. The server, its OAuth endpoints and the onboarding checklist are in the repository, and the operator's setup (the migration that adds the token tables, the GitHub App slug, the App's Setup URL) is documented there, not here: docs/mcp-onboarding.md.

MCP server reference — Merge & Tell