We refused a shared key
Each person signs in with their own account, using OAuth with PKCE. Apps check permissions against the token’s owner, so a shared company key would have shown everyone the same documents.
Per-user accessNothing matches. Try “case”, “resume” or “email”.
Case 02
What changed Each person’s agent reaches only what that person may see, with no shared keys.
MCP is the standard way an AI agent uses a real tool. I built connectors that speak it and hardened the gateway every call passes through, so agents could use company apps without ever holding a key.
An agent decides it needs outside data, so it calls a tool over MCP.
The gateway confirms this agent holds that tool’s permission, and that the tool isn’t switched off.
The vault adds the signed-in person’s own token. The agent never sees it.
The connector turns the tool call into a request to the real app.
The app answers with what this person is allowed to read, and the answer flows back.
How we decided
Each person signs in with their own account, using OAuth with PKCE. Apps check permissions against the token’s owner, so a shared company key would have shown everyone the same documents.
Per-user accessThe gateway enforces permissions before the vendor is ever contacted. Vendor-hosted servers run none of our code, so they ignored our permission headers.
GatewayOur own MCP server publishes its tools, checks permissions itself, and never keeps a token between requests. The vendor’s server couldn’t, and our copy of its tool list kept drifting.
Tested end to endThe tools
Every tool is named service_product_action and carries exactly one permission. Moving to our own server was the chance to fix vague names. An agent can only call what its owner granted, checked before the app is contacted.
knowledge_search_querySearchknowledge:search:readknowledge_chat_askAsk a questionknowledge:chat:readknowledge_documents_readRead a documentknowledge:documents:readHow I tested it
01Against a fake app
Before any real app was involved, a fake one checked that each person’s token is used only for them, and that a request without one is refused.
02With a real teammate
A teammate who didn’t build it asked their own agent.
Just a normal question, the way anyone at work would ask it.
It picked the right connector by itself and found the answer in a ticket.
It named the tools it used, so the answer could be checked.
Where it plugs in
Connectors for many kinds of app, all reached through the same gateway. Some things broke along the way, and each one got a fix.
What broke along the way
A shared key would have shown everyone the same documents. Per-user sign-in cost more work and was the only honest answer.
A vendor server ignored our permission headers, so enforcement moved to the gateway, before the vendor is ever called.
The structured logs I added exposed a connector that was failing silently in production. I fixed its routing.
The real test was a teammate asking a normal question and the agent choosing the right tool on its own.