<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Shiva Padakanti</title>
    <description>The latest articles on DEV Community by Shiva Padakanti (@5h1vmani).</description>
    <link>https://dev.to/5h1vmani</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3845955%2Fbf4e0c61-6129-46f1-a73c-65d1ed3a9a8a.jpg</url>
      <title>DEV Community: Shiva Padakanti</title>
      <link>https://dev.to/5h1vmani</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/5h1vmani"/>
    <language>en</language>
    <item>
      <title>How to Create an MCP Server</title>
      <dc:creator>Shiva Padakanti</dc:creator>
      <pubDate>Thu, 02 Apr 2026 10:56:02 +0000</pubDate>
      <link>https://dev.to/5h1vmani/how-to-create-an-mcp-server-540k</link>
      <guid>https://dev.to/5h1vmani/how-to-create-an-mcp-server-540k</guid>
      <description>&lt;p&gt;An MCP server exposes your API as tools that AI agents can call. The Model Context Protocol defines the transport and schema. You provide the tools.&lt;/p&gt;

&lt;p&gt;There are two ways to build one.&lt;/p&gt;

&lt;h2&gt;
  
  
  The manual way
&lt;/h2&gt;

&lt;p&gt;Install the SDK and write TypeScript:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @modelcontextprotocol/sdk
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;McpServer&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@modelcontextprotocol/sdk/server/mcp.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;StdioServerTransport&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@modelcontextprotocol/sdk/server/stdio.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;zod&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;McpServer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sentry&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1.0.0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;list_issues&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;List issues for a project&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;organization_slug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;project_slug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;organization_slug&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;project_slug&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="s2"&gt;`https://sentry.io/api/0/projects/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;organization_slug&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;project_slug&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/issues/`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Bearer &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SENTRY_TOKEN&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}]&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;transport&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;StdioServerTransport&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;transport&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's one tool. For six tools with input validation, error handling, auth forwarding, and permission checks, you're looking at a few hundred lines. For each API you want to expose.&lt;/p&gt;

&lt;h2&gt;
  
  
  The paso way
&lt;/h2&gt;

&lt;p&gt;Write YAML. Run one command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; usepaso
usepaso init &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"Sentry"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates a &lt;code&gt;usepaso.yaml&lt;/code&gt; file. Fill in your capabilities:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1.0"&lt;/span&gt;

&lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Sentry&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Error monitoring for software teams&lt;/span&gt;
  &lt;span class="na"&gt;base_url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://sentry.io/api/0&lt;/span&gt;
  &lt;span class="na"&gt;auth&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bearer&lt;/span&gt;

&lt;span class="na"&gt;capabilities&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;list_issues&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;List issues for a project&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;GET&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/projects/{organization_slug}/{project_slug}/issues/&lt;/span&gt;
    &lt;span class="na"&gt;permission&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;read&lt;/span&gt;
    &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;organization_slug&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
        &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;The organization slug&lt;/span&gt;
        &lt;span class="na"&gt;in&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;path&lt;/span&gt;
      &lt;span class="na"&gt;project_slug&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
        &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;The project slug&lt;/span&gt;
        &lt;span class="na"&gt;in&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;path&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Validate it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;usepaso validate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;valid (Sentry, 1 capability, 0 regrets)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Start the server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;USEPASO_AUTH_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your-sentry-token usepaso serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;usepaso serving "Sentry" (1 capability). Agents welcome.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's a production MCP server. paso handles protocol compliance, request routing, auth forwarding, input validation, and error formatting.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you don't write
&lt;/h2&gt;

&lt;p&gt;No TypeScript request handlers. No Zod schema definitions. No transport setup. No auth forwarding logic. No error formatting.&lt;/p&gt;

