$ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod"; const server = new McpServer({ name: "Sentry", version: "1.0.0",
}); server.tool( "list_issues", "List issues in a Sentry project", { organization_slug: z.string(), project_slug: z.string(), query: z.string().optional(), }, async ({ organization_slug, project_slug, query }) => { const url = new URL( `https://sentry.io/api/0/projects/${organization_slug}/${project_slug}/issues/` ); if (query) url.searchParams.set("query", query); const res = await fetch(url.toString(), { headers: { Authorization: `Bearer ${process.env.SENTRY_AUTH_TOKEN}`, }, }); const data = await res.json(); return { content: [{ type: "text", text: JSON.stringify(data) }] }; }
); const transport = new StdioServerTransport();
await server.connect(transport);
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod"; const server = new McpServer({ name: "Sentry", version: "1.0.0",
}); server.tool( "list_issues", "List issues in a Sentry project", { organization_slug: z.string(), project_slug: z.string(), query: z.string().optional(), }, async ({ organization_slug, project_slug, query }) => { const url = new URL( `https://sentry.io/api/0/projects/${organization_slug}/${project_slug}/issues/` ); if (query) url.searchParams.set("query", query); const res = await fetch(url.toString(), { headers: { Authorization: `Bearer ${process.env.SENTRY_AUTH_TOKEN}`, }, }); const data = await res.json(); return { content: [{ type: "text", text: JSON.stringify(data) }] }; }
); const transport = new StdioServerTransport();
await server.connect(transport);
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod"; const server = new McpServer({ name: "Sentry", version: "1.0.0",
}); server.tool( "list_issues", "List issues in a Sentry project", { organization_slug: z.string(), project_slug: z.string(), query: z.string().optional(), }, async ({ organization_slug, project_slug, query }) => { const url = new URL( `https://sentry.io/api/0/projects/${organization_slug}/${project_slug}/issues/` ); if (query) url.searchParams.set("query", query); const res = await fetch(url.toString(), { headers: { Authorization: `Bearer ${process.env.SENTRY_AUTH_TOKEN}`, }, }); const data = await res.json(); return { content: [{ type: "text", text: JSON.stringify(data) }] }; }
); const transport = new StdioServerTransport();
await server.connect(transport);
version: "1.0" -weight: 500;">service: name: Sentry description: Error monitoring and performance tracking base_url: https://sentry.io/api/0 auth: type: bearer capabilities: - name: list_issues description: List issues in a project method: GET path: /projects/{organization_slug}/{project_slug}/issues/ permission: read inputs: organization_slug: type: string required: true description: Organization slug in: path project_slug: type: string required: true description: Project slug in: path query: type: string description: "Search query (e.g., 'is:unresolved')" in: query
version: "1.0" -weight: 500;">service: name: Sentry description: Error monitoring and performance tracking base_url: https://sentry.io/api/0 auth: type: bearer capabilities: - name: list_issues description: List issues in a project method: GET path: /projects/{organization_slug}/{project_slug}/issues/ permission: read inputs: organization_slug: type: string required: true description: Organization slug in: path project_slug: type: string required: true description: Project slug in: path query: type: string description: "Search query (e.g., 'is:unresolved')" in: query
version: "1.0" -weight: 500;">service: name: Sentry description: Error monitoring and performance tracking base_url: https://sentry.io/api/0 auth: type: bearer capabilities: - name: list_issues description: List issues in a project method: GET path: /projects/{organization_slug}/{project_slug}/issues/ permission: read inputs: organization_slug: type: string required: true description: Organization slug in: path project_slug: type: string required: true description: Project slug in: path query: type: string description: "Search query (e.g., 'is:unresolved')" in: query
usepaso serve
usepaso serve
usepaso serve
-weight: 500;">npm -weight: 500;">install -g usepaso
-weight: 500;">npm -weight: 500;">install -g usepaso
-weight: 500;">npm -weight: 500;">install -g usepaso
-weight: 500;">pip -weight: 500;">install usepaso
-weight: 500;">pip -weight: 500;">install usepaso
-weight: 500;">pip -weight: 500;">install usepaso
usepaso init --name "Sentry"
usepaso init --name "Sentry"
usepaso init --name "Sentry"
usepaso init --from-openapi ./openapi.json
usepaso init --from-openapi ./openapi.json
usepaso init --from-openapi ./openapi.json
export USEPASO_AUTH_TOKEN="your-api-token"
usepaso serve
export USEPASO_AUTH_TOKEN="your-api-token"
usepaso serve
export USEPASO_AUTH_TOKEN="your-api-token"
usepaso serve
usepaso serving "Sentry" (6 capabilities). Agents welcome.
usepaso serving "Sentry" (6 capabilities). Agents welcome.
usepaso serving "Sentry" (6 capabilities). Agents welcome.
usepaso validate
usepaso validate
usepaso validate
valid (Sentry, 6 capabilities, 0 regrets)
valid (Sentry, 6 capabilities, 0 regrets)
valid (Sentry, 6 capabilities, 0 regrets)
usepaso validate --strict
usepaso validate --strict
usepaso validate --strict
usepaso inspect
usepaso inspect
usepaso inspect
usepaso test list_issues \ -p organization_slug=my-org \ -p project_slug=my-project \ --dry-run
usepaso test list_issues \ -p organization_slug=my-org \ -p project_slug=my-project \ --dry-run
usepaso test list_issues \ -p organization_slug=my-org \ -p project_slug=my-project \ --dry-run
usepaso doctor
usepaso doctor
usepaso doctor
- name: list_issues permission: read # Safe. No data changes. - name: resolve_issue permission: write # Modifies data. Requires caution. - name: delete_issue permission: admin # High risk. Always requires consent.
- name: list_issues permission: read # Safe. No data changes. - name: resolve_issue permission: write # Modifies data. Requires caution. - name: delete_issue permission: admin # High risk. Always requires consent.
- name: list_issues permission: read # Safe. No data changes. - name: resolve_issue permission: write # Modifies data. Requires caution. - name: delete_issue permission: admin # High risk. Always requires consent.
- name: delete_issue permission: admin consent_required: true
- name: delete_issue permission: admin consent_required: true
- name: delete_issue permission: admin consent_required: true
constraints: - max_per_hour: 100 description: Deletion is rate-limited
constraints: - max_per_hour: 100 description: Deletion is rate-limited
constraints: - max_per_hour: 100 description: Deletion is rate-limited
permissions: read: - list_issues write: - resolve_issue forbidden: - drop_database
permissions: read: - list_issues write: - resolve_issue forbidden: - drop_database
permissions: read: - list_issues write: - resolve_issue forbidden: - drop_database
usepaso connect claude-desktop
usepaso connect claude-desktop
usepaso connect claude-desktop
usepaso connect cursor
usepaso connect cursor
usepaso connect cursor
usepaso connect vscode
usepaso connect vscode
usepaso connect vscode
usepaso connect windsurf
usepaso connect windsurf
usepaso connect windsurf
usepaso init --from-openapi ./openapi.json
usepaso init --from-openapi ./openapi.json
usepaso init --from-openapi ./openapi.json
usepaso validate --strict --json
usepaso validate --strict --json
usepaso validate --strict --json
npx usepaso init --name "YourAPI"
npx usepaso init --name "YourAPI"
npx usepaso init --name "YourAPI" - Exposes tools. Each tool has a name, description, and typed inputs. The agent reads these to decide what to call.
- Handles requests. When the agent calls a tool, the server validates inputs, constructs the HTTP request, and forwards it to your API.
- Returns responses. The API response goes back through the MCP protocol to the agent. - Add pagination. Don't let agents fetch unbounded lists.
- Use constraints. Rate limits prevent agents from overwhelming your API.
- Keep declarations focused. 6 well-chosen capabilities serve agents better than 50. - What is a paso Declaration?. field-by-field YAML breakdown
- How to Create an MCP Server. manual vs. paso, side by side
- paso vs Writing MCP Servers by Hand. line-by-line code comparison
- MCP vs REST vs GraphQL. what changes when AI is the client
- Common MCP Server Errors. seven errors and how to fix them
- Five Ways to Test Before You Ship. the complete testing workflow
- MCP Server Performance. benchmarks and optimization
- What Happens When an Agent Calls DELETE. permissions and safety
- Connect Stripe to Claude Desktop. end-to-end API integration
- OpenAPI to MCP in 60 Seconds. import from existing specs
- How to Make Your API Work with Claude. connecting to Claude Desktop
- paso Works the Same in Python. Python support
- Why We Built paso. the motivation