feat: carry tool provenance, watch for capabilities, adopt today's spec changes - #12
Merged
Conversation
…ec changes Three gaps, and an upstream change the tracking caught while closing them. Tool provenance. RegisteredTool.origin is not cosmetic, and an earlier note here calling it a non-signal was wrong: the specification says it "is only meaningful when the tool is cross-origin", which is exactly the case Webby cannot otherwise see. A frame can expose tools into a page via exposedTo, so dropping it meant a third party's tool reaching an MCP client attributed to the page that merely embedded it. It is now carried and sanitized -- only a well-formed http/https origin with no path, query, or fragment is stored -- and the dashboard badges any tool whose origin differs from its page. title is carried alongside it. getTools() is still called without fromOrigins, deliberately: restricting to same-origin would silently drop tools a page meant to expose. Carrying the origin makes that visible instead of hidden. Capability watches. github_file_symbol inverts the usual question, asking whether a symbol has arrived rather than whether a file changed, so an API Webby depends on but upstream had not defined is watched directly. chrome_status tracks Chrome's shipping status. The executeTool watch fired on its first run. Upstream specified it the same day (webmachinelearning/webmcp#226), with the signature Webby already called, {signal} included. #241 also changed RegisteredTool.inputSchema from DOMString to object; Webby accepted both already. Both are reviewed and adopted here, and the comments claiming executeTool was unspecified are corrected -- they would now mislead. Chrome Status cannot answer the origin-trial question that was asked of it: its WebMCP entry reports status Proposed with origintrial false and no milestones, contradicting the spec repo's implementation-status.md, which cites a live trial in Chrome 149. It is tracked for the transition to a shipped status, and the docs say plainly that expiry is not available there. Two bugs found while building this. Req decodes on content-type, so chromestatus's )]}' guard prefix failed before the handler ran; the body is now fetched raw. And raw_headers rebuilt the header list positionally, dropping the authorization header along with the accept it meant to replace -- invisible until a token was present, which is every CI run. test/support.js centralizes the normalized tool shape. Two field additions in a row have meant rewriting every assertion by hand, which is how a suite ends up pinning a shape nobody chose.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes the three gaps listed at the end of #11. One of them resolved itself upstream while this branch was being written, and the tracking is what caught it.
executeTool()was specified todayThe watch added in this PR fired on its first real run. Upstream landed three commits on 2026-08-14:
executeTool()APIRegisteredTool.inputSchema:DOMString→objectexposedTobefore registering theAbortSignalalgorithmThe specified signature is:
Promise<DOMString> executeTool(RegisteredTool tool, DOMString inputArguments, optional ModelContextExecuteToolOptions options = {});That is exactly the call
invokeWebMcpalready made,{signal}included. And #241 is a breaking type change that Webby absorbed for free, because the probe already accepted both a string and an object schema.Both are reviewed and adopted here. The comments asserting
executeToolwas unspecified are corrected — left alone they would now actively mislead.Two things still gate the feature: no browser implements it, and
webmcp-types(0.1.3) predates the change, soprobe.jsstill reaches it through a narrow cast until the definitions catch up.I was wrong about
originI previously wrote that
title/origincarry no safety signal. The spec disagrees:A frame can expose tools into a page via
exposedTo. Droppingoriginmeant a third party's tool reaching an MCP client attributed to the page that merely embedded it. It is now carried, sanitized (only a well-formed http/https origin with no path, query, or fragment is stored), and the dashboard badges any tool whose origin differs from its page.titleis carried alongside.getTools()is still called withoutfromOrigins, deliberately — restricting to same-origin would silently drop tools a page intended to expose. Carrying the origin makes the situation visible rather than hidden or silently trusted.Capability watches
github_file_symbolinverts the usual question: has this arrived rather than has this changed.chrome_statustracks Chrome's shipping status.On the origin-trial gap specifically — Chrome Status cannot answer it. Its WebMCP entry reports
status: Proposed,origintrial: false, and no milestones, contradicting the spec repo'simplementation-status.md, which cites a live trial in Chrome 149. So the contract tracks the shipping-status transition, and the docs say plainly that expiry dates aren't published there rather than implying coverage.Two bugs found building this
content-type, so chromestatus's)]}'anti-hijacking prefix failed before my handler ran. The body is now fetched raw.raw_headersrebuilt the header list positionally, dropping theauthorizationheader along with theacceptit meant to replace. Invisible without a token — and therefore broken on every CI run, whereGITHUB_TOKENis always set. Caught by testing with a real token rather than assuming.Verification
credo --strictclean.mix webby.contracts.checkclean against live upstreams with auth.test/support.jscentralizes the normalized tool shape — two field additions in a row have meant hand-rewriting every assertion, which is how a suite ends up pinning a shape nobody deliberately chose.