Skip to content

Running an MCP server with SSO for a whole company

An MCP server with SSO answers who is calling. It does not answer what they may reach, and the gap between those two questions is where most rollouts get stuck.

Raajshekhar Rajan 5 min read
An identity provider feeding a single endpoint, with role and restriction layers drawn as separate gates behind it

What an MCP server with SSO actually settles

Single sign-on answers one question well: who is making this call. That matters for a Model Context Protocol endpoint because a single address serves the whole company. For an endpoint that any employee can point a client at, that question has to be answered before anything else, so getting it right first is the correct order.

Elaichi supports enterprise SAML and OIDC, both built in-house rather than through a third-party auth vendor, plus SCIM v2 for users and groups. Domains are verified with a DNS TXT record. Alongside the enterprise path there is sign-in with Google, GitHub and Microsoft, email codes, TOTP multi-factor with single-use recovery codes, and passkeys.

Onboarding runs four ways, and which one you pick changes how much of the rest is automatic. Emailed single-use invite links can carry roles and teams already assigned. Verified-domain auto-join admits anybody with a company address and gives them a configurable default role. SCIM provisions from the directory. Just-in-time SSO creates the account at first sign-in.

All four land a person in the organization. None of them decides what that person's agent may do, and that is the part worth spending the rest of a rollout on.

Identity is not authorization

The distinction sounds pedantic until an endpoint is live. Authentication establishes a subject. Authorization decides what that subject may reach. An MCP endpoint that has the first and not the second hands every authenticated employee the full reach of every connected account.

Three layers sit behind sign-in, and keeping them distinct is the single most common way a design goes wrong.

Permissions are role-based: roughly 38 action strings such as tool:execute, restriction:manage, audit:view and connector:create, grouped into roles. The system roles form a strict subset chain, Guest inside Member inside Team Admin inside People Admin inside Org Admin inside Org Owner, each tier built by spreading the one below so the subset relation holds structurally rather than by convention. Billing Admin and Auditor sit off that chain.

Resource sharing is a second, separate primitive: a grant of view, use or edit on a resource to a user, a team, or the whole organization. A member sees only what they own or what was explicitly shared with them, and no org-level permission silently widens a listing. That includes org owners and admins.

Restrictions are the third layer, and they are the one that maps most directly onto what people mean when they say governance: which connectors and which individual tools a target may reach.

How restriction rules resolve

Targets are role or user only. There is no organization target, and that is a deliberate design rather than an omission. The organization default is the absence of any rule, which means allow-all, so the way to tighten the default is to write rules against roles rather than to configure an org-wide setting that does not exist.

Precedence runs user override, then role rule, then org default. A user-targeted rule replaces role rules entirely rather than layering on top of them, which is worth internalizing before writing one: giving a single person a narrow exception discards every role rule that would otherwise have applied to them.

Within the winning layer, allow rules union, block rules union, and blocks always beat allows.

The behavior most likely to surprise you is the allowlist stage. It engages on the presence of an allow rule, not on its contents. An allow rule naming nothing therefore denies everything. That is the strictest rule expressible in the system, and it is reachable by accident, so it is worth knowing before you meet it in production.

Enforcement happens at four points against the same resolver, not once at the door: browse, connect, advertise and execute, plus a final check on the fully-substituted outbound URL.

What the endpoint checks on every call

tool:execute gates the whole endpoint ahead of every narrower scope. Without it, tools/list comes back empty and a call returns an in-band error naming the permission that was missing. Guest, Auditor and Billing Admin do not have it, which is what makes those seats safe to hand out freely.

OAuth scopes form a second ladder: mcp:read, mcp:write, mcp:destructive and mcp:tools. A tool classified forbidden is reachable under no scope at all. mcp:tools does not replace the ladder, so a connected tool whose method is a delete needs mcp:destructive as well as mcp:tools.

There is one address for every client in the organization: POST /mcp, standard MCP over Streamable HTTP, JSON-RPC 2.0, stateless, behind OAuth. Everyone points at the same endpoint and signs in. There is no per-user server to mint, list or revoke, because the endpoint is constant and the grant is what varies.

Propagation has a number, and it is not zero

When you change what a role may reach, the change is not instant, and planning around the real figure is better than assuming the optimistic one.

Role membership and restrictions resolve through a 60-second cache plus edge propagation, so a change takes effect within about two minutes, on every surface alike: the endpoint, the console and the REST interface.

Grant revocation is different and faster. revoked_at is re-read from the organization store on every single call with no cache, and removing or suspending a member revokes every live grant in the same transaction as the membership change. For those, the next call really is the boundary.

Two mechanisms, two timings. Quoting the wrong one during an incident is how a team concludes that a control did not work when it simply had not landed yet.

The discovery threshold changes what the model sees

Past a threshold of 30 tools, connected tools collapse behind two meta-tools, search_tools and execute_tool. The threshold counts catalog operations and connected tools together, and the control-plane catalog alone runs to dozens of operations, so one connected app is normally enough to trip it. Collapse is the normal case rather than an edge case, and a rollout plan that assumes a flat tool list will be wrong on day one.

Only the connected half collapses. Control-plane operations stay listed individually, and search_tools never returns one. Tools withheld by a restriction are excluded from the count, because they were handed to nobody.

execute_tool is only a naming indirection. It unwraps to the same name and the same arguments and falls through the identical gates. There is no separate execution path in it and no privilege attached to it, which is the property that makes the collapse safe rather than merely convenient.

One limitation to state before you deploy

An MCP server never sees a user prompt. Prompt-injection defenses that work in an agent window therefore cannot apply at the endpoint, and Elaichi's do not.

What does hold on POST /mcp: role-based access per operation, the forbidden classification, output redaction, OAuth scope limits and full audit logging. Each call writes one entry, succeeded or failed, naming the account actually reached. Argument names and counts are recorded; argument values never are.

That is a real set of controls and it is worth deploying. It is not the same thing as a guarantee about model behavior, and a rollout that is sold internally as the latter will lose credibility the first time a model does something odd within its permitted scope.

If you are still deciding whether to centralize at all, the tradeoff is set out in the case for and against self-hosting. For a worked example, read how one team gets governed access. See what the catalog covers or how the controls are described for reviewers.

FAQ

Frequently asked questions

Does SSO alone make an MCP endpoint safe to expose company-wide?

No. Single sign-on authenticates the caller and can carry group membership, but it does not decide which connectors and which individual tools that caller may reach. Those are separate rules evaluated after sign-in, and an endpoint with authentication and no such rules grants everybody whatever the connected accounts can do.

How do identity provider groups become permissions?

Through SCIM group-to-role mapping. Groups synced from the identity provider map to roles, and each member holds exactly one role. Changing somebody's group therefore changes their role rather than adding to it, which keeps the effective permission set readable.

Can a person hold two roles at once?

No. Exactly one role per member is enforced by a unique index. Every role is built as a complete persona that includes the tier below it, so the way to give somebody more is to move them up the chain rather than to attach a second role alongside the first.

Do read-only reviewers need a paid seat?

No. Auditor is a free seat class, as are Guest and Billing Admin. A compliance reviewer who only reads the audit trail does not consume a license, which means there is no cost argument for sharing an admin login with them.

Put agents to work on your own systems

14 days on Gold, no credit card. Start with one app and one team.

Works with
Claude ChatGPT Cursor and any other MCP client, or the Elaichi Agent.
When the trial ends
Nothing is deleted. Connections, roles and the audit log stay where they are, so subscribing picks up exactly where you left off.