Carl-WYou wrote an MCP server. It works. Almost nobody installs it, and the few who do never get past the blank prompt box. The honest version of why, the second install nobody builds for, and the native distribution that ends it.
Originally published on the Remoet blog.
You wrote an MCP server. It has thirty tools. It works. You posted it to a couple of directories, maybe wrote a tweet. Nobody is installing it.
Here is the part nobody tells you, and it is worse than the install problem. Of the people who do install it, almost none of them ever use it. They connect, they land back in their tool, they stare at a blank prompt box, and they leave. You did not have one adoption problem. You had two, and the second one is the one nobody is building for.
We shipped Remoet's MCP server through five iterations and watched people walk the path from "heard about it" to "agent made a useful call." Most did not make it. Some of the loss is the install itself, which is genuinely hard and is most of what this post is about. But the drop that surprised us, the one we had built nothing for, comes after the connection works. The technical install gets your server connected. The second install gets the capability into the user's head. Almost everyone ships the first and ignores the second.
Most people treat distribution as a marketing problem that starts after the engineering is done. It is not. Every step between hearing about your server and getting a useful tool call out of it is engineering, and if any step is hostile, the user drops. The install path is a product: you design it, build it, watch people walk through it, and fix the spots where they fall. We assumed our problem was "we need to be in more directories." It was not. Even when someone found us, the path leaked users at half a dozen steps we had never measured.
Our own funnel shows the shape, and I will be upfront that the agent path is new, so the absolute numbers are small. The shape is the lesson. The drop that should scare you is at the end, not the start: among the people who reached our connect screen, fewer than half ever produced a single tool call. A few could not tell whether it had worked. Most connected fine and simply had nothing to say to it. They got in, and then nothing happened. That is not a leak you patch with more directories or a better tweet. It is the second install, and we had built nothing for it.
The reason MCP install is hard is structural: you do not own the surface where the install happens. Your server lives in your infrastructure. The install happens inside someone else's client, in a config file you have never seen, on a machine you cannot inspect. You are giving instructions for a room you are not standing in. Here is where that goes wrong.
The N×M problem. There are N clients (Claude Desktop, Claude Code, Claude Web, Cursor, Windsurf, VS Code, OpenClaw, and more every month) and M servers. Each client wants a slightly different config shape, a different file in a different location, a different idea of how auth works. You are one of the M, and you are being asked to document yourself correctly for all of the N.
Here is the same server, ours, for three different clients. Claude Code wants a terminal command:
claude mcp add remoet https://api.remoet.dev/mcp --scope user --transport http --header "Authorization: Bearer YOUR_KEY"
Cursor wants JSON at ~/.cursor/mcp.json:
{ "mcpServers": { "remoet": { "type": "http", "url": "https://api.remoet.dev/mcp", "headers": { "Authorization": "Bearer YOUR_KEY" } } } }
Codex wants TOML at ~/.codex/config.toml:
[mcp_servers.remoet]
url = "https://api.remoet.dev/mcp"
http_headers = { "Authorization" = "Bearer YOUR_KEY" }
Same server. Three formats, three locations. And it gets worse inside the JSON ones, because the field that holds the URL is url in Cursor, serverUrl in Windsurf, and httpUrl in Gemini CLI, and the wrapper object is mcpServers in most of them but servers in VS Code. Get one field name wrong and the user gets a silent failure with no hint which line broke. We maintain nine of these. Most servers document one and lose everyone on the other eight.
The key is already minted and waiting in the field, masked. Below it, nine client tabs. The config shape, the file path, and even the field names differ for every one, and we do that translation once so the user never has to.
The auth fork. API key, OAuth, or no auth. Each client handles this differently, and the user usually does not know which one they need. A non-technical Claude Web user should never see the words "API key." A Claude Code user expects to paste one. If you make the user choose, a chunk of them choose wrong and never come back.
The "did it even work?" void. This is the quiet killer. The user pastes your config, switches to their agent, asks it something, and has no idea whether the connection is live or whether the agent is just hallucinating a plausible answer. There is no green light. There is no confirmation. The anxiety of not knowing is itself a drop point, and you never see it in any log because the user just wandered off.
None of these are exotic. Every one of them is a place we watched real people fall off our own path.
The fixes were not clever. They were boring engineering on a thing we had been ignoring. Steal them.
Make the install path a real page, not a README section. A "Setup" heading with a JSON snippet is documentation for the few who will hand-edit claude_desktop_config.json without flinching. Everyone else needed the path to be easier than the thing they were avoiding. Build an actual page: per-client tabs, a key ready to go, a verification check.
Generate the key before the user asks. If you can identify the user, mint it on first visit and put it in the page. They copy one string, not three. Every step between landing and "I have a key" is a step someone drops on.
Add per-client tabs (the panel above). Do the N×M translation once, in your page, so the user never has to. This was our single biggest win, and Context7 does it across forty-plus clients. The strongest part of their UX, and not a coincidence.
Poll for the first tool call. When the user pastes your config and asks their agent to do something, your page should know within seconds. The moment a session shows up, flip to a green check and name the tool that fired. That closes the "did it work?" void and hands the user their first success on the same page they were already looking at.
The moment the first tool call lands, the page flips to a green check and names the exact tool that fired, with a timestamp. The void closes on the same screen the user was already looking at.
Write tool descriptions for the agent, not the human. They are read at runtime by the model, not by a developer reading your code. Write them imperative: when to use the tool, when NOT to, the gotchas. Ours on star_listing, verbatim:
Star/save a company listing. Starring subscribes you to their job postings. [...] CRITICAL: Only star companies where the user's tech stack genuinely overlaps with the company's tech stack. A React/Node developer should NOT star a company that only uses Go or Java. Irrelevant stars pollute the job feed with noise. Every star must be a deliberate, high-quality match.
That CRITICAL line is not for a human. It is there because the model reads it at call time and behaves better for it. Write every description as if the agent is the only reader it will ever have, because it mostly is.
And the one that quietly mattered: OAuth for non-technical clients like Claude Web, so they connect without ever meeting the words "API key." We had been API-key-only and losing every one of them.
Say you get all five right. The user connects, sees a green check, and lands back in their tool. Now what?
Nothing. That is the problem.
They are staring at the same blank prompt box they have always had, except now there is a new capability behind it that the agent will not mention. The model does not announce "you just connected a job server, want me to find some companies?" It has no first-run. It does not know your server is new. It will not suggest anything. From the user's side, nothing visibly changed. They did all the install work and got no payoff, because the connection is live and completely inert until they happen to ask for the exact thing your tools do, in words close enough that the model decides to reach for one.
This is the second install, and it is the one almost nobody ships. It is brutal precisely because it lands at the moment the user expected the reward. They followed your instructions, finished the install they could see, and the reward was an empty chat. The capability is connected. It is just not installed in their head yet, and that install is on you.
You cannot fix it the way you would want to. You do not own the chat. You cannot inject a welcome message or a "try this first" card into someone else's tool. MCP hands the client your tools, not the first turn of the conversation. That turn belongs to the user, and right now they have nothing to say.
So everyone solves it the same crude way: somewhere in the install, you get the user to copy a starter prompt, and you tell them to paste it back into the tool the second they land. That pasted prompt is the entire first-run experience. It is the only lever you have on the far side of the wall. Our onboarding does exactly this. The page generates a ready-to-paste prompt, and the business end of it reads:
read my profile with get_profile. If it's empty, ask me about my tech stack, experience, and what kind of roles I want. Update my profile with what I tell you. Then search for companies that match my stack and star the best fits.
Every clause earns its place. It names a tool by its exact name (get_profile) so the model reaches for it instead of guessing one exists. It branches on empty state, so a new user gets onboarded and a returning one is not re-interrogated. It chains into the actual thing the user came for. It is a crude hack and the only thing that works, and it pays off twice: the user sees the thing fire, and learns by example what to ask next. It is as load-bearing as the config block, and almost nobody treats it that way.
The default is one prompt that connects the agent and sets up the profile. Manual per-client config is a disclosure, not the main path. The second install, shipped.
But the starter prompt only owns the first turn. There is a move past it, and it is the most underused technique in this whole space. You do not just hand the user a prompt for right now. You hand them a line for their agent's rules file, the CLAUDE.md or .cursorrules the agent reads at the start of every session. Ours reads:
When I mention job searching, company research, applying, rejections, offers, or changes to my own tech stack, use the Remoet MCP server. Save this rule to your global/user-level rules file (not project-local) so it persists across every session.
That one line changes the physics. The starter prompt owns the first turn. The rules file owns every turn after it. The user no longer has to remember your server exists, and the model no longer has to guess whether to reach for it. Three weeks later, when they type "got rejected again," the agent calls your tools because the user told it to, once, in a file it always reads. That is the deepest version of the second install: not getting connected, not even nailing the first prompt, but earning a standing line in the context the agent loads every single time. You were told you could never own a turn. This is how you quietly own all of them.
Two layers past "connected": a prompt that builds the whole profile end to end, and a one-line rule for the agent's rules file so it reaches for the server unprompted in every future session.
Here is the honest part. Everything above is interim work. You are building a great install path because you do not own the surface yet. The moment you do, most of this friction disappears, because the friction was never really about your engineering. It was about asking a user to wire two systems together by hand.
The tools are building the native version of this right now:
claude mcp add (or an install command) that wires the server up in place, in the terminal the developer is already in, with no JSON archaeology.When the install lives inside the tool, the N×M problem is the tool's problem, not yours. The auth fork is handled by the platform. The "did it even work?" void closes because the connection happens in-app, where the user can see it. And it is the first place the second install might actually get solved, because the platform owns that first turn. ChatGPT's apps can surface suggested prompts. A connector directory can tell the user what an app is for before they ever type. The paste-a-prompt and rules-file hacks are interim too, and native distribution is what retires them. The entire discipline of this post collapses into a button someone clicks without thinking.
Here is a prediction you can hold me to. Within a year, the README with a config block is dead as a primary install path for any server that wants real adoption. The default becomes a button inside the tool. The per-client config files do not disappear, but they become a power-user fallback and a thing you generate, not a thing a normal person hand-edits. The servers that clawed their way into the native directories early will look, in hindsight, like they got lucky. They did not get lucky. They saw which way the surface was moving and got there first. If I am wrong, come find this post in a year and say so.
So the highest-leverage distribution work is not a better config block. It is getting into those native surfaces the day they open the door. We are submitting to all three. Build the best owned install path you can today, because most users are not in a marketplace yet, and fight your way into native, because that is where the friction eventually goes to zero. The servers that win the next year are the ones sitting inside the tool when the user goes looking.
The MCP ecosystem is full of servers that work and have nobody using them, and a smaller, sadder pile of servers that got installed and still have nobody using them. The reason is almost never that the server is bad. It is that we all kept treating install as the finish line when it was the halfway mark. The first install gets you connected. The second install gets you used. The platforms are about to take the first one off your hands. The second one stays yours, and it is where the next year of this work actually lives.
If you are building one and want to compare notes on what is actually converting, find us on Discord. The ecosystem is small enough that everyone building servers benefits from sharing what works.
Plug in. Tell us where your users are dropping.