MCP and OAuth
MCP clients such as Claude Code, Cursor and Claude Desktop reach your actions through one server the package mounts, as the person whose token they hold.
- Claude Codeclaude mcp add
- Cursor.cursor/mcp.json
- Claude Desktopthrough mcp-remote
- auth:sanctumreads the bearer tokenno valid token: 401
- throttle60 a minute, per personpast it: 429
- the MCP doorRead or Write, and #[Expose] allows MCPnever listed
- token abilitiesnamed by the token; * never countsnot named: not listed
- the rest of the pipelinemembership, authorize(), validation, handle()
One server, one tool per action
The server answers at mcp/actions. When your actions are tenant-scoped, set mcp.tenant_path (such as mcp/t/{team}, with your tenant.parameter in the braces) and they are served there instead, one URL per tenant. Each Read or Write action whose #[Expose] allows MCP is one tool. See Where it is mounted.
A token names what it reaches
A client connects with a person's token, and over MCP an ability counts only when the token names it: actions:read, actions:write, and tenant:{key} to bind it to one tenant. Your app mints it; the package ships no token page.
$user->createToken('Claude Code', [
'actions:read',
'actions:write',
'tenant:'.$team->getKey(),
], now()->addDays(90));| The token names | Read actions | Write actions | Destructive, External |
|---|---|---|---|
| actions:read | yes | no | no |
| actions:read, actions:write | yes | yes | no |
| * | no | no | no |
The client then runs as that person, and never does more than the person could in the app: membership, authorize() and validation run on every call. See Tokens and abilities.
One budget per person
All of one person's tokens and tenant URLs share one budget, mcp.per_minute. See Throttle.
Remote clients sign in with OAuth
A Claude custom connector or ChatGPT connects from its provider's cloud and has no field for a pasted token. Add Laravel Passport and name its guard in mcp.middleware: that one line is the switch.
'mcp' => [
// ...
'middleware' => ['auth:sanctum,api', 'throttle:agentic-actions-mcp'],
],- The person adds the URLa custom connector, with mcp/t/design
- 401 names the scopesand the path's OAuth metadata
- The client registersthen the person signs in
- Consent screenthe person approves one URL
- One connectionits token reaches only that URL
- revoke()the next call answers 401
The consent screen appears for every authorization that names one of the package's MCP URLs, even for a client approved before. See OAuth.
Connections can be revoked
Each approval records one connection per client and person. List them on the person's settings page, and revoke() ends the client's tokens at once: its next call answers 401. See Connected apps, and the guarantees in Security.