<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xsl" href="atom.xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://themcpguy.com/blog</id>
    <title>The MCP Guy Blog</title>
    <updated>2026-07-28T00:00:00.000Z</updated>
    <generator>https://github.com/jpmonette/feed</generator>
    <link rel="alternate" href="https://themcpguy.com/blog"/>
    <subtitle>The MCP Guy Blog</subtitle>
    <icon>https://themcpguy.com/img/favicon.svg</icon>
    <entry>
        <title type="html"><![CDATA[MCP Just Went Stateless: What Breaks and What Gets Much Easier]]></title>
        <id>https://themcpguy.com/blog/mcp-goes-stateless</id>
        <link href="https://themcpguy.com/blog/mcp-goes-stateless"/>
        <updated>2026-07-28T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[A client sending many requests through a load balancer to three stateless server instances, with the Mcp-Session-Id header crossed out]]></summary>
        <content type="html"><![CDATA[<p><img decoding="async" loading="lazy" alt="A client sending many requests through a load balancer to three stateless server instances, with the Mcp-Session-Id header crossed out" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA4MDAgNDAwIj4KICA8cmVjdCB3aWR0aD0iODAwIiBoZWlnaHQ9IjQwMCIgZmlsbD0iIzA1MDcxNCIvPgogIDwhLS0gQ2xpZW50IC0tPgogIDxyZWN0IHg9IjQwIiB5PSIxNzAiIHdpZHRoPSIxMTAiIGhlaWdodD0iNjAiIHJ4PSIxMCIgZmlsbD0iIzBkMTExNyIgc3Ryb2tlPSIjMDZiNmQ0IiBzdHJva2Utd2lkdGg9IjIiLz4KICA8dGV4dCB4PSI5NSIgeT0iMTk4IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmaWxsPSIjMjJkM2VlIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMyIgZm9udC13ZWlnaHQ9ImJvbGQiPkNsaWVudDwvdGV4dD4KICA8dGV4dCB4PSI5NSIgeT0iMjE2IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmaWxsPSIjNjQ3NDhiIiBmb250LWZhbWlseT0ibW9ub3NwYWNlIiBmb250LXNpemU9IjEwIj5OIHJlcXVlc3RzPC90ZXh0PgoKICA8IS0tIExvYWQgYmFsYW5jZXIgLS0+CiAgPHJlY3QgeD0iMjUwIiB5PSIxNjAiIHdpZHRoPSIxMjAiIGhlaWdodD0iODAiIHJ4PSIxMCIgZmlsbD0iIzBkMTExNyIgc3Ryb2tlPSIjOGI1Y2Y2IiBzdHJva2Utd2lkdGg9IjIiLz4KICA8dGV4dCB4PSIzMTAiIHk9IjE5NSIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZmlsbD0iI2E3OGJmYSIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTMiIGZvbnQtd2VpZ2h0PSJib2xkIj5Mb2FkPC90ZXh0PgogIDx0ZXh0IHg9IjMxMCIgeT0iMjEzIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmaWxsPSIjYTc4YmZhIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMyIgZm9udC13ZWlnaHQ9ImJvbGQiPmJhbGFuY2VyPC90ZXh0PgogIDx0ZXh0IHg9IjMxMCIgeT0iMjMxIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmaWxsPSIjNjQ3NDhiIiBmb250LWZhbWlseT0ibW9ub3NwYWNlIiBmb250LXNpemU9IjkiPm5vIHN0aWNraW5lc3M8L3RleHQ+CiAgPGxpbmUgeDE9IjE1MCIgeTE9IjIwMCIgeDI9IjI1MCIgeTI9IjIwMCIgc3Ryb2tlPSIjMDZiNmQ0IiBzdHJva2Utd2lkdGg9IjIiLz4KCiAgPCEtLSBUaHJlZSBzdGF0ZWxlc3MgaW5zdGFuY2VzOyBhbnkgcmVxdWVzdCBjYW4gaGl0IGFueSBvbmUgLS0+CiAgPGc+CiAgICA8cmVjdCB4PSI1NjAiIHk9IjYwIiB3aWR0aD0iMTgwIiBoZWlnaHQ9IjY4IiByeD0iMTAiIGZpbGw9IiMwZDExMTciIHN0cm9rZT0iIzEwYjk4MSIgc3Ryb2tlLXdpZHRoPSIyIi8+CiAgICA8dGV4dCB4PSI2NTAiIHk9IjkwIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmaWxsPSIjMzRkMzk5IiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMyIgZm9udC13ZWlnaHQ9ImJvbGQiPkluc3RhbmNlIEE8L3RleHQ+CiAgICA8dGV4dCB4PSI2NTAiIHk9IjExMCIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZmlsbD0iIzY0NzQ4YiIgZm9udC1mYW1pbHk9Im1vbm9zcGFjZSIgZm9udC1zaXplPSIxMCI+c3RhdGVsZXNzPC90ZXh0PgogICAgPHJlY3QgeD0iNTYwIiB5PSIxNjYiIHdpZHRoPSIxODAiIGhlaWdodD0iNjgiIHJ4PSIxMCIgZmlsbD0iIzBkMTExNyIgc3Ryb2tlPSIjMTBiOTgxIiBzdHJva2Utd2lkdGg9IjIiLz4KICAgIDx0ZXh0IHg9IjY1MCIgeT0iMTk2IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmaWxsPSIjMzRkMzk5IiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMyIgZm9udC13ZWlnaHQ9ImJvbGQiPkluc3RhbmNlIEI8L3RleHQ+CiAgICA8dGV4dCB4PSI2NTAiIHk9IjIxNiIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZmlsbD0iIzY0NzQ4YiIgZm9udC1mYW1pbHk9Im1vbm9zcGFjZSIgZm9udC1zaXplPSIxMCI+c3RhdGVsZXNzPC90ZXh0PgogICAgPHJlY3QgeD0iNTYwIiB5PSIyNzIiIHdpZHRoPSIxODAiIGhlaWdodD0iNjgiIHJ4PSIxMCIgZmlsbD0iIzBkMTExNyIgc3Ryb2tlPSIjMTBiOTgxIiBzdHJva2Utd2lkdGg9IjIiLz4KICAgIDx0ZXh0IHg9IjY1MCIgeT0iMzAyIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmaWxsPSIjMzRkMzk5IiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMyIgZm9udC13ZWlnaHQ9ImJvbGQiPkluc3RhbmNlIEM8L3RleHQ+CiAgICA8dGV4dCB4PSI2NTAiIHk9IjMyMiIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZmlsbD0iIzY0NzQ4YiIgZm9udC1mYW1pbHk9Im1vbm9zcGFjZSIgZm9udC1zaXplPSIxMCI+c3RhdGVsZXNzPC90ZXh0PgogIDwvZz4KICA8IS0tIGZhbi1vdXQ6IGFueSByZXF1ZXN0IHRvIGFueSBpbnN0YW5jZSAtLT4KICA8bGluZSB4MT0iMzcwIiB5MT0iMTk1IiB4Mj0iNTYwIiB5Mj0iOTQiIHN0cm9rZT0iIzEwYjk4MSIgc3Ryb2tlLXdpZHRoPSIxLjgiIG9wYWNpdHk9IjAuNyIvPgogIDxsaW5lIHgxPSIzNzAiIHkxPSIyMDAiIHgyPSI1NjAiIHkyPSIyMDAiIHN0cm9rZT0iIzEwYjk4MSIgc3Ryb2tlLXdpZHRoPSIxLjgiIG9wYWNpdHk9IjAuNyIvPgogIDxsaW5lIHgxPSIzNzAiIHkxPSIyMDUiIHgyPSI1NjAiIHkyPSIzMDYiIHN0cm9rZT0iIzEwYjk4MSIgc3Ryb2tlLXdpZHRoPSIxLjgiIG9wYWNpdHk9IjAuNyIvPgoKICA8IS0tIGNyb3NzZWQtb3V0IHNlc3Npb24gaWQgLS0+CiAgPHJlY3QgeD0iMjUwIiB5PSIyOTAiIHdpZHRoPSIyMjAiIGhlaWdodD0iNDAiIHJ4PSI4IiBmaWxsPSIjMGQxMTE3IiBzdHJva2U9IiNlZjQ0NDQiIHN0cm9rZS13aWR0aD0iMS41Ii8+CiAgPHRleHQgeD0iMzYwIiB5PSIzMTUiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZpbGw9IiM2NDc0OGIiIGZvbnQtZmFtaWx5PSJtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTMiPk1jcC1TZXNzaW9uLUlkPC90ZXh0PgogIDxsaW5lIHgxPSIyNjIiIHkxPSIyOTYiIHgyPSI0NTgiIHkyPSIzMjQiIHN0cm9rZT0iI2VmNDQ0NCIgc3Ryb2tlLXdpZHRoPSIyLjUiLz4KICA8dGV4dCB4PSIzNjAiIHk9IjM1MCIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZmlsbD0iI2VmNDQ0NCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTEiPm5vIGhhbmRzaGFrZSwgbm8gc2Vzc2lvbjwvdGV4dD4KCiAgPHRleHQgeD0iNDAwIiB5PSIzODQiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZpbGw9IiM0NzU1NjkiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjEzIj50aGVtY3BndXkuY29tIOKAlCBNQ1AgR29lcyBTdGF0ZWxlc3M8L3RleHQ+Cjwvc3ZnPgo=" width="800" height="400" class="img_ev3q"></p>
<p>If you have ever tried to run a remote MCP server behind a load balancer and discovered that request #2 has no idea what request #1 did, this post is for you. One of the largest changes to the protocol since launch is aimed squarely at that pain, and it does it by <em>removing</em> things.</p>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>Version disclosure (as of July 2026)</div><div class="admonitionContent_BuS1"><p>Everything below describes the <strong><code>2026-07-28</code> MCP specification</strong>, which was <strong>ratified on 28 July 2026</strong> and is now the current stable revision. The session-removal work is SEP-2567 and SEP-2575. One practical caveat: SDKs are still catching up. The Java MCP SDK's latest release, <code>2.0.0</code> from 11 June 2026, predates ratification and still implements <code>2025-11-25</code>, so the stateless protocol described here is not yet something you can adopt from Java without the SDK shipping support. Check your SDK's release notes before planning a migration.</p></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-session-problem">The session problem<a href="https://themcpguy.com/blog/mcp-goes-stateless#the-session-problem" class="hash-link" aria-label="Direct link to The session problem" title="Direct link to The session problem" translate="no">​</a></h2>
<p>Today's remote MCP relies on a session: the client and server do an initialization handshake, the server issues an <code>Mcp-Session-Id</code>, and subsequent requests carry it. That works beautifully on one process and miserably across many. The moment you want to scale horizontally, that session id becomes a sticky leash, because every request for a session has to land on the one instance that holds its state, so you reach for sticky load balancing, shared session stores, and a lot of operational duct tape.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-changed">What changed<a href="https://themcpguy.com/blog/mcp-goes-stateless#what-changed" class="hash-link" aria-label="Direct link to What changed" title="Direct link to What changed" translate="no">​</a></h2>
<p>The <code>2026-07-28</code> revision <strong>removes session management: the <code>Mcp-Session-Id</code> header is gone, and so is the <code>initialize</code>/<code>notifications/initialized</code> handshake.</strong> Each request now carries its protocol version, client identity, and client capabilities in <code>_meta</code> instead. Servers gain a new <code>server/discover</code> RPC that clients can call up front to negotiate versions and capabilities. The protocol becomes effectively stateless at the transport layer: any request can be served by any instance, because no instance is special.</p>
<p>This is one of the largest revisions since MCP launched, and it lines up with the 2026 roadmap's stated priorities of <strong>Transport Evolution and Scalability</strong> and <strong>Enterprise Readiness</strong>. Notably, it does this <em>without</em> introducing a new transport. <strong>Streamable HTTP remains the one remote transport</strong>; the change is about removing session coupling, not adding plumbing.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-breaks">What breaks<a href="https://themcpguy.com/blog/mcp-goes-stateless#what-breaks" class="hash-link" aria-label="Direct link to What breaks" title="Direct link to What breaks" translate="no">​</a></h2>
<p>Be honest with yourself about what leaned on the session:</p>
<ul>
<li class=""><strong>Server-held per-session state</strong> has nowhere to live implicitly anymore. If your server stashed "what we're doing" in memory keyed by session id, that assumption is gone.</li>
<li class=""><strong>Code that reads or asserts <code>Mcp-Session-Id</code></strong> needs to stop.</li>
<li class=""><strong>Init-handshake-dependent flows</strong> must tolerate a world where there is no handshake to hang setup on.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-gets-much-easier">What gets much easier<a href="https://themcpguy.com/blog/mcp-goes-stateless#what-gets-much-easier" class="hash-link" aria-label="Direct link to What gets much easier" title="Direct link to What gets much easier" translate="no">​</a></h2>
<p>This is the trade you are being offered, and it's a good one:</p>
<ul>
<li class=""><strong>Horizontal scaling becomes boring</strong>: spin up N identical instances behind a plain round-robin balancer, no stickiness, no shared session store required for the protocol's sake.</li>
<li class=""><strong>Resilience improves</strong>: an instance dying no longer orphans a session's worth of in-memory state.</li>
<li class=""><strong>Deploys get simpler</strong>: rolling restarts stop being a session-eviction event.</li>
</ul>
<p>State doesn't vanish; it just has to become <strong>explicit</strong>. Anything durable moves to your data layer and is referenced by handle in requests, rather than living implicitly in a session on one box.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="migrating-roughly">Migrating, roughly<a href="https://themcpguy.com/blog/mcp-goes-stateless#migrating-roughly" class="hash-link" aria-label="Direct link to Migrating, roughly" title="Direct link to Migrating, roughly" translate="no">​</a></h2>
<p>The migration shape is:</p>
<ol>
<li class="">Inventory everything that depends on the session or the handshake.</li>
<li class="">Move per-session memory into an external store, keyed by an explicit handle you pass in requests.</li>
<li class="">Stop emitting and requiring <code>Mcp-Session-Id</code>.</li>
<li class="">Put your instances behind a stateless balancer and delete the sticky-session config you no longer need.</li>
</ol>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-bottom-line">The bottom line<a href="https://themcpguy.com/blog/mcp-goes-stateless#the-bottom-line" class="hash-link" aria-label="Direct link to The bottom line" title="Direct link to The bottom line" translate="no">​</a></h2>
<p>MCP is trading a convenience (implicit session state) for the thing enterprises actually need (trivial horizontal scaling). It's the right trade, and the ink is now dry. The remaining constraint is your SDK rather than the spec: make your state explicit now, because that part runs on today's SDKs, and pick up the protocol-level changes as your SDK ships them.</p>
<p><em>This is the spine of our <strong>MCP at Scale</strong> course, which goes deeper on stateless transport, explicit state handles, routing, and horizontal scaling.</em></p>]]></content>
        <author>
            <name>TheMCPGuy</name>
            <uri>https://themcpguy.com</uri>
        </author>
        <category label="mcp" term="mcp"/>
        <category label="scaling" term="scaling"/>
        <category label="transport" term="transport"/>
        <category label="spec" term="spec"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[MCP Grew a UI Layer: The First Official Extension Renders Apps in Your Chat]]></title>
        <id>https://themcpguy.com/blog/first-official-mcp-extension-renders-ui</id>
        <link href="https://themcpguy.com/blog/first-official-mcp-extension-renders-ui"/>
        <updated>2026-07-03T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[A chat window containing an interactive revenue widget rendered inside a sandboxed iframe, with an Export button that triggers a tool call]]></summary>
        <content type="html"><![CDATA[<p><img decoding="async" loading="lazy" alt="A chat window containing an interactive revenue widget rendered inside a sandboxed iframe, with an Export button that triggers a tool call" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA4MDAgNDAwIj4KICA8cmVjdCB3aWR0aD0iODAwIiBoZWlnaHQ9IjQwMCIgZmlsbD0iIzA1MDcxNCIvPgogIDwhLS0gQ2hhdCB3aW5kb3cgZnJhbWUgLS0+CiAgPHJlY3QgeD0iMTgwIiB5PSI0MCIgd2lkdGg9IjQ0MCIgaGVpZ2h0PSIzMjAiIHJ4PSIxNCIgZmlsbD0iIzBkMTExNyIgc3Ryb2tlPSIjMWUyOTNiIiBzdHJva2Utd2lkdGg9IjIiLz4KICA8cmVjdCB4PSIxODAiIHk9IjQwIiB3aWR0aD0iNDQwIiBoZWlnaHQ9IjM0IiByeD0iMTQiIGZpbGw9IiMwYjEwMjAiLz4KICA8Y2lyY2xlIGN4PSIyMDIiIGN5PSI1NyIgcj0iNCIgZmlsbD0iI2VmNDQ0NCIvPgogIDxjaXJjbGUgY3g9IjIxOCIgY3k9IjU3IiByPSI0IiBmaWxsPSIjZjU5ZTBiIi8+CiAgPGNpcmNsZSBjeD0iMjM0IiBjeT0iNTciIHI9IjQiIGZpbGw9IiMxMGI5ODEiLz4KICA8dGV4dCB4PSI0MDAiIHk9IjYxIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmaWxsPSIjNDc1NTY5IiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMSI+QUkgY2hhdDwvdGV4dD4KCiAgPCEtLSB1c2VyIG1lc3NhZ2UgYnViYmxlIC0tPgogIDxyZWN0IHg9IjM2MCIgeT0iOTIiIHdpZHRoPSIyMzIiIGhlaWdodD0iMzQiIHJ4PSIxMCIgZmlsbD0iIzExMWEyZSIvPgogIDx0ZXh0IHg9IjQ3NiIgeT0iMTEzIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmaWxsPSIjOTRhM2I4IiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMiI+U2hvdyBtZSBRMiByZXZlbnVlPC90ZXh0PgoKICA8IS0tIGFzc2lzdGFudCBidWJibGUgY29udGFpbmluZyBhbiBpbnRlcmFjdGl2ZSB3aWRnZXQgLS0+CiAgPHRleHQgeD0iMjA4IiB5PSIxNTAiIGZpbGw9IiM2NDc0OGIiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjExIj5NQ1AgQXBwIMK3IHNhbmRib3hlZCBpZnJhbWU8L3RleHQ+CiAgPHJlY3QgeD0iMjA4IiB5PSIxNTgiIHdpZHRoPSIzODQiIGhlaWdodD0iMTgwIiByeD0iMTAiIGZpbGw9IiMwYjEwMjAiIHN0cm9rZT0iIzA2YjZkNCIgc3Ryb2tlLXdpZHRoPSIxLjUiIHN0cm9rZS1kYXNoYXJyYXk9IjYgNCIvPgogIDwhLS0gd2lkZ2V0IGhlYWRlciAtLT4KICA8dGV4dCB4PSIyMjgiIHk9IjE4NCIgZmlsbD0iIzIyZDNlZSIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTMiIGZvbnQtd2VpZ2h0PSJib2xkIj5SZXZlbnVlIOKAlCBRMiAyMDI2PC90ZXh0PgogIDwhLS0gYmFyIGNoYXJ0IC0tPgogIDxyZWN0IHg9IjIzMiIgeT0iMjUwIiB3aWR0aD0iMzQiIGhlaWdodD0iNTgiIHJ4PSIzIiBmaWxsPSIjMDZiNmQ0Ii8+CiAgPHJlY3QgeD0iMjgyIiB5PSIyMjYiIHdpZHRoPSIzNCIgaGVpZ2h0PSI4MiIgcng9IjMiIGZpbGw9IiM4YjVjZjYiLz4KICA8cmVjdCB4PSIzMzIiIHk9IjI3MCIgd2lkdGg9IjM0IiBoZWlnaHQ9IjM4IiByeD0iMyIgZmlsbD0iIzEwYjk4MSIvPgogIDxyZWN0IHg9IjM4MiIgeT0iMjM4IiB3aWR0aD0iMzQiIGhlaWdodD0iNzAiIHJ4PSIzIiBmaWxsPSIjZjU5ZTBiIi8+CiAgPGxpbmUgeDE9IjIyNiIgeTE9IjMwOCIgeDI9IjQzMCIgeTI9IjMwOCIgc3Ryb2tlPSIjMWUyOTNiIiBzdHJva2Utd2lkdGg9IjEuNSIvPgogIDwhLS0gYW4gaW50ZXJhY3RpdmUgYnV0dG9uIGluc2lkZSB0aGUgd2lkZ2V0IC0tPgogIDxyZWN0IHg9IjQ1MiIgeT0iMjI2IiB3aWR0aD0iMTIwIiBoZWlnaHQ9IjM0IiByeD0iOCIgZmlsbD0icmdiYSg2LDE4MiwyMTIsMC4xMikiIHN0cm9rZT0iIzA2YjZkNCIgc3Ryb2tlLXdpZHRoPSIxLjUiLz4KICA8dGV4dCB4PSI1MTIiIHk9IjI0OCIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZmlsbD0iIzIyZDNlZSIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTIiIGZvbnQtd2VpZ2h0PSI2MDAiPkV4cG9ydCDilrg8L3RleHQ+CiAgPHRleHQgeD0iNDUyIiB5PSIyOTAiIGZpbGw9IiM0NzU1NjkiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjEwIj5jbGljayDihpIgdG9vbCBjYWxsPC90ZXh0PgogIDx0ZXh0IHg9IjQ1MiIgeT0iMzA1IiBmaWxsPSIjNDc1NTY5IiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMCI+KHdpdGggY29uc2VudCk8L3RleHQ+CgogIDx0ZXh0IHg9IjQwMCIgeT0iMzg0IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmaWxsPSIjNDc1NTY5IiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMyI+dGhlbWNwZ3V5LmNvbSDigJQgVGhlIEZpcnN0IE9mZmljaWFsIE1DUCBFeHRlbnNpb248L3RleHQ+Cjwvc3ZnPgo=" width="800" height="400" class="img_ev3q"></p>
<p>For its entire life, MCP has spoken in text. Tools return strings and JSON; the model narrates the result back to you in prose. That was a deliberate, sensible constraint, and it was always going to hit a ceiling. Some answers are a paragraph. Others are a chart, a date picker, a seat map, a diff you want to <em>click</em>.</p>
<p>As of early 2026, MCP has an answer: <strong>MCP Apps</strong>, the protocol's <em>first official extension</em>, which lets a tool ship interactive UI that renders right inside the conversation.</p>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>Version disclosure (as of June 2026)</div><div class="admonitionContent_BuS1"><p>MCP Apps is specified in <strong>SEP-1865</strong>, stabilized <strong>2026-01-26</strong>, and developed collaboratively with the MCP-UI community and maintainers from OpenAI and Anthropic. It targets the <strong>MCP spec <code>2025-11-25</code></strong>. The official SDK published in the <code>ext-apps</code> repo is <strong>TypeScript/JavaScript</strong> (<code>@modelcontextprotocol/ext-apps</code>); OpenAI's Apps SDK is built on the same MCP Apps foundation. Note the SDK language situation below; it matters if, like us, you live in the Java world.</p></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-text-only-ceiling">The text-only ceiling<a href="https://themcpguy.com/blog/first-official-mcp-extension-renders-ui#the-text-only-ceiling" class="hash-link" aria-label="Direct link to The text-only ceiling" title="Direct link to The text-only ceiling" translate="no">​</a></h2>
<p>You have felt this. You ask an agent for "revenue by region this quarter" and get back a tidy ASCII-ish table that you immediately want to sort, filter, or export. The model <em>has</em> the data; the channel just can't render anything you can interact with. Every rich interaction had to bounce out to a separate app.</p>
<p>MCP Apps closes that gap without abandoning the protocol's safety model.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-mcp-apps-actually-is">What MCP Apps actually is<a href="https://themcpguy.com/blog/first-official-mcp-extension-renders-ui#what-mcp-apps-actually-is" class="hash-link" aria-label="Direct link to What MCP Apps actually is" title="Direct link to What MCP Apps actually is" translate="no">​</a></h2>
<p>It is not a new transport or a new primitive grab-bag. It is a focused extension built on two pieces you already know, resources and tools:</p>
<ul>
<li class="">A tool can advertise a <strong>UI resource</strong> via <code>_meta.ui.resourceUri</code>. That resource is HTML, served with the MIME type <code>text/html;profile=mcp-app</code>.</li>
<li class="">The host renders that HTML inside a <strong>sandboxed iframe</strong>, isolated from the page, the model, and your other tools.</li>
<li class="">The iframe talks back to the host over <strong>JSON-RPC sent across <code>postMessage</code></strong>, brokered by the App SDK.</li>
</ul>
<p>So a tool result is no longer just text. It can be "here is the data, <em>and here is a sandboxed widget to render it</em>."</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-part-that-should-make-you-comfortable-consent-didnt-change">The part that should make you comfortable: consent didn't change<a href="https://themcpguy.com/blog/first-official-mcp-extension-renders-ui#the-part-that-should-make-you-comfortable-consent-didnt-change" class="hash-link" aria-label="Direct link to The part that should make you comfortable: consent didn't change" title="Direct link to The part that should make you comfortable: consent didn't change" translate="no">​</a></h2>
<p>The first question a security-minded engineer asks is "so a server can now run arbitrary UI in my client?" The reassuring answer: the widget is sandboxed, and <strong>actions still flow through the same tool-call consent path you already trust.</strong></p>
<p>When a user clicks "Export" in the widget, the iframe doesn't get to quietly do something. It sends a JSON-RPC message that becomes a <strong>tool call</strong>, and that tool call goes through the host's normal approval flow, the same gate that governs every other tool invocation. The UI is new; the trust boundary is not.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="write-once-render-across-hosts">Write once, render across hosts<a href="https://themcpguy.com/blog/first-official-mcp-extension-renders-ui#write-once-render-across-hosts" class="hash-link" aria-label="Direct link to Write once, render across hosts" title="Direct link to Write once, render across hosts" translate="no">​</a></h2>
<p>The reason this is a big deal and not just a vendor feature: it is a shared extension, and the early host list is broad, with <strong>Claude, ChatGPT, VS Code, Goose, Postman, and MCPJam</strong> among the documented adopters. An MCP App you build is meant to render across compliant hosts rather than being locked to one assistant. That cross-host portability is exactly what made base MCP win, now applied to UI.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-this-means-if-you-build-mcp-servers">What this means if you build MCP servers<a href="https://themcpguy.com/blog/first-official-mcp-extension-renders-ui#what-this-means-if-you-build-mcp-servers" class="hash-link" aria-label="Direct link to What this means if you build MCP servers" title="Direct link to What this means if you build MCP servers" translate="no">​</a></h2>
<ul>
<li class=""><strong>Your reach just expanded</strong> from "return good text" to "return a usable interface" (pickers, dashboards, confirmations, forms) without shipping a separate frontend app.</li>
<li class=""><strong>The widget is HTML/JS, by design.</strong> It renders in a browser iframe, so the UI layer is web tech regardless of what your server is written in.</li>
<li class=""><strong>For the Java crowd (us included):</strong> there is real nuance here. You can absolutely <em>serve</em> an MCP App from a Java server by exposing the <code>ui</code> resource and wiring the tool's <code>_meta.ui.resourceUri</code> through the Java SDK. But the <strong>widget itself is HTML/JS</strong>, and the official App SDK published in the <code>ext-apps</code> repo today is TypeScript/JavaScript. So the honest framing is: <em>Java server, web widget.</em> Don't expect to write the UI in Java.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-bottom-line">The bottom line<a href="https://themcpguy.com/blog/first-official-mcp-extension-renders-ui#the-bottom-line" class="hash-link" aria-label="Direct link to The bottom line" title="Direct link to The bottom line" translate="no">​</a></h2>
<p>MCP Apps is the protocol admitting that some answers aren't sentences. It does it the right way, by building on resources and tools, sandboxing the UI, and keeping every action on the existing consent rails. If you've been treating MCP as a backend-only concern, this is the moment it became a product-surface concern too.</p>
<p><em>We're building a full <strong>Building MCP Apps</strong> course around this: the <code>ui</code> resource, the iframe security model, the <code>postMessage</code>/App SDK bridge, the consent path, and a widget built end-to-end (served from a Java MCP server, with an honest accounting of where the web layer begins).</em></p>]]></content>
        <author>
            <name>TheMCPGuy</name>
            <uri>https://themcpguy.com</uri>
        </author>
        <category label="mcp" term="mcp"/>
        <category label="mcp-apps" term="mcp-apps"/>
        <category label="ui" term="ui"/>
        <category label="extensions" term="extensions"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Your Agent Is Drowning in Tool Definitions (Code Execution Throws It a Rope)]]></title>
        <id>https://themcpguy.com/blog/agent-drowning-in-tool-definitions</id>
        <link href="https://themcpguy.com/blog/agent-drowning-in-tool-definitions"/>
        <updated>2026-06-26T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[An overflowing context window stuffed with tool-definition JSON on the left, a slim code file on the right, tokens dropping from 150,000 to 2,000]]></summary>
        <content type="html"><![CDATA[<p><img decoding="async" loading="lazy" alt="An overflowing context window stuffed with tool-definition JSON on the left, a slim code file on the right, tokens dropping from 150,000 to 2,000" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA4MDAgNDAwIj4KICA8cmVjdCB3aWR0aD0iODAwIiBoZWlnaHQ9IjQwMCIgZmlsbD0iIzA1MDcxNCIvPgogIDwhLS0gTEVGVDogYW4gb3ZlcmZsb3dpbmcgY29udGV4dCB3aW5kb3cgLS0+CiAgPHRleHQgeD0iMTcwIiB5PSI1NiIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZmlsbD0iIzQ3NTU2OSIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTMiPkNvbnRleHQgd2luZG93PC90ZXh0PgogIDxyZWN0IHg9IjYwIiB5PSI3MiIgd2lkdGg9IjIyMCIgaGVpZ2h0PSIyNTAiIHJ4PSIxMCIgZmlsbD0iIzBkMTExNyIgc3Ryb2tlPSIjZWY0NDQ0IiBzdHJva2Utd2lkdGg9IjIiLz4KICA8IS0tIHN0YWNrZWQgdG9vbC1kZWZpbml0aW9uIGNhcmRzLCBvdmVyZmxvd2luZyB0aGUgdG9wIC0tPgogIDxnIGZvbnQtZmFtaWx5PSJtb25vc3BhY2UiIGZvbnQtc2l6ZT0iOSIgZmlsbD0iIzY0NzQ4YiI+CiAgICA8cmVjdCB4PSI3NCIgeT0iNTgiIHdpZHRoPSIxOTIiIGhlaWdodD0iMjIiIHJ4PSIzIiBmaWxsPSIjMTExYTJlIiBzdHJva2U9IiNlZjQ0NDQiIHN0cm9rZS13aWR0aD0iMSIgb3BhY2l0eT0iMC43Ii8+CiAgICA8dGV4dCB4PSI4NCIgeT0iNzMiPiJuYW1lIjoiY3JlYXRlX2ludm9pY2UiLCAiZGVzYyI64oCmPC90ZXh0PgogICAgPHJlY3QgeD0iNzQiIHk9Ijg2IiB3aWR0aD0iMTkyIiBoZWlnaHQ9IjIyIiByeD0iMyIgZmlsbD0iIzExMWEyZSIgc3Ryb2tlPSIjZWY0NDQ0IiBzdHJva2Utd2lkdGg9IjEiLz4KICAgIDx0ZXh0IHg9Ijg0IiB5PSIxMDEiPiJuYW1lIjoibGlzdF9jdXN0b21lcnMiLCAicGFyYW1zIuKApjwvdGV4dD4KICAgIDxyZWN0IHg9Ijc0IiB5PSIxMTQiIHdpZHRoPSIxOTIiIGhlaWdodD0iMjIiIHJ4PSIzIiBmaWxsPSIjMTExYTJlIiBzdHJva2U9IiNlZjQ0NDQiIHN0cm9rZS13aWR0aD0iMSIvPgogICAgPHRleHQgeD0iODQiIHk9IjEyOSI+Im5hbWUiOiJ1cGRhdGVfbGVkZ2VyIiwgInNjaGVtYSLigKY8L3RleHQ+CiAgICA8cmVjdCB4PSI3NCIgeT0iMTQyIiB3aWR0aD0iMTkyIiBoZWlnaHQ9IjIyIiByeD0iMyIgZmlsbD0iIzExMWEyZSIgc3Ryb2tlPSIjZWY0NDQ0IiBzdHJva2Utd2lkdGg9IjEiLz4KICAgIDx0ZXh0IHg9Ijg0IiB5PSIxNTciPiJuYW1lIjoic2VuZF9yZW1pbmRlciIsICJpbnB1dCLigKY8L3RleHQ+CiAgICA8cmVjdCB4PSI3NCIgeT0iMTcwIiB3aWR0aD0iMTkyIiBoZWlnaHQ9IjIyIiByeD0iMyIgZmlsbD0iIzExMWEyZSIgc3Ryb2tlPSIjZWY0NDQ0IiBzdHJva2Utd2lkdGg9IjEiLz4KICAgIDx0ZXh0IHg9Ijg0IiB5PSIxODUiPiJuYW1lIjoiZmV0Y2hfcmVwb3J0IiwgInJldHVybnMi4oCmPC90ZXh0PgogICAgPHJlY3QgeD0iNzQiIHk9IjE5OCIgd2lkdGg9IjE5MiIgaGVpZ2h0PSIyMiIgcng9IjMiIGZpbGw9IiMxMTFhMmUiIHN0cm9rZT0iI2VmNDQ0NCIgc3Ryb2tlLXdpZHRoPSIxIi8+CiAgICA8dGV4dCB4PSI4NCIgeT0iMjEzIj4ibmFtZSI6InJlY29uY2lsZV90eG4iLCAiZGVzYyLigKY8L3RleHQ+CiAgICA8cmVjdCB4PSI3NCIgeT0iMjI2IiB3aWR0aD0iMTkyIiBoZWlnaHQ9IjIyIiByeD0iMyIgZmlsbD0iIzExMWEyZSIgc3Ryb2tlPSIjZWY0NDQ0IiBzdHJva2Utd2lkdGg9IjEiIG9wYWNpdHk9IjAuODUiLz4KICAgIDx0ZXh0IHg9Ijg0IiB5PSIyNDEiPiJuYW1lIjoiZXhwb3J0X3BkZiIsICJwYXJhbXMi4oCmPC90ZXh0PgogICAgPHJlY3QgeD0iNzQiIHk9IjI1NCIgd2lkdGg9IjE5MiIgaGVpZ2h0PSIyMiIgcng9IjMiIGZpbGw9IiMxMTFhMmUiIHN0cm9rZT0iI2VmNDQ0NCIgc3Ryb2tlLXdpZHRoPSIxIiBvcGFjaXR5PSIwLjYiLz4KICAgIDx0ZXh0IHg9Ijg0IiB5PSIyNjkiPuKApmFuZCAyNDAgbW9yZSB0b29sczwvdGV4dD4KICA8L2c+CiAgPHRleHQgeD0iMTcwIiB5PSIzMDUiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZpbGw9IiNlZjQ0NDQiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjIwIiBmb250LXdlaWdodD0iYm9sZCI+fjE1MCwwMDAgdG9rZW5zPC90ZXh0PgogIDx0ZXh0IHg9IjE3MCIgeT0iMzI0IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmaWxsPSIjNjQ3NDhiIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMSI+bG9hZGVkIGJlZm9yZSB5b3UgdHlwZSBhIHdvcmQ8L3RleHQ+CgogIDwhLS0gQVJST1cgLS0+CiAgPHRleHQgeD0iNDAwIiB5PSIxOTUiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZpbGw9IiMyMmQzZWUiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjM4Ij7ihpI8L3RleHQ+CiAgPHRleHQgeD0iNDAwIiB5PSIyMjUiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZpbGw9IiM0NzU1NjkiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjEyIj5jb2RlIGV4ZWN1dGlvbjwvdGV4dD4KCiAgPCEtLSBSSUdIVDogYSBzbGltIGNvZGUgZmlsZSAtLT4KICA8dGV4dCB4PSI2MjAiIHk9IjU2IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmaWxsPSIjNDc1NTY5IiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMyI+VG9vbHMgYXMgYSBmaWxlc3lzdGVtIEFQSTwvdGV4dD4KICA8cmVjdCB4PSI1MjAiIHk9IjEyMCIgd2lkdGg9IjIwMCIgaGVpZ2h0PSIxMjAiIHJ4PSIxMCIgZmlsbD0iIzBkMTExNyIgc3Ryb2tlPSIjMTBiOTgxIiBzdHJva2Utd2lkdGg9IjIiLz4KICA8cmVjdCB4PSI1MjAiIHk9IjEyMCIgd2lkdGg9IjIwMCIgaGVpZ2h0PSI0IiByeD0iMiIgZmlsbD0iIzEwYjk4MSIvPgogIDxnIGZvbnQtZmFtaWx5PSJtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTEiIGZpbGw9IiMzNGQzOTkiPgogICAgPHRleHQgeD0iNTM2IiB5PSIxNTAiPmltcG9ydCB7IGludm9pY2VzIH08L3RleHQ+CiAgICA8dGV4dCB4PSI1MzYiIHk9IjE3MCI+ICBmcm9tICIuL3Rvb2xzIjs8L3RleHQ+CiAgICA8dGV4dCB4PSI1MzYiIHk9IjE5NiIgZmlsbD0iIzY0NzQ4YiI+Ly8gbG9hZCBvbmx5IHdoYXQ8L3RleHQ+CiAgICA8dGV4dCB4PSI1MzYiIHk9IjIxMiIgZmlsbD0iIzY0NzQ4YiI+Ly8gdGhpcyB0YXNrIG5lZWRzPC90ZXh0PgogIDwvZz4KICA8dGV4dCB4PSI2MjAiIHk9IjI3MiIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZmlsbD0iIzM0ZDM5OSIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMjAiIGZvbnQtd2VpZ2h0PSJib2xkIj5+MiwwMDAgdG9rZW5zPC90ZXh0PgogIDx0ZXh0IHg9IjYyMCIgeT0iMjkxIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmaWxsPSIjNjQ3NDhiIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMSI+cHJvZ3Jlc3NpdmUgZGlzY2xvc3VyZTwvdGV4dD4KCiAgPHRleHQgeD0iNDAwIiB5PSIzNzIiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZpbGw9IiM0NzU1NjkiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjEzIj50aGVtY3BndXkuY29tIOKAlCBZb3VyIEFnZW50IElzIERyb3duaW5nIGluIFRvb2wgRGVmaW5pdGlvbnM8L3RleHQ+Cjwvc3ZnPgo=" width="800" height="400" class="img_ev3q"></p>
<p>Here is a cost nobody warns you about when you wire up your fifth MCP server: your agent gets <em>dumber and more expensive at the same time</em>, and it happens before the user has typed a single word.</p>
<p>The reason is boring and brutal. Every tool your servers expose ships a definition: a name, a description, a JSON schema for its inputs, often examples. All of it gets serialized into the model's context window on every single turn, just so the model <em>might</em> pick the right tool. Connect a few busy servers and you are spending six figures of tokens describing tools the model will never call for this particular request.</p>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>Version disclosure (as of June 2026)</div><div class="admonitionContent_BuS1"><p>The pattern in this post is described in Anthropic's engineering write-up <em>"Code execution with MCP"</em> (November 2025) and targets the <strong>MCP spec <code>2025-11-25</code></strong>. Token figures below are <strong>illustrative numbers from that article, not a benchmark you should quote as gospel</strong>, so measure your own. As the spec and SDKs evolve, the <em>shape</em> of this technique should hold, but verify the mechanics against the current docs.</p></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-tax-you-didnt-know-you-were-paying">The tax you didn't know you were paying<a href="https://themcpguy.com/blog/agent-drowning-in-tool-definitions#the-tax-you-didnt-know-you-were-paying" class="hash-link" aria-label="Direct link to The tax you didn't know you were paying" title="Direct link to The tax you didn't know you were paying" translate="no">​</a></h2>
<p>There are actually two separate bloat problems, and conflating them is why people "optimize" the wrong one.</p>
<p><strong>1. Definition bloat (up front).</strong> Before any work happens, the client loads every tool definition from every connected server. This is fixed per turn and scales with how many tools you have connected, not with what you are doing. Three hundred tools at ~500 tokens each is ~150,000 tokens of overhead on turn one.</p>
<p><strong>2. Result bloat (at runtime).</strong> A tool returns 4,000 rows of JSON, the model needs three of them, and the other 3,997 sit in the transcript forever, getting re-sent on every subsequent turn.</p>
<p>Definition bloat makes your agent expensive and slow <em>and dumber</em>, because a context window crammed with tool schemas has less room for the actual problem, and models genuinely degrade as the relevant signal gets buried. Result bloat compounds it turn over turn.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-fix-stop-describing-tools-start-importing-them">The fix: stop <em>describing</em> tools, start <em>importing</em> them<a href="https://themcpguy.com/blog/agent-drowning-in-tool-definitions#the-fix-stop-describing-tools-start-importing-them" class="hash-link" aria-label="Direct link to the-fix-stop-describing-tools-start-importing-them" title="Direct link to the-fix-stop-describing-tools-start-importing-them" translate="no">​</a></h2>
<p>The technique Anthropic documented flips the model's relationship to your tools. Instead of presenting every tool as a definition the model reads and then calls via JSON, you present your MCP servers as a <strong>filesystem of code</strong>, a directory of typed functions the model can <code>import</code> and call from inside a sandboxed code-execution environment.</p>
<div class="language-typescript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-typescript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// The model doesn't see 300 tool schemas.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// It sees a filesystem and writes code against it:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> getInvoices </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"./servers/billing"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> getCustomer </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"./servers/crm"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> overdue </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">await</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getInvoices</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> status</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"overdue"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">filter</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">i </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> i</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">daysLate </span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">30</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// Only the 3 rows it needs ever re-enter the context, not 4,000.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token builtin">console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">overdue</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">map</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">i </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> id</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> i</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">id</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> customer</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> i</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">customerName </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<p>Two things just happened:</p>
<ul>
<li class="">The model only <strong>loads the definitions it actually imports</strong>, also known as progressive disclosure. The other 295 tools cost nothing this turn.</li>
<li class="">The model <strong>processes results in code</strong> and returns only the slice it cares about, so result bloat collapses too.</li>
</ul>
<p>Anthropic's worked example moved an agent from roughly <strong>150,000 tokens to roughly 2,000</strong> for the same task, about a 98.7% reduction. Treat that as "an order of magnitude or two, in a favorable case," not a number to put on a slide.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="progressive-disclosure-is-the-real-idea">Progressive disclosure is the real idea<a href="https://themcpguy.com/blog/agent-drowning-in-tool-definitions#progressive-disclosure-is-the-real-idea" class="hash-link" aria-label="Direct link to Progressive disclosure is the real idea" title="Direct link to Progressive disclosure is the real idea" translate="no">​</a></h2>
<p>"Code execution" is the mechanism; <strong>progressive disclosure</strong> is the principle, and it long predates MCP. Don't put everything in front of the model at once. Let it discover the tool surface lazily: list what's available cheaply, load the full signature of a tool only when it intends to use it, fetch only the fields a step needs.</p>
<p>You can apply the principle even without a full code sandbox:</p>
<ul>
<li class="">Group tools and load definitions per-group on demand instead of all at once.</li>
<li class="">Return compact, paginated, or summarized results by default and offer a "drill in" tool for detail.</li>
<li class="">Keep large payloads as <strong>resources the model references by handle</strong>, not as inline tool output it has to carry forever.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="so-who-is-supposed-to-fix-this-you-or-the-client">So who is supposed to fix this, you or the client?<a href="https://themcpguy.com/blog/agent-drowning-in-tool-definitions#so-who-is-supposed-to-fix-this-you-or-the-client" class="hash-link" aria-label="Direct link to So who is supposed to fix this, you or the client?" title="Direct link to So who is supposed to fix this, you or the client?" translate="no">​</a></h2>
<p>This is the honest nuance the headline glosses over: <strong>a lot of definition bloat is the client's problem, not your server's.</strong> How tool definitions are packed into context, whether the host supports a code-execution surface, whether results can be offloaded to resources, much of that lives in the MCP <em>host</em>, not your server.</p>
<p>What you control as a server author:</p>
<ul>
<li class=""><strong>Right-size your results.</strong> Default to lean; make verbosity opt-in.</li>
<li class=""><strong>Lean on resources</strong> for big data instead of stuffing it through tool outputs.</li>
<li class=""><strong>Write tight definitions</strong> (see <a class="" href="https://themcpguy.com/blog/tool-description-is-a-prompt">Your Tool Description Is a Prompt</a>; every wasted word is a wasted token, on every turn).</li>
</ul>
<p>What you control as a host/client author:</p>
<ul>
<li class="">Whether you expose tools as schemas-in-context or as an importable code API.</li>
<li class="">Whether you implement progressive disclosure of definitions at all.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-to-do-monday">What to do Monday<a href="https://themcpguy.com/blog/agent-drowning-in-tool-definitions#what-to-do-monday" class="hash-link" aria-label="Direct link to What to do Monday" title="Direct link to What to do Monday" translate="no">​</a></h2>
<ol>
<li class=""><strong>Measure first.</strong> Log the token count of your tool definitions on a cold turn. People are routinely shocked.</li>
<li class=""><strong>Cut definition bloat</strong> before you touch anything clever: fewer, sharper tools; tighter descriptions.</li>
<li class=""><strong>Move big results to resources</strong> so they stop riding along every turn.</li>
<li class=""><strong>If your host supports it, try the code-execution surface</strong> on your most tool-heavy agent and measure the delta on a real task.</li>
</ol>
<p>The agents that win in 2026 aren't the ones connected to the most MCP servers. They're the ones that can <em>ignore</em> the most servers, cheaply, until the moment a tool is actually needed.</p>
<p><em>Want the full treatment? This is the heart of our upcoming <strong>Context Engineering for MCP</strong> course, covering token accounting, code execution, progressive disclosure, and how to measure the savings instead of trusting a blog post's numbers (including this one).</em></p>]]></content>
        <author>
            <name>TheMCPGuy</name>
            <uri>https://themcpguy.com</uri>
        </author>
        <category label="mcp" term="mcp"/>
        <category label="context-engineering" term="context-engineering"/>
        <category label="tokens" term="tokens"/>
        <category label="performance" term="performance"/>
        <category label="tools" term="tools"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[MCP Has Six Primitives, Not Three. Here's the Half You're Ignoring.]]></title>
        <id>https://themcpguy.com/blog/six-primitives-not-three</id>
        <link href="https://themcpguy.com/blog/six-primitives-not-three"/>
        <updated>2026-06-19T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[A mirror split down the middle: on one side, the symbols for Tools, Resources, and Prompts; on the other, the symbols for Roots, Sampling, and Elicitation, identical in weight but reversed]]></summary>
        <content type="html"><![CDATA[<p><img decoding="async" loading="lazy" alt="A mirror split down the middle: on one side, the symbols for Tools, Resources, and Prompts; on the other, the symbols for Roots, Sampling, and Elicitation, identical in weight but reversed" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA4MDAgNDAwIj4KICA8cmVjdCB3aWR0aD0iODAwIiBoZWlnaHQ9IjQwMCIgZmlsbD0iIzA1MDcxNCIvPgogIDwhLS0gbWlycm9yIGRpdmlkZXIgZG93biB0aGUgbWlkZGxlIC0tPgogIDxsaW5lIHgxPSI0MDAiIHkxPSI0MCIgeDI9IjQwMCIgeTI9IjM1MCIgc3Ryb2tlPSIjMWUyOTNiIiBzdHJva2Utd2lkdGg9IjIiLz4KICA8bGluZSB4MT0iNDAwIiB5MT0iNDAiIHgyPSI0MDAiIHkyPSIzNTAiIHN0cm9rZT0iIzIyZDNlZSIgc3Ryb2tlLXdpZHRoPSIxIiBzdHJva2UtZGFzaGFycmF5PSIzIDciIG9wYWNpdHk9IjAuNCIvPgogIDx0ZXh0IHg9IjIwMCIgeT0iNjIiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZpbGw9IiM2NDc0OGIiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjEzIiBmb250LXdlaWdodD0iYm9sZCI+VGhlIHRocmVlIHlvdSBrbm93PC90ZXh0PgogIDx0ZXh0IHg9IjYwMCIgeT0iNjIiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZpbGw9IiM2NDc0OGIiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjEzIiBmb250LXdlaWdodD0iYm9sZCI+VGhlIGhhbGYgeW91IGlnbm9yZTwvdGV4dD4KCiAgPCEtLSBMRUZUOiBUb29scyAvIFJlc291cmNlcyAvIFByb21wdHMgLS0+CiAgPHJlY3QgeD0iNzAiIHk9IjkwIiB3aWR0aD0iMjYwIiBoZWlnaHQ9IjY0IiByeD0iMTIiIGZpbGw9IiMwZDExMTciIHN0cm9rZT0iIzA2YjZkNCIgc3Ryb2tlLXdpZHRoPSIyIi8+CiAgPHJlY3QgeD0iNzAiIHk9IjkwIiB3aWR0aD0iNCIgaGVpZ2h0PSI2NCIgcng9IjIiIGZpbGw9IiMwNmI2ZDQiLz4KICA8dGV4dCB4PSIxMDQiIHk9IjEzMCIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZmlsbD0iIzIyZDNlZSIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMjIiPvCflKc8L3RleHQ+CiAgPHRleHQgeD0iMTUwIiB5PSIxMjMiIGZpbGw9IiMyMmQzZWUiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjE3IiBmb250LXdlaWdodD0iYm9sZCI+VG9vbHM8L3RleHQ+CiAgPHRleHQgeD0iMTUwIiB5PSIxNDIiIGZpbGw9IiM0NzU1NjkiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjExIj5UaGUgQUkgYWN0czwvdGV4dD4KCiAgPHJlY3QgeD0iNzAiIHk9IjE2OCIgd2lkdGg9IjI2MCIgaGVpZ2h0PSI2NCIgcng9IjEyIiBmaWxsPSIjMGQxMTE3IiBzdHJva2U9IiM4YjVjZjYiIHN0cm9rZS13aWR0aD0iMiIvPgogIDxyZWN0IHg9IjcwIiB5PSIxNjgiIHdpZHRoPSI0IiBoZWlnaHQ9IjY0IiByeD0iMiIgZmlsbD0iIzhiNWNmNiIvPgogIDx0ZXh0IHg9IjEwNCIgeT0iMjA4IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmaWxsPSIjYTc4YmZhIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIyMiI+8J+TijwvdGV4dD4KICA8dGV4dCB4PSIxNTAiIHk9IjIwMSIgZmlsbD0iI2E3OGJmYSIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTciIGZvbnQtd2VpZ2h0PSJib2xkIj5SZXNvdXJjZXM8L3RleHQ+CiAgPHRleHQgeD0iMTUwIiB5PSIyMjAiIGZpbGw9IiM0NzU1NjkiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjExIj5UaGUgQUkgcmVhZHM8L3RleHQ+CgogIDxyZWN0IHg9IjcwIiB5PSIyNDYiIHdpZHRoPSIyNjAiIGhlaWdodD0iNjQiIHJ4PSIxMiIgZmlsbD0iIzBkMTExNyIgc3Ryb2tlPSIjMTBiOTgxIiBzdHJva2Utd2lkdGg9IjIiLz4KICA8cmVjdCB4PSI3MCIgeT0iMjQ2IiB3aWR0aD0iNCIgaGVpZ2h0PSI2NCIgcng9IjIiIGZpbGw9IiMxMGI5ODEiLz4KICA8dGV4dCB4PSIxMDQiIHk9IjI4NiIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZmlsbD0iIzM0ZDM5OSIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMjIiPvCfk508L3RleHQ+CiAgPHRleHQgeD0iMTUwIiB5PSIyNzkiIGZpbGw9IiMzNGQzOTkiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjE3IiBmb250LXdlaWdodD0iYm9sZCI+UHJvbXB0czwvdGV4dD4KICA8dGV4dCB4PSIxNTAiIHk9IjI5OCIgZmlsbD0iIzQ3NTU2OSIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTEiPkh1bWFucyBpbnZva2U8L3RleHQ+CgogIDwhLS0gUklHSFQ6IG1pcnJvcmVkIOKAlCBSb290cyAvIFNhbXBsaW5nIC8gRWxpY2l0YXRpb24gKGFjY2VudCBiYXIgb24gdGhlIHJpZ2h0IGVkZ2UpIC0tPgogIDxyZWN0IHg9IjQ3MCIgeT0iOTAiIHdpZHRoPSIyNjAiIGhlaWdodD0iNjQiIHJ4PSIxMiIgZmlsbD0iIzBkMTExNyIgc3Ryb2tlPSIjMDZiNmQ0IiBzdHJva2Utd2lkdGg9IjIiLz4KICA8cmVjdCB4PSI3MjYiIHk9IjkwIiB3aWR0aD0iNCIgaGVpZ2h0PSI2NCIgcng9IjIiIGZpbGw9IiMwNmI2ZDQiLz4KICA8dGV4dCB4PSI2OTYiIHk9IjEzMCIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZmlsbD0iIzIyZDNlZSIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMjIiPvCfk4E8L3RleHQ+CiAgPHRleHQgeD0iNjUwIiB5PSIxMjMiIHRleHQtYW5jaG9yPSJlbmQiIGZpbGw9IiMyMmQzZWUiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjE3IiBmb250LXdlaWdodD0iYm9sZCI+Um9vdHM8L3RleHQ+CiAgPHRleHQgeD0iNjUwIiB5PSIxNDIiIHRleHQtYW5jaG9yPSJlbmQiIGZpbGw9IiM0NzU1NjkiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjExIj5UaGUgQUkgaXMgc2NvcGVkPC90ZXh0PgoKICA8cmVjdCB4PSI0NzAiIHk9IjE2OCIgd2lkdGg9IjI2MCIgaGVpZ2h0PSI2NCIgcng9IjEyIiBmaWxsPSIjMGQxMTE3IiBzdHJva2U9IiM4YjVjZjYiIHN0cm9rZS13aWR0aD0iMiIvPgogIDxyZWN0IHg9IjcyNiIgeT0iMTY4IiB3aWR0aD0iNCIgaGVpZ2h0PSI2NCIgcng9IjIiIGZpbGw9IiM4YjVjZjYiLz4KICA8dGV4dCB4PSI2OTYiIHk9IjIwOCIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZmlsbD0iI2E3OGJmYSIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMjIiPvCflIE8L3RleHQ+CiAgPHRleHQgeD0iNjUwIiB5PSIyMDEiIHRleHQtYW5jaG9yPSJlbmQiIGZpbGw9IiNhNzhiZmEiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjE3IiBmb250LXdlaWdodD0iYm9sZCI+U2FtcGxpbmc8L3RleHQ+CiAgPHRleHQgeD0iNjUwIiB5PSIyMjAiIHRleHQtYW5jaG9yPSJlbmQiIGZpbGw9IiM0NzU1NjkiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjExIj5UaGUgc2VydmVyIGFza3MgdGhlIEFJPC90ZXh0PgoKICA8cmVjdCB4PSI0NzAiIHk9IjI0NiIgd2lkdGg9IjI2MCIgaGVpZ2h0PSI2NCIgcng9IjEyIiBmaWxsPSIjMGQxMTE3IiBzdHJva2U9IiMxMGI5ODEiIHN0cm9rZS13aWR0aD0iMiIvPgogIDxyZWN0IHg9IjcyNiIgeT0iMjQ2IiB3aWR0aD0iNCIgaGVpZ2h0PSI2NCIgcng9IjIiIGZpbGw9IiMxMGI5ODEiLz4KICA8dGV4dCB4PSI2OTYiIHk9IjI4NiIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZmlsbD0iIzM0ZDM5OSIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMjIiPvCfkqw8L3RleHQ+CiAgPHRleHQgeD0iNjUwIiB5PSIyNzkiIHRleHQtYW5jaG9yPSJlbmQiIGZpbGw9IiMzNGQzOTkiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjE3IiBmb250LXdlaWdodD0iYm9sZCI+RWxpY2l0YXRpb248L3RleHQ+CiAgPHRleHQgeD0iNjUwIiB5PSIyOTgiIHRleHQtYW5jaG9yPSJlbmQiIGZpbGw9IiM0NzU1NjkiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjExIj5UaGUgc2VydmVyIGFza3MgdGhlIHVzZXI8L3RleHQ+CgogIDx0ZXh0IHg9IjQwMCIgeT0iMzcwIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmaWxsPSIjNDc1NTY5IiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMyI+dGhlbWNwZ3V5LmNvbSDigJQgU2l4IFByaW1pdGl2ZXMsIE5vdCBUaHJlZTwvdGV4dD4KPC9zdmc+Cg==" width="800" height="400" class="img_ev3q"></p>
<p>Pop quiz. Name the MCP primitives.</p>
<p>If you've read any MCP introduction in the last eighteen months, you said: <strong>Tools, Resources, Prompts</strong>. You're right. Those are the things you build, the things you expose, the things every tutorial walks you through.</p>
<p>You are also wrong, in the sense that you are halfway right.</p>
<p>MCP has <em>six</em> primitives. The three you know are server-side: things your server exposes to the client. The three nobody seems to want to talk about are client-side: things the client exposes to your server. They are <strong>Roots</strong>, <strong>Sampling</strong>, and <strong>Elicitation</strong>, and the reason they get ignored is exactly the reason you should care about them.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-youve-never-heard-of-the-other-half">Why You've Never Heard of the Other Half<a href="https://themcpguy.com/blog/six-primitives-not-three#why-youve-never-heard-of-the-other-half" class="hash-link" aria-label="Direct link to Why You've Never Heard of the Other Half" title="Direct link to Why You've Never Heard of the Other Half" translate="no">​</a></h2>
<p>The first six months of MCP content focused, sensibly, on the obvious story: you build a server, it exposes tools, the AI uses them. That's the part most developers need first. Most people writing tutorials never get past it.</p>
<p>But MCP is not actually a one-way protocol. The spec is fully bidirectional. Servers can ask clients for things, not just respond to client requests. The client capabilities are how that conversation works.</p>
<p>The asymmetry of attention is partly an SDK story. Until quite recently, most Java and Python frameworks made the server-side primitives much easier to use than the client-side ones. If you were building with Spring AI, you were probably writing <code>@Tool</code>-annotated beans long before you knew you could write a <code>RootsHandler</code>. The protocol always supported it; the ergonomics didn't.</p>
<p>That has changed in the last year. The 2025-06-18 spec made the client-side primitives more useful by adding Elicitation. The 2025-11-25 spec polished the corners. And the SDKs are catching up. If you only know the three server-side primitives, you're working with half the protocol.</p>
<div class="theme-admonition theme-admonition-warning admonition_xJq3 alert alert--warning"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"></path></svg></span>Update (2026-07-31): the deprecation is no longer a proposal</div><div class="admonitionContent_BuS1"><p>When this post was published, deprecating three of these six primitives was only a draft proposal. It is now ratified. The <strong><code>2026-07-28</code></strong> specification, published 28 July 2026, <strong>deprecates Roots, Sampling, and Logging</strong> (SEP-2577), with suggested migrations toward tool parameters, direct LLM-provider integration, and OpenTelemetry respectively. Deprecated does not mean removed: the same revision introduced a feature-lifecycle policy guaranteeing a minimum twelve-month window, and these features remain fully functional throughout it, but new implementations should not adopt them. <strong>Elicitation is not deprecated</strong> and remains the most actively recommended client-side primitive, though <code>2026-07-28</code> changes how it is delivered: server-initiated requests are replaced by the Multi Round-Trip Requests pattern, where the server returns <code>resultType: "input_required"</code> and the client retries with the answers. Read the rest of this post in that context.</p></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="primitive-4-roots-the-server-asks-what-am-i-allowed-to-see">Primitive 4: Roots (The Server Asks "What Am I Allowed To See?")<a href="https://themcpguy.com/blog/six-primitives-not-three#primitive-4-roots-the-server-asks-what-am-i-allowed-to-see" class="hash-link" aria-label="Direct link to Primitive 4: Roots (The Server Asks &quot;What Am I Allowed To See?&quot;)" title="Direct link to Primitive 4: Roots (The Server Asks &quot;What Am I Allowed To See?&quot;)" translate="no">​</a></h2>
<p>Suppose you write a filesystem MCP server. It can read files. Wonderful. Now: <em>which</em> files?</p>
<p>The server doesn't have arbitrary access to the user's machine. It can't. Imagine the security disaster if it did. Some entity has to decide what's on-limits and what isn't. That entity is the <em>client</em>, because the client is the part that knows what the user has authorised.</p>
<p><strong>Roots</strong> are the mechanism for that conversation. When a client supports Roots, it advertises that it can answer the question: <em>"Here are the directories (or, more generally, URI scopes) that this server is allowed to operate on."</em> A filesystem MCP server can call <code>roots/list</code> on the client to find out: maybe the user has granted access to <code>~/Documents/work</code> and nothing else. The server then knows the boundary of its world.</p>
<p>If the user adds a folder to the workspace, the client emits <code>notifications/roots/list_changed</code>. The server re-queries. The boundary updates live, mid-session, without anyone reconnecting.</p>
<p>What this enables in practice:</p>
<ul>
<li class=""><strong>Workspace-aware servers.</strong> Your IDE plugin (Cursor, Continue, Claude Code) can tell the MCP server which project the user is currently working in. The server scopes everything to that project. Switch projects, the scope changes.</li>
<li class=""><strong>Multi-tenant clients.</strong> A single client can serve multiple users; each user has their own roots; the server doesn't have to manage that mapping.</li>
<li class=""><strong>Principle of least access at the protocol layer.</strong> The server cannot accidentally read outside its roots, because there's an explicit protocol-level fence. This is much stronger than "we'll just be careful in the code."</li>
</ul>
<p>If you've ever shipped an MCP server that took a <code>base_directory</code> configuration parameter at startup time, Roots are the more honest version of that pattern. The user, through the client, gets to dynamically tell you what counts as the base.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="primitive-5-sampling-the-server-asks-the-ai-for-help">Primitive 5: Sampling (The Server Asks the AI for Help)<a href="https://themcpguy.com/blog/six-primitives-not-three#primitive-5-sampling-the-server-asks-the-ai-for-help" class="hash-link" aria-label="Direct link to Primitive 5: Sampling (The Server Asks the AI for Help)" title="Direct link to Primitive 5: Sampling (The Server Asks the AI for Help)" translate="no">​</a></h2>
<p>This one bends people's brains, so we'll go slowly.</p>
<p>When you think of an MCP server, you think of something the AI uses. The AI calls a tool; the server runs code; the result goes back to the AI. The intelligence is in the AI; the server is just hands.</p>
<p>But what if the server needs the intelligence too?</p>
<p>Suppose your MCP server fetches a web page and needs to summarise it. Or fetches a code file and needs to extract its dependencies. Or processes a customer support ticket and needs to classify its sentiment. These are tasks that ought to use an LLM. But your MCP server doesn't have direct access to one. It doesn't have an API key. It doesn't know which provider the user is using. It doesn't know if the user wants their requests sent to a third party at all.</p>
<p><strong>Sampling</strong> is the protocol's answer. The server can call <code>sampling/createMessage</code> on the client to say: <em>"I have a prompt. Please run it through whatever model you're using, with whatever budget you allow, and give me the response."</em> The client owns the model relationship. The client can refuse, log, redact, change models, or budget the request. The server doesn't have to think about any of that. It just gets a completion.</p>
<p>This is what makes truly composable agents possible. Without Sampling, every MCP server has to either:</p>
<ol>
<li class="">Be entirely deterministic (no LLM reasoning inside the server), or</li>
<li class="">Bring its own model (with all the configuration, secrets, and surprise-vendor-coupling that implies).</li>
</ol>
<p>With Sampling, the server can borrow the client's brain. A <code>summarise_url</code> tool that uses Sampling internally to produce a high-quality summary, in whatever model the user has chosen, with the user retaining full control. That's a kind of architectural cleanness you can't get any other way.</p>
<p>The caveat, and it's a real one: Sampling has historically been one of the least-implemented capabilities. Many clients don't support it. In fact, the current draft spec proposes to <strong>deprecate</strong> Sampling (alongside Roots and Logging) under SEP-2577, with the suggested migration being direct integration with LLM provider APIs from inside your server. Sampling is still in the stable spec today, but if you're designing new servers, weigh that direction carefully and check whether your target clients support it before depending on it.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="primitive-6-elicitation-the-server-asks-the-user-a-question">Primitive 6: Elicitation (The Server Asks the User a Question)<a href="https://themcpguy.com/blog/six-primitives-not-three#primitive-6-elicitation-the-server-asks-the-user-a-question" class="hash-link" aria-label="Direct link to Primitive 6: Elicitation (The Server Asks the User a Question)" title="Direct link to Primitive 6: Elicitation (The Server Asks the User a Question)" translate="no">​</a></h2>
<p>This is the newest of the client-side primitives. It landed in 2025-06-18 and is the one most likely to change how you design tools.</p>
<p>Picture this. Your MCP server has a <code>deploy_service</code> tool. The user (through the AI) asks to deploy <code>payment-service</code>. Your tool is ready to run, but you need one more piece of information: which environment? Staging, production, or canary?</p>
<p>Before Elicitation, you had four bad options:</p>
<ol>
<li class="">Make the AI ask the user in chat. ("Which environment?") The user answers, the AI parses, the AI re-calls your tool. Three round-trips, hope nothing gets lost in translation.</li>
<li class="">Add <code>environment</code> to your tool's required parameters and hope the AI guessed right.</li>
<li class="">Pop up an OS-level dialog. Out of band. Awful UX.</li>
<li class="">Just pick a default and pray.</li>
</ol>
<p><strong>Elicitation</strong> is option 5. Mid-tool-call, the server can call <code>elicitation/create</code> on the client with a JSON Schema describing the structured input it needs. The client surfaces a form to the user, in the host UI, that exactly matches that schema. The user fills it in. The response comes back to the server as a validated object. The tool continues.</p>
<p>The user always retains the right to cancel. The schema is what the server asked for, but the client owns the rendering. The conversation in chat is uninterrupted.</p>
<p>What this changes:</p>
<ul>
<li class=""><strong>Structured questions stop bouncing through the model.</strong> Previously, "ask the user" had to happen via the model, which meant the model had to <em>understand</em> the question and the answer. Now the question can be structured (a date picker, a dropdown, a typed text field) and the model just receives the validated answer.</li>
<li class=""><strong>Trust boundaries become cleaner.</strong> The server explicitly admits when it doesn't have all the information. The user explicitly approves before the operation proceeds. No more "the AI just decided to deploy to production because it interpreted my sentence aggressively."</li>
<li class=""><strong>The "are you sure?" pattern gets a protocol-level home.</strong> High-risk operations can elicit explicit confirmation, with the confirmation being a typed response, not a chat string the model might paraphrase.</li>
</ul>
<p>This is the primitive I'd predict will reshape tool design over the next year. Once developers internalise that "ask the user a structured question" is a protocol-supported operation, a lot of tools that currently overstuff their parameter schemas will quietly transition to "elicit what's missing."</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-the-asymmetry-matters">Why the Asymmetry Matters<a href="https://themcpguy.com/blog/six-primitives-not-three#why-the-asymmetry-matters" class="hash-link" aria-label="Direct link to Why the Asymmetry Matters" title="Direct link to Why the Asymmetry Matters" translate="no">​</a></h2>
<p>The three server-side primitives encode <em>what your server provides</em>. The three client-side primitives encode <em>what your server can ask for</em>. Both are about explicit capabilities, declared at the start of a session.</p>
<p>This explicit declaration is the part that makes MCP feel different from other AI integration approaches. In a normal SDK, you have to assume the worst about what the other side can do. You write defensive code. You handle the cases that may never arise. You build for the lowest common denominator.</p>
<p>In MCP, the capability declaration at session start tells you exactly what the other side can do. If the client doesn't advertise <code>sampling</code>, you don't call <code>sampling/createMessage</code>, and you also don't have to write code defending against the case where it might not work. If the client advertises <code>elicitation</code>, you can write your tool assuming you can ask for structured input. The contract is upfront.</p>
<p>That bidirectional capability negotiation is what makes MCP, in my view, a serious protocol rather than a thin convention around tool calls. The other half of the primitives is where it shows.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="practical-translation">Practical Translation<a href="https://themcpguy.com/blog/six-primitives-not-three#practical-translation" class="hash-link" aria-label="Direct link to Practical Translation" title="Direct link to Practical Translation" translate="no">​</a></h2>
<p>If you're designing an MCP server today, here are concrete questions to ask:</p>
<p><strong>On Roots:</strong></p>
<ul>
<li class="">Does my server have a notion of "scope"? Could it benefit from the client telling me what scope to use?</li>
<li class="">Am I currently accepting a <code>base_directory</code> (or <code>workspace</code>, or <code>project</code>) configuration parameter that should really be dynamic?</li>
</ul>
<p><strong>On Sampling:</strong></p>
<ul>
<li class="">Are there steps inside my tool implementation that would benefit from an LLM call (classification, summarisation, decision-making)?</li>
<li class="">If yes, am I currently solving that by either (a) being deterministic, or (b) bringing my own model? Could Sampling let me offload that decision to the client?</li>
</ul>
<p><strong>On Elicitation:</strong></p>
<ul>
<li class="">Are there optional parameters in my tools that the model frequently gets wrong, that a structured question to the user would always answer correctly?</li>
<li class="">Are there high-risk operations where I'd like explicit user confirmation outside the chat stream?</li>
</ul>
<p>The first time you ask these questions, you'll probably find at least one tool in your server that would be better if it used one of the client-side primitives. That's how I knew, the first time, that the other half of the protocol was load-bearing.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-bigger-picture">The Bigger Picture<a href="https://themcpguy.com/blog/six-primitives-not-three#the-bigger-picture" class="hash-link" aria-label="Direct link to The Bigger Picture" title="Direct link to The Bigger Picture" translate="no">​</a></h2>
<p>The fact that "MCP has three primitives" became conventional wisdom is a textbook case of protocols being learned through tutorials rather than specs. The tutorial writers wanted to ship the minimum viable mental model. The minimum viable mental model is "tools, resources, prompts." That's good enough to get someone building. It's also wrong by half.</p>
<p>If you're building servers, the three server-side primitives are where you'll spend most of your time. Roots, Sampling, and Elicitation are where you'll unlock the next layer of capability. Many of the patterns that look hard in a server-only world (live workspace scoping, embedded reasoning, mid-tool user input) become clean when you remember that the protocol is two-way.</p>
<p>So: MCP has six primitives. Tools, Resources, Prompts on one side. Roots, Sampling, Elicitation on the other. They're not optional. They're not advanced. They're the part of the protocol that explains the design choices in the part you already know.</p>
<hr>
<p>For the protocol-level mechanics, the <a class="" href="https://themcpguy.com/docs/mcp-fundamentals/capability-negotiation">Capability Negotiation</a> module walks through how clients and servers declare and discover these capabilities at session start.</p>
<p>For a deeper dive on Elicitation specifically (the human-in-the-loop primitive), the <strong>Human in the Loop</strong> module of the Agentic Workflows course shows how to design tools around it — that course is coming soon.</p>
<p>And if you want to see how all six primitives compose into a real architecture, the <strong>MCP Architecture Patterns</strong> course threads them through the bigger picture. It is also coming soon.</p>
<p>Three primitives is the bumper sticker. Six is the protocol.</p>]]></content>
        <author>
            <name>TheMCPGuy</name>
            <uri>https://themcpguy.com</uri>
        </author>
        <category label="mcp" term="mcp"/>
        <category label="primitives" term="primitives"/>
        <category label="roots" term="roots"/>
        <category label="sampling" term="sampling"/>
        <category label="elicitation" term="elicitation"/>
        <category label="client-capabilities" term="client-capabilities"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[The Day MCP Stopped Watching the Clock]]></title>
        <id>https://themcpguy.com/blog/the-day-mcp-stopped-watching-the-clock</id>
        <link href="https://themcpguy.com/blog/the-day-mcp-stopped-watching-the-clock"/>
        <updated>2026-06-05T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[A stopwatch shattering as a paper airplane labeled 'task' soars past it]]></summary>
        <content type="html"><![CDATA[<p><img decoding="async" loading="lazy" alt="A stopwatch shattering as a paper airplane labeled &amp;#39;task&amp;#39; soars past it" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA4MDAgNDAwIj4KICA8cmVjdCB3aWR0aD0iODAwIiBoZWlnaHQ9IjQwMCIgZmlsbD0iIzA1MDcxNCIvPgogIDwhLS0gU3RvcHdhdGNoIGJvZHkgLS0+CiAgPGc+CiAgICA8IS0tIHRvcCBidXR0b24gLS0+CiAgICA8cmVjdCB4PSIyMzIiIHk9Ijg2IiB3aWR0aD0iMzYiIGhlaWdodD0iMjIiIHJ4PSI1IiBmaWxsPSIjMGQxMTE3IiBzdHJva2U9IiM0NzU1NjkiIHN0cm9rZS13aWR0aD0iMiIvPgogICAgPGxpbmUgeDE9IjI1MCIgeTE9Ijg2IiB4Mj0iMjUwIiB5Mj0iMTIwIiBzdHJva2U9IiM0NzU1NjkiIHN0cm9rZS13aWR0aD0iNiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIi8+CiAgICA8IS0tIGRpYWwgLS0+CiAgICA8Y2lyY2xlIGN4PSIyNTAiIGN5PSIyMTAiIHI9IjkyIiBmaWxsPSIjMGQxMTE3IiBzdHJva2U9IiNlZjQ0NDQiIHN0cm9rZS13aWR0aD0iMyIvPgogICAgPGNpcmNsZSBjeD0iMjUwIiBjeT0iMjEwIiByPSI3OCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMWUyOTNiIiBzdHJva2Utd2lkdGg9IjEuNSIvPgogICAgPCEtLSB0aWNrIG1hcmtzIC0tPgogICAgPGxpbmUgeDE9IjI1MCIgeTE9IjEzOCIgeDI9IjI1MCIgeTI9IjE1MCIgc3Ryb2tlPSIjNjQ3NDhiIiBzdHJva2Utd2lkdGg9IjIiLz4KICAgIDxsaW5lIHgxPSIzMjIiIHkxPSIyMTAiIHgyPSIzMTAiIHkyPSIyMTAiIHN0cm9rZT0iIzY0NzQ4YiIgc3Ryb2tlLXdpZHRoPSIyIi8+CiAgICA8bGluZSB4MT0iMjUwIiB5MT0iMjgyIiB4Mj0iMjUwIiB5Mj0iMjcwIiBzdHJva2U9IiM2NDc0OGIiIHN0cm9rZS13aWR0aD0iMiIvPgogICAgPGxpbmUgeDE9IjE3OCIgeTE9IjIxMCIgeDI9IjE5MCIgeTI9IjIxMCIgc3Ryb2tlPSIjNjQ3NDhiIiBzdHJva2Utd2lkdGg9IjIiLz4KICAgIDwhLS0gZnJvemVuIGhhbmRzIC0tPgogICAgPGxpbmUgeDE9IjI1MCIgeTE9IjIxMCIgeDI9IjI1MCIgeTI9IjE1OCIgc3Ryb2tlPSIjOTRhM2I4IiBzdHJva2Utd2lkdGg9IjMiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPgogICAgPGxpbmUgeDE9IjI1MCIgeTE9IjIxMCIgeDI9IjI5MiIgeTI9IjIzMiIgc3Ryb2tlPSIjOTRhM2I4IiBzdHJva2Utd2lkdGg9IjMiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPgogICAgPGNpcmNsZSBjeD0iMjUwIiBjeT0iMjEwIiByPSI1IiBmaWxsPSIjMjJkM2VlIi8+CiAgICA8IS0tIHNoYXR0ZXIgY3JhY2tzIC0tPgogICAgPHBvbHlsaW5lIHBvaW50cz0iMjUwLDIxMCAyMTAsMTUwIDIzMiwxMjgiIGZpbGw9Im5vbmUiIHN0cm9rZT0iI2VmNDQ0NCIgc3Ryb2tlLXdpZHRoPSIyIiBvcGFjaXR5PSIwLjgiLz4KICAgIDxwb2x5bGluZSBwb2ludHM9IjI1MCwyMTAgMzAwLDE3MCAyOTYsMTQwIiBmaWxsPSJub25lIiBzdHJva2U9IiNlZjQ0NDQiIHN0cm9rZS13aWR0aD0iMiIgb3BhY2l0eT0iMC44Ii8+CiAgICA8cG9seWxpbmUgcG9pbnRzPSIyNTAsMjEwIDMwMCwyNjAgMzMyLDI3MiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZWY0NDQ0IiBzdHJva2Utd2lkdGg9IjIiIG9wYWNpdHk9IjAuOCIvPgogICAgPHBvbHlsaW5lIHBvaW50cz0iMjUwLDIxMCAxOTYsMjUwIDE2OCwyNDQiIGZpbGw9Im5vbmUiIHN0cm9rZT0iI2VmNDQ0NCIgc3Ryb2tlLXdpZHRoPSIyIiBvcGFjaXR5PSIwLjgiLz4KICA8L2c+CiAgPCEtLSBmbHlpbmcgc2hhcmRzIC0tPgogIDxwb2x5Z29uIHBvaW50cz0iMzUwLDE1MCAzNzIsMTQyIDM2MCwxNjgiIGZpbGw9IiMwZDExMTciIHN0cm9rZT0iI2VmNDQ0NCIgc3Ryb2tlLXdpZHRoPSIxLjUiIG9wYWNpdHk9IjAuNyIvPgogIDxwb2x5Z29uIHBvaW50cz0iMzYwLDI1MCAzODQsMjU4IDM2NiwyNzIiIGZpbGw9IiMwZDExMTciIHN0cm9rZT0iI2VmNDQ0NCIgc3Ryb2tlLXdpZHRoPSIxLjUiIG9wYWNpdHk9IjAuNyIvPgogIDxwb2x5Z29uIHBvaW50cz0iMTUwLDEyMCAxMzQsMTM0IDE1OCwxNDAiIGZpbGw9IiMwZDExMTciIHN0cm9rZT0iI2VmNDQ0NCIgc3Ryb2tlLXdpZHRoPSIxLjUiIG9wYWNpdHk9IjAuNiIvPgogIDwhLS0gbW90aW9uIHRyYWlsIG9mIHRoZSBwYXBlciBhaXJwbGFuZSAtLT4KICA8bGluZSB4MT0iMzQwIiB5MT0iMjEwIiB4Mj0iNTQwIiB5Mj0iMTUwIiBzdHJva2U9IiMwNmI2ZDQiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWRhc2hhcnJheT0iOCA2IiBvcGFjaXR5PSIwLjUiLz4KICA8IS0tIHBhcGVyIGFpcnBsYW5lIHNvYXJpbmcgcGFzdCAtLT4KICA8Zz4KICAgIDxwb2x5Z29uIHBvaW50cz0iNTYwLDEyOCA2NjAsMTU4IDU4OCwxNzAiIGZpbGw9IiMwZDExMTciIHN0cm9rZT0iIzA2YjZkNCIgc3Ryb2tlLXdpZHRoPSIyIi8+CiAgICA8cG9seWdvbiBwb2ludHM9IjU2MCwxMjggNTg4LDE3MCA2MDAsMTUwIiBmaWxsPSJyZ2JhKDYsMTgyLDIxMiwwLjE1KSIgc3Ryb2tlPSIjMDZiNmQ0IiBzdHJva2Utd2lkdGg9IjEuNSIvPgogICAgPHBvbHlnb24gcG9pbnRzPSI1ODgsMTcwIDYwMCwxNTAgNjEyLDE4MiIgZmlsbD0iIzBkMTExNyIgc3Ryb2tlPSIjMDZiNmQ0IiBzdHJva2Utd2lkdGg9IjEuNSIvPgogIDwvZz4KICA8cmVjdCB4PSI2MDAiIHk9IjE5MCIgd2lkdGg9Ijg2IiBoZWlnaHQ9IjMwIiByeD0iNiIgZmlsbD0iIzBkMTExNyIgc3Ryb2tlPSIjMjJkM2VlIiBzdHJva2Utd2lkdGg9IjEuNSIvPgogIDx0ZXh0IHg9IjY0MyIgeT0iMjEwIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmaWxsPSIjMjJkM2VlIiBmb250LWZhbWlseT0ibW9ub3NwYWNlIiBmb250LXNpemU9IjE0IiBmb250LXdlaWdodD0iYm9sZCI+dGFzazwvdGV4dD4KICA8dGV4dCB4PSI2MDAiIHk9IjI2MiIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZmlsbD0iIzQ3NTU2OSIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTMiPmFzeW5jICZndDsgYmxvY2tpbmc8L3RleHQ+CiAgPHRleHQgeD0iNDAwIiB5PSIzNzAiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZpbGw9IiM0NzU1NjkiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjEzIj50aGVtY3BndXkuY29tIOKAlCBUaGUgRGF5IE1DUCBTdG9wcGVkIFdhdGNoaW5nIHRoZSBDbG9jazwvdGV4dD4KPC9zdmc+Cg==" width="800" height="400" class="img_ev3q"></p>
<p>Every developer who has integrated an AI with a real backend knows this pain. The user says, "Run the data refresh." The MCP tool kicks off a job. The job takes four minutes. The MCP request times out at thirty seconds. The model receives an error and confidently tells the user, "I was unable to run the data refresh," even though the refresh is, at this very moment, happily running.</p>
<p>For about a year, MCP had no good answer for this. You either polled, you faked it, or you accepted that long-running operations weren't really part of the protocol's worldview. The 2025-11-25 spec changed that by introducing <strong>Tasks</strong>: a first-class way to say "this isn't going to finish in the next thirty seconds, and that's fine."</p>
<p>This post is about what Tasks are, what they replace, and why the addition is more interesting than the headline makes it sound.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-synchronous-trap">The Synchronous Trap<a href="https://themcpguy.com/blog/the-day-mcp-stopped-watching-the-clock#the-synchronous-trap" class="hash-link" aria-label="Direct link to The Synchronous Trap" title="Direct link to The Synchronous Trap" translate="no">​</a></h2>
<p>MCP, like JSON-RPC underneath it, started life as a request/response protocol. You send <code>tools/call</code>. You get back <code>CallToolResult</code>. The transport assumes that pair of messages will fit comfortably inside one HTTP round-trip, or one back-and-forth on a stdio pipe, or one quick SSE exchange.</p>
<p>For most tools, that assumption is fine. <code>search_customers</code> runs a database query and returns in 200ms. <code>read_file</code> reads a file and returns immediately. <code>calculate</code> is, well, calculation.</p>
<p>But real systems have operations that don't fit this shape:</p>
<ul>
<li class=""><strong>Deployments</strong> that take minutes to roll out.</li>
<li class=""><strong>Data refreshes</strong> that scan terabytes.</li>
<li class=""><strong>CI runs</strong> that compile, test, and lint at their own pace.</li>
<li class=""><strong>External integrations</strong> that legitimately take a while because they're sending email, generating PDFs, or waiting on a human.</li>
<li class=""><strong>Anything involving "approval"</strong> where a human has to actually look at something.</li>
</ul>
<p>The original MCP answer was: <em>don't do that.</em> Make every tool fast. If you have something slow, kick off a background job from the tool and return a job ID, then have the model poll a separate <code>get_job_status</code> tool until done.</p>
<p>This worked, in the same way that walking up the stairs with a sofa works. You can do it. You won't enjoy it. And every team reinvented it slightly differently.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="enter-tasks">Enter Tasks<a href="https://themcpguy.com/blog/the-day-mcp-stopped-watching-the-clock#enter-tasks" class="hash-link" aria-label="Direct link to Enter Tasks" title="Direct link to Enter Tasks" translate="no">​</a></h2>
<p>The 2025-11-25 spec added <em>experimental</em> support for <strong>Tasks</strong> (SEP-1686). The core idea is small and elegant: certain MCP requests (today, <code>tools/call</code> for clients, and <code>sampling/createMessage</code>/<code>elicitation/create</code> for servers) can be <strong>augmented</strong> with a task. The receiver returns a task handle instead of holding the original request open, and the requestor polls for status and eventually fetches the result. Capability negotiation declares exactly which request categories support task augmentation in each direction.</p>
<p>A task has a lifecycle. The spec defines explicit states:</p>
<ul>
<li class=""><strong>working</strong>: the task is running</li>
<li class=""><strong>input_required</strong>: the task is paused, waiting for more input from the user</li>
<li class=""><strong>completed</strong>: the task is done; the result is ready to fetch</li>
<li class=""><strong>failed</strong>: the task ran but produced an error</li>
<li class=""><strong>cancelled</strong>: the task was cancelled (by the client or the server)</li>
</ul>
<p>That state machine alone solves a lot of problems. The "input_required" state is particularly clever: it gives a clean answer to operations that need to ask the user a question mid-flight, which previously required hacking around the request/response model. (Elicitation, which landed in 2025-06-18, becomes much more powerful when it can be invoked from inside a long-running task instead of having to fit inside a single tool call.)</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-this-is-not-just-async">Why This Is Not Just "Async"<a href="https://themcpguy.com/blog/the-day-mcp-stopped-watching-the-clock#why-this-is-not-just-async" class="hash-link" aria-label="Direct link to Why This Is Not Just &quot;Async&quot;" title="Direct link to Why This Is Not Just &quot;Async&quot;" translate="no">​</a></h2>
<p>The first time I read about Tasks, my reaction was: "Okay, MCP got promises. Took them long enough."</p>
<p>I was wrong. Tasks aren't just <code>async/await</code> for the protocol.</p>
<p>The interesting design choice is that the <strong>client</strong> decides whether to wait. In a normal async API, the server decides whether something runs synchronously or asynchronously, and the client lives with it. In MCP Tasks, the client (the requestor) decides whether to augment a request with a task, choosing between a synchronous call and a task handle. The server doesn't unilaterally upgrade a synchronous call; instead it controls <em>which</em> tools may be run as tasks by declaring each tool's <code>execution.taskSupport</code> as <code>forbidden</code>, <code>optional</code>, or <code>required</code> (a <code>required</code> tool returns an error if the client doesn't augment the call).</p>
<p>That's not promises. That's a <em>negotiation</em> about how long the client is willing to wait.</p>
<p>It also opens up patterns that weren't really possible before:</p>
<ul>
<li class=""><strong>Background work that survives client disconnects.</strong> Start a task. Close your laptop. Open it tomorrow. The task is still there. Fetch the result.</li>
<li class=""><strong>Multi-step approvals.</strong> The task pauses at <code>input_required</code>, the user gets a notification in their host UI, they answer, the task continues.</li>
<li class=""><strong>Cancellation that actually works.</strong> Previously, cancelling a tool call meant ignoring its result. Now there's an explicit <code>cancelled</code> state and a way for the server to clean up.</li>
<li class=""><strong>Resumable interactions</strong> across sessions, devices, or even different clients of the same MCP server.</li>
</ul>
<p>These aren't new ideas in distributed systems. They're new in <em>protocols designed for AI agents</em>, and that's where the leverage is.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-this-means-for-tool-design">What This Means for Tool Design<a href="https://themcpguy.com/blog/the-day-mcp-stopped-watching-the-clock#what-this-means-for-tool-design" class="hash-link" aria-label="Direct link to What This Means for Tool Design" title="Direct link to What This Means for Tool Design" translate="no">​</a></h2>
<p>The introduction of Tasks doesn't mean every tool should be a task. The default is still synchronous, because most tools really should be fast.</p>
<p>But for the operations where Tasks fit, they change how you should think about tool design:</p>
<p><strong>1. Stop returning fake "job started" messages.</strong> If your tool kicks off background work, return a task handle. The client knows what to do with one. It doesn't know what to do with a string that says "Started job 47, check back later."</p>
<p><strong>2. Stop polling from the model side.</strong> A model that calls <code>get_status</code> in a loop is burning your token budget and not actually waiting on anything useful. With Tasks, the client (Spring AI, Claude Desktop, whatever) handles polling for you, with proper exponential backoff, at a layer the model doesn't need to think about.</p>
<p><strong>3. Use <code>input_required</code> instead of inventing your own approval dance.</strong> I have seen MCP servers implement approval flows by returning a tool result that says "Please call <code>approve_deployment(approval_token=...)</code> next." This is, charitably, a workaround. A task that transitions to <code>input_required</code> and uses elicitation to ask the question is the protocol-native version.</p>
<p><strong>4. Design your tool's <em>granularity</em> around the task boundary.</strong> "Run database migration" is one task with several phases. "Run database migration phase 1, then phase 2, then phase 3" is three separate tools that the model has to coordinate, badly. Tasks let you fold internal complexity inside a single logical operation.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="where-its-going">Where It's Going<a href="https://themcpguy.com/blog/the-day-mcp-stopped-watching-the-clock#where-its-going" class="hash-link" aria-label="Direct link to Where It's Going" title="Direct link to Where It's Going" translate="no">​</a></h2>
<p>Tasks are marked <strong>experimental</strong> in 2025-11-25. That word matters: SDKs may implement them at different speeds, transport semantics may shift, edge cases may produce surprising behaviour. If you're building production servers today, treat Tasks as something to plan for rather than something to bet the farm on this quarter. The current draft spec actually moves Tasks out of the core protocol and into an official extension (<code>io.modelcontextprotocol/tasks</code>) under SEP-2663, with a redesigned API (polling via <code>tasks/get</code>, client input via <code>tasks/update</code>). Watch that work carefully if you're writing against the experimental version today.</p>
<p>But the direction is clear. The 2026 MCP roadmap leans heavily into stateless servers, agent-to-agent coordination, and longer-lived interactions. All of those need a vocabulary for "this is going to take a while." Tasks give the protocol that vocabulary for the first time.</p>
<p>There's a deeper architectural point hiding in here. Up until Tasks, MCP encoded one specific kind of interaction: a human (or a model) initiates a step, something happens immediately, a result comes back. That's the shape of a <em>conversation</em>. With Tasks, the protocol can also encode the shape of an <em>operation</em>, something that has its own lifecycle, independent of any particular conversation turn.</p>
<p>Agents, especially multi-agent systems, fundamentally need both. A coordinator agent should be able to dispatch a long-running task to a worker agent, get a handle, do other things, and check back later. That's how real systems are built. Tasks are MCP catching up to that reality.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-counterintuitive-bit">The Counterintuitive Bit<a href="https://themcpguy.com/blog/the-day-mcp-stopped-watching-the-clock#the-counterintuitive-bit" class="hash-link" aria-label="Direct link to The Counterintuitive Bit" title="Direct link to The Counterintuitive Bit" translate="no">​</a></h2>
<p>Here's the thing about Tasks that surprised me when I sat with it.</p>
<p>The most useful Task is not the one that runs for ten minutes. The most useful Task is the one that runs for <em>fifteen seconds</em>.</p>
<p>Long operations (minutes, hours, days) are obvious candidates. Everyone agrees those should be tasks.</p>
<p>But there's a vast middle ground of "long enough to be awkward, short enough that you didn't bother engineering for it." A tool that takes 8-12 seconds. A tool that takes 25 seconds on a bad day. A tool that has to call an external API whose latency is 95th-percentile-bimodal. These are the ones that quietly poison user experience. They're too short to engineer like a job. They're too long to ignore.</p>
<p>Tasks let you handle the "awkwardly long" case the same way you handle the "obviously long" case. That uniformity is the actual win. You stop deciding, per tool, which side of the synchronous/asynchronous fence to land on. You just return a task handle when it makes sense, and the client figures out the rest.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="reading-the-tea-leaves">Reading the Tea Leaves<a href="https://themcpguy.com/blog/the-day-mcp-stopped-watching-the-clock#reading-the-tea-leaves" class="hash-link" aria-label="Direct link to Reading the Tea Leaves" title="Direct link to Reading the Tea Leaves" translate="no">​</a></h2>
<p>If you want to know which direction MCP is moving, the addition of Tasks is one of the strongest signals you'll find. The protocol started as a way to expose tool calls to AI models. It's becoming a way to <em>coordinate work</em> with AI models. Those are different products. The transition is mostly silent, but Tasks are one of the loud moments.</p>
<p>Two more developments to watch in the same direction:</p>
<ul>
<li class=""><strong>Agent Communication.</strong> The 2026 roadmap calls out an "Agent Communication" priority area, with an Agents WG closing operational gaps around Tasks (retry semantics, expiry policies). The combination of Tasks plus richer agent-communication semantics is what you'd build a multi-agent system on top of.</li>
<li class=""><strong>Transport Evolution and Scalability.</strong> Also on the 2026 roadmap. Pairs well with Tasks: a stateless task handler can be horizontally scaled because the state lives in the task itself, not the server process.</li>
</ul>
<p>The 2025-11-25 spec is the first time MCP felt less like an RPC and more like an orchestration substrate. Tasks are the centerpiece of that shift.</p>
<hr>
<p>If you're building Spring AI + MCP servers and want a deeper look at long-running operations, asynchronous tool composition, and the patterns that surround Tasks (resilience, retries, idempotency), the <strong>MCP Architecture Patterns</strong> course has a thread of these patterns running through it. That course is coming soon.</p>
<p>If you want to understand the full evolution of the spec from the first 2024 release to today, the <a class="" href="https://themcpguy.com/docs/mcp-fundamentals/mcp-ecosystem">MCP Ecosystem</a> module walks through every revision and what it added.</p>
<p>Either way: MCP stopped watching the clock. Your tools can finally take as long as they actually take.</p>]]></content>
        <author>
            <name>TheMCPGuy</name>
            <uri>https://themcpguy.com</uri>
        </author>
        <category label="mcp" term="mcp"/>
        <category label="tasks" term="tasks"/>
        <category label="async" term="async"/>
        <category label="spec" term="spec"/>
        <category label="Tue Nov 25 2025 00:00:00 GMT+0000 (Coordinated Universal Time)" term="Tue Nov 25 2025 00:00:00 GMT+0000 (Coordinated Universal Time)"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Your Tool Description Is a Prompt (And You're Writing It Like a JIRA Ticket)]]></title>
        <id>https://themcpguy.com/blog/tool-description-is-a-prompt</id>
        <link href="https://themcpguy.com/blog/tool-description-is-a-prompt"/>
        <updated>2026-05-22T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[A magnifying glass hovering over a tool description, with the word 'description' refracting into prompt-shaped fragments]]></summary>
        <content type="html"><![CDATA[<p><img decoding="async" loading="lazy" alt="A magnifying glass hovering over a tool description, with the word &amp;#39;description&amp;#39; refracting into prompt-shaped fragments" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA4MDAgNDAwIj4KICA8cmVjdCB3aWR0aD0iODAwIiBoZWlnaHQ9IjQwMCIgZmlsbD0iIzA1MDcxNCIvPgogIDwhLS0gVGhlIHRlcnNlIGRlc2NyaXB0aW9uIGNhcmQgKHRoZSAiSklSQSB0aWNrZXQiIHdheSkgLS0+CiAgPHJlY3QgeD0iNTAiIHk9IjEyMCIgd2lkdGg9IjI2MCIgaGVpZ2h0PSIxNzAiIHJ4PSIxMiIgZmlsbD0iIzBkMTExNyIgc3Ryb2tlPSIjMWUyOTNiIiBzdHJva2Utd2lkdGg9IjIiLz4KICA8cmVjdCB4PSI1MCIgeT0iMTIwIiB3aWR0aD0iMjYwIiBoZWlnaHQ9IjQiIHJ4PSIyIiBmaWxsPSIjMWUyOTNiIi8+CiAgPHRleHQgeD0iNzAiIHk9IjE1NSIgZmlsbD0iIzY0NzQ4YiIgZm9udC1mYW1pbHk9Im1vbm9zcGFjZSIgZm9udC1zaXplPSIxMiI+Im5hbWUiOiAicXVlcnlfZGF0YSIsPC90ZXh0PgogIDx0ZXh0IHg9IjcwIiB5PSIxODAiIGZpbGw9IiM2NDc0OGIiIGZvbnQtZmFtaWx5PSJtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTIiPiJkZXNjcmlwdGlvbiI6PC90ZXh0PgogIDx0ZXh0IHg9Ijg2IiB5PSIyMDUiIGZpbGw9IiM5NGEzYjgiIGZvbnQtZmFtaWx5PSJtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTIiPiJRdWVyaWVzIHRoZSBkYXRhLiI8L3RleHQ+CiAgPHRleHQgeD0iNzAiIHk9IjI1NSIgZmlsbD0iIzQ3NTU2OSIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTEiPjIgd29yZHMuPC90ZXh0PgogIDx0ZXh0IHg9IjcwIiB5PSIyNzMiIGZpbGw9IiM0NzU1NjkiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjExIj5BIGZpZWxkIG9uIGEgc3RydWN0LjwvdGV4dD4KICA8IS0tIE1hZ25pZnlpbmcgZ2xhc3MgaG92ZXJpbmcgb3ZlciB0aGUgZGVzY3JpcHRpb24gLS0+CiAgPGNpcmNsZSBjeD0iMjUwIiBjeT0iMjAwIiByPSI2MiIgZmlsbD0icmdiYSg2LDE4MiwyMTIsMC4wNikiIHN0cm9rZT0iIzA2YjZkNCIgc3Ryb2tlLXdpZHRoPSIzIi8+CiAgPGxpbmUgeDE9IjI5NCIgeTE9IjI0NCIgeDI9IjMzOCIgeTI9IjI4OCIgc3Ryb2tlPSIjMDZiNmQ0IiBzdHJva2Utd2lkdGg9IjYiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPgogIDx0ZXh0IHg9IjI1MCIgeT0iMjA2IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmaWxsPSIjMjJkM2VlIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIyMiI+8J+UjTwvdGV4dD4KICA8IS0tIFJlZnJhY3Rpb246IHRoZSB3b3JkIGZyYWdtZW50cyBpbnRvIHByb21wdC1zaGFwZWQgcGllY2VzIC0tPgogIDx0ZXh0IHg9IjQzMCIgeT0iMTIwIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmaWxsPSIjNDc1NTY5IiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMiI+cmVmcmFjdHMgaW50byBhIHByb21wdDwvdGV4dD4KICA8IS0tIHByaXNtIGJlYW1zIC0tPgogIDxsaW5lIHgxPSIzNzUiIHkxPSIyMDAiIHgyPSI0NzAiIHkyPSIxNTAiIHN0cm9rZT0iIzA2YjZkNCIgc3Ryb2tlLXdpZHRoPSIyIiBvcGFjaXR5PSIwLjYiLz4KICA8bGluZSB4MT0iMzc1IiB5MT0iMjAwIiB4Mj0iNDcwIiB5Mj0iMjAwIiBzdHJva2U9IiM4YjVjZjYiIHN0cm9rZS13aWR0aD0iMiIgb3BhY2l0eT0iMC42Ii8+CiAgPGxpbmUgeDE9IjM3NSIgeTE9IjIwMCIgeDI9IjQ3MCIgeTI9IjI1MCIgc3Ryb2tlPSIjMTBiOTgxIiBzdHJva2Utd2lkdGg9IjIiIG9wYWNpdHk9IjAuNiIvPgogIDwhLS0gcHJvbXB0IGZyYWdtZW50cyAtLT4KICA8cmVjdCB4PSI0ODAiIHk9IjEyOCIgd2lkdGg9IjI1MCIgaGVpZ2h0PSI0NCIgcng9IjgiIGZpbGw9IiMwZDExMTciIHN0cm9rZT0iIzA2YjZkNCIgc3Ryb2tlLXdpZHRoPSIxLjUiLz4KICA8dGV4dCB4PSI0OTgiIHk9IjE0OCIgZmlsbD0iIzIyZDNlZSIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTIiIGZvbnQtd2VpZ2h0PSJib2xkIj5XSEVOIHRvIHVzZSBpdDwvdGV4dD4KICA8dGV4dCB4PSI0OTgiIHk9IjE2NCIgZmlsbD0iIzQ3NTU2OSIgZm9udC1mYW1pbHk9Im1vbm9zcGFjZSIgZm9udC1zaXplPSIxMCI+IkNhbGwgdGhpcyB0byBmZXRjaCByb3dzIG1hdGNoaW5nIGEgZmlsdGVy4oCmIjwvdGV4dD4KICA8cmVjdCB4PSI0ODAiIHk9IjE3OCIgd2lkdGg9IjI1MCIgaGVpZ2h0PSI0NCIgcng9IjgiIGZpbGw9IiMwZDExMTciIHN0cm9rZT0iIzhiNWNmNiIgc3Ryb2tlLXdpZHRoPSIxLjUiLz4KICA8dGV4dCB4PSI0OTgiIHk9IjE5OCIgZmlsbD0iI2E3OGJmYSIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTIiIGZvbnQtd2VpZ2h0PSJib2xkIj5XSEFUIGl0IHJldHVybnM8L3RleHQ+CiAgPHRleHQgeD0iNDk4IiB5PSIyMTQiIGZpbGw9IiM0NzU1NjkiIGZvbnQtZmFtaWx5PSJtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTAiPiJBIEpTT04gYXJyYXkgb2YgcmVjb3JkcywgbmV3ZXN0IGZpcnN04oCmIjwvdGV4dD4KICA8cmVjdCB4PSI0ODAiIHk9IjIyOCIgd2lkdGg9IjI1MCIgaGVpZ2h0PSI0NCIgcng9IjgiIGZpbGw9IiMwZDExMTciIHN0cm9rZT0iIzEwYjk4MSIgc3Ryb2tlLXdpZHRoPSIxLjUiLz4KICA8dGV4dCB4PSI0OTgiIHk9IjI0OCIgZmlsbD0iIzM0ZDM5OSIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTIiIGZvbnQtd2VpZ2h0PSJib2xkIj5FWEFNUExFUyAmYW1wOyBlZGdlIGNhc2VzPC90ZXh0PgogIDx0ZXh0IHg9IjQ5OCIgeT0iMjY0IiBmaWxsPSIjNDc1NTY5IiBmb250LWZhbWlseT0ibW9ub3NwYWNlIiBmb250LXNpemU9IjEwIj4iRW1wdHkgZmlsdGVyIHJldHVybnMgZXZlcnl0aGluZ+KApiI8L3RleHQ+CiAgPHRleHQgeD0iNDAwIiB5PSIzNzAiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZpbGw9IiM0NzU1NjkiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjEzIj50aGVtY3BndXkuY29tIOKAlCBZb3VyIFRvb2wgRGVzY3JpcHRpb24gSXMgYSBQcm9tcHQ8L3RleHQ+Cjwvc3ZnPg==" width="800" height="400" class="img_ev3q"></p>
<p>Here is a tool description from a real, public MCP server. The name has been changed because I'm not in the business of public shaming, but the wording is verbatim:</p>
<blockquote>
<p><code>query_data</code>: Queries the data.</p>
</blockquote>
<p>Two words. One of which is the tool's own name. The other a tautology. This is what happens when a developer treats <code>description</code> as a field on a struct rather than what it actually is: a prompt fragment that the AI reads to decide whether to call your tool.</p>
<p>If you are writing tool descriptions the way you write Swagger comments, you are writing them wrong. Let's talk about why.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-misconception">The Misconception<a href="https://themcpguy.com/blog/tool-description-is-a-prompt#the-misconception" class="hash-link" aria-label="Direct link to The Misconception" title="Direct link to The Misconception" translate="no">​</a></h2>
<p>When you define an MCP tool, you provide three things: a <code>name</code>, an <code>inputSchema</code>, and a <code>description</code>. Most developers correctly understand that <code>name</code> and <code>inputSchema</code> are mechanical: they're how the protocol identifies and validates the call. So they treat <code>description</code> the same way: a quick label, half a sentence, just enough to make the linter happy.</p>
<p>But <code>description</code> is not a label. The model never <em>sees</em> the schema as natural language. It sees the schema as structured data. The only natural-language signal the model has, when deciding which of your seventeen tools to call, is the description.</p>
<p>In other words: the description <strong>is the prompt</strong> that decides whether your tool gets used. Treating it like a code comment is treating a load-bearing wall like a coat of paint.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-the-model-actually-sees">What the Model Actually Sees<a href="https://themcpguy.com/blog/tool-description-is-a-prompt#what-the-model-actually-sees" class="hash-link" aria-label="Direct link to What the Model Actually Sees" title="Direct link to What the Model Actually Sees" translate="no">​</a></h2>
<p>Here is the rough shape of what arrives in the model's context window when an MCP client surfaces your tool:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">You have access to the following tools:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">- query_data</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  Queries the data.</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">- search_customers</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  Look up customer records in the CRM. Accepts a search string (matches name,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  email, or phone) and an optional account-status filter. Returns up to 50</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  matching customers with id, name, email, account_status, and last_active_at.</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  Use this when the user asks about specific customers or wants a list of</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  customers matching some criterion. Do not use for bulk export (max 50) or</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  for billing data (see get_customer_billing).</span><br></span></code></pre></div></div>
<p>Now imagine you're the model. The user just asked: <em>"Can you find John Smith's record?"</em></p>
<p>Which tool are you going to call?</p>
<p>The model is doing the same thing a junior developer does when they read your team's documentation: picking the most useful-looking option based on the words on the page. If the words on the page say "Queries the data," that tool is going to be either ignored entirely or called catastrophically wrong, because the model has nothing to ground its decision in except the noun "data" and the verb "queries."</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-anatomy-of-a-good-tool-description">The Anatomy of a Good Tool Description<a href="https://themcpguy.com/blog/tool-description-is-a-prompt#the-anatomy-of-a-good-tool-description" class="hash-link" aria-label="Direct link to The Anatomy of a Good Tool Description" title="Direct link to The Anatomy of a Good Tool Description" translate="no">​</a></h2>
<p>There are four things every tool description should contain. Skip any of them and the model will guess. Models guessing is how you end up debugging at 2am.</p>
<p><strong>1. What it does, in one specific sentence.</strong> Not "queries the data." Specifically: <em>"Look up customer records in the CRM by name, email, or phone."</em> Notice the verbs (<code>look up</code>), the object (<code>customer records</code>), the source (<code>CRM</code>), and the parameters (<code>name, email, or phone</code>). Specificity is the entire game.</p>
<p><strong>2. What it returns, in concrete terms.</strong> The model is about to incorporate your output into its reasoning. If it knows your tool returns "up to 50 matching customers with id, name, email, account_status, and last_active_at," it can plan a multi-step interaction. If your description says it returns "data," the model might call your tool, then call it again because it doesn't trust the result, then summarise it incorrectly.</p>
<p><strong>3. When to use it.</strong> This is the part most developers skip. The description has to position the tool relative to the user's likely intent. "Use this when the user asks about specific customers or wants a list of customers matching some criterion." That sentence is doing the work of about three rounds of trial and error.</p>
<p><strong>4. When <em>not</em> to use it.</strong> This is the part nobody puts in. And it's the most important one. "Do not use for bulk export (max 50) or for billing data (see get_customer_billing)." This single negative clause prevents an entire category of misuse. The model has bounded its own search space.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="a-worked-example">A Worked Example<a href="https://themcpguy.com/blog/tool-description-is-a-prompt#a-worked-example" class="hash-link" aria-label="Direct link to A Worked Example" title="Direct link to A Worked Example" translate="no">​</a></h2>
<p>Here is the same tool, written badly and written well.</p>
<p><strong>Bad:</strong></p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"name"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"create_ticket"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"description"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Creates a support ticket."</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<p>The model will call this when the user mentions tickets. It will guess at the priority field. It will not know whether to put the user's whole message in <code>description</code> or summarise it. It will not know if this tool also notifies the assigned engineer. It will call it once, then call it again with different arguments, because nothing in the description tells it that this operation is not idempotent.</p>
<p><strong>Good:</strong></p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"name"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"create_ticket"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"description"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Create a new support ticket in the helpdesk system. The ticket is assigned to the on-call engineer for the relevant team based on the `category` field. The reporter is notified by email; the on-call engineer is paged for severity P0 and P1 tickets. Use this when the user explicitly asks to file a ticket or report an issue. Do not use to comment on an existing ticket (use `add_ticket_comment`) or to escalate an existing ticket (use `escalate_ticket`). This operation is NOT idempotent: calling twice creates two tickets."</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<p>That is a paragraph. It feels excessive when you're writing it. It is exactly the right length when you remember that the model reads it once and uses it forever.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="tool-descriptions-are-code">Tool Descriptions Are Code<a href="https://themcpguy.com/blog/tool-description-is-a-prompt#tool-descriptions-are-code" class="hash-link" aria-label="Direct link to Tool Descriptions Are Code" title="Direct link to Tool Descriptions Are Code" translate="no">​</a></h2>
<p>Here is the reframing that helps me write better descriptions: the description is part of the contract, not the documentation. If it's wrong, the tool is broken. If it's ambiguous, the tool is fragile. If it's terse, the tool is unsafe.</p>
<p>This has practical consequences:</p>
<ul>
<li class=""><strong>Review descriptions in code review</strong> the way you review function signatures. "Is this clear? Is this complete? Does it explain the edge case?" These are not soft questions.</li>
<li class=""><strong>Test descriptions empirically.</strong> Run your tool against a model with realistic user prompts. If the model calls it at the wrong time, the description is wrong. If the model fails to call it when it should, the description is missing something.</li>
<li class=""><strong>Update descriptions when behaviour changes.</strong> A function with a stale comment is a minor sin. A tool with a stale description will produce wrong results in production until somebody notices.</li>
</ul>
<p>The MCP spec itself agrees: since revision 2025-06-18, tools (alongside resources and prompts) carry an optional <code>title</code> field for human-friendly display, so that <code>name</code> can be used as a programmatic identifier and <code>description</code> is free to be aggressively model-oriented. That's the protocol telling you, directly, that these two audiences are different and the description belongs to the model.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-counterintuitive-bit">The Counterintuitive Bit<a href="https://themcpguy.com/blog/tool-description-is-a-prompt#the-counterintuitive-bit" class="hash-link" aria-label="Direct link to The Counterintuitive Bit" title="Direct link to The Counterintuitive Bit" translate="no">​</a></h2>
<p>Writing good tool descriptions feels like over-engineering. You're sitting there writing a four-sentence paragraph for a function that's eight lines long, and your inner code reviewer is screaming about brevity.</p>
<p>Ignore that voice. It evolved for a different audience.</p>
<p>When you write a Java function, your audience is another developer who has type signatures, tests, the surrounding codebase, and Stack Overflow. Brevity is a virtue because they can recover any missing context.</p>
<p>When you write a tool description, your audience is a language model with one context window, no IDE, no <code>grep</code>, no ability to ask follow-up questions, and a hard incentive to <em>just pick something and try it.</em> It cannot recover missing context. The description is all there is.</p>
<p>In that environment, the brief description is not elegant. It's a failure to communicate.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-test">The Test<a href="https://themcpguy.com/blog/tool-description-is-a-prompt#the-test" class="hash-link" aria-label="Direct link to The Test" title="Direct link to The Test" translate="no">​</a></h2>
<p>Here's a five-minute exercise that will improve every tool description you write.</p>
<p>For each tool in your server, write down the answer to these questions, in plain English:</p>
<ol>
<li class="">What is the most specific verb-and-object phrase that describes what this tool does?</li>
<li class="">What does it return, listed by field?</li>
<li class="">What is a one-line description of when the user would want this called?</li>
<li class="">What other tool in this server might the model confuse this with, and what's the difference?</li>
<li class="">Are there irreversible side effects? Should the model warn the user before calling it?</li>
</ol>
<p>Now collapse those five answers into a paragraph. Drop the bullet structure. Use complete sentences. That's your description.</p>
<p>If your answer to question 4 is "no other tool," you probably have a server with one tool, or you're missing a tool. If your answer to question 5 is "no side effects," your tool might be a Resource instead. (See the <a class="" href="https://themcpguy.com/blog/three-laws-of-mcp">Three Laws of MCP</a> for the Tool-vs-Resource decision.)</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-bigger-pattern">The Bigger Pattern<a href="https://themcpguy.com/blog/tool-description-is-a-prompt#the-bigger-pattern" class="hash-link" aria-label="Direct link to The Bigger Pattern" title="Direct link to The Bigger Pattern" translate="no">​</a></h2>
<p>The lesson here generalises. Anywhere you're writing natural language that an LLM will read, you're writing a prompt. Tool descriptions are prompts. Resource descriptions are prompts. System messages are prompts. The strings inside your retrieval pipeline are prompts.</p>
<p>Software engineering has spent forty years training us to write text aimed at compilers (precise, terse) and humans (clear, structured). LLMs are a third audience. They want specificity, examples, constraints, and explicit negative guidance. They reward verbosity in ways that compilers and humans don't.</p>
<p>Once you internalise that, you stop feeling self-conscious about writing four-sentence descriptions for two-line tools. You start feeling self-conscious about the opposite.</p>
<hr>
<p>If you want a more systematic treatment of tool design (including descriptions, schema, granularity, and the subtle art of when to split a tool in two), the <a class="" href="https://themcpguy.com/docs/mcp-java-sdk/implementing-tools">Implementing Tools</a> module of the Java SDK course walks through the patterns end-to-end. The <a class="" href="https://themcpguy.com/blog/three-laws-of-mcp">Three Laws of MCP</a> covers the Tool / Resource / Prompt decision, which is where description quality starts to matter most.</p>
<p>Your description is a prompt. Write it like one.</p>]]></content>
        <author>
            <name>TheMCPGuy</name>
            <uri>https://themcpguy.com</uri>
        </author>
        <category label="mcp" term="mcp"/>
        <category label="tool-design" term="tool-design"/>
        <category label="prompts" term="prompts"/>
        <category label="craft" term="craft"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Why Hardcoding Tool Calls Is the New Technical Debt]]></title>
        <id>https://themcpguy.com/blog/why-hardcoding-tool-calls-is-technical-debt</id>
        <link href="https://themcpguy.com/blog/why-hardcoding-tool-calls-is-technical-debt"/>
        <updated>2026-05-15T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Technical debt visualised as tangled cables and custom adapters]]></summary>
        <content type="html"><![CDATA[<p><img decoding="async" loading="lazy" alt="Technical debt visualised as tangled cables and custom adapters" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA4MDAgNDAwIj4KICA8cmVjdCB3aWR0aD0iODAwIiBoZWlnaHQ9IjQwMCIgZmlsbD0iIzA1MDcxNCIvPgogIDwhLS0gTGVmdDogY3VzdG9tIGludGVncmF0aW9ucyAoZGVidCkgLS0+CiAgPHRleHQgeD0iMjAwIiB5PSI1MCIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZmlsbD0iI2VmNDQ0NCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTQiIGZvbnQtd2VpZ2h0PSJib2xkIj5DdXN0b20gSW50ZWdyYXRpb25zPC90ZXh0PgogIDx0ZXh0IHg9IjIwMCIgeT0iNjgiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZpbGw9IiM2NDc0OGIiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjExIj4oTiDDlyBNID0gdGVjaG5pY2FsIGRlYnQpPC90ZXh0PgogIDwhLS0gTiBjbGllbnRzIC0tPgogIDxyZWN0IHg9IjMwIiB5PSI5MCIgd2lkdGg9IjgwIiBoZWlnaHQ9IjI4IiByeD0iNSIgZmlsbD0iIzBkMTExNyIgc3Ryb2tlPSIjZWY0NDQ0IiBzdHJva2Utd2lkdGg9IjEuNSIvPgogIDx0ZXh0IHg9IjcwIiB5PSIxMDgiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZpbGw9IiNlZjQ0NDQiIGZvbnQtZmFtaWx5PSJtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTAiPkFwcCBBPC90ZXh0PgogIDxyZWN0IHg9IjMwIiB5PSIxMzUiIHdpZHRoPSI4MCIgaGVpZ2h0PSIyOCIgcng9IjUiIGZpbGw9IiMwZDExMTciIHN0cm9rZT0iI2VmNDQ0NCIgc3Ryb2tlLXdpZHRoPSIxLjUiLz4KICA8dGV4dCB4PSI3MCIgeT0iMTUzIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmaWxsPSIjZWY0NDQ0IiBmb250LWZhbWlseT0ibW9ub3NwYWNlIiBmb250LXNpemU9IjEwIj5BcHAgQjwvdGV4dD4KICA8cmVjdCB4PSIzMCIgeT0iMTgwIiB3aWR0aD0iODAiIGhlaWdodD0iMjgiIHJ4PSI1IiBmaWxsPSIjMGQxMTE3IiBzdHJva2U9IiNlZjQ0NDQiIHN0cm9rZS13aWR0aD0iMS41Ii8+CiAgPHRleHQgeD0iNzAiIHk9IjE5OCIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZmlsbD0iI2VmNDQ0NCIgZm9udC1mYW1pbHk9Im1vbm9zcGFjZSIgZm9udC1zaXplPSIxMCI+QXBwIEM8L3RleHQ+CiAgPCEtLSBNIHRvb2xzIC0tPgogIDxyZWN0IHg9IjI5MCIgeT0iOTAiIHdpZHRoPSI4MCIgaGVpZ2h0PSIyOCIgcng9IjUiIGZpbGw9IiMwZDExMTciIHN0cm9rZT0iI2Y1OWUwYiIgc3Ryb2tlLXdpZHRoPSIxLjUiLz4KICA8dGV4dCB4PSIzMzAiIHk9IjEwOCIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZmlsbD0iI2Y1OWUwYiIgZm9udC1mYW1pbHk9Im1vbm9zcGFjZSIgZm9udC1zaXplPSIxMCI+REIgVG9vbDwvdGV4dD4KICA8cmVjdCB4PSIyOTAiIHk9IjEzNSIgd2lkdGg9IjgwIiBoZWlnaHQ9IjI4IiByeD0iNSIgZmlsbD0iIzBkMTExNyIgc3Ryb2tlPSIjZjU5ZTBiIiBzdHJva2Utd2lkdGg9IjEuNSIvPgogIDx0ZXh0IHg9IjMzMCIgeT0iMTUzIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmaWxsPSIjZjU5ZTBiIiBmb250LWZhbWlseT0ibW9ub3NwYWNlIiBmb250LXNpemU9IjEwIj5GaWxlIFRvb2w8L3RleHQ+CiAgPHJlY3QgeD0iMjkwIiB5PSIxODAiIHdpZHRoPSI4MCIgaGVpZ2h0PSIyOCIgcng9IjUiIGZpbGw9IiMwZDExMTciIHN0cm9rZT0iI2Y1OWUwYiIgc3Ryb2tlLXdpZHRoPSIxLjUiLz4KICA8dGV4dCB4PSIzMzAiIHk9IjE5OCIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZmlsbD0iI2Y1OWUwYiIgZm9udC1mYW1pbHk9Im1vbm9zcGFjZSIgZm9udC1zaXplPSIxMCI+QVBJIFRvb2w8L3RleHQ+CiAgPCEtLSBUYW5nbGVkIGNvbm5lY3Rpb25zIC0tPgogIDxsaW5lIHgxPSIxMTAiIHkxPSIxMDQiIHgyPSIyOTAiIHkyPSIxMDQiIHN0cm9rZT0iI2VmNDQ0NCIgc3Ryb2tlLXdpZHRoPSIxIiBvcGFjaXR5PSIwLjQiLz4KICA8bGluZSB4MT0iMTEwIiB5MT0iMTA0IiB4Mj0iMjkwIiB5Mj0iMTQ5IiBzdHJva2U9IiNlZjQ0NDQiIHN0cm9rZS13aWR0aD0iMSIgb3BhY2l0eT0iMC40Ii8+CiAgPGxpbmUgeDE9IjExMCIgeTE9IjEwNCIgeDI9IjI5MCIgeTI9IjE5NCIgc3Ryb2tlPSIjZWY0NDQ0IiBzdHJva2Utd2lkdGg9IjEiIG9wYWNpdHk9IjAuNCIvPgogIDxsaW5lIHgxPSIxMTAiIHkxPSIxNDkiIHgyPSIyOTAiIHkyPSIxMDQiIHN0cm9rZT0iI2Y1OWUwYiIgc3Ryb2tlLXdpZHRoPSIxIiBvcGFjaXR5PSIwLjQiLz4KICA8bGluZSB4MT0iMTEwIiB5MT0iMTQ5IiB4Mj0iMjkwIiB5Mj0iMTQ5IiBzdHJva2U9IiNmNTllMGIiIHN0cm9rZS13aWR0aD0iMSIgb3BhY2l0eT0iMC40Ii8+CiAgPGxpbmUgeDE9IjExMCIgeTE9IjE0OSIgeDI9IjI5MCIgeTI9IjE5NCIgc3Ryb2tlPSIjZjU5ZTBiIiBzdHJva2Utd2lkdGg9IjEiIG9wYWNpdHk9IjAuNCIvPgogIDxsaW5lIHgxPSIxMTAiIHkxPSIxOTQiIHgyPSIyOTAiIHkyPSIxMDQiIHN0cm9rZT0iIzhiNWNmNiIgc3Ryb2tlLXdpZHRoPSIxIiBvcGFjaXR5PSIwLjQiLz4KICA8bGluZSB4MT0iMTEwIiB5MT0iMTk0IiB4Mj0iMjkwIiB5Mj0iMTQ5IiBzdHJva2U9IiM4YjVjZjYiIHN0cm9rZS13aWR0aD0iMSIgb3BhY2l0eT0iMC40Ii8+CiAgPGxpbmUgeDE9IjExMCIgeTE9IjE5NCIgeDI9IjI5MCIgeTI9IjE5NCIgc3Ryb2tlPSIjOGI1Y2Y2IiBzdHJva2Utd2lkdGg9IjEiIG9wYWNpdHk9IjAuNCIvPgogIDx0ZXh0IHg9IjIwMCIgeT0iMjUwIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmaWxsPSIjZWY0NDQ0IiBmb250LWZhbWlseT0ibW9ub3NwYWNlIiBmb250LXNpemU9IjIyIiBmb250LXdlaWdodD0iYm9sZCI+OSBjdXN0b20gaW50ZWdyYXRpb25zPC90ZXh0PgogIDwhLS0gQXJyb3cgLS0+CiAgPHRleHQgeD0iNDAwIiB5PSIyMDAiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZpbGw9IiMyMmQzZWUiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjM2Ij7ihpI8L3RleHQ+CiAgPCEtLSBSaWdodDogTUNQIChjbGVhbikgLS0+CiAgPHRleHQgeD0iNjAwIiB5PSI1MCIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZmlsbD0iIzIyZDNlZSIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTQiIGZvbnQtd2VpZ2h0PSJib2xkIj5XaXRoIE1DUDwvdGV4dD4KICA8dGV4dCB4PSI2MDAiIHk9IjY4IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmaWxsPSIjNjQ3NDhiIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMSI+KE4gKyBNID0gc3RhbmRhcmQgcHJvdG9jb2wpPC90ZXh0PgogIDwhLS0gU2FtZSBjbGllbnRzIC0tPgogIDxyZWN0IHg9IjQ2MCIgeT0iOTAiIHdpZHRoPSI4MCIgaGVpZ2h0PSIyOCIgcng9IjUiIGZpbGw9IiMwZDExMTciIHN0cm9rZT0iIzA2YjZkNCIgc3Ryb2tlLXdpZHRoPSIxLjUiLz4KICA8dGV4dCB4PSI1MDAiIHk9IjEwOCIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZmlsbD0iIzA2YjZkNCIgZm9udC1mYW1pbHk9Im1vbm9zcGFjZSIgZm9udC1zaXplPSIxMCI+QXBwIEE8L3RleHQ+CiAgPHJlY3QgeD0iNDYwIiB5PSIxMzUiIHdpZHRoPSI4MCIgaGVpZ2h0PSIyOCIgcng9IjUiIGZpbGw9IiMwZDExMTciIHN0cm9rZT0iIzA2YjZkNCIgc3Ryb2tlLXdpZHRoPSIxLjUiLz4KICA8dGV4dCB4PSI1MDAiIHk9IjE1MyIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZmlsbD0iIzA2YjZkNCIgZm9udC1mYW1pbHk9Im1vbm9zcGFjZSIgZm9udC1zaXplPSIxMCI+QXBwIEI8L3RleHQ+CiAgPHJlY3QgeD0iNDYwIiB5PSIxODAiIHdpZHRoPSI4MCIgaGVpZ2h0PSIyOCIgcng9IjUiIGZpbGw9IiMwZDExMTciIHN0cm9rZT0iIzA2YjZkNCIgc3Ryb2tlLXdpZHRoPSIxLjUiLz4KICA8dGV4dCB4PSI1MDAiIHk9IjE5OCIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZmlsbD0iIzA2YjZkNCIgZm9udC1mYW1pbHk9Im1vbm9zcGFjZSIgZm9udC1zaXplPSIxMCI+QXBwIEM8L3RleHQ+CiAgPCEtLSBNQ1AgaHViIC0tPgogIDxjaXJjbGUgY3g9IjYwMCIgY3k9IjE0OSIgcj0iMjgiIGZpbGw9InJnYmEoNiwxODIsMjEyLDAuMTIpIiBzdHJva2U9IiMwNmI2ZDQiIHN0cm9rZS13aWR0aD0iMiIvPgogIDx0ZXh0IHg9IjYwMCIgeT0iMTU0IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmaWxsPSIjMjJkM2VlIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMiIgZm9udC13ZWlnaHQ9ImJvbGQiPk1DUDwvdGV4dD4KICA8bGluZSB4MT0iNTQwIiB5MT0iMTA0IiB4Mj0iNTcyIiB5Mj0iMTM1IiBzdHJva2U9IiMwNmI2ZDQiIHN0cm9rZS13aWR0aD0iMS41IiBvcGFjaXR5PSIwLjciLz4KICA8bGluZSB4MT0iNTQwIiB5MT0iMTQ5IiB4Mj0iNTcyIiB5Mj0iMTQ5IiBzdHJva2U9IiMwNmI2ZDQiIHN0cm9rZS13aWR0aD0iMS41IiBvcGFjaXR5PSIwLjciLz4KICA8bGluZSB4MT0iNTQwIiB5MT0iMTk0IiB4Mj0iNTcyIiB5Mj0iMTYzIiBzdHJva2U9IiMwNmI2ZDQiIHN0cm9rZS13aWR0aD0iMS41IiBvcGFjaXR5PSIwLjciLz4KICA8IS0tIE1DUCBzZXJ2ZXJzIC0tPgogIDxyZWN0IHg9IjY2MCIgeT0iOTAiIHdpZHRoPSI4MCIgaGVpZ2h0PSIyOCIgcng9IjUiIGZpbGw9IiMwZDExMTciIHN0cm9rZT0iIzEwYjk4MSIgc3Ryb2tlLXdpZHRoPSIxLjUiLz4KICA8dGV4dCB4PSI3MDAiIHk9IjEwOCIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZmlsbD0iIzEwYjk4MSIgZm9udC1mYW1pbHk9Im1vbm9zcGFjZSIgZm9udC1zaXplPSIxMCI+REIgU2VydmVyPC90ZXh0PgogIDxyZWN0IHg9IjY2MCIgeT0iMTM1IiB3aWR0aD0iODAiIGhlaWdodD0iMjgiIHJ4PSI1IiBmaWxsPSIjMGQxMTE3IiBzdHJva2U9IiMxMGI5ODEiIHN0cm9rZS13aWR0aD0iMS41Ii8+CiAgPHRleHQgeD0iNzAwIiB5PSIxNTMiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZpbGw9IiMxMGI5ODEiIGZvbnQtZmFtaWx5PSJtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTAiPkZpbGUgU2VydmVyPC90ZXh0PgogIDxyZWN0IHg9IjY2MCIgeT0iMTgwIiB3aWR0aD0iODAiIGhlaWdodD0iMjgiIHJ4PSI1IiBmaWxsPSIjMGQxMTE3IiBzdHJva2U9IiMxMGI5ODEiIHN0cm9rZS13aWR0aD0iMS41Ii8+CiAgPHRleHQgeD0iNzAwIiB5PSIxOTgiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZpbGw9IiMxMGI5ODEiIGZvbnQtZmFtaWx5PSJtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTAiPkFQSSBTZXJ2ZXI8L3RleHQ+CiAgPGxpbmUgeDE9IjYyOCIgeTE9IjEzNSIgeDI9IjY2MCIgeTI9IjEwNCIgc3Ryb2tlPSIjMTBiOTgxIiBzdHJva2Utd2lkdGg9IjEuNSIgb3BhY2l0eT0iMC43Ii8+CiAgPGxpbmUgeDE9IjYyOCIgeTE9IjE0OSIgeDI9IjY2MCIgeTI9IjE0OSIgc3Ryb2tlPSIjMTBiOTgxIiBzdHJva2Utd2lkdGg9IjEuNSIgb3BhY2l0eT0iMC43Ii8+CiAgPGxpbmUgeDE9IjYyOCIgeTE9IjE2MyIgeDI9IjY2MCIgeTI9IjE4MCIgc3Ryb2tlPSIjMTBiOTgxIiBzdHJva2Utd2lkdGg9IjEuNSIgb3BhY2l0eT0iMC43Ii8+CiAgPHRleHQgeD0iNjAwIiB5PSIyNTAiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZpbGw9IiMyMmQzZWUiIGZvbnQtZmFtaWx5PSJtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMjIiIGZvbnQtd2VpZ2h0PSJib2xkIj42IGltcGxlbWVudGF0aW9uczwvdGV4dD4KICA8dGV4dCB4PSI0MDAiIHk9IjM3MCIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZmlsbD0iIzQ3NTU2OSIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTMiPnRoZW1jcGd1eS5jb20g4oCUIFN0b3AgQWNjdW11bGF0aW5nIEFJIEludGVncmF0aW9uIERlYnQ8L3RleHQ+Cjwvc3ZnPgo=" width="800" height="400" class="img_ev3q"></p>
<p>Every time you write a bespoke AI tool integration without a standard, you're making a promise to your future self: <em>I will maintain this forever, or I will rewrite it later.</em></p>
<p>You're not going to maintain it. And "later" has a way of arriving at the worst possible moment.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-hardcoded-tool-calls-look-like">What Hardcoded Tool Calls Look Like<a href="https://themcpguy.com/blog/why-hardcoding-tool-calls-is-technical-debt#what-hardcoded-tool-calls-look-like" class="hash-link" aria-label="Direct link to What Hardcoded Tool Calls Look Like" title="Direct link to What Hardcoded Tool Calls Look Like" translate="no">​</a></h2>
<p>Here's a pattern you've probably written, or will write soon:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">call_ai_with_tools</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">user_message</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    response </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> openai</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">chat</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">completions</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">create</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        model</span><span class="token operator" style="color:#393A34">=</span><span class="token string" style="color:#e3116c">"gpt-4o"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        messages</span><span class="token operator" style="color:#393A34">=</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">{</span><span class="token string" style="color:#e3116c">"role"</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"user"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"content"</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> user_message</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        tools</span><span class="token operator" style="color:#393A34">=</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token string" style="color:#e3116c">"type"</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"function"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token string" style="color:#e3116c">"function"</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    </span><span class="token string" style="color:#e3116c">"name"</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"search_customers"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    </span><span class="token string" style="color:#e3116c">"description"</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Search customers"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    </span><span class="token string" style="color:#e3116c">"parameters"</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                        </span><span class="token string" style="color:#e3116c">"type"</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"object"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                        </span><span class="token string" style="color:#e3116c">"properties"</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                            </span><span class="token string" style="color:#e3116c">"query"</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token string" style="color:#e3116c">"type"</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"string"</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> response</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">choices</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">message</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">tool_calls</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        tool_call </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> response</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">choices</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">message</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">tool_calls</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> tool_call</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">function</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">name </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"search_customers"</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            args </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> json</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">loads</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tool_call</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">function</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">arguments</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            results </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> db</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">search_customers</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">args</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"query"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token comment" style="color:#999988;font-style:italic"># ... feed results back to model</span><br></span></code></pre></div></div>
<p>This code works. Right now. For this model. In this application.</p>
<p>The debt isn't visible yet. The debt appears when:</p>
<ul>
<li class="">You want the same tool in a different application → copy-paste, diverge forever</li>
<li class="">You switch from GPT-4 to Claude → the tool definition format is different, rewrite</li>
<li class="">You want to use a specialised AI client (Cursor, Claude Desktop) → they can't use your custom function definitions, rewrite</li>
<li class="">A colleague builds the same tool for their project → you now have two implementations of <code>search_customers</code>, slowly diverging</li>
</ul>
<p>This is technical debt in its purest form: a decision that makes today faster at the cost of tomorrow's flexibility.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-root-cause-integration-without-a-standard">The Root Cause: Integration Without a Standard<a href="https://themcpguy.com/blog/why-hardcoding-tool-calls-is-technical-debt#the-root-cause-integration-without-a-standard" class="hash-link" aria-label="Direct link to The Root Cause: Integration Without a Standard" title="Direct link to The Root Cause: Integration Without a Standard" translate="no">​</a></h2>
<p>The underlying problem isn't that your code is bad. It's that you're implementing the integration layer from scratch, with no standard to ensure interoperability.</p>
<p>Every AI provider has slightly different function-calling APIs:</p>
<ul>
<li class="">OpenAI: <code>tools</code> array with <code>type: "function"</code> wrappers</li>
<li class="">Anthropic: <code>tools</code> array with different schema structure</li>
<li class="">Google: <code>function_declarations</code> in a different format altogether</li>
</ul>
<p>Every AI client has different integration mechanisms:</p>
<ul>
<li class="">Claude Desktop: process-based, reads config JSON</li>
<li class="">Cursor: extension-based, different config format</li>
<li class="">Your custom chat UI: whatever you built last year</li>
</ul>
<p>Without a standard, you're writing N × M integrations, where N is the number of tools and M is the number of clients/models. Every combination is custom. Every combination is technical debt.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="mcp-as-the-technical-debt-cure">MCP as the Technical Debt Cure<a href="https://themcpguy.com/blog/why-hardcoding-tool-calls-is-technical-debt#mcp-as-the-technical-debt-cure" class="hash-link" aria-label="Direct link to MCP as the Technical Debt Cure" title="Direct link to MCP as the Technical Debt Cure" translate="no">​</a></h2>
<p>MCP changes the equation. Instead of N × M integrations, you write N + M.</p>
<p>Write your <code>search_customers</code> Tool in an MCP server once. It works with every MCP-compatible AI client: Claude Desktop, Cursor, GitHub Copilot, any agent framework that implements the spec. Write your client integration once (or just configure a supported client). It works with every MCP server.</p>
<p>The math is simple. The implications are significant.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="but-im-moving-fast-right-now">"But I'm Moving Fast Right Now"<a href="https://themcpguy.com/blog/why-hardcoding-tool-calls-is-technical-debt#but-im-moving-fast-right-now" class="hash-link" aria-label="Direct link to &quot;But I'm Moving Fast Right Now&quot;" title="Direct link to &quot;But I'm Moving Fast Right Now&quot;" translate="no">​</a></h2>
<p>The most common objection: "MCP is extra complexity I don't need yet."</p>
<p>Let me challenge that framing. Writing a custom tool integration isn't "moving fast." It's taking on debt with a high interest rate. You will pay that debt: when you switch models, when you add a second client, when a colleague needs the same tool, when you need to audit every place your database is accessed by an AI.</p>
<p>MCP is not extra complexity. It's upfront complexity in exchange for long-term simplicity. It's the architectural equivalent of writing a test, it costs time now, saves time continuously.</p>
<p>The developers who say "we'll standardise later" are the same developers who rewrite their entire data access layer after three years of accumulated debt. Standardising later always costs more than standardising now.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-one-valid-exception">The One Valid Exception<a href="https://themcpguy.com/blog/why-hardcoding-tool-calls-is-technical-debt#the-one-valid-exception" class="hash-link" aria-label="Direct link to The One Valid Exception" title="Direct link to The One Valid Exception" translate="no">​</a></h2>
<p>If you're building a one-off prototype that will be thrown away after a demo, hardcode everything. Life's short. Ship the prototype.</p>
<p>The moment "prototype" becomes "this is what we're building on," you're in the technical debt danger zone. The prototype's tool integration doesn't get deleted, it becomes the foundation. And foundations matter.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-migration-path">The Migration Path<a href="https://themcpguy.com/blog/why-hardcoding-tool-calls-is-technical-debt#the-migration-path" class="hash-link" aria-label="Direct link to The Migration Path" title="Direct link to The Migration Path" translate="no">​</a></h2>
<p>Already have custom tool integrations? Migration to MCP is mechanical, not creative:</p>
<ol>
<li class="">Extract your tool's execution logic into a standalone class</li>
<li class="">Wrap it in an MCP server with the appropriate Tool definition</li>
<li class="">Replace your custom function-calling code with an MCP client connection</li>
<li class="">Delete the old integration code</li>
</ol>
<p>For most tools, this is a day's work. For a large system with many tools, a week. The payoff is proportional to how many clients and models you eventually want to support.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="a-standard-is-not-a-constraint-its-a-superpower">A Standard Is Not a Constraint, It's a Superpower<a href="https://themcpguy.com/blog/why-hardcoding-tool-calls-is-technical-debt#a-standard-is-not-a-constraint-its-a-superpower" class="hash-link" aria-label="Direct link to A Standard Is Not a Constraint, It's a Superpower" title="Direct link to A Standard Is Not a Constraint, It's a Superpower" translate="no">​</a></h2>
<p>I want to end with a mindset shift.</p>
<p>Standards feel like constraints when you first encounter them. You have to learn the protocol. You have to implement a server. You can't just hack a function call directly.</p>
<p>But standards are how ecosystems are built. HTTP felt like overhead until the entire web was built on it. USB-C felt like a forced migration until you stopped carrying five chargers.</p>
<p>MCP is the point where AI tool integration stops being a proprietary, application-specific concern and becomes a shared, ecosystem-level capability. Every server you build contributes to that ecosystem. Every server someone else builds is a server you might not need to build.</p>
<p>Build MCP servers. Not because it's easier today, it might not be. Because it's the only thing that doesn't become technical debt tomorrow.</p>
<hr>
<p>Ready to start? The <a class="" href="https://themcpguy.com/docs/mcp-java-sdk/environment-setup">Java SDK course</a> takes you from "what even is an MCP server" to production-grade deployment. The <a class="" href="https://themcpguy.com/docs/welcome">MCP Fundamentals course</a> gives you the theory first, if you prefer to understand before you build.</p>]]></content>
        <author>
            <name>TheMCPGuy</name>
            <uri>https://themcpguy.com</uri>
        </author>
        <category label="mcp" term="mcp"/>
        <category label="architecture" term="architecture"/>
        <category label="best-practices" term="best-practices"/>
        <category label="technical-debt" term="technical-debt"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[The Three Laws of MCP (Asimov Can Rest Easy)]]></title>
        <id>https://themcpguy.com/blog/three-laws-of-mcp</id>
        <link href="https://themcpguy.com/blog/three-laws-of-mcp"/>
        <updated>2026-05-08T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Three geometric shapes representing Tools, Resources, and Prompts in cyan, violet, and green]]></summary>
        <content type="html"><![CDATA[<p><img decoding="async" loading="lazy" alt="Three geometric shapes representing Tools, Resources, and Prompts in cyan, violet, and green" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA4MDAgNDAwIj4KICA8cmVjdCB3aWR0aD0iODAwIiBoZWlnaHQ9IjQwMCIgZmlsbD0iIzA1MDcxNCIvPgogIDwhLS0gVGhyZWUgY2FyZHMgLS0+CiAgPCEtLSBUb29sIGNhcmQgLS0+CiAgPHJlY3QgeD0iNTAiIHk9IjgwIiB3aWR0aD0iMjAwIiBoZWlnaHQ9IjI0MCIgcng9IjEyIiBmaWxsPSIjMGQxMTE3IiBzdHJva2U9IiMwNmI2ZDQiIHN0cm9rZS13aWR0aD0iMiIvPgogIDxyZWN0IHg9IjUwIiB5PSI4MCIgd2lkdGg9IjIwMCIgaGVpZ2h0PSI0IiByeD0iMiIgZmlsbD0iIzA2YjZkNCIvPgogIDxjaXJjbGUgY3g9IjExMCIgY3k9IjE2MCIgcj0iMjgiIGZpbGw9InJnYmEoNiwxODIsMjEyLDAuMSkiIHN0cm9rZT0iIzA2YjZkNCIgc3Ryb2tlLXdpZHRoPSIxLjUiLz4KICA8dGV4dCB4PSIxMTAiIHk9IjE2NiIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZmlsbD0iIzIyZDNlZSIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMjAiPvCflKc8L3RleHQ+CiAgPHRleHQgeD0iMTUwIiB5PSIyMTAiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZpbGw9IiMyMmQzZWUiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjE4IiBmb250LXdlaWdodD0iYm9sZCI+VG9vbHM8L3RleHQ+CiAgPHRleHQgeD0iMTUwIiB5PSIyMzIiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZpbGw9IiM2NDc0OGIiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjEyIj5UaGUgQUkgQWN0czwvdGV4dD4KICA8dGV4dCB4PSIxNTAiIHk9IjI1NCIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZmlsbD0iIzQ3NTU2OSIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTEiPk1vZGVsLWNvbnRyb2xsZWQ8L3RleHQ+CiAgPHRleHQgeD0iMTUwIiB5PSIyNzIiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZpbGw9IiM0NzU1NjkiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjExIj5TaWRlIGVmZmVjdHMgYWxsb3dlZDwvdGV4dD4KICA8dGV4dCB4PSIxNTAiIHk9IjI5NiIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZmlsbD0iIzFlMjkzYiIgZm9udC1mYW1pbHk9Im1vbm9zcGFjZSIgZm9udC1zaXplPSIxMCI+cnVuX3F1ZXJ5KCkgc2VuZF9lbWFpbCgpPC90ZXh0PgogIDwhLS0gUmVzb3VyY2UgY2FyZCAtLT4KICA8cmVjdCB4PSIzMDAiIHk9IjgwIiB3aWR0aD0iMjAwIiBoZWlnaHQ9IjI0MCIgcng9IjEyIiBmaWxsPSIjMGQxMTE3IiBzdHJva2U9IiM4YjVjZjYiIHN0cm9rZS13aWR0aD0iMiIvPgogIDxyZWN0IHg9IjMwMCIgeT0iODAiIHdpZHRoPSIyMDAiIGhlaWdodD0iNCIgcng9IjIiIGZpbGw9IiM4YjVjZjYiLz4KICA8Y2lyY2xlIGN4PSIzNjAiIGN5PSIxNjAiIHI9IjI4IiBmaWxsPSJyZ2JhKDEzOSw5MiwyNDYsMC4xKSIgc3Ryb2tlPSIjOGI1Y2Y2IiBzdHJva2Utd2lkdGg9IjEuNSIvPgogIDx0ZXh0IHg9IjM2MCIgeT0iMTY2IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmaWxsPSIjYTc4YmZhIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIyMCI+8J+TijwvdGV4dD4KICA8dGV4dCB4PSI0MDAiIHk9IjIxMCIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZmlsbD0iI2E3OGJmYSIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTgiIGZvbnQtd2VpZ2h0PSJib2xkIj5SZXNvdXJjZXM8L3RleHQ+CiAgPHRleHQgeD0iNDAwIiB5PSIyMzIiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZpbGw9IiM2NDc0OGIiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjEyIj5UaGUgQUkgUmVhZHM8L3RleHQ+CiAgPHRleHQgeD0iNDAwIiB5PSIyNTQiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZpbGw9IiM0NzU1NjkiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjExIj5BcHAtY29udHJvbGxlZDwvdGV4dD4KICA8dGV4dCB4PSI0MDAiIHk9IjI3MiIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZmlsbD0iIzQ3NTU2OSIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTEiPlJlYWQtb25seSwgbm8gc2lkZSBlZmZlY3RzPC90ZXh0PgogIDx0ZXh0IHg9IjQwMCIgeT0iMjk2IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmaWxsPSIjMWUyOTNiIiBmb250LWZhbWlseT0ibW9ub3NwYWNlIiBmb250LXNpemU9IjEwIj51c2VyczovLzQyICBsb2dzOi8vYXBwPC90ZXh0PgogIDwhLS0gUHJvbXB0IGNhcmQgLS0+CiAgPHJlY3QgeD0iNTUwIiB5PSI4MCIgd2lkdGg9IjIwMCIgaGVpZ2h0PSIyNDAiIHJ4PSIxMiIgZmlsbD0iIzBkMTExNyIgc3Ryb2tlPSIjMTBiOTgxIiBzdHJva2Utd2lkdGg9IjIiLz4KICA8cmVjdCB4PSI1NTAiIHk9IjgwIiB3aWR0aD0iMjAwIiBoZWlnaHQ9IjQiIHJ4PSIyIiBmaWxsPSIjMTBiOTgxIi8+CiAgPGNpcmNsZSBjeD0iNjEwIiBjeT0iMTYwIiByPSIyOCIgZmlsbD0icmdiYSgxNiwxODUsMTI5LDAuMSkiIHN0cm9rZT0iIzEwYjk4MSIgc3Ryb2tlLXdpZHRoPSIxLjUiLz4KICA8dGV4dCB4PSI2MTAiIHk9IjE2NiIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZmlsbD0iIzM0ZDM5OSIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMjAiPvCfk508L3RleHQ+CiAgPHRleHQgeD0iNjUwIiB5PSIyMTAiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZpbGw9IiMzNGQzOTkiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjE4IiBmb250LXdlaWdodD0iYm9sZCI+UHJvbXB0czwvdGV4dD4KICA8dGV4dCB4PSI2NTAiIHk9IjIzMiIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZmlsbD0iIzY0NzQ4YiIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTIiPkh1bWFucyBJbnZva2U8L3RleHQ+CiAgPHRleHQgeD0iNjUwIiB5PSIyNTQiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZpbGw9IiM0NzU1NjkiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjExIj5Vc2VyLWNvbnRyb2xsZWQ8L3RleHQ+CiAgPHRleHQgeD0iNjUwIiB5PSIyNzIiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZpbGw9IiM0NzU1NjkiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjExIj5SZXVzYWJsZSB0ZW1wbGF0ZXM8L3RleHQ+CiAgPHRleHQgeD0iNjUwIiB5PSIyOTYiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZpbGw9IiMxZTI5M2IiIGZvbnQtZmFtaWx5PSJtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTAiPmNvZGVfcmV2aWV3ICBzdGFuZHVwPC90ZXh0PgogIDx0ZXh0IHg9IjQwMCIgeT0iMzcwIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmaWxsPSIjNDc1NTY5IiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMyI+dGhlbWNwZ3V5LmNvbSDigJQgVGhlIFRocmVlIExhd3Mgb2YgTUNQPC90ZXh0Pgo8L3N2Zz4K" width="800" height="400" class="img_ev3q"></p>
<p>Asimov's Three Laws of Robotics encoded a philosophy about how robots should relate to humans. They weren't just rules, they were a framework for reasoning about harm, autonomy, and control. The laws conflicted with each other by design, forcing a hierarchy.</p>
<p>MCP's three primitives, Tools, Resources, and Prompts, encode a similar philosophy. They're not just API categories. They're a framework for reasoning about <em>how</em> AI should interact with the world: what it can change, what it can only read, and what humans explicitly invoke.</p>
<p>Get them right, and your MCP server is intuitive, safe, and composable. Get them wrong, and you'll wonder why the AI keeps calling the wrong thing at the wrong time.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-three-laws">The Three Laws<a href="https://themcpguy.com/blog/three-laws-of-mcp#the-three-laws" class="hash-link" aria-label="Direct link to The Three Laws" title="Direct link to The Three Laws" translate="no">​</a></h2>
<p><strong>Law 1 (Tools): The AI may act, but only through declared, validated interfaces.</strong></p>
<p><strong>Law 2 (Resources): The AI may observe, but only read, never modify.</strong></p>
<p><strong>Law 3 (Prompts): Humans may invoke structured workflows; the AI executes but does not initiate.</strong></p>
<p>Simple rules. Complex implications.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="law-1-tools-the-ai-acts">Law 1: Tools (The AI Acts)<a href="https://themcpguy.com/blog/three-laws-of-mcp#law-1-tools-the-ai-acts" class="hash-link" aria-label="Direct link to Law 1: Tools (The AI Acts)" title="Direct link to Law 1: Tools (The AI Acts)" translate="no">​</a></h2>
<p>A Tool is the mechanism through which an AI model takes action in the world. Call an API. Write a file. Insert a database record. Send a message.</p>
<p>The crucial design principle here is <strong>model-invoked</strong>. When you define a Tool, you're telling the AI: "When you judge that this action is appropriate, you may perform it." The model decides. You define the action and its parameters.</p>
<p>This is both powerful and slightly terrifying if you think about it too long.</p>
<p>The <em>validation</em> part of Law 1 matters enormously. Tools have JSON Schema-defined parameters. The SDK validates incoming tool calls against the schema before your handler runs. But JSON Schema validates structure, not semantics. A <code>run_sql</code> tool that validates that <code>query</code> is a string doesn't prevent the model from running <code>DROP TABLE users</code>. That's why:</p>
<ul>
<li class="">Tool scope should be as narrow as possible</li>
<li class="">High-risk tools should have the risk encoded in their names</li>
<li class="">Your handler must perform semantic validation the schema can't express</li>
<li class="">Destructive tools should ideally require host-level user confirmation</li>
</ul>
<p>When I see a <code>manage_everything</code> MCP tool that accepts raw SQL, I see a liability. When I see <code>search_orders</code>, <code>update_order_status</code>, and <code>cancel_order</code>, I see three safe, auditable tools.</p>
<p><strong>The counterintuitive guidance:</strong> More, smaller tools are better than fewer, broader ones. The AI can reason about specific tools more accurately than Swiss-army-knife tools.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="law-2-resources-the-ai-observes">Law 2: Resources (The AI Observes)<a href="https://themcpguy.com/blog/three-laws-of-mcp#law-2-resources-the-ai-observes" class="hash-link" aria-label="Direct link to Law 2: Resources (The AI Observes)" title="Direct link to Law 2: Resources (The AI Observes)" translate="no">​</a></h2>
<p>A Resource is data the AI can read. Files. Database records. API responses. Log streams. The AI doesn't modify Resources, it consumes them as context.</p>
<p>The safety property is clear: if the AI can only read a Resource, it cannot corrupt your data by accident. A hallucinating model with access to a filesystem Resource can read the wrong file. A hallucinating model with a filesystem write Tool can delete it.</p>
<p><strong>The design principle that most developers miss:</strong> Resources shouldn't just be "the read-only version of a Tool." They should be identified by stable URIs that the application (not the model) can decide to attach to context.</p>
<p>This is a subtle but important difference. A Tool is called when the model thinks it's a good idea. A Resource can be pre-fetched by the host application before the conversation even starts. Claude Desktop can attach a resource to every conversation in a project. A Cursor workspace can always have the relevant codebase resources available.</p>
<p>This means Resources enable <strong>ambient context</strong>, the AI always knows about certain data, not just when it explicitly decides to look.</p>
<p><strong>The test for Resources vs. Tools:</strong> "Does this operation have side effects?" If yes → Tool. If no → Resource. It's almost always that simple.</p>
<p>Corollary: if you find yourself building a <code>get_user</code> Tool, it should probably be a <code>users://{userId}</code> Resource. Save the Tools for <code>update_user</code>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="law-3-prompts-humans-invoke-ai-executes">Law 3: Prompts (Humans Invoke, AI Executes)<a href="https://themcpguy.com/blog/three-laws-of-mcp#law-3-prompts-humans-invoke-ai-executes" class="hash-link" aria-label="Direct link to Law 3: Prompts (Humans Invoke, AI Executes)" title="Direct link to Law 3: Prompts (Humans Invoke, AI Executes)" translate="no">​</a></h2>
<p>Prompts are the most frequently misunderstood primitive. They're not instructions the AI sends to itself. They're instruction <em>templates</em> that humans explicitly invoke from the host UI.</p>
<p>Think of them as slash commands with arguments:</p>
<ul>
<li class=""><code>/code-review language=java focus=security</code></li>
<li class=""><code>/standup-summary team=backend</code></li>
<li class=""><code>/explain-error log-level=error component=payment-service</code></li>
</ul>
<p>The human chooses to invoke a Prompt. The Prompt expands into a carefully crafted conversation structure, system messages, context, initial user message, designed to produce high-quality, consistent AI output for that specific task.</p>
<p><strong>Why this matters:</strong> Without Prompts, every developer on your team writes their code review instruction differently. "Review this code" produces mediocre results. "You are an expert Java security engineer. Review the following code for SQL injection vulnerabilities, insecure deserialization, missing input validation, and authentication gaps. For each issue, cite the CWE, provide a severity rating, and show the corrected code." produces good results. But who writes that every time?</p>
<p>Prompts let you write the expert instruction once and distribute it to everyone through their AI tool.</p>
<p><strong>The Asimov parallel:</strong> Law 3 is the one about human control. Tools can run autonomously. Resources can be ambient. But Prompts are explicitly human-initiated. The AI doesn't invoke a Prompt, humans do. This preserves human agency for high-level workflow initiation while letting the AI operate autonomously at the execution level.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="when-the-laws-conflict">When the Laws Conflict<a href="https://themcpguy.com/blog/three-laws-of-mcp#when-the-laws-conflict" class="hash-link" aria-label="Direct link to When the Laws Conflict" title="Direct link to When the Laws Conflict" translate="no">​</a></h2>
<p>Asimov's genius was in the conflicts between his laws. The MCP primitives have their own tensions:</p>
<p><strong>"Should I make this a Tool or a Resource?"</strong></p>
<p>The primary question is side effects. But there's a secondary question: control. If you want the model to autonomously decide when to fetch data, you need a Tool (the model decides). If you want the host application to control what data is available to the model, you want a Resource (the application decides).</p>
<p><strong>"Is this a Resource or a Prompt?"</strong></p>
<p>Resources provide <em>data</em>. Prompts provide <em>instructions</em>. A resource with product documentation is data. A prompt that says "review this product documentation for inconsistencies and suggest improvements" is an instruction template. Often you use both together: the Prompt includes an embedded Resource reference.</p>
<p><strong>"Do I need a Tool if I already have a Prompt for this?"</strong></p>
<p>Yes. A Prompt for "search for customers" that the user invokes is different from a Tool for <code>search_customers</code> that the AI invokes autonomously mid-conversation. They serve different use cases and you might want both.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-framework-in-practice">The Framework in Practice<a href="https://themcpguy.com/blog/three-laws-of-mcp#the-framework-in-practice" class="hash-link" aria-label="Direct link to The Framework in Practice" title="Direct link to The Framework in Practice" translate="no">​</a></h2>
<p>Here's how I think through a new capability when building an MCP server:</p>
<ol>
<li class=""><strong>Does it write, modify, or have side effects?</strong> → Tool (with careful scope definition)</li>
<li class=""><strong>Does it read stable, addressable data?</strong> → Resource (with a meaningful URI)</li>
<li class=""><strong>Is it a recurring, high-quality workflow?</strong> → Prompt (that wraps Tools and Resources)</li>
<li class=""><strong>Could it be both a Tool and a Resource?</strong> → Yes, and that's fine. Implement both.</li>
</ol>
<p>The laws give you a framework. They don't make every decision for you. But they prevent the most common mistakes: read-only operations implemented as Tools (losing the composability benefit of Resources), and write operations implemented as Resources (breaking the safety contract).</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-philosophical-point">The Philosophical Point<a href="https://themcpguy.com/blog/three-laws-of-mcp#the-philosophical-point" class="hash-link" aria-label="Direct link to The Philosophical Point" title="Direct link to The Philosophical Point" translate="no">​</a></h2>
<p>I started with Asimov because the analogy runs deeper than it seems.</p>
<p>Asimov's laws were about the relationship between robots and humans, about who has agency and who has authority. Law 1 (don't harm humans) prioritises human safety. Law 2 (obey humans) prioritises human authority. Law 3 (protect yourself) enables robot agency within those bounds.</p>
<p>MCP's three primitives encode a similar relationship between AI and the systems it operates in:</p>
<ul>
<li class="">Tools encode that the AI can <em>act</em>, but only through declared, safe interfaces</li>
<li class="">Resources encode that the AI can <em>know</em>, but only through read-only access to data</li>
<li class="">Prompts encode that humans can <em>direct</em>, and the AI will follow high-quality structured guidance</li>
</ul>
<p>These aren't just implementation details. They're a philosophy of how AI should be integrated into production systems: capable but bounded, powerful but controlled, autonomous but within declared limits.</p>
<p>Asimov's laws failed in the stories because real situations are too complex for simple rules. MCP's three primitives work because they're not about ethics, they're about a clean architectural separation of concerns. And that, as we've known for decades, is where software elegance lives.</p>
<hr>
<p>Want to build servers that implement these three primitives correctly?</p>
<p>Start with <a class="" href="https://themcpguy.com/docs/welcome">MCP Fundamentals</a> for the theory, or jump straight to <a class="" href="https://themcpguy.com/docs/mcp-java-sdk/environment-setup">Building MCP Servers in Java</a> if you learn better by doing.</p>]]></content>
        <author>
            <name>TheMCPGuy</name>
            <uri>https://themcpguy.com</uri>
        </author>
        <category label="mcp" term="mcp"/>
        <category label="architecture" term="architecture"/>
        <category label="tools" term="tools"/>
        <category label="resources" term="resources"/>
        <category label="prompts" term="prompts"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[MCP: The USB-C Port Your AI Has Been Waiting For]]></title>
        <id>https://themcpguy.com/blog/mcp-usb-c-for-ai</id>
        <link href="https://themcpguy.com/blog/mcp-usb-c-for-ai"/>
        <updated>2026-04-24T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[A single elegant connector replacing a mess of tangled cables]]></summary>
        <content type="html"><![CDATA[<p><img decoding="async" loading="lazy" alt="A single elegant connector replacing a mess of tangled cables" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA4MDAgNDAwIj4KICA8cmVjdCB3aWR0aD0iODAwIiBoZWlnaHQ9IjQwMCIgZmlsbD0iIzA1MDcxNCIvPgogIDwhLS0gQ2hhb3Mgb2YgZGlmZmVyZW50IGNvbm5lY3RvcnMgKGJlZm9yZSkgLS0+CiAgPHRleHQgeD0iMTUwIiB5PSI2MCIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZmlsbD0iIzQ3NTU2OSIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTIiPkJlZm9yZSBNQ1A8L3RleHQ+CiAgPHJlY3QgeD0iMzAiIHk9IjgwIiB3aWR0aD0iNzAiIGhlaWdodD0iMzAiIHJ4PSI0IiBmaWxsPSIjMGQxMTE3IiBzdHJva2U9IiNlZjQ0NDQiIHN0cm9rZS13aWR0aD0iMS41Ii8+CiAgPHRleHQgeD0iNjUiIHk9IjEwMCIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZmlsbD0iI2VmNDQ0NCIgZm9udC1mYW1pbHk9Im1vbm9zcGFjZSIgZm9udC1zaXplPSIxMCI+T3BlbkFJIEFQSTwvdGV4dD4KICA8cmVjdCB4PSIzMCIgeT0iMTMwIiB3aWR0aD0iNzAiIGhlaWdodD0iMzAiIHJ4PSI0IiBmaWxsPSIjMGQxMTE3IiBzdHJva2U9IiNmNTllMGIiIHN0cm9rZS13aWR0aD0iMS41Ii8+CiAgPHRleHQgeD0iNjUiIHk9IjE1MCIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZmlsbD0iI2Y1OWUwYiIgZm9udC1mYW1pbHk9Im1vbm9zcGFjZSIgZm9udC1zaXplPSIxMCI+Q2xhdWRlIEFQSTwvdGV4dD4KICA8cmVjdCB4PSIzMCIgeT0iMTgwIiB3aWR0aD0iNzAiIGhlaWdodD0iMzAiIHJ4PSI0IiBmaWxsPSIjMGQxMTE3IiBzdHJva2U9IiM4YjVjZjYiIHN0cm9rZS13aWR0aD0iMS41Ii8+CiAgPHRleHQgeD0iNjUiIHk9IjIwMCIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZmlsbD0iIzhiNWNmNiIgZm9udC1mYW1pbHk9Im1vbm9zcGFjZSIgZm9udC1zaXplPSIxMCI+R2VtaW5pIEFQSTwvdGV4dD4KICA8IS0tIFRhbmdsZWQgY2FibGVzIC0tPgogIDxwYXRoIGQ9Ik0xMDAgOTUgQzE1MCA5NSAxMjAgMjAwIDIwMCAyMDAiIHN0cm9rZT0iI2VmNDQ0NCIgc3Ryb2tlLXdpZHRoPSIxLjUiIGZpbGw9Im5vbmUiIG9wYWNpdHk9IjAuNSIvPgogIDxwYXRoIGQ9Ik0xMDAgMTQ1IEMxNjAgMTAwIDE0MCAyNTAgMjAwIDIzMCIgc3Ryb2tlPSIjZjU5ZTBiIiBzdHJva2Utd2lkdGg9IjEuNSIgZmlsbD0ibm9uZSIgb3BhY2l0eT0iMC41Ii8+CiAgPHBhdGggZD0iTTEwMCAxOTUgQzE3MCAxNTAgMTMwIDI4MCAyMDAgMjYwIiBzdHJva2U9IiM4YjVjZjYiIHN0cm9rZS13aWR0aD0iMS41IiBmaWxsPSJub25lIiBvcGFjaXR5PSIwLjUiLz4KICA8IS0tIFRvb2xzIG9uIHJpZ2h0IHNpZGUgLS0+CiAgPHJlY3QgeD0iMjAwIiB5PSIxNzAiIHdpZHRoPSI2MCIgaGVpZ2h0PSIyNSIgcng9IjQiIGZpbGw9IiMwZDExMTciIHN0cm9rZT0iIzFlMjkzYiIgc3Ryb2tlLXdpZHRoPSIxIi8+CiAgPHRleHQgeD0iMjMwIiB5PSIxODYiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZpbGw9IiM2NDc0OGIiIGZvbnQtZmFtaWx5PSJtb25vc3BhY2UiIGZvbnQtc2l6ZT0iOSI+RGF0YWJhc2U8L3RleHQ+CiAgPHJlY3QgeD0iMjAwIiB5PSIyMTUiIHdpZHRoPSI2MCIgaGVpZ2h0PSIyNSIgcng9IjQiIGZpbGw9IiMwZDExMTciIHN0cm9rZT0iIzFlMjkzYiIgc3Ryb2tlLXdpZHRoPSIxIi8+CiAgPHRleHQgeD0iMjMwIiB5PSIyMzEiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZpbGw9IiM2NDc0OGIiIGZvbnQtZmFtaWx5PSJtb25vc3BhY2UiIGZvbnQtc2l6ZT0iOSI+RmlsZXM8L3RleHQ+CiAgPHJlY3QgeD0iMjAwIiB5PSIyNjAiIHdpZHRoPSI2MCIgaGVpZ2h0PSIyNSIgcng9IjQiIGZpbGw9IiMwZDExMTciIHN0cm9rZT0iIzFlMjkzYiIgc3Ryb2tlLXdpZHRoPSIxIi8+CiAgPHRleHQgeD0iMjMwIiB5PSIyNzYiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZpbGw9IiM2NDc0OGIiIGZvbnQtZmFtaWx5PSJtb25vc3BhY2UiIGZvbnQtc2l6ZT0iOSI+QVBJczwvdGV4dD4KICA8IS0tIEFycm93IC0tPgogIDx0ZXh0IHg9IjQwMCIgeT0iMjEwIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmaWxsPSIjMjJkM2VlIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSI0MCI+4oaSPC90ZXh0PgogIDwhLS0gQWZ0ZXIgTUNQOiBjbGVhbiBzaW5nbGUgc3RhbmRhcmQgLS0+CiAgPHRleHQgeD0iNjIwIiB5PSI2MCIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZmlsbD0iIzQ3NTU2OSIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTIiPkFmdGVyIE1DUDwvdGV4dD4KICA8cmVjdCB4PSI0ODAiIHk9IjgwIiB3aWR0aD0iNzAiIGhlaWdodD0iMzAiIHJ4PSI0IiBmaWxsPSIjMGQxMTE3IiBzdHJva2U9IiMwNmI2ZDQiIHN0cm9rZS13aWR0aD0iMS41Ii8+CiAgPHRleHQgeD0iNTE1IiB5PSIxMDAiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZpbGw9IiMwNmI2ZDQiIGZvbnQtZmFtaWx5PSJtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTAiPkFueSBDbGllbnQ8L3RleHQ+CiAgPGxpbmUgeDE9IjU1MCIgeTE9Ijk1IiB4Mj0iNjEwIiB5Mj0iMjAwIiBzdHJva2U9IiMwNmI2ZDQiIHN0cm9rZS13aWR0aD0iMiIgb3BhY2l0eT0iMC44Ii8+CiAgPCEtLSBNQ1AgU2VydmVyIC0tPgogIDxyZWN0IHg9IjYxMCIgeT0iMTcwIiB3aWR0aD0iOTAiIGhlaWdodD0iNjAiIHJ4PSI4IiBmaWxsPSIjMGQxMTE3IiBzdHJva2U9IiMwNmI2ZDQiIHN0cm9rZS13aWR0aD0iMiIvPgogIDx0ZXh0IHg9IjY1NSIgeT0iMTk3IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmaWxsPSIjMjJkM2VlIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMyIgZm9udC13ZWlnaHQ9ImJvbGQiPk1DUDwvdGV4dD4KICA8dGV4dCB4PSI2NTUiIHk9IjIxNSIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZmlsbD0iIzY0NzQ4YiIgZm9udC1mYW1pbHk9Im1vbm9zcGFjZSIgZm9udC1zaXplPSIxMCI+U3RhbmRhcmQ8L3RleHQ+CiAgPCEtLSBDbGVhbiBjb25uZWN0aW9ucyAtLT4KICA8bGluZSB4MT0iNzAwIiB5MT0iMTkwIiB4Mj0iNzQwIiB5Mj0iMTUwIiBzdHJva2U9IiMwNmI2ZDQiIHN0cm9rZS13aWR0aD0iMS41IiBvcGFjaXR5PSIwLjciLz4KICA8bGluZSB4MT0iNzAwIiB5MT0iMjAwIiB4Mj0iNzUwIiB5Mj0iMjAwIiBzdHJva2U9IiMwNmI2ZDQiIHN0cm9rZS13aWR0aD0iMS41IiBvcGFjaXR5PSIwLjciLz4KICA8bGluZSB4MT0iNzAwIiB5MT0iMjEwIiB4Mj0iNzQwIiB5Mj0iMjUwIiBzdHJva2U9IiMwNmI2ZDQiIHN0cm9rZS13aWR0aD0iMS41IiBvcGFjaXR5PSIwLjciLz4KICA8Y2lyY2xlIGN4PSI3NDUiIGN5PSIxNTAiIHI9IjYiIGZpbGw9IiM4YjVjZjYiLz4KICA8Y2lyY2xlIGN4PSI3NTUiIGN5PSIyMDAiIHI9IjYiIGZpbGw9IiMxMGI5ODEiLz4KICA8Y2lyY2xlIGN4PSI3NDUiIGN5PSIyNTAiIHI9IjYiIGZpbGw9IiNmNTllMGIiLz4KICA8dGV4dCB4PSI0MDAiIHk9IjM3MCIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZmlsbD0iIzQ3NTU2OSIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTMiPnRoZW1jcGd1eS5jb208L3RleHQ+Cjwvc3ZnPgo=" width="800" height="400" class="img_ev3q"></p>
<p>Remember 2018? Every device had a different port. Your laptop needed USB-A. Your phone needed Micro-USB or Lightning depending on the religion of its manufacturer. Your camera used Mini-USB because it was made by people who clearly hated you.</p>
<p>Carrying a bag of adapters was not a software problem. It was a standards problem. USB-C solved it not by being a better technology than its predecessors (it was also just a connector), but by being a <em>common</em> connector. One port. One cable. Every device.</p>
<p>The AI tool integration ecosystem looks exactly like 2018's port situation. MCP is the USB-C moment.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-cable-bag-problem">The Cable Bag Problem<a href="https://themcpguy.com/blog/mcp-usb-c-for-ai#the-cable-bag-problem" class="hash-link" aria-label="Direct link to The Cable Bag Problem" title="Direct link to The Cable Bag Problem" translate="no">​</a></h2>
<p>Before I explain MCP, let me describe what it's replacing.</p>
<p>If you've built any kind of AI-powered application in the last two years, you've built some version of this:</p>
<ol>
<li class="">You identified a capability the AI needed: search the database, read a file, call an API.</li>
<li class="">You wrote the integration: a function definition in the model's API format, a handler that executes the function, a result-formatting step that feeds the output back.</li>
<li class="">You moved to the next capability and did it again.</li>
<li class="">Three months later, you want to use a different AI model. The function definition format is different. You rewrite everything.</li>
<li class="">Six months later, you want to use the same capabilities in a different application. You copy-paste the code, adapt it, and maintain two versions forever.</li>
</ol>
<p>Every integration is a custom cable. And custom cables don't interoperate.</p>
<p>This isn't an exotic problem. Ask any developer who's built an AI-powered product in the last two years. They've all got the cable bag.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-a-standard-actually-does">What a Standard Actually Does<a href="https://themcpguy.com/blog/mcp-usb-c-for-ai#what-a-standard-actually-does" class="hash-link" aria-label="Direct link to What a Standard Actually Does" title="Direct link to What a Standard Actually Does" translate="no">​</a></h2>
<p>A standard is a shared contract. Both sides agree to implement it, and interoperability follows automatically.</p>
<p>USB-C's contract: these are the pin layouts, these are the signal specifications, this is the power delivery protocol. Every manufacturer who implements the spec creates a device that works with every other USB-C cable and device.</p>
<p>MCP's contract: this is how a client discovers an AI server's capabilities. This is how a tool call is structured. This is how results are returned. Every client that implements MCP can talk to every server that implements MCP.</p>
<p>The underlying technology didn't change. Databases still query the same way. APIs still return JSON. Files still sit on filesystems. What changed is that there's now a single, agreed-upon way to connect an AI to all of it.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-three-plugs">The Three Plugs<a href="https://themcpguy.com/blog/mcp-usb-c-for-ai#the-three-plugs" class="hash-link" aria-label="Direct link to The Three Plugs" title="Direct link to The Three Plugs" translate="no">​</a></h2>
<p>USB-C replaced the mess with one port. MCP replaces the mess with three concepts:</p>
<p><strong>Tools</strong>, the AI does things. Creates records. Calls APIs. Sends messages. Writes files. Tools are model-invoked: the AI decides autonomously when to call a tool based on the conversation context.</p>
<p><strong>Resources</strong>, the AI reads things. Database records. File contents. API responses. Live metrics. Resources are application-invoked: the host decides what context to provide to the AI, or the user explicitly attaches resources to a conversation.</p>
<p><strong>Prompts</strong>, the AI follows templates. Predefined, parameterised instruction recipes that appear in the client UI as slash commands or workflow options.</p>
<p>Tools, Resources, and Prompts. You could argue this is overly elegant, why not just "functions"? But the three-way distinction encodes something important: not everything the AI can access should be treated as something the AI can modify. Resources are read-only by design. That's a safety property, not just a naming convention.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="adoption-the-real-test-of-a-standard">Adoption: The Real Test of a Standard<a href="https://themcpguy.com/blog/mcp-usb-c-for-ai#adoption-the-real-test-of-a-standard" class="hash-link" aria-label="Direct link to Adoption: The Real Test of a Standard" title="Direct link to Adoption: The Real Test of a Standard" translate="no">​</a></h2>
<p>A specification document is a proposal. Adoption is the proof.</p>
<p>Within months of Anthropic publishing MCP (November 2024), it was integrated into:</p>
<ul>
<li class=""><strong>Cursor</strong>, the AI-native code editor</li>
<li class=""><strong>GitHub Copilot</strong>, Microsoft's AI coding assistant embedded in VS Code</li>
<li class=""><strong>Zed</strong>, the editor built for AI-assisted development</li>
<li class=""><strong>Continue</strong>, the open-source AI coding assistant</li>
<li class=""><strong>Claude Desktop</strong>, Anthropic's own application</li>
<li class=""><strong>Windsurf, Cline, LibreChat</strong>, and a growing list of agentic tools</li>
</ul>
<p>By late 2025 the community had published a wide range of MCP servers on GitHub, covering Git providers, databases, communication tools, filesystem access, browser automation, and more. In December 2025 MCP became a founding project of the <strong>Agentic AI Foundation (AAIF)</strong>, a Linux Foundation directed fund whose technical projects include MCP, <code>goose</code>, and <code>AGENTS.md</code>, formalising MCP as a vendor-neutral industry project.</p>
<p>This is what successful standards look like. Not a committee. Not a consortium. A specification that solved a real problem, published openly, adopted rapidly because developers were tired of the alternative.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-this-means-for-you">What This Means for You<a href="https://themcpguy.com/blog/mcp-usb-c-for-ai#what-this-means-for-you" class="hash-link" aria-label="Direct link to What This Means for You" title="Direct link to What This Means for You" translate="no">​</a></h2>
<p>If you're building AI applications, you have a choice:</p>
<p><strong>Option A:</strong> Continue building custom integrations. Each one is tailored to your specific application and model. Each one is maintained separately. When you want to use a different AI host, you rewrite the integration layer.</p>
<p><strong>Option B:</strong> Build MCP servers. Each server works with any MCP-compatible AI client. You write it once. It composes with other servers. When Cursor adds a new feature that leverages MCP, your server benefits automatically.</p>
<p>Option A is the cable bag. Option B is USB-C.</p>
<p>The economic case is clear: every hour you spend building a custom AI integration is an hour you could spend building the thing your application actually does. MCP doesn't just solve a technical problem, it saves engineering time at scale.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="not-every-cable-is-usb-c-yet">Not Every Cable Is USB-C Yet<a href="https://themcpguy.com/blog/mcp-usb-c-for-ai#not-every-cable-is-usb-c-yet" class="hash-link" aria-label="Direct link to Not Every Cable Is USB-C Yet" title="Direct link to Not Every Cable Is USB-C Yet" translate="no">​</a></h2>
<p>A few honest caveats:</p>
<p>MCP is still young. The spec is evolving. Some authentication patterns are still being standardised. Some client implementations are more complete than others. The Java ecosystem is behind TypeScript and Python in terms of community servers, though the official SDK is solid.</p>
<p>And USB-C took years to fully displace its predecessors. Some devices still ship with Micro-USB. Some cables are USB-C in shape but not in capability. Standards win gradually, then suddenly.</p>
<p>MCP is in the "gradually" phase. But the trajectory is clear.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="get-started">Get Started<a href="https://themcpguy.com/blog/mcp-usb-c-for-ai#get-started" class="hash-link" aria-label="Direct link to Get Started" title="Direct link to Get Started" translate="no">​</a></h2>
<p>If you want to understand MCP before you implement it, the <a class="" href="https://themcpguy.com/docs/welcome">MCP Fundamentals course</a> covers the theory from first principles, no code required.</p>
<p>If you want to build in Java, the <a class="" href="https://themcpguy.com/docs/mcp-java-sdk/environment-setup">Java SDK course</a> takes you from environment setup to a production-ready HTTP server.</p>
<p>One standard. All the tools. No more cable bags.</p>]]></content>
        <author>
            <name>TheMCPGuy</name>
            <uri>https://themcpguy.com</uri>
        </author>
        <category label="mcp" term="mcp"/>
        <category label="explainer" term="explainer"/>
        <category label="standards" term="standards"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Your AI Is Flying Blind: How MCP Finally Gives It Eyes]]></title>
        <id>https://themcpguy.com/blog/your-ai-is-flying-blind</id>
        <link href="https://themcpguy.com/blog/your-ai-is-flying-blind"/>
        <updated>2026-04-10T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[AI model confined to a box, with protocol connections breaking through the walls]]></summary>
        <content type="html"><![CDATA[<p><img decoding="async" loading="lazy" alt="AI model confined to a box, with protocol connections breaking through the walls" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA4MDAgNDAwIj4KICA8cmVjdCB3aWR0aD0iODAwIiBoZWlnaHQ9IjQwMCIgZmlsbD0iIzA1MDcxNCIvPgogIDwhLS0gR3JpZCBsaW5lcyAtLT4KICA8bGluZSB4MT0iMCIgeTE9IjIwMCIgeDI9IjgwMCIgeTI9IjIwMCIgc3Ryb2tlPSIjMWUyOTNiIiBzdHJva2Utd2lkdGg9IjEiLz4KICA8bGluZSB4MT0iNDAwIiB5MT0iMCIgeDI9IjQwMCIgeTI9IjQwMCIgc3Ryb2tlPSIjMWUyOTNiIiBzdHJva2Utd2lkdGg9IjEiLz4KICA8IS0tIElzb2xhdGVkIEFJIGJveCAtLT4KICA8cmVjdCB4PSI2MCIgeT0iMTIwIiB3aWR0aD0iMjIwIiBoZWlnaHQ9IjE2MCIgcng9IjEyIiBmaWxsPSIjMGQxMTE3IiBzdHJva2U9IiMxZTI5M2IiIHN0cm9rZS13aWR0aD0iMiIvPgogIDxyZWN0IHg9IjYwIiB5PSIxMjAiIHdpZHRoPSIyMjAiIGhlaWdodD0iNCIgcng9IjIiIGZpbGw9IiMxZTI5M2IiLz4KICA8Y2lyY2xlIGN4PSI4MCIgY3k9IjEyMiIgcj0iNCIgZmlsbD0iI2VmNDQ0NCIvPgogIDxjaXJjbGUgY3g9Ijk4IiBjeT0iMTIyIiByPSI0IiBmaWxsPSIjZjU5ZTBiIi8+CiAgPGNpcmNsZSBjeD0iMTE2IiBjeT0iMTIyIiByPSI0IiBmaWxsPSIjMTBiOTgxIi8+CiAgPHRleHQgeD0iMTcwIiB5PSIxNjUiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZpbGw9IiM5NGEzYjgiIGZvbnQtZmFtaWx5PSJtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTMiPkFJIE1vZGVsPC90ZXh0PgogIDx0ZXh0IHg9IjE3MCIgeT0iMTg4IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmaWxsPSIjNjQ3NDhiIiBmb250LWZhbWlseT0ibW9ub3NwYWNlIiBmb250LXNpemU9IjEwIj5rbm93czogZXZlcnl0aGluZzwvdGV4dD4KICA8dGV4dCB4PSIxNzAiIHk9IjIwNSIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZmlsbD0iIzY0NzQ4YiIgZm9udC1mYW1pbHk9Im1vbm9zcGFjZSIgZm9udC1zaXplPSIxMCI+c2Vlczogbm90aGluZzwvdGV4dD4KICA8IS0tIEJyb2tlbiBjb25uZWN0aW9ucyAoY3Jvc3NlZCBvdXQpIC0tPgogIDxsaW5lIHgxPSIyODAiIHkxPSIxNzAiIHgyPSIzODAiIHkyPSIxMjAiIHN0cm9rZT0iI2VmNDQ0NCIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtZGFzaGFycmF5PSI2IDQiIG9wYWNpdHk9IjAuNiIvPgogIDxsaW5lIHgxPSIyODAiIHkxPSIyMDAiIHgyPSIzODAiIHkyPSIyMDAiIHN0cm9rZT0iI2VmNDQ0NCIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtZGFzaGFycmF5PSI2IDQiIG9wYWNpdHk9IjAuNiIvPgogIDxsaW5lIHgxPSIyODAiIHkxPSIyMzAiIHgyPSIzODAiIHkyPSIyODAiIHN0cm9rZT0iI2VmNDQ0NCIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtZGFzaGFycmF5PSI2IDQiIG9wYWNpdHk9IjAuNiIvPgogIDwhLS0gRXh0ZXJuYWwgc3lzdGVtcyAtLT4KICA8cmVjdCB4PSIzOTAiIHk9IjgwIiB3aWR0aD0iMTAwIiBoZWlnaHQ9IjUwIiByeD0iOCIgZmlsbD0iIzBkMTExNyIgc3Ryb2tlPSIjMWUyOTNiIiBzdHJva2Utd2lkdGg9IjEuNSIvPgogIDx0ZXh0IHg9IjQ0MCIgeT0iMTA4IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmaWxsPSIjOTRhM2I4IiBmb250LWZhbWlseT0ibW9ub3NwYWNlIiBmb250LXNpemU9IjExIj5EYXRhYmFzZTwvdGV4dD4KICA8cmVjdCB4PSIzOTAiIHk9IjE3NSIgd2lkdGg9IjEwMCIgaGVpZ2h0PSI1MCIgcng9IjgiIGZpbGw9IiMwZDExMTciIHN0cm9rZT0iIzFlMjkzYiIgc3Ryb2tlLXdpZHRoPSIxLjUiLz4KICA8dGV4dCB4PSI0NDAiIHk9IjIwMyIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZmlsbD0iIzk0YTNiOCIgZm9udC1mYW1pbHk9Im1vbm9zcGFjZSIgZm9udC1zaXplPSIxMSI+RmlsZXM8L3RleHQ+CiAgPHJlY3QgeD0iMzkwIiB5PSIyNzAiIHdpZHRoPSIxMDAiIGhlaWdodD0iNTAiIHJ4PSI4IiBmaWxsPSIjMGQxMTE3IiBzdHJva2U9IiMxZTI5M2IiIHN0cm9rZS13aWR0aD0iMS41Ii8+CiAgPHRleHQgeD0iNDQwIiB5PSIyOTgiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZpbGw9IiM5NGEzYjgiIGZvbnQtZmFtaWx5PSJtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTEiPkFQSXM8L3RleHQ+CiAgPCEtLSBNQ1Agc2VjdGlvbiAtLT4KICA8bGluZSB4MT0iNTEwIiB5MT0iMjAwIiB4Mj0iNTYwIiB5Mj0iMjAwIiBzdHJva2U9IiMwNmI2ZDQiIHN0cm9rZS13aWR0aD0iMiIvPgogIDx0ZXh0IHg9IjYwMCIgeT0iMTUwIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmaWxsPSIjMjJkM2VlIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxNiIgZm9udC13ZWlnaHQ9ImJvbGQiPk1DUDwvdGV4dD4KICA8dGV4dCB4PSI2MDAiIHk9IjE3MiIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZmlsbD0iIzY0NzQ4YiIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTEiPmNvbm5lY3RzPC90ZXh0PgogIDx0ZXh0IHg9IjYwMCIgeT0iMTg4IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmaWxsPSIjNjQ3NDhiIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMSI+ZXZlcnl0aGluZzwvdGV4dD4KICA8IS0tIFRpdGxlIC0tPgogIDx0ZXh0IHg9IjQwMCIgeT0iMzcwIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmaWxsPSIjNDc1NTY5IiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMyI+dGhlbWNwZ3V5LmNvbTwvdGV4dD4KPC9zdmc+Cg==" width="800" height="400" class="img_ev3q"></p>
<p>Your AI knows things. An extraordinary amount of things. It can explain the Krebs cycle, debug a segfault, and write a sonnet about dependency injection. And yet, it cannot tell you what's currently in your calendar.</p>
<p>This isn't a capability gap. It's an architecture problem. And MCP exists to solve it.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-brilliant-prisoner-problem">The Brilliant Prisoner Problem<a href="https://themcpguy.com/blog/your-ai-is-flying-blind#the-brilliant-prisoner-problem" class="hash-link" aria-label="Direct link to The Brilliant Prisoner Problem" title="Direct link to The Brilliant Prisoner Problem" translate="no">​</a></h2>
<p>Imagine the world's most knowledgeable professor. She's read every book, every research paper, every technical document ever written. Her recall is perfect. Her reasoning is exceptional. She can synthesise ideas across disciplines in seconds.</p>
<p>Now lock her in a room.</p>
<p>She gets messages slipped under the door. She writes responses and slips them back. The advice is brilliant. The analysis is excellent. But ask her to check something on your company's internal dashboard, and she stares at the ceiling. She doesn't have internet access. She doesn't have access to your systems. She doesn't have access to anything that happened after the last time someone updated her training data.</p>
<p>That's a large language model. GPT-4, Claude, Gemini, it doesn't matter which one. They all share this fundamental limitation: they know a staggering amount about the world as it was when they were trained, but the real world is a live, dynamic system they cannot directly observe.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-brute-force-solutions">The Brute-Force Solutions<a href="https://themcpguy.com/blog/your-ai-is-flying-blind#the-brute-force-solutions" class="hash-link" aria-label="Direct link to The Brute-Force Solutions" title="Direct link to The Brute-Force Solutions" translate="no">​</a></h2>
<p>Developers are creative people. We don't wait for elegant solutions when we need something to work today. So before MCP, we built work-arounds:</p>
<p><strong>Prompt stuffing.</strong> Copy the relevant data, paste it into the prompt. Need the AI to analyse your latest sales figures? Paste the CSV. Need it to review a database record? Copy the row. This works until the data is too large, too dynamic, or too sensitive to paste.</p>
<p><strong>Custom tool calls.</strong> OpenAI's function-calling feature (2023) let you define functions the model could invoke. The model would produce a function call; your code would execute it; you'd feed the result back. Brilliant. Except: every application reinvented this from scratch, for every model, every tool, every use case. There was no standard. The integration you built for GPT-4 didn't work with Claude. The tool you wrote for your chatbot didn't work in your code assistant.</p>
<p><strong>RAG without standards.</strong> Retrieval-Augmented Generation let models fetch relevant documents from a vector database at query time. Excellent for static knowledge. Not great for "what's currently in the order queue" or "what does this API endpoint return right now."</p>
<p>None of these are wrong. They're all useful. But they're all reinventing the wheel.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="mcp-a-standard-for-the-integration-layer">MCP: A Standard for the Integration Layer<a href="https://themcpguy.com/blog/your-ai-is-flying-blind#mcp-a-standard-for-the-integration-layer" class="hash-link" aria-label="Direct link to MCP: A Standard for the Integration Layer" title="Direct link to MCP: A Standard for the Integration Layer" translate="no">​</a></h2>
<p>In November 2024, Anthropic open-sourced the <strong>Model Context Protocol</strong>, a specification for how AI applications should connect to external tools and data sources.</p>
<p>The elegant insight behind MCP is that the integration layer was the problem, not the tools themselves. Everyone was building database connectors, filesystem tools, and API bridges. The tools worked. But there was no standard for <em>how</em> an AI application was supposed to talk to them.</p>
<p>MCP provides that standard:</p>
<ul>
<li class="">Define a <strong>Tool</strong> once: the AI can call it to take actions</li>
<li class="">Define a <strong>Resource</strong> once: the AI can read it for context</li>
<li class="">Define a <strong>Prompt</strong> once: users can invoke structured workflows</li>
</ul>
<p>Build your database MCP server once. It works with Claude Desktop. It works with Cursor. It works with GitHub Copilot. It works with your custom agent. Stop writing the same integration four times.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-flying-blind-actually-means">What "Flying Blind" Actually Means<a href="https://themcpguy.com/blog/your-ai-is-flying-blind#what-flying-blind-actually-means" class="hash-link" aria-label="Direct link to What &quot;Flying Blind&quot; Actually Means" title="Direct link to What &quot;Flying Blind&quot; Actually Means" translate="no">​</a></h2>
<p>Here's a concrete example of what changes.</p>
<p><strong>Before MCP:</strong> You're debugging a production issue. You paste the last 50 lines of the log into Claude. You paste the relevant code. You describe what you think the problem might be. You wait. Claude gives you a plausible but potentially wrong answer because it's working from a snapshot you curated, not from the live system.</p>
<p><strong>With MCP:</strong> Your AI assistant has a filesystem MCP server and a database MCP server connected. You say "why is the payment service erroring?" The assistant reads the live logs directly (via a Resource). It queries the relevant database tables to check transaction state (via a Tool). It examines the actual service code (via the filesystem Resource). It gives you an answer grounded in what's actually happening, not what you remembered to paste.</p>
<p>The AI isn't flying blind anymore. It can see.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-its-different-this-time">Why It's Different This Time<a href="https://themcpguy.com/blog/your-ai-is-flying-blind#why-its-different-this-time" class="hash-link" aria-label="Direct link to Why It's Different This Time" title="Direct link to Why It's Different This Time" translate="no">​</a></h2>
<p>"AI + tools" sounds like a solved problem. We had plugins. We had function calling. We had RAG. What makes MCP different?</p>
<p><strong>Standards.</strong> USB-A worked. USB-B worked. MicroUSB worked. But nobody was happy about carrying four cables. USB-C isn't a new technology; it's a standard that ended the fragmentation. MCP isn't new technology; it's the standard the AI tool ecosystem has needed.</p>
<p><strong>Adoption velocity.</strong> The sign that a standard is working isn't the spec document, it's adoption. Within months of publication MCP was integrated into Cursor, GitHub Copilot, Zed, and dozens of other tools. By late 2025 the community had published a wide range of MCP servers on GitHub, and in December 2025 MCP became a founding project of the <strong>Agentic AI Foundation (AAIF)</strong>, a Linux Foundation directed fund whose technical projects include MCP, <code>goose</code>, and <code>AGENTS.md</code>. Vendor-neutral governance was the official seal on what adoption had already proved. When a standard solves a real problem, adoption is fast.</p>
<p><strong>Open ecosystem.</strong> MCP is not Anthropic-proprietary. The spec is open. Any model, any client, any server can implement it. That's the difference between a standard and a vendor feature.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="where-to-go-from-here">Where to Go From Here<a href="https://themcpguy.com/blog/your-ai-is-flying-blind#where-to-go-from-here" class="hash-link" aria-label="Direct link to Where to Go From Here" title="Direct link to Where to Go From Here" translate="no">​</a></h2>
<p>If this sparked something, you're in the right place. TheMCPGuy is built to be the definitive learning resource for MCP, from theory to production Java implementation.</p>
<p>Start with <a class="" href="https://themcpguy.com/docs/welcome">MCP Fundamentals</a>, eight modules covering everything from the architecture to the security model, without writing a single line of code. Understand the protocol before you implement it.</p>
<p>Then, when you're ready to build, the <a class="" href="https://themcpguy.com/docs/mcp-java-sdk/environment-setup">Java SDK course</a> takes you from zero to a production-grade MCP server in Java.</p>
<p>Your AI has been flying blind long enough.</p>]]></content>
        <author>
            <name>TheMCPGuy</name>
            <uri>https://themcpguy.com</uri>
        </author>
        <category label="mcp" term="mcp"/>
        <category label="explainer" term="explainer"/>
        <category label="fundamentals" term="fundamentals"/>
    </entry>
</feed>