&lt;p&gt;Each new capability is a few lines of YAML:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;resolve_issue&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Resolve an issue&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PUT&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/issues/{issue_id}/&lt;/span&gt;
    &lt;span class="na"&gt;permission&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt;
    &lt;span class="na"&gt;consent_required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;issue_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
        &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;The issue ID&lt;/span&gt;
        &lt;span class="na"&gt;in&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;path&lt;/span&gt;
      &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;enum&lt;/span&gt;
        &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="na"&gt;values&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;resolved&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;unresolved&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;ignored&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
        &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;New status for the issue&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Six capabilities. One YAML file. No TypeScript to maintain.&lt;/p&gt;

&lt;h2&gt;
  
  
  Side-by-side
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Manual MCP server&lt;/th&gt;
&lt;th&gt;paso&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Language&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;TypeScript or Python&lt;/td&gt;
&lt;td&gt;YAML&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Lines of code&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;100-500+ per API&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Schema definitions&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Zod / Pydantic in code&lt;/td&gt;
&lt;td&gt;Declared in YAML&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Auth handling&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;You write it&lt;/td&gt;
&lt;td&gt;Automatic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Input validation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;You write it&lt;/td&gt;
&lt;td&gt;Automatic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;New endpoint&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;New handler function&lt;/td&gt;
&lt;td&gt;New YAML block&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Protocol changes&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Rewrite handlers&lt;/td&gt;
&lt;td&gt;Update paso&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Custom logic&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Full control&lt;/td&gt;
&lt;td&gt;Not supported&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Already have an OpenAPI spec?
&lt;/h2&gt;

&lt;p&gt;Generate the declaration from it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;usepaso init &lt;span class="nt"&gt;--from-openapi&lt;/span&gt; ./openapi.json &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"Sentry"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;paso reads the spec, generates the YAML, and you edit it to curate which endpoints agents can access.&lt;/p&gt;

&lt;h2&gt;
  
  
  Connect to Claude Desktop
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;usepaso connect claude-desktop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;paso writes the config for you. Restart Claude Desktop. Your API is now agent-ready.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verify before you ship
&lt;/h2&gt;

&lt;p&gt;paso gives you five checks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;usepaso validate &lt;span class="nt"&gt;--strict&lt;/span&gt;    &lt;span class="c"&gt;# Structure + best practices&lt;/span&gt;
usepaso inspect              &lt;span class="c"&gt;# Review what agents will see&lt;/span&gt;
usepaso &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;--all&lt;/span&gt; &lt;span class="nt"&gt;--dry-run&lt;/span&gt; &lt;span class="c"&gt;# Verify all requests build correctly&lt;/span&gt;
usepaso doctor               &lt;span class="c"&gt;# End-to-end setup check&lt;/span&gt;
usepaso serve                &lt;span class="c"&gt;# Ship it&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The tradeoff
&lt;/h2&gt;

&lt;p&gt;The manual approach gives you full control over every handler. You can run database queries, call multiple APIs in sequence, or apply complex business logic before returning a result. paso gives you an MCP server in minutes with no protocol code. If your API follows REST conventions and you want agents to call it, paso is faster. If your MCP server needs custom orchestration logic, write it by hand.&lt;/p&gt;

&lt;h2&gt;
  
  
  Questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Does paso work with Cursor and other MCP clients?&lt;/strong&gt;&lt;br&gt;
