[SECURITY] Claude Teams: Custom MCP connectors expose shared credentials to all team members — no per-user scoping
What is the expected behavior?
When an admin adds a custom MCP connector on Claude Teams, they should be able to assign it to specific team members. Only assigned members should see and be able to connect to that connector. Members not assigned should not see the connector URL or be able to authenticate with it.
Steps to reproduce
- On a Claude Teams plan, go to Organization Settings → Connectors
- Add a custom MCP connector with a URL (e.g., a Cloudflare Worker at
https://my-worker.example.com/mcp) - Log in as a different team member
- Go to Customize → Connectors
- Observe: the custom connector is visible with its full URL
- Click Connect — authentication completes via auto-approve OAuth with no identity verification
- The team member now has full access to whatever the connector provides
Expected: Only assigned team members can see and connect to the connector.
Actual: Every team member can see the URL and connect with zero identity verification.
Why this is a security issue
The connector URL IS the credential. Auto-approve OAuth means anyone who clicks Connect gets a valid bearer token. There is no per-user scoping, no identity binding, and no way for the MCP server to distinguish which team member is connecting.
Real-world impact: We built a custom Gmail MCP connector (Cloudflare Worker with Google Service Account delegation) for multi-account email access. We cannot deploy it for personal inboxes because any team member could connect and access another person's email. The same risk applies to CRM, financial, and task management connectors.
What we tried that doesn't work:
- Cloudflare Access (SSO gate): Claude's MCP client cannot complete browser-based SSO flows or send custom auth headers like
CF-Access-Client-Id - URL-embedded secrets: The full URL (including any secrets) is visible in Teams connector settings to all members
- Per-subdomain routing: Tokens from auto-approve OAuth are bearer credentials — possession = access
Requested features (any would help)
- Per-user connector scoping — admins assign specific connectors to specific team members
- User-provided secret during Connect flow — a prompt for a key/passphrase when clicking Connect, validated by the MCP server
- Custom header support — allow the MCP client to send configurable headers (e.g., for external auth layers like Cloudflare Access)
- Per-user connector visibility — team members only see connectors assigned to them
- Identity passthrough — pass the authenticated Teams user's identity (email) to the MCP server so it can enforce per-user access control server-side
MCP Server
Custom Cloudflare Worker implementing MCP protocol (JSON-RPC 2.0, protocol version 2025-03-26) with OAuth 2.1 + PKCE (S256) auto-approve flow. Architecture documented and reviewed through 4 rounds of security review before discovering this Teams-level limitation.
Environment
- Claude Teams plan
- Custom MCP connector via Cloudflare Workers (self-hosted)
- macOS, Claude Desktop + Claude Code
- MCP protocol version 2025-03-26
9 Comments
I just ran into this also. similar setup. I am using context forge gateway with an oauth bridge. i have permissions set for each auth credential but when the admin sets up the mcp connection in teams, all team members get the access he used. Not sure how to get around it. On the single person plans it worked well... everyone just used their assigned credentials.
We hit the exact same issue with an internal enterprise tool
Our MCP server uses user-scoped auth — each user authenticates with their own
credentials, and the API enforces row-level data visibility based on their
permissions. That's the correct security model for a multi-tenant internal tool.
With the current org connector model on claude.ai / claude cide, this is completely broken:
whoever re-authenticates last sets the shared token for the entire org. If a
user with limited access re-auths, they silently break data scoping for everyone.
We've filed a related feature request at #46207 focusing on the per-user auth
angle. The two issues are the same underlying gap — the connector model was
designed for shared service accounts, not delegated user identity.
So, adding a non org-scoped MCP is still visible for me on Claude.ai. I would almost -expect- this behavior at the org-level, so we can, like with GitHub auth flows for external CI/CD, set it up once and allow all tools to be used inside the org.
So, this seems to be poorly thought out and executed, and the gaps in documentation and features are significant. If added at the org level, we should be able to at LEAST control which users get access to it within Anthropic because of precisely what you said.
We created a custom MCP connector to our Salesforce instance. Each user has to connect their own Claude account via the Customize > Connectors screen and then log in and authorize their Salesforce account. This seems to be scoped per-user, which we can verify by asking Claude the details of current user from Salesforce. It always responds with information from Salesforce about the correct user they authenticated to Salesforce with.
Am I misunderstanding something here or is what is asked for in this request already possible?
Closing for now — inactive for too long. Please open a new issue if this is still relevant.
@ajhpw the problem is with tools that just have one API token without oauth. Admin wants to add this and assign to specific teams/members only.
Sharing the workaround we've run in production for ~6 months, since native per-user scoping still isn't here. It solves the access-control half of this completely, and — for OAuth-capable upstreams — the per-user-identity half too.
Pattern: self-host each connector as a small serverless worker that puts your own identity gate in front of the upstream API. The worker speaks MCP OAuth to the client but delegates login to an IdP (we use Google / Workspace SSO):
That alone kills the "admin adds one connector and the whole org inherits one credential" problem: the upstream API key lives only in the worker's secret store and is never handed to clients; access to the worker is gated per-identity and revoked instantly by editing the allowlist.
For the single-API-token tools @REFoqus mentioned (no upstream OAuth): this is the fix. The shared token stays server-side; you gate who can reach the worker per-user. You get "assign to specific members" without the upstream supporting OAuth at all.
For upstreams that DO support OAuth and you need true per-user identity (row-level scoping, "act as me"): have the worker store a per-user refresh token keyed by verified email (encrypt them — envelope/AES-GCM), and exchange per-user at call time. Each user then acts as themselves against the upstream, and whoever-authed-last can't clobber a shared token — the exact failure @GBR-Rise described.
Stack we use: Cloudflare Workers + KV for token storage, Google as the IdP, an
ALLOWED_EMAILSsecret as the allowlist — roughly one worker per upstream. Happy to share a skeleton if it's useful.None of this should be necessary — native per-user connector scoping (and per-user secret entry during the Connect flow) is still the right ask, and this still feels like it merits staying open rather than auto-closed as "not planned." But if you're blocked today, this works.
Want to raise a failure mode with the SSO + allowlist approach - our team hit this not long ago.
Users can connect the MCP to a personal account and re-use it via org identity.
So verifying SSO + an email allowlist gates who the user is, but it doesn't bind which account the connection runs in.
Steps to reproduce:
you@gmail.com).you@yourorg.comopen in that browser (normal if you're signed into Gmail/Workspace for work).email_verified,hd,allowlistall pass, because it genuinely is a real org user.you@yourorg.com.We can't cover it only on MCP app Server Side. We need gate right during the Connection to MCP.
This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.