How an agent connects, before and after. Each line on the right is enforced in code and covered by tests.
The setup
TEAMBOX has an MCP server: the standard interface AI agents use to call a product’s tools. Until September, connecting an agent meant creating a personal API token, installing a Node.js bridge and editing a JSON config by hand. Customer teams without a developer could not finish that. Worse, the token was the same kind a full API client uses, so an agent connected that way could call the whole API, not just the tools meant for agents.
Standard OAuth, built in six stacked steps
I made the agent endpoint an OAuth resource server on top of the OAuth library the product already used, and split the work into six branches that build on each other, each reviewed on its own. Agent apps find the sign-in through standard discovery metadata and register themselves as public clients with PKCE, with rules for allowed redirect addresses and a cap on idle registrations. The user approves the agent on a consent screen protected by a one-time token.
Access tokens last 15 minutes. Refresh tokens last 30 days and rotate on every use, and a refresh token used twice ends the whole connection: only a copied token is ever used twice. Users see and revoke connected agents in their settings, and one switch turns the whole flow on or off. All of it follows published standards (RFC 9728, 8414, 7591, 7009 and the 9700 security guidance), so any MCP client that speaks OAuth can connect without custom code.
A token that only works where it should
A token issued to an agent names its audience: the agent endpoint. Every other entry point rejects it. The check is built so that the safe answer is the default. The function that validates tokens must be told where it is being called from, and only the agent endpoint says so. A new endpoint added next year that forgets the argument rejects agent tokens instead of quietly accepting them.
The agent token is accepted in one place. Everywhere else rejects it, including endpoints that do not exist yet.
Tools that follow the customer’s permissions
Every tool used to be offered as soon as the MCP server was on, including tools for modules a customer does not have. Now each tool declares its module, the permission rule of the API route behind it, the settings it needs and whether it writes. A tool that is switched off answers exactly like a tool that does not exist, so an agent learns nothing from it. Tools that touch personal data are off by default.
The same pass fixed what review had found in the existing tools. One promised all tasks and returned only the user’s own. Several lists stopped silently at 100 rows and now page. One summary loaded up to 10,000 rows into PHP to add them up; it is now a single grouped SQL query with the same row permissions. New tools cover time entries, tasks, budgets, comments, people and absences, which takes the server from 17 tools to 30. Five of them change data, such as logging time or finishing a task, and they stay off until the customer switches them on. Every change was written test-first: each feature commit follows a commit with a failing test.
The audit around it
Opening an API to agents is a good moment to check what the API already allows. An inventory listed every operation the interface uses, with who may call it and what it reads or writes, so the audit covered everything instead of a sample. Every permission gap it found was first proved with a failing test, then fixed, and review found more of the same kind, which went through the same loop. The permission tests run to about 700 lines, and each test sets up its own data.
Two smaller fixes belong to the same theme. The logger now masks credentials before anything reaches central logging. And the repository’s own AI agent commands, for releases, KPIs and reviews, no longer ask anyone to paste a token into the chat: they read secrets from files created outside the agent, refuse files that other users can read, and never print the value.
What mattered
An AI agent is a new kind of client, and the cheapest moment to decide what it may do is before the first one connects. Here that meant three boundaries: who the agent acts for (OAuth and consent), where its token works (one endpoint, closed by default), and what it may touch (the same permissions as the person behind it).
Status, plainly: the six OAuth steps and the new tools now land together as one change, behind one switch. It is in final review and QA on staging. The audit fixes are merged.