Yes. paso generates a standard MCP server. Any MCP client that supports the Model Context Protocol can connect to it: Claude Desktop, Cursor, Windsurf, and others.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I use paso with Python?&lt;/strong&gt;&lt;br&gt;
Yes. &lt;code&gt;pip install usepaso&lt;/code&gt;. Same CLI, same YAML format, same output. &lt;a href="https://usepaso.dev/blog/paso-works-the-same-in-python/" rel="noopener noreferrer"&gt;Read more about Python support.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What if my API needs custom logic per request?&lt;/strong&gt;&lt;br&gt;
paso handles REST endpoint mapping. If a capability requires database queries, multi-step orchestration, or custom transformations, write that handler manually using the MCP SDK.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Related:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://usepaso.dev/blog/the-complete-guide-to-mcp-servers/" rel="noopener noreferrer"&gt;The Complete Guide to MCP Servers&lt;/a&gt;. the full reference&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://usepaso.dev/blog/openapi-to-mcp-in-60-seconds/" rel="noopener noreferrer"&gt;OpenAPI to MCP in 60 Seconds&lt;/a&gt; if you already have a spec&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://usepaso.dev/blog/five-ways-to-test-before-you-ship/" rel="noopener noreferrer"&gt;Five Ways to Test Before You Ship&lt;/a&gt; to verify your server&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://usepaso.dev/blog/how-to-make-your-api-work-with-claude/" rel="noopener noreferrer"&gt;How to Make Your API Work with Claude&lt;/a&gt; for Claude Desktop setup&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>mcp</category>
      <category>tutorial</category>
      <category>ai</category>
      <category>devtools</category>
    </item>
    <item>
      <title>The Complete Guide to MCP Servers</title>
      <dc:creator>Shiva Padakanti</dc:creator>
      <pubDate>Thu, 02 Apr 2026 10:47:54 +0000</pubDate>
      <link>https://dev.to/5h1vmani/the-complete-guide-to-mcp-servers-3al9</link>
      <guid>https://dev.to/5h1vmani/the-complete-guide-to-mcp-servers-3al9</guid>
      <description>&lt;p&gt;MCP (Model Context Protocol) is how AI agents connect to your API. An MCP server exposes your API's capabilities as tools that agents like Claude, Cursor, and Copilot can discover and call at runtime.&lt;/p&gt;

&lt;p&gt;This guide covers everything: what MCP servers are, how to build one, how to test it, how to secure it, and how to deploy it. Whether you're writing one from scratch or generating one from a YAML file, this is the reference.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is an MCP server?
&lt;/h2&gt;

&lt;p&gt;An MCP server is a process that speaks the Model Context Protocol. It sits between your API and an AI agent, translating your endpoints into typed tools the agent can understand and call.&lt;/p&gt;

&lt;p&gt;The protocol was created by Anthropic in late 2024 and donated to the Linux Foundation's Agentic AI Foundation in December 2025. It's an open standard. Over 5,000 MCP servers exist as of early 2026.&lt;/p&gt;

&lt;p&gt;An MCP server does three things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Exposes tools.&lt;/strong&gt; Each tool has a name, description, and typed inputs. The agent reads these to decide what to call.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Handles requests.&lt;/strong&gt; When the agent calls a tool, the server validates inputs, constructs the HTTP request, and forwards it to your API.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Returns responses.&lt;/strong&gt; The API response goes back through the MCP protocol to the agent.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The key difference between MCP and a regular REST API: MCP clients discover available actions at runtime. A developer hardcodes API calls. An agent discovers them dynamically, decides which to use based on context, and constructs the inputs itself.&lt;/p&gt;

&lt;p&gt;For a deeper comparison with REST and GraphQL, see &lt;a href="https://usepaso.dev/blog/mcp-vs-rest-vs-graphql/" rel="noopener noreferrer"&gt;MCP vs REST vs GraphQL: What Changes When AI is the Client&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two ways to build an MCP server
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Option A: Write it by hand
&lt;/h3&gt;

&lt;p&gt;The MCP TypeScript SDK gives you full control. You register tools, define input schemas, and write handler functions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;McpServer&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@modelcontextprotocol/sdk/server/mcp.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;StdioServerTransport&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@modelcontextprotocol/sdk/server/stdio.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;zod&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;McpServer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Sentry&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1.0.0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;list_issues&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;List issues in a Sentry project&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;organization_slug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;project_slug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;optional&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;organization_slug&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;project_slug&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="s2"&gt;`https://sentry.io/api/0/projects/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;organization_slug&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;project_slug&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/issues/`&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;searchParams&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;query&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Bearer &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SENTRY_AUTH_TOKEN&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}]&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;transport&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;StdioServerTransport&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;transport&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's one tool. For a real API with 6 capabilities, you're looking at 200+ lines. Each tool needs input validation, URL construction, auth forwarding, and error handling. It works. It's just a lot of repetitive code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Option B: Declare it with paso
&lt;/h3&gt;

