
Guide
Agentic Ops
When the caller is not on your payroll: permissions for partners, customers and other teams' agents
Guillaume Rigal
An outsourcer's analyst and the finance team's procurement agent are the same governance problem. Neither is an employee. Both need an identity, a scope, and a line in the log.
Every permission model you have ever configured makes the same assumption. The caller is an employee, on your payroll, using an interface you built, reachable by somebody who can revoke their access on a Monday.
That assumption is breaking in two directions at once, and most teams are only watching one of them. Outward, partners, outsourcers and your own customers increasingly touch data that lives in your systems. Inward, and this is the newer direction, your own functional teams are running AI agents they bought themselves, several of which nobody in engineering has heard of.
These look like two problems and they are one. Both are callers your permission model never anticipated, and neither can be managed by the process you use for staff. So you have to decide how somebody you do not employ gets an identity, what that identity may reach, and what makes the access stop.
We take the two directions in turn, then the part they share: giving every caller an identity, a scope, an expiry and a line in the log.
Every permission model assumes an employee
It is worth being precise about what the assumption actually buys you, because that is what you lose.
The assumption | What it gives you for free | What breaks without it |
|---|---|---|
The caller is on your payroll | HR tells you when they arrive and leave | Nothing tells you when the relationship ends |
The caller has a manager | Somebody notices when their access looks wrong | Nobody owns the review |
The caller uses your interface | The interface enforces what the model says | The API is the interface, and it enforces only what the model says |
The caller is one person | One identity, one name in the log | One credential, many actors, no attribution |
Every failure in that right-hand column is a governance failure rather than a technical one, which is why buying a better permission system does not fix it on its own.
Outward: partners, outsourcers and your own customers
The outward direction is old enough to have established answers. The most important one is that roles alone are the wrong instrument.
A support outsourcer's analyst in Manila and your own analyst in Paris may do exactly the same job, with exactly the same permissions. The difference is not what they can do. It is whose records they may touch. That is not a role question, it is an isolation question, and the two need different mechanisms.
Tenant isolation is a separate layer, underneath roles. A role says what operations are available. Isolation says which slice of the data exists at all for this caller. Implemented properly, a caller in the wrong tenant does not get a permission error, because the record was never in their result set to begin with. That distinction matters: a permission error tells an attacker the record exists.
Three rules hold whatever the outward case looks like:
Isolate at the query, not at the interface. A filter applied in the front end is not isolation. The API returns what the API returns.
Make the relationship expire. A partner contract has an end date. The access should carry the same one, set at creation, so ending the relationship does not depend on somebody remembering.
Give the partner organization an identity, and each of their people an identity underneath it. One shared login for the outsourcer is the single most common shortcut here, and it destroys attribution for every person behind it.
Your own customers are the same mechanism at a different scale. If a customer can see their own records in something you built, they are a tenant, and everything above applies.
What happens when a team buys its own AI agent?
This is the newer direction and the one moving fastest. Compliance has an agent. Support has one. Finance is running a procurement tool that reads your supplier data on a schedule. Several of these were bought on a corporate card, configured by somebody in the team, and connected to your systems without a conversation with engineering.
None of this is unreasonable behavior. The tool works, the team is faster, and asking permission would have taken a quarter. But look at what it means from the permission model's point of view.
That agent is a caller with no employment relationship, no manager, no departure date, and frequently no owner after the person who set it up moves teams. It reads data continuously rather than occasionally. And it is often external software, meaning the credential you issued is sitting in somebody else's infrastructure.
The instinct is to ban these tools. That does not work, because the team will find another way and you will lose sight of the very thing you were trying to control. The workable position is narrower:
Any agent reaching your data gets an identity from you, not a shared key from a team.
It gets a named human owner, recorded somewhere that is not the head of the person who set it up.
It gets a grant built from what it does, not a copy of the role its team holds.
It gets a review date on the same cycle as everything else.
That is four fields, not a process. It is also the difference between having an inventory and finding out during an audit.
Why does "just give it an API key" fail?
Because a key is not an identity. It is a password with no owner, and every property you need for governance is missing from it.
What you need | A key gives you | An identity gives you |
|---|---|---|
Attribution | "The key acted" | "The procurement agent acted, owner: the finance lead" |
Revocation | Break everything that shares it | Revoke one caller |
Scope | Whatever the key was issued with, usually broad | A role, narrowed to the operations it performs |
Review | Nothing prompts anybody | An owner and a date |
Rotation | Nobody dares, because nobody knows what breaks | Routine |
The failure is not that a key is insecure. It is that a key cannot be governed. Once the same string is in three services and a password manager, the answer to "who did this" is permanently unavailable, and no amount of logging recovers it.
One identity per caller. It is the whole fix, it is cheap at the moment you create the integration and expensive eighteen months later, and what an identity looks like in practice, service accounts included, is in our guide to user authentication.
How do you limit what an AI agent can do through the Forest MCP Server?
If the caller is an AI client rather than a person, there is a control surface above the permission model. An agent acting for somebody can only do what that person may do, which sets the ceiling. The three controls below narrow it further, and they apply to every caller behind the server.
Choose which operations exist. The Forest MCP Server publishes a fixed set of tools. You decide which of them are available:
That configuration is a read-only agent, permanently, whatever the user's role says.
Tool | What it lets an AI agent do | Risk class |
|---|---|---|
| Read the shape of your data model | Always on, required for the server to function |
| Read records and their relations, within the user's scope | Read |
| Change records, within the user's scope | Write |
| Change relations between records | Write |
| Read an action's form, then run it | Write, and the widest of the set |
executeAction is the one that runs your business logic, and it is the first to leave off when you are not sure. Tools added in future releases stay off until you opt in.
Choose which clients may connect. An OAuth flow will authorize any registered client. allowedOAuthClients narrows that to the domains you name, and everything else is rejected before it authenticates.
Shorten the tokens. Forest's MCP access tokens last an hour by default, with a refresh token that lives for the session. tokenTtl shortens both. It can only shorten, never extend beyond what Forest grants.
The same controls apply to a Ruby back-end with one difference. Mounting the MCP Server on the back-end is Node.js only. A Ruby back-end runs the standalone Forest MCP Server instead, installed with npm install @forestadmin/mcp-server and pointed at your Ruby back-end. It is configured through environment variables rather than code, and it needs Node.js on the machine that runs it, even though your back-end is Ruby.
None of this replaces the permission model. It reduces the blast radius of a model that is briefly wrong, which every model occasionally is.
How do you review a grant you do not manage?
This is the uncomfortable part, and it has no clean answer. You can review your own staff because you control the roster. You do not control the outsourcer's roster, and you certainly do not control what the finance team's vendor ships next month.
What you can do is make the review possible from your side:
Review the organization, not the individuals. You are checking that the partner still has a contract and still needs the scope, not auditing their staffing.
Put expiry on everything external. An access that ends by default converts a review you might skip into an outage somebody will report. That is a better failure mode.
Watch the shape of usage, not just the grant. An integration that read two hundred records a day for a year and now reads forty thousand has changed, whether or not its permissions did. That is visible in your logs and nowhere else.
Ask for the owner, annually, in writing. Half the value is discovering that the named owner left eight months ago.
Run this on the same cycle as your internal access review rather than as a separate exercise, or it will not happen twice.
What does the log say when the actor is neither an employee nor your software?
It has to say something more specific than "an API call happened", and there are three things worth recording.
Which caller. Not the key, not the integration category. The named identity you issued, which is why one identity per caller is the prerequisite for all of this.
Whose data. The tenant, explicitly, so a cross-tenant read is visible as an anomaly rather than as an ordinary successful request.
On whose behalf, when there is a person. An outsourcer's analyst acting through a partner integration is still a person, and the record should say which one.
The test does not change because the actor is external. Six months from now, somebody asks why this record was read. You should be able to answer it about a partner's analyst and a finance team's procurement agent exactly as easily as about your own staff.
Frequently asked questions
Is tenant isolation the same as role-based access control?
No, and they operate at different layers. Roles decide which operations are available. Isolation decides which records exist for this caller at all. You need both, and isolation has to sit underneath, because a role applied to the wrong tenant's data is still the wrong data.
Should an external AI agent have a service account or act as a user?
If a person at the partner or in the team asked for the specific action, it should act as that person. If it runs on a schedule or on an event with nobody behind it, it needs an identity of its own. The test is whether a human user asked for this specific action.
How do we find the agents our teams have already connected?
Start with the credentials, not the tools. Every integration needed a key or an OAuth grant from somewhere, so list what has been issued and work backwards to what is using it. Anything you cannot attribute to a named owner is the finding.
The assumption was always going to break
The permission model most companies run was designed for a world where everybody who could reach the data collected a payslip from you. That world is not coming back, and the pressure is arriving from both directions at once.
The response is not a second permission system for outsiders. It is the same one, applied without the assumption: every caller has an identity, every identity has an owner, every grant has a scope and an end date, and every action has a line in the log naming who was behind it.
The model that all of this narrows, including how platform capability and data access come apart, is in our guide to user roles and permissions.
