On this page
You give an AI agent access to your API. The agent can list records. It can create records. It can also delete them.
The question every security-conscious team asks: “What stops the agent from deleting everything?”
If your MCP server has no permission model, the answer is: nothing.
The default is open
A basic MCP server registers tools. Each tool is callable. There’s no built-in distinction between reading data and deleting it. An agent that can call list_users can also call delete_user if both tools are registered.
This is fine for local development. It’s not fine when the agent is connected to a production API with real data.
Three layers of control
Agent access control needs three things:
- Classification. Which operations are reads? Which are writes? Which are destructive?
- Consent. Which operations require human confirmation before execution?
- Prohibition. Which operations should never be callable, period?
Without all three, you have a gap. Classification without consent means the agent can silently write data. Consent without prohibition means a confused agent can still ask to delete the production database. And if nothing is classified, you can’t apply either of the other two.
How paso handles this
paso’s declaration format has permission controls built into the same YAML where you declare capabilities.
Permission tiers
Every capability gets a permission level: read, write, or admin.
capabilities:
- name: list_projects
description: List all projects
method: GET
path: /projects
permission: read
- name: create_project
description: Create a new project
method: POST
path: /projects
permission: write
- name: delete_project
description: Permanently delete a project and all its data
method: DELETE
path: /projects/{id}
permission: admin
The tiers are enforced at the server level. An agent operating with read permissions cannot call write or admin tools.
Consent gates
For operations where the agent should ask before acting, add consent_required: true:
- name: resolve_issue
description: Mark an issue as resolved
method: PUT
path: /issues/{id}
permission: write
consent_required: true
When Claude encounters a tool with consent_required, it shows the user what it’s about to do and waits for confirmation. The agent cannot silently mutate data.
Use consent gates for any operation that changes state: updates, creates, deletes. Read operations don’t need them.
The forbidden list
Some endpoints should never be callable by an agent. Not even with confirmation.
permissions:
read:
- list_projects
- get_project
write:
- create_project
- resolve_issue
admin:
- delete_project
forbidden:
- delete_organization
- transfer_ownership
- update_billing
- rotate_api_keys
Forbidden capabilities are not registered as MCP tools. The agent doesn’t see them. It can’t call them. They don’t exist from the agent’s perspective.
This is the strongest control. If you have endpoints that should never be agent-accessible (billing, account deletion, key rotation), put them in forbidden.
Rate limits
Even safe operations can be harmful at scale. An agent calling list_users a thousand times per hour is a problem.
- name: list_users
description: List all users
method: GET
path: /users
permission: read
constraints:
max_per_hour: 60
paso enforces max_per_hour at the server level. If the agent exceeds the limit, the server returns an error. No API call is made.
The checklist
Before connecting an MCP server to a production API:
- Every capability has a
permissionlevel (read, write, or admin) - Every write and admin capability has
consent_required: true - Destructive endpoints (DELETE, account-level changes) are either
adminwith consent or inforbidden - Sensitive endpoints (billing, auth, settings) are in
forbidden - High-frequency read endpoints have
max_per_hourconstraints
paso’s --strict validation mode checks for most of these:
usepaso validate --strict
warning: delete_project has permission "admin" but consent_required is not set.
Agents could delete data without human confirmation.
warning: No forbidden list. Consider adding sensitive endpoints.
Strict mode won’t stop you from shipping. It flags the things you probably want to think about.
What this doesn’t solve
Permission tiers and consent gates control agent behavior at the MCP layer. They don’t replace your API’s own authorization.
If your API token has admin access, the MCP server can make admin requests. paso controls which tools the agent can call and whether it needs confirmation. Your API’s auth controls what the token is allowed to do.
Use both. A scoped API token (read-only, or limited to specific resources) combined with paso’s permission model gives you defense in depth.
The answer
“What stops the agent from deleting everything?”
Three things. Permission tiers that classify operations. Consent gates that require human confirmation. A forbidden list that removes destructive endpoints entirely.
Declare them in YAML. paso enforces them at the server level.
permissions:
read:
- list_projects
- get_project
write:
- create_project
- update_project
forbidden:
- delete_project
- delete_organization
usepaso validate --strict
usepaso serve
Your API is agent-accessible. With boundaries.
Related:
- The Complete Guide to MCP Servers. the full reference
- How to Create an MCP Server for the full setup walkthrough
- paso vs. Writing MCP Servers by Hand to understand where paso fits
- Why We Built paso for the motivation behind the safety model
Read more:
- Permissions & Safety for the full permission spec
- Declaration format for all YAML fields