&lt;p&gt;paso takes a different approach. You describe your API in a YAML file and paso generates the MCP server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1.0"&lt;/span&gt;

&lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Sentry&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Error monitoring and performance tracking&lt;/span&gt;
  &lt;span class="na"&gt;base_url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://sentry.io/api/0&lt;/span&gt;
  &lt;span class="na"&gt;auth&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bearer&lt;/span&gt;

&lt;span class="na"&gt;capabilities&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;list_issues&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;List issues in a project&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;GET&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/projects/{organization_slug}/{project_slug}/issues/&lt;/span&gt;
    &lt;span class="na"&gt;permission&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;read&lt;/span&gt;
    &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;organization_slug&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
        &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Organization slug&lt;/span&gt;
        &lt;span class="na"&gt;in&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;path&lt;/span&gt;
      &lt;span class="na"&gt;project_slug&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
        &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Project slug&lt;/span&gt;
        &lt;span class="na"&gt;in&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;path&lt;/span&gt;
      &lt;span class="na"&gt;query&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
        &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Search&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;query&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;(e.g.,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;'is:unresolved')"&lt;/span&gt;
        &lt;span class="na"&gt;in&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;query&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;usepaso serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same MCP server. Same protocol compliance. 30 lines instead of 200+. The YAML file is called a paso declaration. See &lt;a href="https://usepaso.dev/blog/what-is-a-paso-declaration/" rel="noopener noreferrer"&gt;What is a paso Declaration?&lt;/a&gt; for a field-by-field breakdown.&lt;/p&gt;

&lt;p&gt;For a detailed side-by-side comparison, see &lt;a href="https://usepaso.dev/blog/how-to-create-an-mcp-server/" rel="noopener noreferrer"&gt;How to Create an MCP Server&lt;/a&gt; and &lt;a href="https://usepaso.dev/blog/paso-vs-writing-mcp-servers-by-hand/" rel="noopener noreferrer"&gt;paso vs Writing MCP Servers by Hand&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting started
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Install
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Node.js:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; usepaso
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Python:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;usepaso
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both produce the same MCP server from the same YAML file. See &lt;a href="https://usepaso.dev/blog/paso-works-the-same-in-python/" rel="noopener noreferrer"&gt;paso Works the Same in Python&lt;/a&gt; for the Python walkthrough.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create a declaration
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;usepaso init &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"Sentry"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This generates a &lt;code&gt;usepaso.yaml&lt;/code&gt; template. Edit it to describe your API's capabilities.&lt;/p&gt;

&lt;p&gt;If you have an OpenAPI spec, skip writing YAML by hand:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;usepaso init &lt;span class="nt"&gt;--from-openapi&lt;/span&gt; ./openapi.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;paso converts OpenAPI 3.x specs into declarations. See &lt;a href="https://usepaso.dev/blog/openapi-to-mcp-in-60-seconds/" rel="noopener noreferrer"&gt;OpenAPI to MCP in 60 Seconds&lt;/a&gt; for the walkthrough.&lt;/p&gt;

&lt;h3&gt;
  
  
  Serve
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;USEPASO_AUTH_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"your-api-token"&lt;/span&gt;
usepaso serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;usepaso serving "Sentry" (6 capabilities). Agents welcome.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your API is now accessible to MCP clients.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing before you ship
&lt;/h2&gt;

&lt;p&gt;Never connect an untested MCP server to an agent. paso gives you five ways to verify your declaration before going live.&lt;/p&gt;

