Permissions & Safety
Control what MCP tools agents can access with permission tiers and constraints.
How does paso control what agents can do?
paso provides multiple layers of safety to control what agents can do with your API. Every capability is classified by risk, and you can add constraints, consent gates, and a forbidden list.
read: Safe operations that don’t modify data. Agents can call these without special approval.
write: Operations that modify data. Should use consent_required: true so the user confirms before execution.
admin: High-risk operations like deleting resources or changing access controls. Always require consent.
forbidden: Capabilities explicitly blocked from agents. They are never exposed as MCP tools.
consent_required: A boolean flag that forces the agent to show a confirmation dialog before executing the capability.
constraint: A business rule applied to a capability. Limits calls per hour, items per request, or restricts input values.
Permission Tiers
Every capability has a permission field that classifies its risk level.
read
Safe operations that don’t modify data. Listing items, fetching details, searching.
- name: list_issues
description: List issues in a project
method: GET
path: /projects/{organization_slug}/{project_slug}/issues/
permission: read
write
Operations that modify data. Creating items, updating fields, posting content.
- name: resolve_issue
description: Mark an issue as resolved
method: PUT
path: /issues/{issue_id}/
permission: write
consent_required: true
inputs:
issue_id:
type: string
required: true
description: The issue ID
in: path
status:
type: enum
required: true
values: [resolved, unresolved, ignored]
description: New status for the issue
admin
High-risk operations. Deleting resources, changing settings, managing access.
- name: delete_issue
description: Permanently delete an issue and all its events
method: DELETE
path: /issues/{issue_id}/
permission: admin
consent_required: true
inputs:
issue_id:
type: string
required: true
description: The issue ID
in: path
Consent Required
For sensitive operations, require the user to explicitly approve each call.
- name: create_payment_intent
description: Create a payment intent to charge a customer
method: POST
path: /payment_intents
permission: write
consent_required: true
inputs:
amount:
type: integer
required: true
description: Amount in cents (e.g., 2000 = $20.00)
currency:
type: string
required: true
description: Three-letter ISO currency code (e.g., usd)
When consent_required: true, the agent shows a confirmation dialog before executing.
Constraints
Limit resource usage and prevent abuse. Constraints are an array of objects on each capability.
max_per_hour
Maximum calls per hour.
constraints:
- max_per_hour: 100
description: Status changes are rate-limited
max_per_request
Maximum items per request (for bulk operations).
constraints:
- max_per_request: 50
description: Batch operations limited to 50 items
max_value
Maximum numeric value for an input.
constraints:
- max_value: 99999999
description: Maximum single charge is $999,999.99
allowed_values
Restrict an input to specific values beyond its enum.
constraints:
- allowed_values: [usd, eur, gbp]
description: Only these currencies are supported
requires_field
Another input that must be present when this constraint applies.
constraints:
- requires_field: currency
description: Currency is required when specifying an amount
Combining Constraints
Use multiple constraint objects together:
constraints:
- max_per_hour: 500
description: Payment creation is rate-limited
- max_value: 99999999
description: Maximum single charge is $999,999.99
- requires_field: currency
description: Currency is required when specifying an amount
Permissions Object
The top-level permissions object groups capabilities by tier. This provides an explicit access control list.
permissions:
read:
- list_issues
- get_issue
- list_projects
write:
- resolve_issue
- assign_issue
admin:
- delete_issue
If permissions is omitted, each capability’s permission field is used directly.
Forbidden
The forbidden list explicitly blocks capabilities from being exposed to agents.
permissions:
read:
- list_customers
- get_customer
write:
- create_customer
forbidden:
- delete_customer
A capability cannot appear in both a permission tier and forbidden. The forbidden tier may reference capability names not declared in capabilities, to explicitly block endpoints you don’t want exposed.
Safety Best Practices
1. Start Conservative
Expose only what’s needed. It’s easier to add capabilities later than remove them.
2. Use Permission Tiers
Assign the lowest tier appropriate for each operation.
# Read for safe queries
- name: list_customers
permission: read
# Write for modifications
- name: create_customer
permission: write
# Admin for deletion
- name: refund_payment
permission: admin
3. Require Consent for Mutations
Any operation that creates, modifies, or deletes data should require consent.
- name: create_customer
permission: write
consent_required: true
- name: delete_issue
permission: admin
consent_required: true
4. Add Constraints to Write and Admin
Rate limits and guardrails prevent abuse.
- name: resolve_issue
permission: write
consent_required: true
constraints:
- max_per_hour: 100
description: Bulk status changes are rate-limited
5. Use Forbidden for Sensitive Operations
Explicitly block capabilities you never want agents to use.
permissions:
read:
- list_customers
write:
- create_customer
forbidden:
- delete_customer
Real-World Example
A Stripe declaration with careful permission boundaries:
version: "1.0"
service:
name: Stripe
description: Payment processing and billing infrastructure for internet businesses
base_url: https://api.stripe.com/v1
auth:
type: bearer
capabilities:
- name: list_customers
description: List customers, optionally filtered by email
method: GET
path: /customers
permission: read
inputs:
email:
type: string
description: Filter by exact email match
in: query
limit:
type: integer
description: Number of results (1-100)
default: 10
in: query
- name: create_customer
description: Create a new customer
method: POST
path: /customers
permission: write
consent_required: true
inputs:
email:
type: string
required: true
description: Customer email address
name:
type: string
description: Customer full name
- name: create_payment_intent
description: Create a payment intent to charge a customer
method: POST
path: /payment_intents
permission: write
consent_required: true
inputs:
amount:
type: integer
required: true
description: Amount in cents (e.g., 2000 = $20.00)
currency:
type: string
required: true
description: Three-letter ISO currency code
constraints:
- max_value: 99999999
description: Maximum single charge is $999,999.99
- max_per_hour: 500
description: Payment creation is rate-limited
- name: refund_payment
description: Create a refund for a payment intent
method: POST
path: /refunds
permission: admin
consent_required: true
inputs:
payment_intent:
type: string
required: true
description: The payment intent ID to refund
amount:
type: integer
description: Amount to refund in cents (partial refund). Omit for full refund.
permissions:
read:
- list_customers
write:
- create_customer
- create_payment_intent
admin:
- refund_payment
forbidden:
- delete_customer
Your API is locked down.
Permission tiers, consent gates, constraints, and a forbidden list. Agents can only do what you allow.
Next, you might want to:
- Declarations. learn the full YAML format
- CLI Commands. test capabilities before deployment
- Testing Capabilities. safely preview requests
From the blog:
- What Happens When an Agent Calls DELETE. why permission tiers and consent gates exist