<?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: Wils Dawson</title>
    <description>The latest articles on DEV Community by Wils Dawson (@wdawson).</description>
    <link>https://dev.to/wdawson</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%2F3806690%2Fe4e06bcd-adae-4b85-9791-cce9353aa906.jpg</url>
      <title>DEV Community: Wils Dawson</title>
      <link>https://dev.to/wdawson</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/wdawson"/>
    <language>en</language>
    <item>
      <title>Building MCP Together: Arcade's Contribution to Secure Agent Auth</title>
      <dc:creator>Wils Dawson</dc:creator>
      <pubDate>Wed, 04 Mar 2026 23:44:14 +0000</pubDate>
      <link>https://dev.to/wdawson/building-mcp-together-arcades-contribution-to-secure-agent-auth-eoh</link>
      <guid>https://dev.to/wdawson/building-mcp-together-arcades-contribution-to-secure-agent-auth-eoh</guid>
      <description>&lt;p&gt;&lt;strong&gt;See URL Mode Elicitation in Action →&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;em&gt;Watch our engineer Wils Dawson walk through the new MCP proposal that's solving one of the biggest security gaps in AI tool-calling. In 15 minutes, you'll see how agents can finally handle OAuth flows, payment confirmations, and API keys without exposing sensitive data to the LLM.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Watch the technical walkthrough →&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;

  &lt;iframe src="https://www.youtube.com/embed/VWvs6XQAK-g"&gt;
  &lt;/iframe&gt;


&lt;/p&gt;

&lt;p&gt;Your AI agent needs to search Gmail for that weekly report. You've built an MCP server, the tool definition, everything's wired up perfectly. One problem: there's no secure path in the protocol to get the OAuth 2.0 bearer token your agent needs to call the Gmail API.&lt;/p&gt;

&lt;p&gt;This is the gap between MCP's design and production reality. While the protocol handles client-server authentication beautifully, it completely lacks a mechanism for servers to securely obtain third-party credentials. At Arcade.dev, we've been working to fix this fundamental limitation.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;The Technical Problem: Credential Flow in Distributed Systems&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Let's break down what's actually happening. Your MCP server needs to make authenticated requests to external APIs. But MCP has no secure credential gathering mechanism.&lt;/p&gt;

&lt;p&gt;Current workarounds are all security anti-patterns for multi-user production systems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Service account tokens with excessive scopes&lt;/li&gt;
&lt;li&gt;Credentials hardcoded in server configs&lt;/li&gt;
&lt;li&gt;Passing tokens through the MCP client (violating the principle of least privilege)&lt;/li&gt;
&lt;li&gt;Client-side credential storage (hello, token exfiltration risks)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This isn't just bad UX—it's a fundamental security architecture flaw. MCP clients are often untrusted code running on user devices. They're OAuth 2.0 "public clients" that can't securely store secrets. Yet today, that's exactly what developers are forced to do.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Our Engineering Journey: Two Approaches to Secure Auth&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/modelcontextprotocol/modelcontextprotocol/pull/475" rel="noopener noreferrer"&gt;&lt;strong&gt;PR #475&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;: Adding User Interaction as a Client Capability&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Our initial proposal introduced a new client capability for user interactions. The core insight: leverage the browser as a trusted security context, just like OAuth 2.0 has done successfully for 15+ years.&lt;/p&gt;

&lt;p&gt;The implementation added a &lt;em&gt;userInteraction&lt;/em&gt; capability:&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="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;UserInteractionRequest&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;userInteraction&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;url&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;number&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allowed servers to redirect users to secure endpoints for credential gathering, keeping sensitive data out of the client execution context entirely. The proposal sparked extensive discussion and security review with 50+ contributors examining attack vectors, CSRF protections, and state management.&lt;/p&gt;