&lt;h3&gt;
  
  
  Validate
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;usepaso validate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;valid (Sentry, 6 capabilities, 0 regrets)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Catches structural issues: missing fields, invalid URLs, path parameter mismatches, duplicate names. See &lt;a href="https://usepaso.dev/blog/common-mcp-server-errors/" rel="noopener noreferrer"&gt;Common MCP Server Errors&lt;/a&gt; for the seven errors you're most likely to hit and how to fix each one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Strict mode
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;usepaso validate &lt;span class="nt"&gt;--strict&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Flags best-practice issues: DELETE without consent gates, short descriptions, write operations without constraints.&lt;/p&gt;

&lt;h3&gt;
  
  
  Inspect
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;usepaso inspect
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Shows exactly what MCP tools your declaration produces. This is what agents see.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dry run
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;usepaso &lt;span class="nb"&gt;test &lt;/span&gt;list_issues &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="nv"&gt;organization_slug&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;my-org &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="nv"&gt;project_slug&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;my-project &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--dry-run&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Previews the exact HTTP request without sending it. Verify URL construction, parameter placement, and auth headers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Doctor
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;usepaso doctor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;End-to-end check: file exists, YAML parses, validation passes, auth token is set, base URL is reachable. If doctor passes, you're ready to serve.&lt;/p&gt;

&lt;p&gt;For the full testing workflow, see &lt;a href="https://usepaso.dev/blog/five-ways-to-test-before-you-ship/" rel="noopener noreferrer"&gt;Five Ways to Test Before You Ship&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Permissions and safety
&lt;/h2&gt;

&lt;p&gt;An MCP server without permissions is an API with no access controls. Any agent can call any tool. That includes &lt;code&gt;DELETE&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;paso provides four layers of safety. See &lt;a href="https://usepaso.dev/blog/what-happens-when-an-agent-calls-delete/" rel="noopener noreferrer"&gt;What Happens When an Agent Calls DELETE&lt;/a&gt; for why each one matters.&lt;/p&gt;

&lt;h3&gt;
  
  
  Permission tiers
&lt;/h3&gt;

&lt;p&gt;Every capability has a &lt;code&gt;permission&lt;/code&gt; field: &lt;code&gt;read&lt;/code&gt;, &lt;code&gt;write&lt;/code&gt;, or &lt;code&gt;admin&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;list_issues&lt;/span&gt;
  &lt;span class="na"&gt;permission&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;read&lt;/span&gt;        &lt;span class="c1"&gt;# Safe. No data changes.&lt;/span&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;resolve_issue&lt;/span&gt;
  &lt;span class="na"&gt;permission&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt;       &lt;span class="c1"&gt;# Modifies data. Requires caution.&lt;/span&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;delete_issue&lt;/span&gt;
  &lt;span class="na"&gt;permission&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;admin&lt;/span&gt;       &lt;span class="c1"&gt;# High risk. Always requires consent.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Consent gates
&lt;/h3&gt;

&lt;p&gt;Force the agent to ask the user before executing sensitive operations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;delete_issue&lt;/span&gt;
  &lt;span class="na"&gt;permission&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;admin&lt;/span&gt;
  &lt;span class="na"&gt;consent_required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Constraints
&lt;/h3&gt;

&lt;p&gt;Rate limits and guardrails.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;constraints&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;max_per_hour&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deletion is rate-limited&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Forbidden list
&lt;/h3&gt;

&lt;p&gt;Explicitly block capabilities from being exposed to agents.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;read&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;list_issues&lt;/span&gt;
  &lt;span class="na"&gt;write&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;resolve_issue&lt;/span&gt;
  &lt;span class="na"&gt;forbidden&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;drop_database&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A capability in &lt;code&gt;forbidden&lt;/code&gt; is never registered as an MCP tool. It doesn't exist as far as the agent is concerned.&lt;/p&gt;

&lt;h2&gt;
  
  
  Connecting to clients
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Claude Desktop
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;usepaso connect claude-desktop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;paso writes the config file for you. Restart Claude Desktop. Your capabilities appear as tools.&lt;/p&gt;

