<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Razvan</title>
    <description>The latest articles on DEV Community by Razvan (@razvan_dim).</description>
    <link>https://dev.to/razvan_dim</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F575223%2Fbd857649-cd45-4dff-a786-bb7e89906ea7.jpg</url>
      <title>DEV Community: Razvan</title>
      <link>https://dev.to/razvan_dim</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/razvan_dim"/>
    <language>en</language>
    <item>
      <title>WebMCP: A new contract between AI agents and websites</title>
      <dc:creator>Razvan</dc:creator>
      <pubDate>Tue, 03 Mar 2026 16:06:18 +0000</pubDate>
      <link>https://dev.to/playfulprogramming/webmcp-a-new-contract-between-ai-agents-and-websites-4g07</link>
      <guid>https://dev.to/playfulprogramming/webmcp-a-new-contract-between-ai-agents-and-websites-4g07</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;🚨 Update on WebMCP: the API shape is already evolving.&lt;br&gt;
Starting in Chrome 147.0.7721.0, &lt;strong&gt;provideContext()&lt;/strong&gt; and &lt;strong&gt;clearContext()&lt;/strong&gt; are being removed in favor of a more secure, additive model.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;To prevent malicious scripts from "hijacking" user-agent interactions.&lt;/li&gt;
&lt;li&gt;To align with standard web API patterns like addEventListener.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;You've probably already heard of MCP from Anthropic, the protocol &lt;a href="https://dev.to/playfulprogramming/bridging-the-gap-a-deep-dive-into-the-model-context-protocol-mcp-4e0p"&gt;bridging the gap between AI and our data&lt;/a&gt;. Now Google is taking that idea one step further, bringing it directly into the browser. Meet &lt;strong&gt;WebMCP&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If you've watched an AI agent trying to interact with a website, you've probably seen it scraping the entire DOM, downloading a dump of the entire HTML page, taking screenshots, and only after that understanding what it can do. This operation takes time and it's a &lt;strong&gt;waste of precious tokens&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;WebMCP is proposing a new way for developers to define a &lt;strong&gt;public interface&lt;/strong&gt; for their website that AI agents can discover and use to interact with it. This is definitely quicker and cheaper.&lt;/p&gt;

&lt;p&gt;I built a small shopping cart demo to explore the proposed APIs. You can find it &lt;a href="https://github.com/Razvy13/webmcp-playground" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is WebMCP, exactly?
&lt;/h2&gt;

