On this page
A paso declaration is a usepaso.yaml file. It describes your API and what agents are allowed to do with it. paso reads this file and generates a standards-compliant MCP server. No protocol code. No SDK wiring. One file.
The smallest working declaration
version: "1.0"
service:
name: Inventory
description: Product inventory management for e-commerce
base_url: https://api.inventory.com/v1
auth:
type: bearer
capabilities:
- name: list_products
description: List all products, optionally filtered by category
method: GET
path: /products
permission: read
inputs:
category:
type: string
description: Filter by product category
in: query
That’s 18 lines. It produces one MCP tool that agents can call. Let’s break it down.
service: who you are
The service block tells agents what this API does and how to reach it.
service:
name: Inventory
description: Product inventory management for e-commerce
base_url: https://api.inventory.com/v1
auth:
type: bearer
- name: Shows up in logs and tool registration. Keep it short.
- description: Agents read this to decide if the API is relevant. Write it for an LLM, not a human.
- base_url: The root URL. All capability paths are appended to this.
- auth.type: How the token is sent. Options:
bearer,api_key,oauth2,none.
The actual token is always provided at runtime via USEPASO_AUTH_TOKEN. It never goes in the YAML file.
capabilities: what agents can do
Each capability maps to one API endpoint. It’s a single action an agent can take.
capabilities:
- name: create_product
description: Create a new product listing
method: POST
path: /products
permission: write
consent_required: true
inputs:
name:
type: string
required: true
description: Product name
price:
type: integer
required: true
description: Price in cents (e.g., 1999 = $19.99)
category:
type: enum
values: [electronics, clothing, food, other]
description: Product category
The required fields: name, description, method, path, permission.
- name: Must be
snake_case. This becomes the MCP tool name. - description: Agents use this to decide when to call the tool. Be specific. “Create a new product listing” beats “Create product”.
- method:
GET,POST,PUT,PATCH,DELETE. - path: Relative to
base_url. Use{param}for path variables and add a matching input within: path. - permission:
read,write, oradmin. Controls the risk tier.
inputs
Each input describes a parameter the agent sends.
| Field | Required | Purpose |
|---|---|---|
type | Yes | string, integer, number, boolean, enum, array, object |
required | No | Default: false |
description | Yes | What this parameter does |
in | No | Where it goes: path, query, body, header. Defaults to body for POST/PUT/PATCH, query for GET/DELETE |
values | For enum | Allowed values |
default | No | Default value |
consent_required
When set to true, the agent shows a confirmation dialog before executing. Use it for anything that creates, modifies, or deletes data.
permissions: what’s allowed and what’s not
The permissions object groups capabilities by risk tier.
permissions:
read:
- list_products
- get_product
write:
- create_product
- update_product
admin:
- delete_product
forbidden:
- purge_all_products
- read: Safe operations. Listing, searching, fetching details.
- write: Modifications. Creating, updating. Should use
consent_required: true. - admin: High-risk. Deleting, changing access controls. Always require consent.
- forbidden: Explicitly blocked. Never exposed as MCP tools.
If you omit the permissions object, each capability’s individual permission field is used directly.
constraints: guardrails
Add business rules to limit what agents can do.
- name: create_product
permission: write
consent_required: true
constraints:
- max_per_hour: 100
description: Product creation is rate-limited
- max_value: 99999999
description: Maximum price is $999,999.99
Available constraints: max_per_hour, max_per_request, max_value, allowed_values, requires_field.
A complete declaration
Putting it all together for a real API:
version: "1.0"
service:
name: Inventory
description: Product inventory management for e-commerce
base_url: https://api.inventory.com/v1
auth:
type: bearer
capabilities:
- name: list_products
description: List all products, optionally filtered by category
method: GET
path: /products
permission: read
inputs:
category:
type: string
description: Filter by product category
in: query
limit:
type: integer
description: Number of results (1-100)
default: 20
in: query
- name: create_product
description: Create a new product listing
method: POST
path: /products
permission: write
consent_required: true
inputs:
name:
type: string
required: true
description: Product name
price:
type: integer
required: true
description: Price in cents
constraints:
- max_per_hour: 100
description: Product creation is rate-limited
- name: delete_product
description: Permanently delete a product and its history
method: DELETE
path: /products/{product_id}
permission: admin
consent_required: true
inputs:
product_id:
type: string
required: true
description: The product ID
in: path
permissions:
read:
- list_products
write:
- create_product
admin:
- delete_product
30 lines of YAML for a three-tool MCP server with permission tiers, consent gates, and rate limits. The equivalent hand-written MCP server is 200+ lines of TypeScript.
Verify it
usepaso validate
valid (Inventory, 3 capabilities, 0 regrets)
Then serve it:
export USEPASO_AUTH_TOKEN="your-token"
usepaso serve
Your API is agent-ready.
Questions
Do I need a separate YAML file per API?
Yes. One usepaso.yaml per API. If you have a Stripe API and a Sentry API, that’s two files, two servers.
What if my API uses an API key instead of a bearer token?
Set auth.type: api_key and optionally auth.header: X-API-Key. paso sends the USEPASO_AUTH_TOKEN value in that header.
Can I generate this from an OpenAPI spec?
Yes. usepaso init --from-openapi ./openapi.json converts an OpenAPI 3.x spec into a usepaso.yaml. You’ll want to review and customize the output.
Related:
- How to Create an MCP Server for a side-by-side comparison with hand-written servers
- Common MCP Server Errors for fixing validation issues
- What Happens When an Agent Calls DELETE for why permissions matter