&lt;p&gt;For the full walkthrough, see &lt;a href="https://usepaso.dev/blog/connect-stripe-to-claude-desktop/" rel="noopener noreferrer"&gt;Connect Stripe to Claude Desktop in 5 Minutes&lt;/a&gt;. The same pattern works for any API.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cursor
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;usepaso connect cursor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;paso writes &lt;code&gt;.cursor/mcp.json&lt;/code&gt; in your project root. Restart Cursor to connect.&lt;/p&gt;

&lt;h3&gt;
  
  
  VS Code
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;usepaso connect vscode
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;paso writes &lt;code&gt;.vscode/mcp.json&lt;/code&gt; in your project root. Reload VS Code to connect.&lt;/p&gt;

&lt;h3&gt;
  
  
  Windsurf
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;usepaso connect windsurf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;paso writes the Windsurf config file. Restart Windsurf to connect.&lt;/p&gt;

&lt;h3&gt;
  
  
  Other MCP clients
&lt;/h3&gt;

&lt;p&gt;Any MCP-compatible client can connect. The server speaks standard MCP over stdio. No client-specific code needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance
&lt;/h2&gt;

&lt;p&gt;paso adds minimal overhead on top of the MCP protocol.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cold start&lt;/td&gt;
&lt;td&gt;~0.9s (including Node.js startup)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;paso overhead at startup&lt;/td&gt;
&lt;td&gt;~50ms (YAML parsing + tool registration)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Per-request overhead&lt;/td&gt;
&lt;td&gt;2-5ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dominant latency&lt;/td&gt;
&lt;td&gt;Your API's response time&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The cold start is mostly Node.js module loading. The per-request cost is input validation and HTTP request construction. single-digit milliseconds.&lt;/p&gt;

&lt;p&gt;For detailed benchmarks and optimization tips, see &lt;a href="https://usepaso.dev/blog/mcp-server-performance/" rel="noopener noreferrer"&gt;MCP Server Performance: What to Expect&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Optimization tips
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Add pagination.&lt;/strong&gt; Don't let agents fetch unbounded lists.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use constraints.&lt;/strong&gt; Rate limits prevent agents from overwhelming your API.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep declarations focused.&lt;/strong&gt; 6 well-chosen capabilities serve agents better than 50.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  How paso compares to hand-written servers
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Hand-written&lt;/th&gt;
&lt;th&gt;paso&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Code to write&lt;/td&gt;
&lt;td&gt;200+ lines TypeScript&lt;/td&gt;
&lt;td&gt;30 lines YAML&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Adding a tool&lt;/td&gt;
&lt;td&gt;New function + registration + validation&lt;/td&gt;
&lt;td&gt;8 lines of YAML&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Protocol compliance&lt;/td&gt;
&lt;td&gt;Manual&lt;/td&gt;
&lt;td&gt;Automatic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auth forwarding&lt;/td&gt;
&lt;td&gt;Manual&lt;/td&gt;
&lt;td&gt;Automatic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Input validation&lt;/td&gt;
&lt;td&gt;Manual (Zod schemas)&lt;/td&gt;
&lt;td&gt;Automatic (from declaration)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Permission model&lt;/td&gt;
&lt;td&gt;Build it yourself&lt;/td&gt;
&lt;td&gt;Built-in tiers + consent + constraints&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multiple protocols&lt;/td&gt;
&lt;td&gt;Rewrite per protocol&lt;/td&gt;
&lt;td&gt;Declaration stays the same&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;paso handles MCP today. When A2A or the next protocol arrives, your declaration doesn't change. The protocol layer is paso's problem, not yours.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common patterns
&lt;/h2&gt;

&lt;h3&gt;
  
  
  One API, one declaration
&lt;/h3&gt;

&lt;p&gt;Each &lt;code&gt;usepaso.yaml&lt;/code&gt; describes one API. If you have Sentry, Stripe, and GitHub, that's three declarations, three servers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Start with read, add write later
&lt;/h3&gt;

&lt;p&gt;Expose read-only capabilities first. Verify they work. Then add write operations with consent gates.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use OpenAPI as a starting point
&lt;/h3&gt;