&lt;p&gt;The core idea is that a website can publish a &lt;strong&gt;structured contract&lt;/strong&gt; (a set of named tools with explicit schemas) that any AI agent can discover and use reliably. Instead of the agent reverse-engineering your UI, your site simply says: &lt;em&gt;"&lt;/em&gt;&lt;em&gt;Here are the things you can do, and here's exactly how to do them.&lt;/em&gt;&lt;em&gt;"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The spec defines three pillars:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Discovery:&lt;/strong&gt; a standard way for agents to query which tools a page exposes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Schemas:&lt;/strong&gt; explicit input/output definitions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;State:&lt;/strong&gt; a shared understanding of what's currently available on the page&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Think of it as an MCP server, but baked into the browser and tied directly to the page's live DOM.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;Availability&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;WebMCP is an &lt;strong&gt;experimental proposed standard&lt;/strong&gt; behind a Chrome flag. If you want to play with it, you need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Chrome&lt;/strong&gt;: Version 146.0.7672.0 or higher&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flags&lt;/strong&gt;: The "WebMCP for testing" flag must be enabled (&lt;code&gt;chrome://flags/#enable-webmcp-testing&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ℹ️ To inspect registered functions, execute them manually or test them with an agent, install the &lt;a href="https://chromewebstore.google.com/detail/model-context-tool-inspec/gbpdfapgefenggkahomfgkhfehlcenpd" rel="noopener noreferrer"&gt;Model Context Tool Inspector&lt;/a&gt; Chrome extension.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Two APIs, two philosophies
&lt;/h2&gt;

&lt;p&gt;WebMCP offers two complementary ways to expose tools.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Imperative API
&lt;/h3&gt;

&lt;p&gt;The Imperative API is JavaScript-first approach. You register tools programmatically via &lt;code&gt;window.navigator.modelContext&lt;/code&gt;, giving each one a name, a description, a JSON Schema for its inputs, and an &lt;code&gt;execute&lt;/code&gt; function that runs when an agent calls it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;modelContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;registerTool&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;addToCart&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Add a product to the shopping cart&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;inputSchema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;object&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;product_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;number&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;product_id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;product_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;quantity&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// your logic here&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Added &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;x &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;product_id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt; &lt;span class="p"&gt;}]&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;registerTool&lt;/code&gt; registers a single tool without touching the others. When you need to register multiple tools at once, &lt;code&gt;provideContext&lt;/code&gt; is the right call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;modelContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;provideContext&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;getCart&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="c1"&gt;// ...&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;‼️ &lt;strong&gt;Watch out: &lt;code&gt;provideContext&lt;/code&gt; replaces ALL registered tools — including declarative ones.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is a subtle but important gotcha. When you call &lt;code&gt;provideContext&lt;/code&gt;, it doesn't just add tools, it wipes out the entire existing set and replaces it. This includes any tools the browser has already registered from your declarative HTML forms. &lt;/p&gt;

&lt;p&gt;There is already an &lt;a href="https://github.com/webmachinelearning/webmcp/issues/101" rel="noopener noreferrer"&gt;open discussion&lt;/a&gt; about this function and it looks like the developers are not very happy about this API. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you need to remove a specific tool at any point, you can use &lt;code&gt;unregisterTool&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;modelContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unregisterTool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;addTodo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Declarative API
&lt;/h3&gt;

&lt;p&gt;The Declarative API takes a different approach: rather than writing JavaScript, you annotate your existing HTML forms with a small set of custom attributes and let the browser do the heavy lifting.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt;
  &lt;span class="na"&gt;toolname=&lt;/span&gt;&lt;span class="s"&gt;"applyCoupon"&lt;/span&gt;
  &lt;span class="na"&gt;tooldescription=&lt;/span&gt;&lt;span class="s"&gt;"Apply a discount coupon code to the cart"&lt;/span&gt;
  &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"coupon-form"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"coupon_code"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Coupon Code&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt;
    &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;
    &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"coupon_code"&lt;/span&gt;
    &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"coupon_code"&lt;/span&gt;
    &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"e.g. SAVE10"&lt;/span&gt;
    &lt;span class="na"&gt;toolparamtitle=&lt;/span&gt;&lt;span class="s"&gt;"Coupon Code"&lt;/span&gt;
    &lt;span class="na"&gt;toolparamdescription=&lt;/span&gt;&lt;span class="s"&gt;"A valid discount coupon code"&lt;/span&gt;
  &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Apply Coupon&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The browser reads these annotations at parse time and internally constructs the same JSON Schema that the Imperative API produces manually. When an agent invokes the tool, the browser focuses the form, populates the fields and, if &lt;code&gt;toolautosubmit&lt;/code&gt; is set submits it automatically without requiring user interaction.&lt;/p&gt;

&lt;p&gt;The attributes available are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;toolname&lt;/code&gt;: the registered name of the tool that the AI agent can call&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tooldescription&lt;/code&gt;: human readable description of what the tool does&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;toolautosubmit&lt;/code&gt;: lets the AI agent submit the form automatically&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;toolparamtitle&lt;/code&gt;: maps to the JSON Schema property key. If omitted, the browser defaults to the input element's &lt;code&gt;name&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;toolparamdescription&lt;/code&gt;: maps to the property description within the JSON Schema. If omitted, the browser uses the text content of the associated &lt;code&gt;&amp;lt;label&amp;gt;&lt;/code&gt; element, or the &lt;code&gt;aria-description&lt;/code&gt; if no label exists&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Knowing when an agent is in charge
&lt;/h4&gt;

&lt;p&gt;The &lt;code&gt;SubmitEvent&lt;/code&gt; introduces a new &lt;code&gt;agentInvoked&lt;/code&gt; boolean attribute. This lets you understand who triggered the action, the agent or the user and adapt your app's behaviour accordingly.&lt;/p&gt;

&lt;p&gt;Additionally, &lt;code&gt;SubmitEvent&lt;/code&gt; now includes a &lt;code&gt;respondWith(Promise&amp;lt;any&amp;gt;)&lt;/code&gt; method which lets you pass a promise to the browser that resolves with the form's result data. That value is then serialized and returned to the model as the tool's output. You must first call &lt;code&gt;preventDefault()&lt;/code&gt; to stop the browser's standard form submission.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;submit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;doTheWork&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;agentInvoked&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;respondWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Visual feedback
&lt;/h4&gt;

&lt;p&gt;There are also CSS pseudo-classes for visual feedback when an agent is interacting with a form: &lt;code&gt;:tool-form-active&lt;/code&gt; is applied to the form itself, and &lt;code&gt;:tool-submit-active&lt;/code&gt; to its submit button. These are useful for showing the user that an agent is in control. Pair them with the &lt;code&gt;toolactivated&lt;/code&gt; and &lt;code&gt;toolcancel&lt;/code&gt; window events to hook into the full tool lifecycle:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;toolactivated&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;toolName&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;toolName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; was activated by an agent`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;toolcancel&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;toolName&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;toolName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; was cancelled`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;ℹ️ &lt;strong&gt;Practical note: you must serve over HTTP&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Opening an HTML file directly via &lt;code&gt;file://&lt;/code&gt; will silently fail — &lt;code&gt;window.navigator.modelContext&lt;/code&gt; simply won't initialize. This is a standard browser security boundary, not a WebMCP bug. Any local server works: &lt;code&gt;npx http-server&lt;/code&gt;, &lt;code&gt;python3 -m http.server 3000&lt;/code&gt;, or &lt;code&gt;npx vite&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;AI agents are increasingly the ones interacting with the software we build, but our websites were never designed for them. Web scraping and visual UI parsing are fragile, slow, and expensive in tokens. WebMCP could solve this by letting us define a clear, explicit contract between our website and any agent that wants to interact with it, without rewriting everything from scratch. The Declarative API in particular is compelling precisely because it progressively enhances forms that already exist.&lt;/p&gt;

&lt;p&gt;It's still an experimental proposed standard, but the core idea is solid. I hope it sees the light soon.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>webmcp</category>
      <category>web</category>
    </item>
    <item>
      <title>Bridging the Gap: A Deep Dive into the Model Context Protocol (MCP)</title>
      <dc:creator>Razvan</dc:creator>
      <pubDate>Thu, 05 Feb 2026 07:32:36 +0000</pubDate>
      <link>https://dev.to/playfulprogramming/bridging-the-gap-a-deep-dive-into-the-model-context-protocol-mcp-4e0p</link>
      <guid>https://dev.to/playfulprogramming/bridging-the-gap-a-deep-dive-into-the-model-context-protocol-mcp-4e0p</guid>
      <description>&lt;p&gt;In the rapidly evolving world of AI, Large Language Models (LLMs) are only as powerful as the data they can access and the tools they can use. Historically, connecting an AI application to a local database or a specific API required custom, bespoke integration or a lot of manual copy-pasting.&lt;/p&gt;

&lt;p&gt;That changed at the end of 2024, when Anthropic released the &lt;a href="https://www.anthropic.com/news/model-context-protocol" rel="noopener noreferrer"&gt;&lt;strong&gt;Model Context Protocol (MCP)&lt;/strong&gt;&lt;/a&gt; specification. MCP is an open-source standard for connecting AI to external systems, whether it’s browsing local files, querying a database, or triggering complex workflows.&lt;/p&gt;

&lt;p&gt;Let’s start with the basics.&lt;/p&gt;

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

&lt;p&gt;At its core, MCP is an open-source standard that enables AI applications like ChatGPT or Claude to access data sources, tools, and workflows. By providing a unified bridge between the model and the “outside world,” MCP gives AI "superpowers", moving it beyond a simple chat interface and offering users infinite possibilities.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Architecture: Host, Client, and Server
&lt;/h2&gt;

&lt;p&gt;The architecture is elegantly simple, following a client-server model. Applications like VS Code or Claude Desktop are the &lt;strong&gt;MCP Host&lt;/strong&gt; and connects to a local or remote program that exposes data or functionality, the &lt;strong&gt;MCP Server&lt;/strong&gt;. The &lt;strong&gt;MCP Client&lt;/strong&gt; is a dedicated connection within the host for every specific server.&lt;/p&gt;

&lt;p&gt;One of my first experiments was connecting &lt;strong&gt;Jira&lt;/strong&gt; to &lt;strong&gt;GitHub Copilot&lt;/strong&gt; on VSCode (the Host). When VSCode connects to the Jira &lt;strong&gt;MCP server&lt;/strong&gt;, it instantiates an &lt;strong&gt;MCP client&lt;/strong&gt; object to maintain that specific connection. If I then connect to my local filesystem, VSCode simply instantiates additional client objects for those connections.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnj809baqggo3mdggt73l.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnj809baqggo3mdggt73l.jpeg" alt="MCP Architecture infographics" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Two-Layer System
&lt;/h2&gt;

&lt;p&gt;The protocol is split into two distinct layers to handle communication:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Data Layer:&lt;/strong&gt; Defines &lt;em&gt;what&lt;/em&gt; is being said. Based on &lt;a href="https://en.wikipedia.org/wiki/JSON-RPC" rel="noopener noreferrer"&gt;JSON-RPC&lt;/a&gt;, it handles the connection lifecycle and core primitives (tools, resources, and prompts).&lt;br&gt;
&lt;strong&gt;The Transport Layer:&lt;/strong&gt; Defines &lt;em&gt;how&lt;/em&gt; the message gets there.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Stdio Transport:&lt;/strong&gt; Used for local processes on the same machine (e.g., VSCode talking to your local files). It’s lightning-fast with zero network overhead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Streamable HTTP Transport:&lt;/strong&gt; Used for remote servers (e.g., the official Jira MCP server running on the Atlassian platform). It uses HTTP POST and &lt;a href="https://en.wikipedia.org/wiki/Server-sent_events" rel="noopener noreferrer"&gt;Server-Sent Events (SSE)&lt;/a&gt; and supports secure authentication like OAuth.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Building Blocks
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Core Primitives
&lt;/h3&gt;

&lt;p&gt;Once your host is connected to a server, the AI can interact with three main "primitives":&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tools (Executable Functions):&lt;/strong&gt; The AI can actually &lt;em&gt;do&lt;/em&gt; things.

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Example:&lt;/em&gt; &lt;code&gt;create_issue&lt;/code&gt; creates a Jira ticket; &lt;code&gt;add_comment&lt;/code&gt; updates a task.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Resources (Data Sources):&lt;/strong&gt; These provide the context the AI needs.

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Example:&lt;/em&gt; &lt;strong&gt;Project Schemas&lt;/strong&gt; help the AI understand that "Priority Highest" means "Blocker" while &lt;strong&gt;User Profiles&lt;/strong&gt; help it map names to IDs.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Prompts (Templates):&lt;/strong&gt; Reusable instructions that structure the interaction.

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Example:&lt;/em&gt; A &lt;strong&gt;"Bug Reporter" Prompt&lt;/strong&gt; can force the AI to ask for "Steps to Reproduce" before it is allowed to create a ticket.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Server-to-Client Primitives: A Two-Way Street
&lt;/h3&gt;

&lt;p&gt;MCP isn't just a one-way street. Servers can also request help from the Client:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sampling:&lt;/strong&gt; A server can ask the AI Host to complete a task. For instance, a Jira server could say: &lt;em&gt;"Hey, use your language skills to summarise these 10 tickets into a release note paragraph for me."&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Elicitation:&lt;/strong&gt; This allows a server to ask the user for missing info. If the AI tries to create a ticket but doesn't know the project, the server triggers a request: &lt;em&gt;"Which project should this ticket go into?"&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Logging:&lt;/strong&gt; Enables servers to send debug messages to the client for easy monitoring.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Staying Sync
&lt;/h3&gt;

&lt;p&gt;In a dynamic environment, tools and data sources change constantly. MCP handles this through notification system: using &lt;strong&gt;JSON-RPC 2.0&lt;/strong&gt;, a server can "push" updates to the client without waiting for a request.  &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;📖 &lt;a href="https://en.wikipedia.org/wiki/JSON-RPC" rel="noopener noreferrer"&gt;JSON-RPC&lt;/a&gt; (JavaScript Object Notation-Remote Procedure Call) is a JSON-based wire protocol for remote procedure calls (RPC). JSON-RPC allows for notifications (data sent to the server that does not require a response) and for multiple calls to be sent to the server which may be answered asynchronously. &lt;/p&gt;

&lt;p&gt;For more information about JSON-RPC specification click &lt;a href="https://www.jsonrpc.org/specification" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The Notification system is a very important component of the MCP architecture. The client doesn't have to keep asking "Is there anything new?", it just waits to be told. If a database goes offline or a new tool becomes available, the AI knows instantly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;As LLMs become more powerful, their utility depends on context. The MCP specification provides a standardised way to provide that context, making our lives easier. By standardising how models access information and execute tasks, MCP is paving the way for AI tools that are more integrated, more capable, and easier to build than ever before.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PS&lt;/strong&gt;: More and more companies are releasing official MCP servers every day. You can explore the most popular ones on the official &lt;a href="https://github.com/modelcontextprotocol/servers" rel="noopener noreferrer"&gt;Anthropic MCP Gallery&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>ai</category>
      <category>mcp</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
