Inspiration
A print-on-demand seller with forty designs does the same chore forty times, multiplied by every marketplace they sell on. Etsy allows a 140 character title and 13 tags. Amazon Merch allows 60 characters, no price claims, and two bullets. Redbubble wants 15 tags of up to 30 characters each. The work is not creative. It is compliance, and it eats a day.
Handing it to an AI has always meant choosing between two bad options. Either the agent described what to write and the seller pasted forty listings by hand, or the seller handed an opaque tool their credentials and hoped. One is dictation. The other is abdication. Neither is collaboration.
Why this is a strong fit for WebMCP
WebMCP changes the shape of the problem, because the tools live on the page the seller is already looking at.
The studio is a grid. Designs down the side, marketplaces across the top, one listing per square. It publishes twelve tools with document.modelContext.registerTool. Ask the agent to fill the grid and the squares fill in front of you. Every field stays editable. Every action, yours or the agent's, lands in the same activity log stamped with who did it.
The design rule the whole project follows is that a tool is never a private back door. Each one is a thin wrapper over an action that a button in the interface also calls. One store, one set of mutations, one log.
buttons (app.js) ---+
+---> studio.js ---> live TagTitan API
tools (webmcp.js) --+ |
+---> one grid, one activity log
That symmetry is what makes the collaboration legible. The agent cannot do anything the seller cannot see, undo, or do themselves.
How it creates a better user experience
The seller never leaves the page, never pastes anything, and never loses sight of what was done on their behalf. They can interrupt at any square. A batch that would have been forty context switches becomes one instruction and a grid they supervise.
It also degrades honestly. With no agent connected the studio is a complete tool you can drive by hand, and the header states plainly which mode you are in.
What people and agents can do together that was difficult before
- Supervised bulk work. "Take all four designs, do Etsy and Redbubble, premium voice." The agent calls the same actions the buttons call, and the seller watches each square resolve, fixing anything wrong in place.
- A critique loop against a real scorer. The agent calls
grade_listing, reads back a 0 to 100 score broken into title, tags, description and readability with concrete fixes, then callsupdate_listingto apply one. It checks its own work against the same grader the seller sees. - Marketplace rules as shared context.
list_marketplacesreturns live character and tag limits for 18 marketplaces, so the agent reasons about real constraints instead of guessing. - Correction without restarting. "The Etsy title is too generic, make it about cottagecore." One field changes. Nothing else regenerates and no context is lost.
- Knowing when to stop and ask.
account_statusreports remaining quota, so before a large batch the agent can tell the seller to sign in rather than burning what is left.
How we built it
The front end is deliberately plain: no build step, no framework, no dependencies. studio.js holds all state and every mutation. app.js renders it and wires the buttons. webmcp.js registers the tools. The last two are peers, and neither can reach past the store.
document.modelContext.registerTool({
name: "generate_listings",
description: "Write full listings for products across the selected marketplaces...",
inputSchema: { type: "object", properties: { /* ... */ } },
execute: async (input) => { /* ... */ },
});
Every execute is wrapped so a thrown error becomes a readable tool error rather than a crash, and each call writes to the shared activity log before returning.
The listing engine behind it is the live TagTitan API, a shipped commercial product, so the output is what real sellers actually publish rather than demo filler.
The twelve tools
| Tool | What it does |
|---|---|
read_studio |
Full state: products, marketplaces, listing status, scores |
account_status |
Whether the seller is signed in and how much quota remains |
list_marketplaces |
18 marketplaces with live title, tag and content limits |
add_product |
Add a design as a new row |
remove_product |
Drop a row and its listings |
set_marketplaces |
Choose which marketplaces are columns |
set_tone |
Set the brand voice for everything generated after |
suggest_keywords |
Real buyer search phrases for a seed term |
generate_listings |
Write listings across the grid |
grade_listing |
Score a listing 0 to 100 and return fixes |
update_listing |
Rewrite one field of one listing |
export_csv |
Every finished listing as bulk-upload CSV |
Challenges we ran into
The API restricts CORS to an allowlist. Calling it from a new origin returned 400 with no allow header. Rather than widen the allowlist we proxy /api server-side, so the browser only ever makes same-origin requests and the backend needed no change at all. That also let the session cookie ride along without any SameSite juggling.
The free tier allows one listing per browser, in total. Cookie tracked, and it silently truncates a multi-marketplace request to a single marketplace. Anyone opening the site cold got one square filled and then a wall, which made the whole studio look broken. Adding sign-in fixed it, and signed in the API writes every marketplace in a single call.
The backend sleeps. It runs on a free instance that takes about 23 seconds to wake. A judge whose first click hangs that long assumes the project is broken, so a scheduled function now pings it every ten minutes.
What we learned
The interesting constraint in WebMCP is not what the agent can do. It is what the human can still see. It would have been easier to give the agent a fast private path to the API and let the UI catch up afterwards. Everything good about this project came from refusing that and making both paths identical.
What's next
Unifying the studio session with the main TagTitan app, image-driven listings so a design can be dropped straight in, and pushing finished rows to marketplace APIs directly instead of exporting CSV.
Log in or sign up for Devpost to join the conversation.