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. It adds two skills: one 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), and one that drafts an ICP from a repository or a product site and points repositories at it.

claude plugin marketplace add mergetel/agents
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, and on a new account it does not require one at all. The consent completes and the account lands on the free trial, which is entitled: one repository, one product, two connected accounts, ten merged PRs queued a month and twenty-five generations. Every tool works inside those numbers. A tool that answers with a checkout link is telling you a subscription ended, not that you never had one.

On an account with no plan at all, what still works: 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 ten steps in order, each with a status. The agent works the first step it can actually do 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. Never chosen as the next step while anything actionable remains.
unknown
A read failed. The error is attached. It is never shown as todo.
  1. 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).
  2. Describe the product. The agent reads your site and proposes a one-liner and a description, then points each repository at it. The first product is adopted by every repository that names none.
  3. Name the reader. Who every post is written for, and which repositories generate for that reader. Done only when every repository names an ICP that exists; the first ICP is adopted the same way.
  4. Choose a voice. Brand (we) or person (I). Person-voiced copy never auto-publishes.
  5. Connect a social account. Browser: OAuth consent for X, LinkedIn, Mastodon, WordPress.com; an in-app form for Bluesky, Discord, WordPress.
  6. Route repositories to accounts. Social sets, when you have more than one product or a founder account.
  7. Timezone and posting times.
  8. Queue the first post. Preview, generate, show the plan, ask, approve.
  9. Let posts go out without you. The step the rest lead to. It stays open until the posts your rules send go out with nobody pressing a button, and says how close you are: how many wait on an Ask me cell, a Review cell, a roundup, shadow mode or a person voice.
  10. Plan. Last, and done on a new account, which starts on the free trial. It carries the account's limits as facts so an agent can say what you are allowed before you hit a refusal. Only a lapsed subscription turns this into a browser step with a Stripe link.

