[{"data":1,"prerenderedAt":1171},["ShallowReactive",2],{"post-\u002Fposts\u002Ffrom-browsing-to-asking-the-web-learns-to-take-action":3},{"id":4,"title":5,"body":6,"contentId":1159,"date":1160,"description":1161,"extension":1162,"meta":1163,"navigation":111,"path":1164,"rawbody":1165,"robots":1166,"schemaOrg":1166,"seo":1167,"sitemap":1168,"stem":1169,"__hash__":1170},"posts\u002Fposts\u002Ffrom-browsing-to-asking-the-web-learns-to-take-action.md","From Browsing to Asking: The Web Learns to Take Action",{"type":7,"value":8,"toc":1152},"minimark",[9,19,22,25,30,33,36,39,42,63,66,70,73,88,91,95,104,122,125,134,137,140,143,147,150,156,164,167,395,412,445,460,470,564,567,916,930,933,942,1109,1120,1124,1127,1130,1133,1136,1139,1148],[10,11,12,13,18],"p",{},"A couple of months ago, I wrote an article titled ",[14,15,17],"a",{"href":16},"\u002Fposts\u002Fai-agents-will-deeply-transform-our-experience-with-the-web","AI Agents Will Deeply Transform Our Experience With the Web",". I shared my vision of how AI agents will radically change our experience with the web. I concluded by saying that a new paradigm would emerge: \"Website as a Search Bar.\" I never really explained what I meant because it was more of a feeling, based on my reading of the ecosystem, than something concrete.",[10,20,21],{},"Since then, a lot has changed, and that idea is now a reality. I never expected the future to arrive so quickly. Things have been moving insanely fast lately.",[10,23,24],{},"In that future, which is already here, we will ask agents to take action, and I already love it.",[26,27,29],"h2",{"id":28},"website-as-a-search-bar","Website as a Search Bar",[10,31,32],{},"Today, we navigate the web. We click links, scroll through pages, fill out forms, and read content. The same used to be true of my work as a software engineer. Since I started using AI agents, that is no longer the case for me. Now, I ask them to take action more often than I perform those actions myself. That new behavior is coming to the web.",[10,34,35],{},"The idea behind \"Website as a Search Bar\" is that a website's main page will simply be a search bar: an input where we can ask for anything we want to do on the website. Behind the scenes, the website will have an agent that acts for us. When I first thought about it, I imagined an MCP server and a server-side agent. The agent would call the MCP server to perform actions, and the UI would intelligently adapt or refresh based on the server's response. That experience is similar to what Notion AI offers today, and it works very well.",[10,37,38],{},"However, a new approach has recently begun to emerge.",[10,40,41],{},"The Chrome team is developing two new APIs that could completely reshape how a website becomes a search bar:",[43,44,45,55],"ol",{},[46,47,48,54],"li",{},[14,49,53],{"href":50,"rel":51},"https:\u002F\u002Fdeveloper.chrome.com\u002Fdocs\u002Fai\u002Fwebmcp",[52],"nofollow","WebMCP",", which lets you build and expose structured tools for AI agents;",[46,56,57,62],{},[14,58,61],{"href":59,"rel":60},"https:\u002F\u002Fdeveloper.chrome.com\u002Fdocs\u002Fai\u002Fprompt-api",[52],"The Prompt API",", which lets you send natural language requests to an LLM in Chrome.",[10,64,65],{},"With both, we can now have client-side agents that perform actions on the web on our behalf. This is mind-blowing.",[26,67,69],{"id":68},"the-future-is-already-here","The future is already here",[10,71,72],{},"Yes, that sounds crazy, I know, but the future is already here.",[10,74,75,76,81,82,87],{},"Both WebMCP and the Prompt API are already available experimentally in Chrome. This is no longer just a discussion, an idea, or a specification: experimental implementations are available and working. You can now create a website that exposes WebMCP tools, and you can ",[14,77,80],{"href":78,"rel":79},"https:\u002F\u002Fdeveloper.chrome.com\u002Fblog\u002Fprompt-api-with-vercel-ai",[52],"chat with an in-browser AI",". ",[14,83,86],{"href":84,"rel":85},"https:\u002F\u002Fblog.cloudflare.com\u002Fwebmcp\u002F#:~:text=You%20do%20not,Copy%20link",[52],"Cloudflare is also experimenting with WebMCP"," through its BrowserRun product, and ChatGPT Desktop supports WebMCP to make browsing the web easier for agents.",[10,89,90],{},"In-browser AI refers to LLMs such as Chrome's Gemini Nano or Google's Gemma models that can run privately and entirely in the browser on your computer. I'm not talking about Codex or Claude connecting to your browser and performing actions by reading the DOM or taking screenshots. I'm talking about an agent whose model can run offline and use dedicated APIs to interact seamlessly with websites.",[26,92,94],{"id":93},"ask-for-actions","Ask for actions",[10,96,97,98,103],{},"To make the idea more concrete, I built a small demo showing how it works. At first, my goal was simply to explore and use WebMCP. It turned into something bigger than I expected because, apart from ",[14,99,102],{"href":100,"rel":101},"https:\u002F\u002Fchromewebstore.google.com\u002Fdetail\u002Fwebmcp-model-context-tool\u002Fgbpdfapgefenggkahomfgkhfehlcenpd?pli=1",[52],"a test browser extension",", I couldn't find any other tool for testing it.",[105,106,107,108,107,118],"figure",{},"\n  ",[109,110,112,113,107],"video",{"autoPlay":111,"loop":111,"muted":111,"playsInline":111},true,"\n    ",[114,115],"source",{"src":116,"type":117},"https:\u002F\u002Fimages.soubiran.dev\u002Fposts\u002Ffrom-browsing-to-asking-the-web-learns-to-take-action\u002Fdemo.mp4","video\u002Fmp4",[119,120,121],"figcaption",{},"Demo of the in-browser AI assistant performing actions on the website.",[10,123,124],{},"What did you just see?",[10,126,127,128,133],{},"We are using ",[14,129,132],{"href":130,"rel":131},"https:\u002F\u002Fcode.soubiran.dev",[52],"code",", my tool for turning raw code into beautiful, shareable images. You paste a code snippet, select the language and background color, and capture it as an image. Then, you can share it with anyone on social media.",[10,135,136],{},"Normally, the user performs all the actions I've described manually.",[10,138,139],{},"The agent edits the code using the prompt provided, changes the settings, and finally takes a screenshot of the result. In the end, that is nothing more than what a human can do, but a local agent performs all those actions. That is the real change, and that is the future.",[10,141,142],{},"I know that this demo is useless. However, it gives you a concrete idea of this new paradigm. Everything, from the interface to the experience, still has to be invented and designed.",[26,144,146],{"id":145},"two-apis-to-make-it-happen","Two APIs to make it happen",[10,148,149],{},"If this is the future, we should take a closer look at the two APIs that make it possible. I have good news for you: on the surface, they are dead simple. However, the new doors they open make using them more complex than they initially seem.",[10,151,152,155],{},[14,153,53],{"href":50,"rel":154},[52]," comes in two forms:",[43,157,158,161],{},[46,159,160],{},"An imperative API for defining tools using JavaScript;",[46,162,163],{},"A declarative API for defining tools using HTML annotations.",[10,165,166],{},"The first is similar to the way an MCP server defines tools.",[168,169,174],"pre",{"className":170,"code":171,"language":172,"meta":173,"style":173},"language-typescript shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","await document.modelContext.registerTool({\n  name: 'performAction',\n  description: 'Perform an action on the page.',\n  inputSchema: {\n    type: 'object',\n    properties: {\n      input: { type: 'string' },\n    },\n    required: ['input'],\n  },\n  execute: async ({ input }) => {\n    \u002F\u002F Add the logic to perform the action here\n  },\n})\n","typescript","",[132,175,176,208,231,248,259,276,286,312,318,341,347,374,381,386],{"__ignoreMap":173},[177,178,181,185,189,193,196,198,202,205],"span",{"class":179,"line":180},"line",1,[177,182,184],{"class":183},"s7zQu","await",[177,186,188],{"class":187},"sTEyZ"," document",[177,190,192],{"class":191},"sMK4o",".",[177,194,195],{"class":187},"modelContext",[177,197,192],{"class":191},[177,199,201],{"class":200},"s2Zo4","registerTool",[177,203,204],{"class":187},"(",[177,206,207],{"class":191},"{\n",[177,209,211,215,218,221,225,228],{"class":179,"line":210},2,[177,212,214],{"class":213},"swJcz","  name",[177,216,217],{"class":191},":",[177,219,220],{"class":191}," '",[177,222,224],{"class":223},"sfazB","performAction",[177,226,227],{"class":191},"'",[177,229,230],{"class":191},",\n",[177,232,234,237,239,241,244,246],{"class":179,"line":233},3,[177,235,236],{"class":213},"  description",[177,238,217],{"class":191},[177,240,220],{"class":191},[177,242,243],{"class":223},"Perform an action on the page.",[177,245,227],{"class":191},[177,247,230],{"class":191},[177,249,251,254,256],{"class":179,"line":250},4,[177,252,253],{"class":213},"  inputSchema",[177,255,217],{"class":191},[177,257,258],{"class":191}," {\n",[177,260,262,265,267,269,272,274],{"class":179,"line":261},5,[177,263,264],{"class":213},"    type",[177,266,217],{"class":191},[177,268,220],{"class":191},[177,270,271],{"class":223},"object",[177,273,227],{"class":191},[177,275,230],{"class":191},[177,277,279,282,284],{"class":179,"line":278},6,[177,280,281],{"class":213},"    properties",[177,283,217],{"class":191},[177,285,258],{"class":191},[177,287,289,292,294,297,300,302,304,307,309],{"class":179,"line":288},7,[177,290,291],{"class":213},"      input",[177,293,217],{"class":191},[177,295,296],{"class":191}," {",[177,298,299],{"class":213}," type",[177,301,217],{"class":191},[177,303,220],{"class":191},[177,305,306],{"class":223},"string",[177,308,227],{"class":191},[177,310,311],{"class":191}," },\n",[177,313,315],{"class":179,"line":314},8,[177,316,317],{"class":191},"    },\n",[177,319,321,324,326,329,331,334,336,339],{"class":179,"line":320},9,[177,322,323],{"class":213},"    required",[177,325,217],{"class":191},[177,327,328],{"class":187}," [",[177,330,227],{"class":191},[177,332,333],{"class":223},"input",[177,335,227],{"class":191},[177,337,338],{"class":187},"]",[177,340,230],{"class":191},[177,342,344],{"class":179,"line":343},10,[177,345,346],{"class":191},"  },\n",[177,348,350,353,355,359,362,366,369,372],{"class":179,"line":349},11,[177,351,352],{"class":200},"  execute",[177,354,217],{"class":191},[177,356,358],{"class":357},"spNyl"," async",[177,360,361],{"class":191}," ({",[177,363,365],{"class":364},"sHdIc"," input",[177,367,368],{"class":191}," })",[177,370,371],{"class":357}," =>",[177,373,258],{"class":191},[177,375,377],{"class":179,"line":376},12,[177,378,380],{"class":379},"sHwdD","    \u002F\u002F Add the logic to perform the action here\n",[177,382,384],{"class":179,"line":383},13,[177,385,346],{"class":191},[177,387,389,392],{"class":179,"line":388},14,[177,390,391],{"class":191},"}",[177,393,394],{"class":187},")\n",[10,396,397,398,401,402,404,405,407,408,411],{},"The ",[132,399,400],{},"document"," gets a new property called ",[132,403,195],{},", which is the entry point for creating and registering tools on the current page. Agents using your site need to know which tools are available, so ",[132,406,195],{}," exposes a ",[132,409,410],{},"getTools()"," method that returns the list of tools available on the page.",[168,413,415],{"className":170,"code":414,"language":172,"meta":173,"style":173},"const tools = await document.modelContext.getTools()\n",[132,416,417],{"__ignoreMap":173},[177,418,419,422,425,428,431,433,435,437,439,442],{"class":179,"line":180},[177,420,421],{"class":357},"const",[177,423,424],{"class":187}," tools ",[177,426,427],{"class":191},"=",[177,429,430],{"class":183}," await",[177,432,188],{"class":187},[177,434,192],{"class":191},[177,436,195],{"class":187},[177,438,192],{"class":191},[177,440,441],{"class":200},"getTools",[177,443,444],{"class":187},"()\n",[10,446,447,448,451,452,459],{},"This is similar to the ",[132,449,450],{},"listTools()"," method exposed by ",[14,453,456],{"href":454,"rel":455},"https:\u002F\u002Fai-sdk.dev\u002Fdocs\u002Freference\u002Fai-sdk-core\u002Fcreate-mcp-client",[52],[132,457,458],{},"createMCPClient()"," in the AI SDK. It can be a little confusing because, in the browser, we act as both the server by registering tools and the client by accessing them. That is because your website is not necessarily the consumer of those tools.",[10,461,462,463,466,467,469],{},"You can also execute a tool using the ",[132,464,465],{},"executeTool()"," method of the ",[132,468,195],{}," object.",[168,471,473],{"className":170,"code":472,"language":172,"meta":173,"style":173},"const [tool] = await document.modelContext.getTools()\n\nawait document.modelContext.executeTool(tool, JSON.stringify({\n  input: '...',\n}))\n",[132,474,475,503,508,541,557],{"__ignoreMap":173},[177,476,477,479,481,484,486,489,491,493,495,497,499,501],{"class":179,"line":180},[177,478,421],{"class":357},[177,480,328],{"class":191},[177,482,483],{"class":187},"tool",[177,485,338],{"class":191},[177,487,488],{"class":191}," =",[177,490,430],{"class":183},[177,492,188],{"class":187},[177,494,192],{"class":191},[177,496,195],{"class":187},[177,498,192],{"class":191},[177,500,441],{"class":200},[177,502,444],{"class":187},[177,504,505],{"class":179,"line":210},[177,506,507],{"emptyLinePlaceholder":111},"\n",[177,509,510,512,514,516,518,520,523,526,529,532,534,537,539],{"class":179,"line":233},[177,511,184],{"class":183},[177,513,188],{"class":187},[177,515,192],{"class":191},[177,517,195],{"class":187},[177,519,192],{"class":191},[177,521,522],{"class":200},"executeTool",[177,524,525],{"class":187},"(tool",[177,527,528],{"class":191},",",[177,530,531],{"class":187}," JSON",[177,533,192],{"class":191},[177,535,536],{"class":200},"stringify",[177,538,204],{"class":187},[177,540,207],{"class":191},[177,542,543,546,548,550,553,555],{"class":179,"line":250},[177,544,545],{"class":213},"  input",[177,547,217],{"class":191},[177,549,220],{"class":191},[177,551,552],{"class":223},"...",[177,554,227],{"class":191},[177,556,230],{"class":191},[177,558,559,561],{"class":179,"line":261},[177,560,391],{"class":191},[177,562,563],{"class":187},"))\n",[10,565,566],{},"The second is the declarative API, which lets you define tools using HTML annotations. It is primarily designed for forms:",[168,568,572],{"className":569,"code":570,"language":571,"meta":173,"style":173},"language-html shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u003Cform toolname=\"supportRequestTool\"\n  tooldescription=\"Submit a request for support.\"\n  action=\"\u002Fsubmit\">\n\n  \u003Clabel for=\"firstName\">First Name\u003C\u002Flabel>\n  \u003Cinput type=text name=firstName>\n\n  \u003Clabel for=\"lastName\">Last Name\u003C\u002Flabel>\n  \u003Cinput type=text name=lastName>\n\n  \u003Cselect name=\"select\" required\n    toolparamdescription=\"Determines what team this request is routed to.\">\n    \u003Coption value=\"Customer happiness team\">Return my purchase.\u003C\u002Foption>\n    \u003Coption value=\"Distribution team\">Check where my package is.\u003C\u002Foption>\n    \u003Coption value=\"Website support team\">Get help on the website.\u003C\u002Foption>\n  \u003C\u002Fselect>\n\n  \u003Cbutton type=submit>Submit\u003C\u002Fbutton>\n\u003C\u002Fform>\n","html",[132,573,574,596,610,627,631,664,686,690,718,738,742,762,778,809,837,866,876,881,907],{"__ignoreMap":173},[177,575,576,579,582,585,587,590,593],{"class":179,"line":180},[177,577,578],{"class":191},"\u003C",[177,580,581],{"class":213},"form",[177,583,584],{"class":357}," toolname",[177,586,427],{"class":191},[177,588,589],{"class":191},"\"",[177,591,592],{"class":223},"supportRequestTool",[177,594,595],{"class":191},"\"\n",[177,597,598,601,603,605,608],{"class":179,"line":210},[177,599,600],{"class":357},"  tooldescription",[177,602,427],{"class":191},[177,604,589],{"class":191},[177,606,607],{"class":223},"Submit a request for support.",[177,609,595],{"class":191},[177,611,612,615,617,619,622,624],{"class":179,"line":233},[177,613,614],{"class":357},"  action",[177,616,427],{"class":191},[177,618,589],{"class":191},[177,620,621],{"class":223},"\u002Fsubmit",[177,623,589],{"class":191},[177,625,626],{"class":191},">\n",[177,628,629],{"class":179,"line":250},[177,630,507],{"emptyLinePlaceholder":111},[177,632,633,636,639,642,644,646,649,651,654,657,660,662],{"class":179,"line":261},[177,634,635],{"class":191},"  \u003C",[177,637,638],{"class":213},"label",[177,640,641],{"class":357}," for",[177,643,427],{"class":191},[177,645,589],{"class":191},[177,647,648],{"class":223},"firstName",[177,650,589],{"class":191},[177,652,653],{"class":191},">",[177,655,656],{"class":187},"First Name",[177,658,659],{"class":191},"\u003C\u002F",[177,661,638],{"class":213},[177,663,626],{"class":191},[177,665,666,668,670,672,674,677,680,682,684],{"class":179,"line":278},[177,667,635],{"class":191},[177,669,333],{"class":213},[177,671,299],{"class":357},[177,673,427],{"class":191},[177,675,676],{"class":223},"text",[177,678,679],{"class":357}," name",[177,681,427],{"class":191},[177,683,648],{"class":223},[177,685,626],{"class":191},[177,687,688],{"class":179,"line":288},[177,689,507],{"emptyLinePlaceholder":111},[177,691,692,694,696,698,700,702,705,707,709,712,714,716],{"class":179,"line":314},[177,693,635],{"class":191},[177,695,638],{"class":213},[177,697,641],{"class":357},[177,699,427],{"class":191},[177,701,589],{"class":191},[177,703,704],{"class":223},"lastName",[177,706,589],{"class":191},[177,708,653],{"class":191},[177,710,711],{"class":187},"Last Name",[177,713,659],{"class":191},[177,715,638],{"class":213},[177,717,626],{"class":191},[177,719,720,722,724,726,728,730,732,734,736],{"class":179,"line":320},[177,721,635],{"class":191},[177,723,333],{"class":213},[177,725,299],{"class":357},[177,727,427],{"class":191},[177,729,676],{"class":223},[177,731,679],{"class":357},[177,733,427],{"class":191},[177,735,704],{"class":223},[177,737,626],{"class":191},[177,739,740],{"class":179,"line":343},[177,741,507],{"emptyLinePlaceholder":111},[177,743,744,746,749,751,753,755,757,759],{"class":179,"line":349},[177,745,635],{"class":191},[177,747,748],{"class":213},"select",[177,750,679],{"class":357},[177,752,427],{"class":191},[177,754,589],{"class":191},[177,756,748],{"class":223},[177,758,589],{"class":191},[177,760,761],{"class":357}," required\n",[177,763,764,767,769,771,774,776],{"class":179,"line":376},[177,765,766],{"class":357},"    toolparamdescription",[177,768,427],{"class":191},[177,770,589],{"class":191},[177,772,773],{"class":223},"Determines what team this request is routed to.",[177,775,589],{"class":191},[177,777,626],{"class":191},[177,779,780,783,786,789,791,793,796,798,800,803,805,807],{"class":179,"line":383},[177,781,782],{"class":191},"    \u003C",[177,784,785],{"class":213},"option",[177,787,788],{"class":357}," value",[177,790,427],{"class":191},[177,792,589],{"class":191},[177,794,795],{"class":223},"Customer happiness team",[177,797,589],{"class":191},[177,799,653],{"class":191},[177,801,802],{"class":187},"Return my purchase.",[177,804,659],{"class":191},[177,806,785],{"class":213},[177,808,626],{"class":191},[177,810,811,813,815,817,819,821,824,826,828,831,833,835],{"class":179,"line":388},[177,812,782],{"class":191},[177,814,785],{"class":213},[177,816,788],{"class":357},[177,818,427],{"class":191},[177,820,589],{"class":191},[177,822,823],{"class":223},"Distribution team",[177,825,589],{"class":191},[177,827,653],{"class":191},[177,829,830],{"class":187},"Check where my package is.",[177,832,659],{"class":191},[177,834,785],{"class":213},[177,836,626],{"class":191},[177,838,840,842,844,846,848,850,853,855,857,860,862,864],{"class":179,"line":839},15,[177,841,782],{"class":191},[177,843,785],{"class":213},[177,845,788],{"class":357},[177,847,427],{"class":191},[177,849,589],{"class":191},[177,851,852],{"class":223},"Website support team",[177,854,589],{"class":191},[177,856,653],{"class":191},[177,858,859],{"class":187},"Get help on the website.",[177,861,659],{"class":191},[177,863,785],{"class":213},[177,865,626],{"class":191},[177,867,869,872,874],{"class":179,"line":868},16,[177,870,871],{"class":191},"  \u003C\u002F",[177,873,748],{"class":213},[177,875,626],{"class":191},[177,877,879],{"class":179,"line":878},17,[177,880,507],{"emptyLinePlaceholder":111},[177,882,884,886,889,891,893,896,898,901,903,905],{"class":179,"line":883},18,[177,885,635],{"class":191},[177,887,888],{"class":213},"button",[177,890,299],{"class":357},[177,892,427],{"class":191},[177,894,895],{"class":223},"submit",[177,897,653],{"class":191},[177,899,900],{"class":187},"Submit",[177,902,659],{"class":191},[177,904,888],{"class":213},[177,906,626],{"class":191},[177,908,910,912,914],{"class":179,"line":909},19,[177,911,659],{"class":191},[177,913,581],{"class":213},[177,915,626],{"class":191},[917,918,919],"blockquote",{},[10,920,921,924,925,192],{},[177,922,923],{},"!NOTE","\nExample from the ",[14,926,929],{"href":927,"rel":928},"https:\u002F\u002Fdeveloper.chrome.com\u002Fdocs\u002Fai\u002Fwebmcp\u002Fdeclarative-api",[52],"WebMCP Declarative API documentation",[10,931,932],{},"Then comes the Prompt API. It is more complicated because it requires more availability and lifecycle management. For example, you need to detect whether the in-browser LLM is available. If it isn't, you need to know why. Maybe the device is incompatible, or the LLM hasn't been downloaded yet. If it can be downloaded, you have to tell the browser to download it, which can take a while. You therefore need to inform the user that something is happening in the background. On top of that, the API exposes low-level primitives that you probably don't want to deal with directly.",[10,934,935,936,941],{},"That is more work than calling an API. The good news is that a community provider called ",[14,937,940],{"href":938,"rel":939},"https:\u002F\u002Fai-sdk.dev\u002Fproviders\u002Fcommunity-providers\u002Fbrowser-ai",[52],"Browser AI"," makes the Prompt API easier to use with the AI SDK.",[168,943,945],{"className":170,"code":944,"language":172,"meta":173,"style":173},"import { browserAI } from '@browser-ai\u002Fcore'\nimport { streamText } from 'ai'\n\nconst model = browserAI()\n\nconst { textStream } = streamText({\n  model,\n  prompt: 'Describe the future of the web in five sentences.',\n})\n\nfor await (const textPart of textStream) {\n  console.log(textPart)\n}\n",[132,946,947,971,991,995,1008,1012,1031,1038,1054,1060,1064,1087,1104],{"__ignoreMap":173},[177,948,949,952,954,957,960,963,965,968],{"class":179,"line":180},[177,950,951],{"class":183},"import",[177,953,296],{"class":191},[177,955,956],{"class":187}," browserAI",[177,958,959],{"class":191}," }",[177,961,962],{"class":183}," from",[177,964,220],{"class":191},[177,966,967],{"class":223},"@browser-ai\u002Fcore",[177,969,970],{"class":191},"'\n",[177,972,973,975,977,980,982,984,986,989],{"class":179,"line":210},[177,974,951],{"class":183},[177,976,296],{"class":191},[177,978,979],{"class":187}," streamText",[177,981,959],{"class":191},[177,983,962],{"class":183},[177,985,220],{"class":191},[177,987,988],{"class":223},"ai",[177,990,970],{"class":191},[177,992,993],{"class":179,"line":233},[177,994,507],{"emptyLinePlaceholder":111},[177,996,997,999,1002,1004,1006],{"class":179,"line":250},[177,998,421],{"class":357},[177,1000,1001],{"class":187}," model ",[177,1003,427],{"class":191},[177,1005,956],{"class":200},[177,1007,444],{"class":187},[177,1009,1010],{"class":179,"line":261},[177,1011,507],{"emptyLinePlaceholder":111},[177,1013,1014,1016,1018,1021,1023,1025,1027,1029],{"class":179,"line":278},[177,1015,421],{"class":357},[177,1017,296],{"class":191},[177,1019,1020],{"class":187}," textStream ",[177,1022,391],{"class":191},[177,1024,488],{"class":191},[177,1026,979],{"class":200},[177,1028,204],{"class":187},[177,1030,207],{"class":191},[177,1032,1033,1036],{"class":179,"line":288},[177,1034,1035],{"class":187},"  model",[177,1037,230],{"class":191},[177,1039,1040,1043,1045,1047,1050,1052],{"class":179,"line":314},[177,1041,1042],{"class":213},"  prompt",[177,1044,217],{"class":191},[177,1046,220],{"class":191},[177,1048,1049],{"class":223},"Describe the future of the web in five sentences.",[177,1051,227],{"class":191},[177,1053,230],{"class":191},[177,1055,1056,1058],{"class":179,"line":320},[177,1057,391],{"class":191},[177,1059,394],{"class":187},[177,1061,1062],{"class":179,"line":343},[177,1063,507],{"emptyLinePlaceholder":111},[177,1065,1066,1069,1071,1074,1076,1079,1082,1085],{"class":179,"line":349},[177,1067,1068],{"class":183},"for",[177,1070,430],{"class":183},[177,1072,1073],{"class":187}," (",[177,1075,421],{"class":357},[177,1077,1078],{"class":187}," textPart ",[177,1080,1081],{"class":191},"of",[177,1083,1084],{"class":187}," textStream) ",[177,1086,207],{"class":191},[177,1088,1089,1092,1094,1097,1099,1102],{"class":179,"line":376},[177,1090,1091],{"class":187},"  console",[177,1093,192],{"class":191},[177,1095,1096],{"class":200},"log",[177,1098,204],{"class":213},[177,1100,1101],{"class":187},"textPart",[177,1103,394],{"class":213},[177,1105,1106],{"class":179,"line":383},[177,1107,1108],{"class":191},"}\n",[917,1110,1111],{},[10,1112,1113,1115,1116,192],{},[177,1114,923],{},"\nI highly recommend reading the article ",[14,1117,1119],{"href":78,"rel":1118},[52],"Use the built-in Prompt API with the Vercel AI SDK",[26,1121,1123],{"id":1122},"thats-only-the-beginning","That's only the beginning",[10,1125,1126],{},"For now, even though you can already test both APIs, they remain experimental and have limited browser support. This means that most people won't be able to use them. They still need to be standardized and adopted by other browser vendors, such as Mozilla and Apple.",[10,1128,1129],{},"Also, in-browser models are limited, especially compared with state-of-the-art models. They can answer questions and call tools, but you have to keep both the instructions and tool parameters simple, really simple.",[10,1131,1132],{},"They will inevitably become smarter and smarter. Recently, Qwen released Qwen3.8-27B, a model that can run on some consumer devices. Google is also making significant progress with its Gemma series of models, which are designed to run on-device. Devices are becoming more powerful and better able to run these models. Apple's M-series SoCs include a Neural Engine, or NPU, and Google has done the same with its Tensor SoCs. The latest version of Siri also performs AI work on-device, and it seems really powerful. Now, it is only a matter of time.",[10,1134,1135],{},"Finally, when all of this is standardized and mature, having everything ready to use will give you a competitive advantage.",[1137,1138],"hr",{},[10,1140,1141,1142,1147],{},"While I was writing this article, OpenAI announced a ",[14,1143,1146],{"href":1144,"rel":1145},"https:\u002F\u002Fopenai.com\u002Fwebmcp-challenge\u002F",[52],"WebMCP challenge"," to explore what is possible. It looks like I'm heading in the right direction.",[1149,1150,1151],"style",{},"html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":173,"searchDepth":210,"depth":210,"links":1153},[1154,1155,1156,1157,1158],{"id":28,"depth":210,"text":29},{"id":68,"depth":210,"text":69},{"id":93,"depth":210,"text":94},{"id":145,"depth":210,"text":146},{"id":1122,"depth":210,"text":1123},"b3613556-823c-4765-820b-142659321461","2026-08-28","WebMCP and Chrome's Prompt API are bringing client-side AI agents to the web, letting users ask websites to take action on their behalf.","md",{},"\u002Fposts\u002Ffrom-browsing-to-asking-the-web-learns-to-take-action","---\ncontentId: b3613556-823c-4765-820b-142659321461\ntitle: \"From Browsing to Asking: The Web Learns to Take Action\"\ndescription: WebMCP and Chrome's Prompt API are bringing client-side AI agents to the web, letting users ask websites to take action on their behalf.\ndate: 2026-08-28\n---\n\nA couple of months ago, I wrote an article titled [AI Agents Will Deeply Transform Our Experience With the Web](\u002Fposts\u002Fai-agents-will-deeply-transform-our-experience-with-the-web). I shared my vision of how AI agents will radically change our experience with the web. I concluded by saying that a new paradigm would emerge: \"Website as a Search Bar.\" I never really explained what I meant because it was more of a feeling, based on my reading of the ecosystem, than something concrete.\n\nSince then, a lot has changed, and that idea is now a reality. I never expected the future to arrive so quickly. Things have been moving insanely fast lately.\n\nIn that future, which is already here, we will ask agents to take action, and I already love it.\n\n## Website as a Search Bar\n\nToday, we navigate the web. We click links, scroll through pages, fill out forms, and read content. The same used to be true of my work as a software engineer. Since I started using AI agents, that is no longer the case for me. Now, I ask them to take action more often than I perform those actions myself. That new behavior is coming to the web.\n\nThe idea behind \"Website as a Search Bar\" is that a website's main page will simply be a search bar: an input where we can ask for anything we want to do on the website. Behind the scenes, the website will have an agent that acts for us. When I first thought about it, I imagined an MCP server and a server-side agent. The agent would call the MCP server to perform actions, and the UI would intelligently adapt or refresh based on the server's response. That experience is similar to what Notion AI offers today, and it works very well.\n\nHowever, a new approach has recently begun to emerge.\n\nThe Chrome team is developing two new APIs that could completely reshape how a website becomes a search bar:\n\n1. [WebMCP](https:\u002F\u002Fdeveloper.chrome.com\u002Fdocs\u002Fai\u002Fwebmcp), which lets you build and expose structured tools for AI agents;\n2. [The Prompt API](https:\u002F\u002Fdeveloper.chrome.com\u002Fdocs\u002Fai\u002Fprompt-api), which lets you send natural language requests to an LLM in Chrome.\n\nWith both, we can now have client-side agents that perform actions on the web on our behalf. This is mind-blowing.\n\n## The future is already here\n\nYes, that sounds crazy, I know, but the future is already here.\n\nBoth WebMCP and the Prompt API are already available experimentally in Chrome. This is no longer just a discussion, an idea, or a specification: experimental implementations are available and working. You can now create a website that exposes WebMCP tools, and you can [chat with an in-browser AI](https:\u002F\u002Fdeveloper.chrome.com\u002Fblog\u002Fprompt-api-with-vercel-ai). [Cloudflare is also experimenting with WebMCP](https:\u002F\u002Fblog.cloudflare.com\u002Fwebmcp\u002F#:~:text=You%20do%20not,Copy%20link) through its BrowserRun product, and ChatGPT Desktop supports WebMCP to make browsing the web easier for agents.\n\nIn-browser AI refers to LLMs such as Chrome's Gemini Nano or Google's Gemma models that can run privately and entirely in the browser on your computer. I'm not talking about Codex or Claude connecting to your browser and performing actions by reading the DOM or taking screenshots. I'm talking about an agent whose model can run offline and use dedicated APIs to interact seamlessly with websites.\n\n## Ask for actions\n\nTo make the idea more concrete, I built a small demo showing how it works. At first, my goal was simply to explore and use WebMCP. It turned into something bigger than I expected because, apart from [a test browser extension](https:\u002F\u002Fchromewebstore.google.com\u002Fdetail\u002Fwebmcp-model-context-tool\u002Fgbpdfapgefenggkahomfgkhfehlcenpd?pli=1), I couldn't find any other tool for testing it.\n\n\u003Cfigure>\n  \u003Cvideo autoplay loop muted playsinline>\n    \u003Csource src=\"https:\u002F\u002Fimages.soubiran.dev\u002Fposts\u002Ffrom-browsing-to-asking-the-web-learns-to-take-action\u002Fdemo.mp4\" type=\"video\u002Fmp4\">\n  \u003C\u002Fvideo>\n  \u003Cfigcaption>Demo of the in-browser AI assistant performing actions on the website.\u003C\u002Ffigcaption>\n\u003C\u002Ffigure>\n\nWhat did you just see?\n\nWe are using [code](https:\u002F\u002Fcode.soubiran.dev), my tool for turning raw code into beautiful, shareable images. You paste a code snippet, select the language and background color, and capture it as an image. Then, you can share it with anyone on social media.\n\nNormally, the user performs all the actions I've described manually.\n\nThe agent edits the code using the prompt provided, changes the settings, and finally takes a screenshot of the result. In the end, that is nothing more than what a human can do, but a local agent performs all those actions. That is the real change, and that is the future.\n\nI know that this demo is useless. However, it gives you a concrete idea of this new paradigm. Everything, from the interface to the experience, still has to be invented and designed.\n\n## Two APIs to make it happen\n\nIf this is the future, we should take a closer look at the two APIs that make it possible. I have good news for you: on the surface, they are dead simple. However, the new doors they open make using them more complex than they initially seem.\n\n[WebMCP](https:\u002F\u002Fdeveloper.chrome.com\u002Fdocs\u002Fai\u002Fwebmcp) comes in two forms:\n\n1. An imperative API for defining tools using JavaScript;\n2. A declarative API for defining tools using HTML annotations.\n\nThe first is similar to the way an MCP server defines tools.\n\n```typescript\nawait document.modelContext.registerTool({\n  name: 'performAction',\n  description: 'Perform an action on the page.',\n  inputSchema: {\n    type: 'object',\n    properties: {\n      input: { type: 'string' },\n    },\n    required: ['input'],\n  },\n  execute: async ({ input }) => {\n    \u002F\u002F Add the logic to perform the action here\n  },\n})\n```\n\nThe `document` gets a new property called `modelContext`, which is the entry point for creating and registering tools on the current page. Agents using your site need to know which tools are available, so `modelContext` exposes a `getTools()` method that returns the list of tools available on the page.\n\n```typescript\nconst tools = await document.modelContext.getTools()\n```\n\nThis is similar to the `listTools()` method exposed by [`createMCPClient()`](https:\u002F\u002Fai-sdk.dev\u002Fdocs\u002Freference\u002Fai-sdk-core\u002Fcreate-mcp-client) in the AI SDK. It can be a little confusing because, in the browser, we act as both the server by registering tools and the client by accessing them. That is because your website is not necessarily the consumer of those tools.\n\nYou can also execute a tool using the `executeTool()` method of the `modelContext` object.\n\n```typescript\nconst [tool] = await document.modelContext.getTools()\n\nawait document.modelContext.executeTool(tool, JSON.stringify({\n  input: '...',\n}))\n```\n\nThe second is the declarative API, which lets you define tools using HTML annotations. It is primarily designed for forms:\n\n```html\n\u003Cform toolname=\"supportRequestTool\"\n  tooldescription=\"Submit a request for support.\"\n  action=\"\u002Fsubmit\">\n\n  \u003Clabel for=\"firstName\">First Name\u003C\u002Flabel>\n  \u003Cinput type=text name=firstName>\n\n  \u003Clabel for=\"lastName\">Last Name\u003C\u002Flabel>\n  \u003Cinput type=text name=lastName>\n\n  \u003Cselect name=\"select\" required\n    toolparamdescription=\"Determines what team this request is routed to.\">\n    \u003Coption value=\"Customer happiness team\">Return my purchase.\u003C\u002Foption>\n    \u003Coption value=\"Distribution team\">Check where my package is.\u003C\u002Foption>\n    \u003Coption value=\"Website support team\">Get help on the website.\u003C\u002Foption>\n  \u003C\u002Fselect>\n\n  \u003Cbutton type=submit>Submit\u003C\u002Fbutton>\n\u003C\u002Fform>\n```\n\n> [!NOTE]\n> Example from the [WebMCP Declarative API documentation](https:\u002F\u002Fdeveloper.chrome.com\u002Fdocs\u002Fai\u002Fwebmcp\u002Fdeclarative-api).\n\nThen comes the Prompt API. It is more complicated because it requires more availability and lifecycle management. For example, you need to detect whether the in-browser LLM is available. If it isn't, you need to know why. Maybe the device is incompatible, or the LLM hasn't been downloaded yet. If it can be downloaded, you have to tell the browser to download it, which can take a while. You therefore need to inform the user that something is happening in the background. On top of that, the API exposes low-level primitives that you probably don't want to deal with directly.\n\nThat is more work than calling an API. The good news is that a community provider called [Browser AI](https:\u002F\u002Fai-sdk.dev\u002Fproviders\u002Fcommunity-providers\u002Fbrowser-ai) makes the Prompt API easier to use with the AI SDK.\n\n```typescript\nimport { browserAI } from '@browser-ai\u002Fcore'\nimport { streamText } from 'ai'\n\nconst model = browserAI()\n\nconst { textStream } = streamText({\n  model,\n  prompt: 'Describe the future of the web in five sentences.',\n})\n\nfor await (const textPart of textStream) {\n  console.log(textPart)\n}\n```\n\n> [!NOTE]\n> I highly recommend reading the article [Use the built-in Prompt API with the Vercel AI SDK](https:\u002F\u002Fdeveloper.chrome.com\u002Fblog\u002Fprompt-api-with-vercel-ai).\n\n## That's only the beginning\n\nFor now, even though you can already test both APIs, they remain experimental and have limited browser support. This means that most people won't be able to use them. They still need to be standardized and adopted by other browser vendors, such as Mozilla and Apple.\n\nAlso, in-browser models are limited, especially compared with state-of-the-art models. They can answer questions and call tools, but you have to keep both the instructions and tool parameters simple, really simple.\n\nThey will inevitably become smarter and smarter. Recently, Qwen released Qwen3.8-27B, a model that can run on some consumer devices. Google is also making significant progress with its Gemma series of models, which are designed to run on-device. Devices are becoming more powerful and better able to run these models. Apple's M-series SoCs include a Neural Engine, or NPU, and Google has done the same with its Tensor SoCs. The latest version of Siri also performs AI work on-device, and it seems really powerful. Now, it is only a matter of time.\n\nFinally, when all of this is standardized and mature, having everything ready to use will give you a competitive advantage.\n\n---\n\nWhile I was writing this article, OpenAI announced a [WebMCP challenge](https:\u002F\u002Fopenai.com\u002Fwebmcp-challenge\u002F) to explore what is possible. It looks like I'm heading in the right direction.\n",null,{"title":5,"description":1161},{"loc":1164},"posts\u002Ffrom-browsing-to-asking-the-web-learns-to-take-action","NbBqeCP5zVJdevnMFtQX7Dha_0D696XVqulhOJn5BFw",1790086899658]