Give each agent its own credential, then bind that credential to the sources, tool classes and expiry window needed for one job. Do not hand an agent a human token or a workspace-wide integration secret; put those behind the MCP server or gateway and make the agent key authorize only the protocol actions it should perform. The useful boundary is source plus read/write class plus revocation path, verified with real tools/list and tools/call behavior.
Start With The Job The Key Serves
An agent key should describe a task boundary, not a person, team or vendor preference. A support triage agent might need GitHub issue search, Sentry event lookup and a read-only customer-status view. It does not need Stripe refunds, Google Drive exports or a general SQL console. A finance review agent might need invoice reports and a picked folder, but no source-code tools. If those two agents share one broad key, every prompt, plugin and accidental tool choice inherits the larger blast radius.
Write the policy in terms an MCP server can enforce. MCP clients discover tools with tools/list and invoke tools with tools/call; the tool specification allows the returned set to vary by the authorization presented on the request. That means a server can show one key only the tools its grants permit while another key sees a different set. Use that as the design point: one stable endpoint, many credentials, each credential carrying the smallest source set that makes its job possible.
The related article on read-only versus write tools goes deeper on operation class. This guide is about the credential that sits above that decision: which sources may be opened, which tool class may be called, how long the key lives and what the audit log should prove after the fact.
Make Sources The First Boundary
Start with a source allowlist because source names match how engineers reason during review. A policy that says sources: ["github", "sentry"] is easier to audit than a policy that lists 37 tool names with no system context. It also survives ordinary upstream changes: if GitHub adds a new read-only search tool, the team can decide whether the source-level policy plus read-only policy is enough, instead of hunting for every agent config that mentions GitHub.
{
"key_name": "support-triage-readonly",
"subject": "agent:support-triage",
"sources": ["github", "sentry", "postgres_support"],
"grants": ["call:tools"],
"expires_at": "2026-11-13T00:00:00Z",
"max_calls_per_hour": 300,
"rotation_owner": "support-platform"
}That policy deliberately avoids a global tools:* grant. It says the key can call read-class tools, but only inside three sources. If the same workflow later needs to create GitHub issues, issue a second key or update the policy through the same review path you would use for any other production permission change. The migration guide for moving from per-agent configs to one endpoint is the cleaner path when source credentials are still scattered through local client files.
Split Read Tools From Write Tools
The read/write split should be enforced before an upstream request leaves your boundary. MCP tool annotations include hints such as readOnlyHint, destructiveHint, idempotentHint and openWorldHint, but the MCP docs are explicit that annotations are not trustworthy unless they come from a trusted server. Treat a missing or untrusted readOnlyHint as write-capable for authorization. A model should not get to turn a broad key into a narrow one by choosing a friendly-sounding tool description.
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list",
"params": {}
}{
"jsonrpc": "2.0",
"id": 1,
"result": {
"tools": [
{
"name": "github/search_issues",
"description": "Search issues in approved repositories.",
"inputSchema": {
"type": "object",
"properties": {
"query": { "type": "string" },
"limit": { "type": "integer" }
},
"required": ["query"]
},
"annotations": { "readOnlyHint": true }
},
{
"name": "github/create_issue",
"description": "Create an issue in an approved repository.",
"inputSchema": {
"type": "object",
"properties": {
"repo": { "type": "string" },
"title": { "type": "string" },
"body": { "type": "string" }
},
"required": ["repo", "title"]
},
"annotations": { "readOnlyHint": false, "destructiveHint": false }
}
]
}
}A key with only call:tools should be able to call github/search_issues after the source and trust checks pass. It should be denied for github/create_issue unless a separate write grant is present. Log the denial as a policy decision, not as an upstream failure; no provider token should be used for a call the agent credential was never allowed to make.
Keep Upstream Credentials Narrow
Agent-key scope and upstream scope are different layers, and both matter. OAuth defines access-token scope as the resource access requested by the client and reflected by the authorization server; MCP HTTP authorization builds on OAuth-style protected resource metadata and authorization-server discovery. If the MCP endpoint signs in to an upstream provider on behalf of a workspace, request the narrow upstream scopes that match the source, then apply the agent-key policy on top.
For databases, use native grants before the agent ever sees a tool. A reporting role can connect to one database, use one schema and select from approved tables or views:
CREATE ROLE agent_support_reader LOGIN PASSWORD 'replace-with-secret';
GRANT CONNECT ON DATABASE appdb TO agent_support_reader;
GRANT USAGE ON SCHEMA support_reporting TO agent_support_reader;
GRANT SELECT ON ALL TABLES IN SCHEMA support_reporting TO agent_support_reader;For Drive-style document access, prefer per-file selection over broad document access when the product supports it. Google's Drive documentation describes drive.file as a narrower scope that lets users choose which files to share with an app, especially when combined with Picker. The same idea applies at the agent layer: a source named drive_selected_contracts is easier to review than a source named drive_all_files.
Put Scoped Keys Into Real Clients
The client configuration should contain one endpoint and one agent credential. It should not contain a GitHub token, database password or provider refresh token. In Claude Code, a remote HTTP MCP endpoint can be added from a URL; if the endpoint uses an authorization header, pass the scoped agent key there:
claude mcp add --transport http spyn3 https://api.spyn3.com/agent/mcp --header "Authorization: Bearer $SPYN3_AGENT_KEY"Cursor supports project configuration at .cursor/mcp.json and environment interpolation in remote-server headers. That makes the committed file stable while each developer or automation supplies a different scoped key:
{
"mcpServers": {
"spyn3": {
"url": "https://api.spyn3.com/agent/mcp",
"headers": {
"Authorization": "Bearer ${env:SPYN3_AGENT_KEY}"
}
}
}
}VS Code can use an mcp.json file with a top-level servers object for remote MCP servers. Keep the endpoint in the file and keep the secret in the authentication flow or user secret handling:
{
"servers": {
"spyn3": {
"type": "http",
"url": "https://api.spyn3.com/agent/mcp"
}
}
}After wiring a client, test scope with protocol calls rather than visual inspection. Run tools/list and confirm only the expected sources or source-opening tools are reachable. Then run one allowed read call and one intentionally denied write call. A passing setup proves both sides: the client can authenticate, and the server enforces the key's boundary.
Audit And Rotate By Key
Least privilege is incomplete unless each key has an owner, an expiry and a removal path. Record the key id, subject, source allowlist, grants, issuer, creation time, expiry time and last-used time. For each tools/call, log the key id, source, tool, required grant, decision, upstream credential version, duration and result class. Avoid logging raw secrets or full result payloads; the audit trail needs the permission decision and request shape, not another copy of sensitive data.
Rotation should be boring. Issue a replacement key with the same policy, update the client secret store, verify one allowed call, then revoke the old key and verify it can no longer list or call tools. If the upstream credential changes instead, keep the agent key and client files unchanged; rotate the source credential behind the endpoint and prove the next tool call used the new upstream version. That operational model pairs with rotating credentials without changing every agent config.
Review Test
If a reviewer cannot answer "which systems can this key reach?" and "can it write?" from one policy record, the key is too vague. If revocation requires editing multiple repos, the secret is sitting in the wrong layer.
How SPYN3 scopes keys
A SPYN3 key carries two independent limits. One is which sources it may reach. The other is whether it may call write tools at all: call:tools covers read-only tools, and call:write_tools is a separate grant. A key that can only read sources you name is a small thing to leak. The dashboard creates and revokes keys, and a revoked key is refused on its next request.
Built for the next step
Issue smaller keys
Give each agent only the sources and tool classes it needs.
Scope a keySPYN3 is a consolidated MCP layer: one hosted endpoint in front of every system you connect — MCP servers, Postgres, REST APIs, Google Drive — with tools foldered by source and read/write permissions per key. Switching agents means moving one URL. Free plan available; current capabilities are documented on the product facts page.
Sources
- MCP specification: tools — tool discovery, invocation and security considerations. Verified 14 Oct 2026
- MCP project: tool annotations — risk hints and their enforcement limits. Verified 14 Oct 2026
- MCP specification: authorization — OAuth-based authorization for HTTP MCP servers. Verified 14 Oct 2026
- RFC 6749: OAuth 2.0 Authorization Framework — authorization grants, access tokens, refresh tokens and scopes. Verified 14 Oct 2026
- PostgreSQL documentation: GRANT — object privileges including SELECT and schema-level grants. Verified 14 Oct 2026
- Google Drive API: choose scopes — drive.file scope and narrow per-file Drive access. Verified 14 Oct 2026
- Anthropic docs: Claude Code MCP setup — Claude Code MCP commands, scopes, transports and JSON configuration. Verified 14 Oct 2026
- VS Code documentation: add and manage MCP servers — VS Code MCP configuration, trust and logging behavior. Verified 14 Oct 2026
- Cursor documentation: MCP integrations — Cursor MCP configuration locations, remote URL entries, headers and approval behavior. Verified 14 Oct 2026
