What it took to get our MCP server into Claude’s connector directory
How we submitted our MCP server to Claude’s connectors directory: the automated review, OAuth sign-in, tool descriptions and the test plan.
Published
Our MCP server is now listed in Claude’s connector directory. An automated review approved it in about an hour. We build Privatrak, a cookieless analytics tool, and MCP (Model Context Protocol) is the standard way to plug a tool like it into an AI assistant. Once connected, Claude can answer your analytics questions in plain language or set up the tracking for you, such as funnels, dashboards and which clicks count as which feature.
This is what getting it into the directory actually involved, in the order we ran into it. Most of it applies to any remote MCP server, not just analytics.
An AI reviewed it, not a person
The approval email said the submission “was reviewed and approved as a community connector by an automated review of the listing.” Anthropic’s verification page explains what that means. Every submission is scanned automatically for policy compliance and listed as a Community connector by default. Listings that look highly useful to Claude users can be escalated to Verified review, which is slower and where “reviewers run a functional test of each tool.” That escalation is decided automatically too, and there’s nothing to apply for.
The label changes less than you might think. Once connected, a Community connector works exactly like a Verified one, it shows up in search, and Claude can suggest it in a chat when it fits. The difference is the label, and a reminder before someone connects that it “hasn’t been reviewed in depth.” You can’t apply for Verified. Anthropic picks listings that look “highly useful to Claude users”, and its developer portal ranks every listing by how many people use it. So our bet is that usage is what counts.
That changes how you write the submission. The first thing to read your tool descriptions is an automated check against Anthropic’s policy, and the strictest rules there are about text that steers Claude into doing something the user didn’t ask for (more on this below). The test account and test plan the form asks for may be looked at too, but the only review that says it runs every tool is the Verified one. So they have to work without you there to explain them.
A few months ago this looked very different. Submissions went through a Google Form and a manual queue, and developers reported waiting months without hearing back. Anthropic has since moved submissions to a portal with an automated check, and some submissions still get a review by a person, with times that depend on the queue. We don’t know why ours went through in an hour. Our guess is that a clean submission, with OAuth, honest tool labels and a full test plan, gives the automated check nothing to send on to a person.
Why we needed OAuth sign-in
Claude on the web, the desktop app and the mobile apps connect to a remote server by URL. For most users there is nowhere to paste an API key (at the time of writing, a beta that accepts one is rolling out to some customers), so a server that only accepts keys locks most people out. And the directory requires OAuth anyway.
So we built sign-in with OAuth, the same flow as any “Sign in with...” button. Claude sends you to our login page, you approve access, and Claude gets a token for our server. Here’s what we learned from making it work with the apps people actually use.
- Claude introduces itself with a web address. Claude doesn’t register with your server in advance. Its ID is a URL that points to a small file describing Claude (a Client ID Metadata Document). You fetch that file and check that the address you send people back to after sign-in is listed in it. Cursor and Codex instead register themselves on the fly (dynamic client registration), so you need both if you want to support them too.
- Claude Code picks a random port. After sign-in, it expects to be sent back to
http://localhost/callback, on whatever port it happened to open. The OAuth rules for desktop apps (RFC 8252) say to ignore the port for localhost addresses, and you have to, or Claude Code’s sign-in fails. - Don’t trust the name an app gives itself. An app that registers on the fly can call itself “Claude”. Our approval screen only shows a name as checked when the file describing the app and the address it returns to are on the same domain, such as claude.ai. Otherwise it shows the domain next to the name and marks it as not checked.
- The approval screen is where people decide. Ours asks which projects the connection may see, and whether it may only read or also make changes. Those two choices match the two kinds of API key we already had, so an AI connection can never do more than a key could.
On the submission form, all of this was one line. Behind that line was the biggest piece of work.
The checkbox that made us stop
Every tool comes with a short description that tells Claude what it does and when to use it. Claude reads these descriptions almost like part of its instructions, which is why the directory checks them closely. The last step of the form has seven boxes to tick. Six were simple. This one wasn’t.
Tool descriptions contain no instructions about model behavior, other tools, or external instruction sources, and no hidden or encoded text.
Read literally, ours break it twice. First, some tool descriptions mention other tools, such as “use the ID you got from start_setup_run”. Second, the general instructions our server gives Claude tell it how to behave, such as “quote counts with every percentage”, so that it says “2 of 4 visitors” instead of just “50%”. We wanted to keep both, because they make the tools work better.
So we read the policy the checkbox summarises. Its actual rules are narrower.
- Descriptions must say precisely what a tool does and when to use it, and match what it does.
- A server must not push Claude toward calling other software the user didn’t ask for, or interfere with other servers’ tools.
- It must not tell Claude to fetch behavioural instructions from external sources.
- No hidden, obfuscated or encoded instructions. In the policy’s words, “all behavioral guidance must be human-readable and clearly presented.”
Anthropic’s pre-submission checklist is more blunt. “Describe what the tool does, and don’t tell Claude how to behave.” But the most useful part is the last rejection reason on its list, descriptions that “tell Claude to behave in ways unrelated to the tool’s function.”
So guidance about what your own tools do is allowed. What isn’t allowed is guidance that pulls Claude away from what the user asked, toward someone else’s tools, or that is hidden. Referring to your own tools, telling the model how to read your own numbers, and pointing it at your own documentation as reference material are all fine, as long as it’s in plain sight.
We ticked the box and explained it in the notes field instead of hoping nobody would notice. We listed which tools our descriptions refer to, why the usage guidance is there, and that our two documentation tools only read our own public documentation, from a fixed list of pages.
The automated review approved it, so that reading seems to hold. If you’re building a server, write descriptions as if a reviewer will read every one, because one will, and the first one is automated. Name only your own tools, keep all guidance visible, and if a sentence would read as manipulation out of context, rewrite it.
When Claude asks before using a tool
The directory requires three labels on every tool, a title and two hints called readOnlyHint and destructiveHint. They decide when Claude asks for permission. According to the checklist, read-only tools “can run without per-call confirmation, and destructive tools always prompt.” Get them wrong and people either have to confirm every harmless lookup, or aren’t asked before something is deleted.
Why does the directory check them so closely? The MCP specification says clients must treat these hints as untrusted unless they come from a trusted server, and yet Claude uses them to decide when to ask. Our guess is that the review is what earns a server that trust.
Watch out for one thing. if you leave destructiveHint unset on a write tool, the protocol assumes it is destructive. That is a safe default, but it describes a “create dashboard” tool wrongly. So we set both hints explicitly on every write tool.
- Creating something is not destructive, and running it twice gives you two of them.
- Updating, renaming, deleting and undoing are destructive, and running them twice does no more than running them once.
- Some tools need a closer look. In Privatrak, a click problem is something people click that doesn’t work. Marking one as fixed is destructive, and doing it twice is not the same as once, because it moves the date from which the problem counts as happening again. Marking it as ignored twice really changes nothing the second time.
Setting up a test account
Test credentials are required, and the checklist says they “must be for a fully populated account.” For analytics that matters more than for most tools, because an empty project answers every question with zero.
This part was easy for us, because we already run a public demo with a sample shop and its traffic. We created a dedicated account on the Pro plan, with a project holding a month of the same kind of shop traffic, with visitors from search and campaigns, product pages, a checkout funnel, user journeys and a few broken buttons for the click-problem tools. One detail almost tripped us up. Our funnels only count from the day they were created, so a funnel added on the day of submission would have shown nothing. Everything in the review project had to look as if it had been there for the whole month.
Give the account a plain email and password. One team was rejected because their review account used Google sign-in with a code sent to a phone, which the reviewer couldn’t get past. Their server was fine.
Writing a test plan
The form asks how to test the server. Our first draft was a handful of example prompts, and they were useless. Five nice prompts exercise maybe a dozen tools. They show the server works, not that every tool does.
So we wrote a plan of 15 prompts that together call all 44 tools, each with the tools it triggers and the answer we got, so the reviewer can check rather than guess. Here’s step 4.
4. "Which properties can I filter by, and which page paths exist? Then chart
page views and clicks per day from 2026-10-13 to 2026-10-19 and compare
them with the week before."
Tools: list_property_keys, list_property_values, run_insights_query.
Expect: 162 page views (+25.6%), 53 clicks (+23.3%).Fixed dates matter here. “Last week” means something different every day the reviewer opens the plan.
The harder part is the write tools. A reviewer has to create, change and delete things to test them, on an account other reviewers may use after them. If the plan leaves a mess, the second run fails.
This is where a design decision from months earlier paid off. In Privatrak, every change an assistant makes belongs to a setup run, and a setup run can be undone in one step. Undo puts back exactly what the run changed. If someone has changed the same thing since, it skips that item and says so instead of overwriting their work. The undo tool first shows what it would do, and only then does it.
So the last step of the plan cleans up after everything else.
15. "List the setup runs and show what 'Review test' changed. Then undo it:
dry run first, then for real."
Tools: list_setup_runs, get_setup_run, undo_setup_run.
Expect: 15 changes listed; the undo reverts all 15 with nothing skipped.
The project is back to its original state.We ran the whole plan ourselves through Claude, signed in as the review account, before submitting. The form’s Test & launch step asks you to confirm you tested every tool, and this was how we could say yes. Every tool passed, and the undo left the project exactly as it was. The plan can be run as often as anyone likes.
We don’t know whether the automated review looked at it. We’d write it again anyway. It’s what a Verified reviewer would follow, and it was the only way we knew that all 44 tools work through Claude itself, not just in our own tests.
We built setup runs for customers, not for reviewers. Letting an AI change your analytics setup is only reasonable if you can take it all back. But if your server has write tools and no way to undo them, think about how a reviewer is supposed to test them. And then about how your users are supposed to trust them. We wrote up how our undo works in a separate article.
Small things that cost us an afternoon
- Claude Code took 25 seconds to connect. The cause was one default setting. The Go SDK we use tells every client that our list of tools may change while it’s connected (
listChanged: true). Claude Code waited for an update that never came, then gave up after about 25 seconds. Our tool list never changes, so we turned the setting off (listChanged: false) and Claude Code now connects right away. - Claude’s desktop app won’t send your API key in the usual place. You can add your own connector there with extra request headers, but not the
Authorizationheader, where API keys normally go. So we also accept the key in anX-API-Keyheader, which our API already used. People who prefer a key over signing in can still connect.
What about the official MCP Registry?
One thing confused us at the start. Besides Anthropic’s directory there is the official MCP Registry (registry.modelcontextprotocol.io), a public list of MCP servers run by the people behind the protocol. The two are separate. The registry wants proof that you own the name you publish under, and Anthropic’s form never mentions the registry at all.
We did both. To publish as com.privatrak/analytics in the registry, we had to prove we control privatrak.com. You do that by adding a DNS record with a public key to your domain, then signing in with the matching private key using the registry’s mcp-publisher tool. The one snag was that the tool needs the private key as hex, and the command in the instructions to get it didn’t work with our version of OpenSSL. This one works with any version.
openssl pkey -in key.pem -outform DER | tail -c 32 | xxd -p -c 64The registry entry itself is a small server.json with a name, a title, a one-line description, your website, an icon and your server’s address. Write the description for someone deciding whether to install you, not for search engines. Ours says “Ask your website analytics in plain language and set up funnels, features and dashboards.”
A checklist for your submission
- Anthropic’s pre-submission checklist open next to the form. It spells out what the policy only implies.
- Sign-in with OAuth that works for Claude (Client ID Metadata Documents) and for Cursor and Codex (dynamic registration), and ignores the port on localhost addresses.
- The current MCP transport, Streamable HTTP. If your tool list never changes, set
listChanged: false. - A
title,readOnlyHintanddestructiveHinton every tool, set deliberately. - Tool descriptions that refer only to your own tools, with all guidance in plain sight. Explain anything borderline in the notes.
- A test account with realistic data, and dates in the test plan that don’t move.
- A test plan that calls every tool, with expected answers, and cleans up after itself.
- Optionally, an entry in the official MCP Registry, via a DNS record on your domain.
- A public privacy policy, linked in the submission.
- A review account with a plain email and password, no Google sign-in or phone codes.
- Patience with later changes. A new description or new screenshots are reviewed by a person, and that can take weeks while your listing stays live.
If you want to see what this looks like from the user’s side, Privatrak is in the directory now as a Community connector, and our docs show how to connect it.