The model said it had written a melody and “read it back to verify.” The call log told a slightly different story: one read, then one write. There was no second read.
The write operation returned the saved score, so the model did have the result in context. But its explanation described an extra step that never happened.
That small discrepancy is a good example of why I built WebMCP DevTools, a Chrome extension for inspecting page tools and their execution. I want to compare what an agent says with what an application actually did.
To explore that, I made an English-language workshop with three small workspaces: a music editor, an expense dataset, and an invitation-page editor. This post walks through a fresh run using the real DeepSeek API and the tools registered by those pages.
What the webpage contributes
WebMCP is a proposed web standard for exposing structured tools from webpages. A tool has a name, a description, an input schema, and an implementation supplied by the page.
In this workshop, the useful state already exists in the browser: the current score, the current query, and the current invitation revision. A tool reads or modifies that state. The interface then renders the result, and a person can keep working on it.
The site needs to implement these capabilities. An extension cannot manufacture a reliable business API for every page you visit. Browser support is still evolving, too.
1. A melody you can keep editing
Here is the request I used:
Write an original eight-bar birthday-style melody in C major, 3/4, 108 BPM, with piano and a soft bass part. Title it A Little Birthday Waltz. Use varied note lengths and end on C.
The model called music_get_state, then music_set_song. It produced 29 piano notes and eight bass notes: 37 notes across 24 beats, about 13.33 seconds.
Each note has a pitch, start time, duration, and velocity. That makes the result editable data. I can change the bass volume while the piece is playing, modify the score, or export a MIDI file for another application.
This is symbolic music composition. There is no audio model generating a finished recording. The browser synthesizes the score, and the model is responsible for choosing the notes.
The test checked that playback entered its playing state, that the position advanced after a volume change, and that MIDI export produced a file with the expected header. It did not evaluate whether the music sounds good. The exported MIDI is available if you want to listen.
About that “read-back” claim: the saved score came back in the write response. A separate test read later confirmed it. Keeping the trace made that distinction visible.
2. A total with evidence behind it
The expense sample has nine records, including one missing amount. I asked for October spending by category, excluding missing amounts rather than treating them as zero.
The model read the dataset and called data_query with this input:
{
"aggregate": "sum",
"groupBy": "Category",
"metric": "Amount",
"filters": [
{ "column": "Date", "op": "contains", "value": "2026-10" }
]
}
The page calculated $275 from six usable records. Seven records matched October; one was excluded because its amount was missing.
Food accounted for $168: $48 on physical CSV row 4 and $120 on row 6. The pending food receipt on row 10 was excluded. Row 1 is the header.
That is a useful division of work. The model chooses the query and explains the result. The application computes it and returns the source rows. If I disagree with the explanation, I can inspect the data rather than rerun a conversation and hope for a better answer.
3. A page edit with a revision check
For the website example, I asked for Alex's Birthday Picnic, on October 31, 2026 at 2 PM in Riverside Park, with a warm orange accent.
This time the model made three calls: site_get_state, site_update, and another site_get_state. The invitation moved from revision 1 to revision 2.
The update requires expectedRevision. If someone changes the page after the agent reads it, a stale update is rejected. The agent must read the current state before trying again.
This is a small safeguard, but it matters when a person and an agent share an editor. A valid JSON object can still be based on outdated assumptions.
The test automation also filled the preview's RSVP form with “Sam” and two guests, checked its confirmation, and exported the HTML. Those actions were performed by the test automation, not by DeepSeek. The form is a local demonstration; it does not submit registrations to a server or send invitations.
Where the extension fits
You can install WebMCP DevTools from the Chrome Web Store. Open its side panel on a WebMCP-enabled page to inspect the available tools and run them with your own inputs.
While building these examples, I wanted a place to inspect tool descriptions and schemas, execute known inputs, and review results and errors. Those are the core jobs of WebMCP DevTools. It also provides an AI panel for connecting a model provider.
My debugging order is to test a tool with known arguments first, then let a model choose the calls. That separates an application bug from a poor tool description, an invalid argument, or an incorrect explanation.
The extension and the workshop are separate projects. The workshop supplies the application state and tool implementations; a client discovers and invokes them. The same tools can be exercised by other compatible clients.
For this English run, a small test harness connected DeepSeek to the browser's native WebMCP tools through browser automation. It did not run inside the extension's chat panel. The screenshots show actual page states; after a UI fix, recorded model arguments were replayed to capture the final interface. They are not mock conversations or translated screenshots.
What this run establishes
There were seven model-issued tool calls across the three tasks: two for music, two for data, and three for the website. All seven returned successfully. Separate checks covered playback, volume changes, exports, the RSVP form, and overflow at mobile width. The project test suite passed 27 tests, including stale-write rejection and preserving the old score after an invalid edit.
This is a small functional test, not a benchmark. The model's extra “read-back” claim is a reminder that a successful tool response and an accurate explanation are different things.
The design idea I want to keep exploring is straightforward: let the page own its validation and state, give the agent well-defined operations, and leave the result somewhere a person can inspect and continue editing.
Try it yourself
- Install WebMCP DevTools from the Chrome Web Store.
- Open the English workshop in a compatible Chrome setup.
- Click the extension icon to open the side panel, inspect a tool's schema, and run it with known arguments before trying a model-driven workflow.
You can use the workshop's manual controls without a model account. Native tool access requires a compatible browser setup; Chrome's documentation explains the current requirements. AI clients use your own provider credentials, and prompts, tool definitions, and returned data go to that provider. The workshop itself does not ask for an API key. Export your work before reloading the tab.
For implementation context, the extension source is WebMCP DevTools on GitHub. The English workshop is a focused companion demo, not a translation of every page in the larger Playground.
If you are adding tools to an existing application, I would be interested in how you handle edits based on stale state. Do you reject them, merge them, or ask the user to review a proposal?
Disclosure: AI assisted with implementation, testing, and drafting this article. The examples use real DeepSeek API responses and recorded browser tool executions. The seven-call count refers only to the new English run.



Top comments (0)