Running your own MCP servers, or not
Running your own MCP servers is cheap for one team and expensive for a company. The line is not the servers, it is credentials, revocation and the audit trail.
What running your own MCP servers actually buys you
An Model Context Protocol server you run is a process you control. You choose the version, you see the logs, you can read the code, and nothing about your data leaves a boundary you did not draw. For a team that is already comfortable operating services, none of that is hard, and the first server is genuinely quick.
It also fits a real situation. One team, three or four systems, a shared service account per system, and one person who knows how it is wired. That team does not have an access-control problem, because everyone on it is allowed to reach everything the servers reach. The server is doing the only job it needs to do, which is speaking the protocol.
The reason to look further is not that this setup is bad. It is that two of its assumptions stop holding at a predictable point, and neither of them is about servers.
The credential math changes with the second team
A self-hosted server needs a credential for the system behind it. With a shared service account, that is one credential per system, and the agent acts as that account for everybody.
That is workable until someone asks a question the shared account cannot answer: should this person be able to reach this record. A shared account has one answer for the whole company, so the moment two groups need different answers, the credential has to become per person. Now the count is people multiplied by systems, and every one of those is a secret that has to be issued, stored, rotated and eventually removed.
In Elaichi, connector credentials are not held by the control plane at all. A
separate credential service owns per-account secrets, encrypted at rest with
AES-256-GCM, and owns refresh as well. A refresh that fails marks the connection
needs_reauth instead of failing quietly, which matters because a quiet
credential failure looks exactly like an agent deciding not to do something.
Single sign-on in front of that endpoint is a separate decision, and it settles identity rather than authorization.
There is one address for clients: POST /mcp, standard MCP over Streamable
HTTP, behind OAuth. There are no per-toolbox URLs and no embedded tokens, so
there is no per-user server to mint, list or revoke. The endpoint is constant
and the grant is what varies.
Revocation is the part that decides it
Ask how long it takes to cut somebody off. The answer separates the two approaches more cleanly than any feature list.
With servers holding per-person credentials, revocation is a sweep. You need the list of every credential that person holds, across every server, and you need it to be complete. Nothing produces that list for you, and an incomplete sweep leaves a working credential behind with no signal that it is still there.
Through a control plane the timings are specific, and worth stating precisely because they are not all the same. Removing or suspending a member revokes every live grant in the same transaction as the membership change, and the OAuth grant is re-read from the org store on every single call with no cache, so for those the next call is genuinely the boundary. Role membership and restrictions are different: they resolve through a 60-second cache plus edge propagation, so a change to what a role may reach takes effect within about two minutes, on every surface alike.
Two minutes is not instant, and saying so is the point. A number you can plan around beats a promise you cannot verify.
Offboarding has a step people forget
Removing a person is not only a credential problem. It is also a question of what happens to the connections they set up.
Elaichi refuses the removal if a personal connection that person owns is still referenced by a toolbox entry, until that connection is resolved: transferred to the org, to a team, or to another member, or deleted. Unreferenced personal connections are cleaned up. A private connection is not transferable at all, because a credential that only its owner could ever use does not become somebody else's when its owner leaves.
That preflight is the kind of thing that does not exist until someone builds it, and its absence is invisible until the week after a departure, when a scheduled job stops working and nobody can say why.
What the audit trail has to answer
The question that arrives after an unexpected change is narrow: which account did the agent write to. Not which server, and not which user was logged in. Which of the two Notion workspaces.
Elaichi writes one entry per tool-call attempt, succeeded or failed, and both name the account. The recorded connection is the one actually reached, taken from the execution rather than from the intent, which is the distinction that makes the record usable. Recorded alongside it: the operation and tool, the classification, whether it was approved, the outcome, and an error code. Argument names and counts are logged. Argument values never are.
actor_kind is a field rather than an inference, and ai_assistant is one of
its values. Whether an action was taken by an AI is written at the point of
action, not guessed later from a user agent string. Self-hosted servers can
produce logs, and often good ones, but they produce them per server in whatever
shape each one emits, and correlating those by eye is the work you are actually
signing up for.
When running your own is the right call
There are cases where the honest answer is that you do not need a control plane.
If one team uses two systems, shares a service account for each, and nobody outside that team will ever connect, a self-hosted server is less machinery for the same result. If a system has no per-user concept at all, adding per-user governance in front of it buys nothing. If your constraint is that a particular workload cannot leave hardware you own, that constraint outranks convenience and should win.
The mixed shape is also legitimate. Route the systems that need per-person rules and a defensible trail through the governed endpoint, and leave a single-account internal tool where it is. That is a smaller change than a migration and it puts the effort where the risk is.
The trade-off, stated plainly
A control plane centralizes. That is the benefit and the cost in the same sentence. One endpoint means one place to reason about access, and it also means one dependency in the path between a client and the systems it reaches.
What you get for that is a single answer to who may reach what, a revocation story with numbers attached, and one record shape that answers what happened without correlating two systems by hand. What you give up is the ability to read every line of the process in the path.
One more limit worth naming, because it is easy to assume otherwise: an MCP server never sees a user prompt, so no endpoint of this kind can be protected against prompt injection, and Elaichi's is not. What does hold on the endpoint is role-based access per operation, the forbidden classification, output redaction, OAuth scope limits and full audit logging. That is a real set of controls, and it is not the same thing as making a model trustworthy.
If you are weighing the two, the useful question is not which is more secure in the abstract. It is whether you can currently produce, in under a minute, the list of every system one departing person's agent could reach. If you can, stay where you are. If you cannot, that is the gap, and more servers will not close it.
For the shape of a first rollout, see a team-by-team playbook. Browse what connects today or read how the access model is layered.