Programmatic Usage
Use paso as a library to parse declarations and generate MCP servers programmatically.
Can I use paso as a library instead of the CLI?
Yes. paso exports a programmatic API in both Node.js and Python. Use it to parse declarations, validate them, build requests, or generate MCP servers from your own code.
parseFile / parse_file: Load and parse a usepaso.yaml file into a structured object.
validate: Check a parsed declaration against the spec. Returns errors and warnings.
generateMcpServer / generate_mcp_server: Generate a running MCP server from a parsed declaration.
buildRequest / build_request: Construct an HTTP request from a capability name and parameters.
Install
Node.js:
npm install usepaso
Python:
pip install usepaso
Parse a Declaration
Read and parse a usepaso.yaml file into a typed object.
Node.js:
import { parseFile, parseString } from 'usepaso';
// From a file
const decl = parseFile('./usepaso.yaml');
// From a string
const yaml = `
version: "1.0"
service:
name: MyAPI
description: My API service
base_url: https://api.example.com
capabilities: []
`;
const decl2 = parseString(yaml);
Python:
from usepaso import parse_file, parse_string
# From a file
decl = parse_file('./usepaso.yaml')
# From a string
yaml_content = """
version: "1.0"
service:
name: MyAPI
description: My API service
base_url: https://api.example.com
capabilities: []
"""
decl2 = parse_string(yaml_content)
Validate
Check a parsed declaration against the spec. Returns a list of errors and warnings.
Node.js:
import { parseFile, validate } from 'usepaso';
const decl = parseFile('./usepaso.yaml');
const results = validate(decl);
const errors = results.filter(r => r.level !== 'warning');
const warnings = results.filter(r => r.level === 'warning');
if (errors.length > 0) {
for (const err of errors) {
console.error(`${err.path}: ${err.message}`);
}
}
Python:
from usepaso import parse_file, validate
decl = parse_file('./usepaso.yaml')
results = validate(decl)
errors = [r for r in results if getattr(r, 'level', 'error') != 'warning']
warnings = [r for r in results if getattr(r, 'level', 'error') == 'warning']
if errors:
for err in errors:
print(f"{err.path}: {err.message}")
Parse and Validate in One Step
A convenience function that parses and validates together. Throws if validation fails. Returns the declaration and any warnings.
Node.js:
import { parseFileAndValidate } from 'usepaso';
try {
const { declaration, warnings } = parseFileAndValidate('./usepaso.yaml');
console.log(`Loaded ${declaration.service.name} with ${declaration.capabilities.length} capabilities`);
} catch (err) {
console.error(err.message);
}
Python:
from usepaso import parse_file_and_validate
try:
result = parse_file_and_validate('./usepaso.yaml')
print(f"Loaded {result.declaration.service.name} with {len(result.declaration.capabilities)} capabilities")
except ValueError as err:
print(err)
There’s also parseAndValidate / parse_and_validate for parsing from a YAML string instead of a file.
Generate an MCP Server
Create an MCP server from a declaration. The server uses stdio transport.
Node.js:
import { parseFileAndValidate, generateMcpServer } from 'usepaso';
const { declaration } = parseFileAndValidate('./usepaso.yaml');
const server = generateMcpServer(declaration);
The returned McpServer object is from the @modelcontextprotocol/sdk package. Each capability becomes an MCP tool with a typed schema and HTTP handler.
Python:
from usepaso import parse_file_and_validate, generate_mcp_server
result = parse_file_and_validate('./usepaso.yaml')
server = generate_mcp_server(result.declaration)
Logging
Pass a callback to log requests:
Node.js:
const server = generateMcpServer(declaration, (capName, result, decl) => {
console.error(`${capName} → ${result.request.method} ${result.request.url} ← ${result.status}`);
});
Build and Execute Requests
Build HTTP requests from a capability without running a server. Useful for testing or custom integrations.
Node.js:
import { parseFileAndValidate, buildRequest, executeRequest } from 'usepaso';
const { declaration } = parseFileAndValidate('./usepaso.yaml');
const cap = declaration.capabilities.find(c => c.name === 'list_issues');
const authToken = process.env.USEPASO_AUTH_TOKEN;
const req = buildRequest(cap, { organization_slug: 'my-org', project_slug: 'my-project' }, declaration, authToken);
console.log(`${req.method} ${req.url}`);
// GET https://sentry.io/api/0/projects/my-org/my-project/issues/
// Execute it
const result = await executeRequest(req);
console.log(result.status, result.body);
Python:
import os
from usepaso import parse_file_and_validate, build_request, execute_request
result = parse_file_and_validate('./usepaso.yaml')
cap = next(c for c in result.declaration.capabilities if c.name == 'list_issues')
auth_token = os.environ.get('USEPASO_AUTH_TOKEN')
req = build_request(cap, {'organization_slug': 'my-org', 'project_slug': 'my-project'}, result.declaration, auth_token)
print(f"{req.method} {req.url}")
# Execute it
res = execute_request(req)
print(res.status, res.body)
Types
The SDK exports all declaration types for use in your own code.
Node.js:
import type {
PasoDeclaration,
PasoService,
PasoAuth,
PasoCapability,
PasoInput,
PasoOutput,
PasoConstraint,
PasoPermissions,
ValidationError,
} from 'usepaso';
Key Types
| Type | Description |
|---|---|
PasoDeclaration | Top-level object: version, service, capabilities, permissions |
PasoService | Service metadata: name, description, base_url, auth |
PasoAuth | Auth config: type (api_key, bearer, oauth2, none), header, prefix |
PasoCapability | A single capability: name, method, path, permission, inputs, output, constraints |
PasoInput | Input parameter: type, required, description, values, default, in |
PasoOutput | Output field: type, description |
PasoConstraint | Constraint: max_per_hour, max_per_request, max_value, requires_field |
PasoPermissions | Permission tiers: read, write, admin, forbidden (arrays of capability names) |
ValidationError | Validation result: path, message, level (error or warning) |
API Reference
| Function | Description |
|---|---|
parseFile / parse_file | Parse a YAML file into a PasoDeclaration |
parseString / parse_string | Parse a YAML string into a PasoDeclaration |
validate | Validate a declaration, returns ValidationError[] |
parseAndValidate / parse_and_validate | Parse string + validate. Throws on errors. |
parseFileAndValidate / parse_file_and_validate | Parse file + validate. Throws on errors. |
generateMcpServer / generate_mcp_server | Generate an MCP server from a declaration |
buildRequest / build_request | Build an HTTP request from a capability + args |
executeRequest / execute_request | Execute a built request, returns status + body |
formatError / format_error | Format an error response with contextual help |
generateFromOpenApi | Convert an OpenAPI spec object to a YAML declaration (Node.js only) |
Your code, your server.
The CLI is the fastest path. The programmatic API is for when you need more control.
Next, you might want to:
- CLI Commands. command reference
- Declaration Spec. full YAML specification
- Examples. real-world declarations