&lt;p&gt;But MCP 2025-06-18 shipped with  elicitation, a client capability for dynamically rendering forms and gathering data from the user. Elicitation via forms doesn't work for credentials or sensitive data, but could it be extended to enable secure user interactions?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/modelcontextprotocol/modelcontextprotocol/pull/887" rel="noopener noreferrer"&gt;&lt;strong&gt;PR #887&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;: Extending Elicitation with URL Mode&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Rather than having two similar-but-different client capabilities, we evolved our approach. PR #887 extends the elicitation framework with a new mode:&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="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;UrlElicitation&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;url&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;oauth_provider&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;required_scopes&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="nl"&gt;state&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates clear separation of concerns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Form mode&lt;/strong&gt;: Client-rendered UI for non-sensitive data (preferences, parameters)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;URL mode&lt;/strong&gt;: Direct browser navigation for sensitive flows (OAuth 2.0, payments, WebAuthn, SAML)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The security model is explicit: form elicitation flows data through the client, URL elicitation bypasses the client  entirely. But why does that matter?&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Deep Dive: Why URL Elicitation Matters&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Proper OAuth 2.0 Implementation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Consider implementing GitHub integration. With URL elicitation, you get proper OAuth 2.0:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Server initiates OAuth flow
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;handle_github_tool_call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;has_valid_token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generate_secure_state&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;code_verifier&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generate_code_verifier&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="n"&gt;auth_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;build_oauth_url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;client_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;GITHUB_CLIENT_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;redirect_uri&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;CALLBACK_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;code_challenge&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;hash_verifier&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;code_verifier&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;repo:read&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ElicitationRequired&lt;/span&gt;&lt;span class="p"&gt;([{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;github-auth-&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mode&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;auth_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Authorize GitHub access&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;metadata&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;oauth_provider&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;github&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;required_scopes&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;repo:read&lt;/span&gt;&lt;span class="sh"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or, something other than OAuth entirely: a redirect to a payment portal, enterprise IDP login page, etc. The client just opens the URL. For the client, that means no token handling, no state management, no security responsibilities.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Respecting Security Boundaries&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;URL elicitation enforces proper security boundaries:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Client (untrusted)&lt;/strong&gt;: Facilitates navigation, handles retry logic&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Server (trusted)&lt;/strong&gt;: Manages tokens, validates state, enforces scopes&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Auth provider (trusted)&lt;/strong&gt;: Handles user authentication, consent&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This mirrors established web security patterns. The MCP client never touches credentials, preventing entire classes of attacks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Token exfiltration via compromised clients&lt;/li&gt;
&lt;li&gt;Scope escalation through client manipulation&lt;/li&gt;
&lt;li&gt;The "confused deputy" problem&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Real Implementation Benefits&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;From our research into production-ready MCP servers at Arcade:&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="c1"&gt;// Before: Insecure token passing&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&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;mcp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;callTool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;search_gmail&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;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;weekly report&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gmail_token&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;// 🚨 Security nightmare&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// After: Secure URL elicitation&lt;/span&gt;
&lt;span class="k"&gt;try&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;result&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;mcp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;callTool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;search_gmail&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;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;weekly report&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="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&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;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ELICITATION_REQUIRED&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="c1"&gt;// Client opens URL, user auths, server stores token&lt;/span&gt;
    &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;elicitations&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&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="c1"&gt;// Retry after auth completes&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This pattern mirrors what client apps already do to interact with services that require redirects for authorization.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Multi-Provider Authentication&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Real agents need multiple auth providers. URL elicitation handles this elegantly:&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="c1"&gt;// Server can request multiple authorizations&lt;/span&gt;
&lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ElicitationRequired&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gmail-auth&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;url&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;getGoogleOAuthUrl&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Authorize Gmail access&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="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;slack-auth&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;url&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;getSlackOAuthUrl&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Connect Slack workspace&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="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What This Enables&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;With proper authorization, MCP servers are one step closer to being production-ready:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Scoped access&lt;/strong&gt;: Request minimum necessary permissions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Token refresh&lt;/strong&gt;: Handle expiry without user intervention&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Audit trails&lt;/strong&gt;: Track what actions were taken with which authorizations&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Revocation&lt;/strong&gt;: Users can revoke access anytime through the provider&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The technical foundations matter. This is the difference between a demo and production infrastructure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Implementation Timeline&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;PR #887 is under active review. For early adopters:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Today&lt;/strong&gt;: Arcade.dev tools already implement these patterns &lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Near term&lt;/strong&gt;: URL elicitation standardizes the approach&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Future&lt;/strong&gt;: The MCP ecosystem adopts these patterns in both clients and servers&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Want to accelerate this?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/modelcontextprotocol/modelcontextprotocol/pull/887" rel="noopener noreferrer"&gt;Review PR #887&lt;/a&gt; and stress-test the security model&lt;/li&gt;
&lt;li&gt;Implement URL elicitation in your MCP server&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without a way to securely interact with the user, MCP is limited to servers that only connect to first-party APIs. By adding a mechanism that respects the security boundaries of the client (inspired by the battle-tested patterns used by OAuth), more powerful and interesting MCP servers are possible. We're excited about the future of MCP, what about you?&lt;/p&gt;




&lt;p&gt;&lt;em&gt;The Arcade.dev team has spent years hardening auth at Okta, Stormpath, and Redis. We're applying those lessons to make AI infrastructure production-ready.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;*Want to build AI agents that actually work in production?&lt;/strong&gt; While we wait for authorization to land in MCP, Arcade already implements secure auth for 100+ integrations. No bot tokens, no security nightmares—just real OAuth flows that work.*&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Start building with Arcade →&lt;/em&gt; &lt;a href="https://account.arcade.dev/" rel="noopener noreferrer"&gt;&lt;em&gt;Sign Up&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>mcp</category>
    </item>
    <item>
      <title>Production-Ready MCP: Why Security Standards Matter for AI Tool Infrastructure</title>
      <dc:creator>Wils Dawson</dc:creator>
      <pubDate>Wed, 04 Mar 2026 23:29:59 +0000</pubDate>
      <link>https://dev.to/wdawson/production-ready-mcp-why-security-standards-matter-for-ai-tool-infrastructure-5229</link>
      <guid>https://dev.to/wdawson/production-ready-mcp-why-security-standards-matter-for-ai-tool-infrastructure-5229</guid>
      <description>&lt;p&gt;After eight years building authentication systems at Okta, followed by stints at Kong and ngrok working on developer tools and API gateways, I've seen how to build systems that are secure by default. Now at Arcade.dev, I'm watching the MCP ecosystem struggle to get there.&lt;/p&gt;

&lt;p&gt;The Model Context Protocol has incredible potential for enabling AI agents to interact with real-world systems. But there's a gap between experimental implementations and production-ready infrastructure that most developers aren't addressing.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;The Current State of MCP Security&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The MCP specification (as of June 18, 2025) defines authentication between clients and servers. This is essential, but it's only part of the story. The spec handles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Local transport (stdio)&lt;/strong&gt;: Suitable for development and single-user scenarios&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Remote transport (HTTP)&lt;/strong&gt;: Requires OAuth-based authorization&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This foundation is solid. The challenge comes when MCP servers need to interact with external APIs and services—which is arguably the entire point of building them.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;The Authorization Gap&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Here's the critical issue: when your MCP server needs to access third-party APIs (Google Drive, Slack, Salesforce), you face an architectural decision with significant security implications.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Anti-Pattern&lt;/strong&gt;: Embedding admin-level credentials in your MCP server. This forces the server to reimplement the authorization logic of every system it touches. It's not just a security risk—it's an engineering nightmare that doesn't scale.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Solution&lt;/strong&gt;: User-specific authorization flows. The MCP server obtains tokens scoped to individual users, inheriting their permissions from the downstream systems. This is what our &lt;a href="https://github.com/modelcontextprotocol/specification/pull/475" rel="noopener noreferrer"&gt;PR #475&lt;/a&gt; addresses—enabling secure token exchange without exposing credentials to clients or LLMs.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Why Standards Compliance Matters&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The temptation to bypass security standards is strong, especially during rapid prototyping. But consider the implications:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Interoperability&lt;/strong&gt;: Non-compliant servers won't work with Claude Desktop, Cursor, VS Code, or other standard MCP clients&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Security vulnerabilities&lt;/strong&gt;: Improper token handling exposes attack vectors that standard OAuth flows prevent&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Scalability issues&lt;/strong&gt;: What works for one user breaks at scale without proper session management and authorization&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Audit requirements&lt;/strong&gt;: Enterprise deployments often require SOC 2 compliance and security attestations, forcing you into complex rebuilds&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Production Readiness Beyond Security&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Security is foundational, but production-ready MCP deployments require:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Observability&lt;/strong&gt;: Detailed logging and monitoring of tool calls and data access&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability&lt;/strong&gt;: Multi-instance deployment with proper session handling&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error handling&lt;/strong&gt;: Graceful degradation when downstream services fail&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rate limiting&lt;/strong&gt;: Protection against abuse and unexpected usage patterns&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Audit trails&lt;/strong&gt;: Compliance with data governance requirements&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;The Path Forward&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The MCP community is at an inflection point. We can either implement secure standards now or become irrelevant when something else does. It has to be easy to do the secure and scalable thing. At Arcade.dev, we're building infrastructure that makes security and production-readiness the default, not an afterthought.&lt;/p&gt;

&lt;p&gt;This isn't about gatekeeping or adding unnecessary complexity. It's about learning from decades of API development and applying those lessons to the next generation of agentic AI infrastructure.&lt;/p&gt;

&lt;p&gt;The future of AI agents depends on their ability to safely and reliably interact with real-world systems. That future requires more than just functional code—it requires infrastructure built on proven security principles.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Arcade.dev provides production-ready infrastructure for AI tool-calling, with built-in authentication, authorization, and enterprise-grade security. Learn more in our&lt;/em&gt; &lt;a href="https://docs.arcade.dev/home" rel="noopener noreferrer"&gt;&lt;em&gt;documentation&lt;/em&gt;&lt;/a&gt; &lt;em&gt;or join our&lt;/em&gt; &lt;a href="https://discord.gg/5ZJekdky" rel="noopener noreferrer"&gt;&lt;em&gt;Discord community&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>thoughtleadership</category>
    </item>
  </channel>
</rss>