&lt;p&gt;If you have an OpenAPI spec, generate the declaration instead of writing it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;usepaso init &lt;span class="nt"&gt;--from-openapi&lt;/span&gt; ./openapi.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Review the output, set appropriate permissions, remove capabilities you don't want exposed, then validate and serve.&lt;/p&gt;

&lt;h3&gt;
  
  
  CI validation
&lt;/h3&gt;

&lt;p&gt;Add validation to your CI pipeline:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;usepaso validate &lt;span class="nt"&gt;--strict&lt;/span&gt; &lt;span class="nt"&gt;--json&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Returns structured output with a non-zero exit code on failure. Treat it like a linter.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;p&gt;MCP is one year old. The ecosystem is growing fast. Over 5,000 servers exist. The protocol is moving from local development tools to production infrastructure with Streamable HTTP transport for remote servers.&lt;/p&gt;

&lt;p&gt;paso's bet: the protocol layer should be abstracted. You describe what your API can do. paso handles how it's exposed. When the protocol changes, your declaration stays the same.&lt;/p&gt;

&lt;p&gt;Your API is one YAML file away from being agent-ready.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx usepaso init &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"YourAPI"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;All guides in this series:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://usepaso.dev/blog/what-is-a-paso-declaration/" rel="noopener noreferrer"&gt;What is a paso Declaration?&lt;/a&gt;. field-by-field YAML breakdown&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://usepaso.dev/blog/how-to-create-an-mcp-server/" rel="noopener noreferrer"&gt;How to Create an MCP Server&lt;/a&gt;. manual vs. paso, side by side&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://usepaso.dev/blog/paso-vs-writing-mcp-servers-by-hand/" rel="noopener noreferrer"&gt;paso vs Writing MCP Servers by Hand&lt;/a&gt;. line-by-line code comparison&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://usepaso.dev/blog/mcp-vs-rest-vs-graphql/" rel="noopener noreferrer"&gt;MCP vs REST vs GraphQL&lt;/a&gt;. what changes when AI is the client&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://usepaso.dev/blog/common-mcp-server-errors/" rel="noopener noreferrer"&gt;Common MCP Server Errors&lt;/a&gt;. seven errors and how to fix them&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://usepaso.dev/blog/five-ways-to-test-before-you-ship/" rel="noopener noreferrer"&gt;Five Ways to Test Before You Ship&lt;/a&gt;. the complete testing workflow&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://usepaso.dev/blog/mcp-server-performance/" rel="noopener noreferrer"&gt;MCP Server Performance&lt;/a&gt;. benchmarks and optimization&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://usepaso.dev/blog/what-happens-when-an-agent-calls-delete/" rel="noopener noreferrer"&gt;What Happens When an Agent Calls DELETE&lt;/a&gt;. permissions and safety&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://usepaso.dev/blog/connect-stripe-to-claude-desktop/" rel="noopener noreferrer"&gt;Connect Stripe to Claude Desktop&lt;/a&gt;. end-to-end API integration&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://usepaso.dev/blog/openapi-to-mcp-in-60-seconds/" rel="noopener noreferrer"&gt;OpenAPI to MCP in 60 Seconds&lt;/a&gt;. import from existing specs&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://usepaso.dev/blog/how-to-make-your-api-work-with-claude/" rel="noopener noreferrer"&gt;How to Make Your API Work with Claude&lt;/a&gt;. connecting to Claude Desktop&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://usepaso.dev/blog/paso-works-the-same-in-python/" rel="noopener noreferrer"&gt;paso Works the Same in Python&lt;/a&gt;. Python support&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://usepaso.dev/blog/why-we-built-usepaso/" rel="noopener noreferrer"&gt;Why We Built paso&lt;/a&gt;. the motivation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://usepaso.dev/docs/getting-started/" rel="noopener noreferrer"&gt;Get started now.&lt;/a&gt;&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>tutorial</category>
      <category>ai</category>
      <category>devtools</category>
    </item>
  </channel>
</rss>
