MCP Server Permissions and Scopes Explained
MCP server permissions decide what a connected agent can read, write or delete — scopes, API keys and safe defaults explained.
MCP server permissions decide what a connected agent can actually do, from reading a table to deleting a repository. Some servers use OAuth scopes that limit access to specific actions; others hand over an API key with whatever privilege that key carries account-wide. Before installing anything, checking the tool list a server exposes — and the credential it asks for — tells you more about real risk than any star count or badge on its page.
What Can an MCP Server Actually Do Once Connected?
MCP's specification (version 2025-06-18) describes the protocol as a standardized way for applications to share contextual information with language models and expose tools and capabilities to AI systems. In practice that means every server you connect to Claude Code, Cursor or another MCP client registers a fixed list of callable tools — and each tool is a door the agent can open on its own, without you copying data between windows or approving each individual API call by hand.
The range across servers is wide. The PostgreSQL server exposes four tools — query, list_schemas, list_tables and describe_table — all of which read data back to the agent. The GitHub server exposes nine, mixing reads like get_repository and list_pull_requests with writes like create_issue, create_pull_request and create_or_update_file. The Stripe server exposes seven, and several of them move money or create real invoices. That spread is exactly why mcp server permissions deserve a look before you type an install command, not after.
OAuth Scopes vs Broad API Keys: Two Different Permission Models
Two very different credential shapes show up across the catalog. Some servers authenticate with a scoped token — GitHub's fine-grained personal access tokens let you pick exactly which repositories and which permissions (read issues, write pull requests, and so on) a token can use. Others authenticate with a single secret that carries whatever privilege it was issued with: the Stripe server's install command takes the form npx -y @stripe/mcp --api-key=YOUR_STRIPE_SECRET_KEY, and the Postgres server's command embeds a full connection string, postgresql://user:password@host:5432/dbname, directly in the config.
The practical difference is what happens if the credential leaks or the agent misfires. A narrow GitHub token limited to one repository's issues can only do damage inside that repository. A Stripe secret key or a Postgres connection string, by contrast, is the permission — there's no separate scope selector in the install command itself, so whatever the underlying account or database role allows, the agent can attempt. That makes the account or role attached to the key the real control surface.
For GitHub, the smallest recommended scope is read-only repo and issues access, upgraded to write only when a human explicitly approves the step. For Postgres, the same logic applies to database roles: use a read-only role for analysis workflows and switch to a write role only when explicit human approval gates the action. Neither server enforces this for you — it's a configuration choice made before the agent ever calls a tool.
How Do You Read the Permissions a Server Requests Before Installing?
Start with the tool list on the server's own listing and split it mentally into two columns: tools whose names start with get_, list_, describe_ or query (read) and tools whose names start with create_, update_ or delete (write). GitHub's nine tools split roughly evenly — get_repository, list_issues, list_pull_requests and get_file_contents on the read side, create_issue, create_pull_request and create_or_update_file on the write side. Stripe's seven tools lean write-heavy: create_customer, create_payment_link, create_invoice and create_refund sit next to list_customers, list_products and list_subscriptions.
Then look at the install command itself, since that's where the credential shape shows up. npx -y @modelcontextprotocol/server-github needs a personal access token configured separately, which is where scope selection happens. npx -y @stripe/mcp --api-key=YOUR_STRIPE_SECRET_KEY takes a full secret key inline. npx -y @modelcontextprotocol/server-postgres postgresql://user:password@host:5432/dbname takes a connection string inline — the string itself, including whatever role it authenticates as, is the entire permission grant.
Reading mcp server permissions this way — tool list plus credential shape — takes less time than skimming a README, and it tells you concretely what the agent can reach the moment the server starts, before any tool has actually been called. For a fuller walkthrough of this process, see how to audit an MCP server before install.
Read-Only vs Write-Enabled Servers: Why Does the Distinction Matter?
Postgres makes the read side of this concrete: the query tool runs SQL verbatim, with no query planner safety check in front of it. An agent that decides to "see all rows" will run SELECT * FROM events against a 50-million-row table and hang the connection. That's a read-only mistake — annoying, but it doesn't destroy data. The fix, per the server's own guidance, is to include a LIMIT instruction in the prompt or pre-create read-only views with sane defaults so the agent never has the option to pull everything.
Write access changes the failure mode entirely. GitHub's create_or_update_file tool commits through the API, which means no GPG signing, no pre-commit hooks, and no CI run on that commit unless branch protection blocks direct pushes. The guidance for anything beyond a small docs fix is to have the agent push to a branch and open a pull request — never commit straight to main. A read tool returning the wrong rows is a bug; a write tool committing to main is a bug that's already live.
Stripe sharpens the same point with real money attached. create_refund and create_invoice sit in the same tool list as list_customers and list_products. A misread of a customer record is a wrong answer the agent gives you; a misfired create_refund is a refund that already happened. That asymmetry — read mistakes are recoverable, write mistakes often aren't — is the reason to treat write-capable tools as a different category from read-only ones when deciding what to install.
How Do You Reduce the Blast Radius of a Compromised Key?
For GitHub, scope the fine-grained token to the specific repositories the agent actually needs, and note the pitfall: the "all repositories" toggle does not include private repositories by default, so a token that looks broad can still miss the repo you meant to grant. Combine that with the read-only repo and issues default, and upgrade to write scopes only for the specific task at hand, rather than leaving a standing write-capable token configured for daily use.
For Postgres, the equivalent move is a dedicated read-only database role for analysis workflows, separate from any role with DDL rights, so a runaway query can't drop a table even if the agent tries. Connection pooling matters too: each tool call opens a new connection unless the server sits behind a pooler, so pointing the connection string at the pooler port (typically 6543 on managed Postgres) keeps a long agent session from exhausting max_connections on the underlying database.
Rate limits act as an incidental circuit breaker. GitHub's authenticated PAT is capped at 5,000 requests per hour — an aggressive triage of 200 issues at five calls each stays comfortably under that at 1,000 requests, but a repository-wide audit across 50 repositories can hit the wall. Hitting a rate limit unexpectedly is also worth checking on its own: it can mean the agent is calling tools far more often than the task actually required.
Stripe, GitHub, Postgres: What Changes Depending on the Scope You Choose
Lined up side by side, the three servers show three different shapes of the same problem: how many tools are exposed, what credential unlocks them, and what a sane default looks like.
- GitHub — Tools exposed: 9 tools (read + write) — Auth type: Fine-grained personal access token — Recommended default: Read-only repo and issues scope
- Stripe — Tools exposed: 7 tools, mostly write — Auth type: Single Stripe secret API key — Recommended default: No separate read/write scope shown
- PostgreSQL — Tools exposed: 4 tools (read-only query surface) — Auth type: Connection string tied to DB role — Recommended default: Read-only Postgres role for analysis
GitHub's official server ships nine tools maintained by the Model Context Protocol team, covering roughly 90 percent of daily GitHub usage according to its own pitfalls notes; a more aggressive community fork adds full Actions, projects and package support for teams that need it. Its search_code tool relies on GitHub's code search index, which is eventually consistent — recently pushed code can take five to thirty minutes to appear, and some file types like lock files aren't indexed at all, so an agent should fall back to cloning and grepping when a search returns fewer than three hits. See how to use GitHub MCP with Claude Code for the full tool walkthrough.
Stripe's agent-toolkit repository had been audited by CheckMCP at 98/100, grade A, as of the listing's September 24, 2026 update — with a last commit 2 days old, 1,760 stars, an MIT licence and 77 open issues at that time. Because the install command takes one secret key rather than a granular token, the seven-tool list itself is the thing worth reviewing closely before connecting it to a live Stripe account. More detail is in how to use Stripe MCP with Claude Code.
With only four tools, the model rarely picks the wrong one. The tradeoff is that the server has no built-in sandbox — the connection string's database role is the only thing standing between "read some rows" and "drop a table," which is why the role matters more than the tool count.
Frequently Asked Questions About MCP Server Permissions
Does OAuth automatically make a server safer than an API key?
Not automatically. A scoped OAuth token only helps if the server requests narrow scopes and you grant narrow ones — a broad OAuth grant covering an entire account behaves like a broad API key. GitHub's fine-grained tokens are useful because you can pick individual repositories and specific read or write permissions; Stripe's and Postgres's credentials in this catalog don't offer that same per-tool granularity, so the account or database role behind the key is what actually limits the agent.
What tools does the GitHub MCP server expose by default?
The official server lists nine: get_repository, list_issues, create_issue, list_pull_requests, create_pull_request, get_file_contents and create_or_update_file among them, covering repositories, issues, pull requests and file reads or writes. Roughly half of those are read-only and the rest can change data in the repository, which is why the description recommends starting with a read-only repo and issues scope and adding write access only when a human is approving each step.
Does the Stripe MCP listing state a subscription price?
The available facts describe Stripe's audit score, star count, licence and open issue count, but not a subscription price for using the server itself. What's documented is the install command, which takes a Stripe secret API key directly, and the seven tools that key unlocks — from create_customer and list_products to create_refund, all reachable through whatever privilege that one key carries.