The same call returns the readiness bars (the ones on the app's Readiness screen), led by Autopilot, the share of your posts that would go out with nobody pressing a button, and the ranked list of fixes, and every call is logged with each step's status, which is how John finds out where people get stuck. Ask an agent “what do I need to do to get set up” and this call is the answer it reads from.

Tools

62 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, "what do I need to do to get set up" is answered here, and so is "how close am I to never pressing a button".

  • 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. It ends on autopilot: open until posts go out with nobody pressing a button.
  • get_statusreadPublishing health in one call: the streak, every product and non-hidden repository against its own posting frequency (or `no target` where none is set), what needs a person, and what to do next. The answer to “how are we doing”.
  • get_readinessreadHow close the account is to running itself: the autopilot bar (the share of posts the rules send with nobody pressing a button) and the four it rests on (reach, brief, 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, Threads, Mastodon or WordPress.com.
  • get_secret_form_linkreadhands over a linkA link to the in-app form for Bluesky, Discord, Slack, WordPress, Resend or Mailchimp, 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, quiet hours, weekend skip, merge cooldown, link policy and every posting slot.
  • get_writing_stylereadAccount-wide anti-AI banned-phrase layer: whether the built-in list is on, extra phrases, allowed exceptions, extra rules, and the resolved list the generator uses.
  • 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 and the media each one carries.
  • get_pr_mediareadThe images and video a pull request attaches to its posts, in order, with alt text, where each came from, whether its link works, how it fits each connected network, and any media hold.
  • get_publish_planreadWhat approving a pull request would do: which drafts go where, in which voice.
  • list_subscribersreadThe account’s own newsletter subscribers, with each one’s consent source and suppression. Also served at GET /api/v1/subscribers.
  • get_highlightsreadThe biggest user-facing things shipped in a recent window, ranked, with any copy already written and where each was already published. For writing about them by hand. Also served at GET /api/v1/highlights.
  • get_product_evidencereadEverything that says what a product is: the saved profile, the repository association, the repository description and README through the installed GitHub App, and the public site, each excerpt carrying its source and its retrieval date, and a repository excerpt also the git object it came from (a web page has none). Distinguishes a source it could not read from one that said nothing.
  • draft_product_profilereadA save_product-shaped draft built from that evidence, with a citation per field, the questions its gaps raise, and an outcome of ready_for_review, needs_input or insufficient_evidence. Leaves unsupported fields empty; never treats a placeholder page or a README roadmap as proof.
  • get_label_mapreadWhat each GitHub label means to the classifier: the account map, the built-in defaults, and every label on the account’s PRs with its count and current meaning.
  • get_routing_rulesreadThe custom rules and routing matrix that decide publish, review, ask, roundup or skip per network for a classified PR, each social set’s changed cells, and the presets.

Configuring

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

  • derive_briefconfigureRead a public product site with a model and propose the product description and the reader. Saves nothing; rate-limited like the demo. Prefer get_product_evidence and draft_product_profile when setting a profile up.
  • save_productconfigureCreate or update a product by name. The account’s first product is adopted by every repository that names none.
  • add_subscribersconfigureAdd the account’s own customers to its newsletter list with a required consent note. Suppressed addresses are skipped; the list is pushed to the connected Resend or Mailchimp, which does the mailing. Also served at POST /api/v1/subscribers.
  • unsubscribe_subscriberconfigureRecord that one address unsubscribed. It is never pushed again, and the next sync marks it unsubscribed at the provider. Also served at DELETE /api/v1/subscribers.
  • save_icpconfigureCreate or update the reader posts are written for, by name. The first ICP is adopted by every repository that names none.
  • link_repo_icpconfigureAssociate a reader with a repository. A repository pointing at no reader starts generating for it; one that already points at another keeps it. Refused for a hidden repository.
  • save_voiceconfigureCreate or update a voice by name: brand (we, or it) 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_repoconfigureSave the app-owned half of a repository’s configuration: product, reader, voice, social set, style rules. The product and the reader are stored as the rows they point at; a name or id that matches nothing is refused, and an empty one clears it.
  • set_repo_hiddenconfigureconfirmHide or unhide a repository. A hidden one records nothing on merge.
  • create_social_setconfigureA named group of connected accounts.
  • 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, quiet hours, weekend skip, merge cooldown and link policy. Only the fields given change.
  • save_label_mapconfigureMap GitHub labels to a kind, size or visibility, or to never-market / ask-me, account-wide. Merges by default; `remove` drops a mapping.
  • save_routing_rulesconfigureconfirmReplace the custom rules and routing matrix, adopt a preset, or reset to the defaults. Validated with the engine’s own parser. Turning on Publish needs the confirm flag and the publish scope.
  • save_writing_styleconfigureAccount-wide anti-AI banned-phrase layer for generated drafts. 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.
  • draft_highlight_postconfigureWrite a Reddit reply, Reddit post, forum reply, X, Bluesky or LinkedIn post about one highlight, in the account’s voice, answering a pasted thread first. Saves and publishes nothing. Costs one generation. Also served at POST /api/v1/highlights/draft.
  • 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.
  • set_pr_mediaconfigureAttach a public image or video link to a pull request, with alt text. Every post of it that has not gone out carries it. The link is checked first; one that fails is recorded with the host’s reason.
  • set_pr_media_altconfigureReplace the alt text of one media item on a pull request.
  • remove_pr_mediaconfigureTake one media item, or all of them, off a pull request’s unpublished posts.
  • 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 which account a connection signs in as, 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, voices, product profiles, readers and readiness, so an agent writes a config file from the real format rather than from memory, and writes a product description from what your README and site actually say rather than from what a product with that name usually does.

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. Merge & Tell stores only its hash, so a leaked one cannot be recovered from the server, 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 saving routing rules that turn on Publish 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
A new account is not this. Signing up puts you on the free trial, which is entitled. Seeing this means a subscription ended, so the account fell back to no plan and generating and publishing are off. 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.