Build with an agent
Set up a coding agent to build, price, test and ship an extension on Toolaby.
A coding agent, such as Claude Code, Codex, Cursor, VS Code with Copilot, Gemini CLI or Windsurf, can do most of the work of selling an extension on Toolaby. It reads the files the command line writes into your project, acts on your tools through Toolaby's MCP server, and checks its own work with check.
This page covers the setup, what an agent does and what you do, how it verifies its work, and the reference: every MCP tool and command, the docs for agents, safety and troubleshooting.
Before you begin
- A workspace on Toolaby, and Node.js 20 or later.
- A coding agent that connects to MCP servers.
1. Set up your agent
npx -y toolaby@latest agentsagents registers Toolaby's MCP server in each coding agent it finds on this machine: Claude Code, Codex, Cursor, VS Code and Gemini CLI. It registers it for your user, so it works in every project. Run again, it changes nothing.
| Option | Does |
|---|---|
--client <name> | Only that client: claude-code, codex, cursor, vscode, gemini, or all. |
--project | In this project instead: .mcp.json and .cursor/mcp.json, to commit for your team. |
--json | What was done and what failed, as JSON. |
Restart the agent, or reload its MCP servers. Its tools now include toolaby_get_tool and the others below.
wire and create print this command when they finish.
2. Or add the server by hand
The server is the command npx -y toolaby@latest mcp, on stdio. It acts on Test. For Live, add a second server named toolaby-live that runs npx -y toolaby@latest mcp --live.
Claude Code
Toolaby's plugin brings the skills, five commands (/toolaby:sell, /toolaby:check, /toolaby:test-unlock, /toolaby:ship, /toolaby:move-from-extensionpay) and Toolaby's docs server, at https://toolaby.app/api/mcp. Its commands act with the command line, as shell commands you see, and approve unless you have allowed them. In Claude Code:
/plugin marketplace add toolaby/claude-plugin
/plugin install toolaby@toolabyFor the toolaby_* tools as well, add the server, with or without the plugin:
claude mcp add --scope user toolaby -- npx -y toolaby@latest mcpThe plugin starts nothing on your computer by itself: the server that acts is one you add.
Codex
codex mcp add toolaby -- npx -y toolaby@latest mcpOr in ~/.codex/config.toml:
[mcp_servers.toolaby]
command = "npx"
args = ["-y", "toolaby@latest", "mcp"]Cursor
Add to Cursor, or in ~/.cursor/mcp.json:
{
"mcpServers": {
"toolaby": { "command": "npx", "args": ["-y", "toolaby@latest", "mcp"] }
}
}VS Code
Install in VS Code, or in .vscode/mcp.json:
{
"servers": {
"toolaby": { "type": "stdio", "command": "npx", "args": ["-y", "toolaby@latest", "mcp"] }
}
}Gemini CLI
gemini mcp add toolaby npx -y toolaby@latest mcpWindsurf
In ~/.codeium/windsurf/mcp_config.json:
{
"mcpServers": {
"toolaby": { "command": "npx", "args": ["-y", "toolaby@latest", "mcp"] }
}
}Other clients
Any client that starts an MCP server from a command: npx with the arguments -y toolaby@latest mcp.
3. Sign in once
The server acts as you, with the command line's session, on the tools of your workspaces. Without a session, a call answers that you are not signed in.
- In the agent:
toolaby_sign_inanswers a link and a code. Open the link, check the code and approve. The server waits for your approval; the agent's next call works. - From a terminal, or an agent without MCP:
npx -y toolaby@latest login --no-wait --jsonanswers{ url, code, deviceCode, expiresIn }and exits at once. After you approve,npx -y toolaby@latest login --poll <deviceCode>ends with exit code0.
Sessions are per side. Live needs its own: npx -y toolaby@latest login --live.
4. Ask for the work
- Make the tool: in the dashboard, or ask the agent (
toolaby_create_tool). - Wire the extension:
npx -y toolaby@latest wire <tool-id>in its folder, ornpx -y toolaby@latest create <tool-id>for a new one. Both write the files agents read. - Ask in one sentence: "Make exporting the counts as CSV a Pro feature, $5 once."
- The agent reads
TOOLABY.md, adds the plan (toolaby_add_plan), then the feature and the plan that unlocks it (toolaby_set_features), putsgate({ feature: 'export' })before the export, and verifies. - It ends with what changed and the steps left for you.
What an agent does, and what you do
| An agent does alone | You do, once |
|---|---|
| Create and change tools, plans, trials, seats, features, the Free plan and coupons, on Test | Approve the command line's sign-in, on each side |
Write the code behind gate(), and fix what check reports | Connect Stripe on Live, under Configure → Payments |
Prove a paid feature unlocks on Test: test-unlock, then check --browser --as <plan> | Make a purchase in the browser, when you want to see Checkout |
| Read customers, grant access, refund and cancel, with your confirmation on Live | Upload the zip to the Chrome Web Store, and submit it |
| Copy the tool to Live, write the Live key, pack the store zip | Make the first real purchase on Live |
The skills and TOOLABY.md tell the agent never to report your steps as done.
The files agents read
create, wire and upgrade write these at the project's root: the folder with package.json, above a folder a build copies, such as public/.
| File | For | Written |
|---|---|---|
TOOLABY.md | Every agent. The files Toolaby owns, where toolaby.js is imported from in this kind of project (plain, a bundler, WXT, CRXJS, Plasmo), gate() and the paywall, subscription and trial states, this tool's features and plans, the commands, the verify checklist, what only you can do, and links to these docs as Markdown. With --from-extensionpay, the move's steps. On Live, every command carries --live. | Every time. |
.claude/skills/toolaby*/SKILL.md | Claude Code, Cursor and Copilot: the skills below. | Every time. |
.agents/skills/toolaby*/SKILL.md | Codex, Cursor and Copilot: the same skills. | Every time. |
AGENTS.md | Every agent reads it first. | Where the project has none. |
CLAUDE.md | Claude Code. It reads AGENTS.md. | Where the project has none. |
Where the project has its own AGENTS.md or CLAUDE.md, the command adds a short block to it, between <!-- TOOLABY START --> and <!-- TOOLABY END -->: where TOOLABY.md and the skills are, and the check. Run again, it replaces only what is between the markers. A CLAUDE.md that already reads AGENTS.md (@AGENTS.md) gets no block of its own.
Skills
| Skill | For |
|---|---|
toolaby | What Toolaby is, which skill fits, setup, sign-in and safety. |
toolaby-sell-a-feature | Making something Pro: the plan, the feature, gate({ feature }), a free or daily allowance. |
toolaby-pricing | Plans one-time or by subscription, trials, devices, seats, coupons, the Free plan. |
toolaby-test-a-purchase | test-unlock and check --browser --as <plan>; a purchase with a test card. |
toolaby-ship | Copy to Live, login --live, upgrade --live, pack, the store listing address. |
toolaby-extensionpay-move | Moving from ExtensionPay, and your steps after it. |
toolaby-extension-patterns | Where gate() goes in a background, popup, side panel or content script, module scripts, the client's port, offline answers. |
To add the skills to any project, without wiring it: npx skills add toolaby/claude-plugin, from the plugin's public repository, or npx skills add https://toolaby.app, where Toolaby serves them at /.well-known/agent-skills/index.json.
Verify
An agent says the work is done only after these pass.
npx -y toolaby@latest check --jsonin the extension's folder. It exits0, andokistrue.toolaby_get_tool: the plan at the price asked, and the feature the code gates among the plan's features.- Built,
npx -y toolaby@latest check --json --browser --built <output folder>: Chromium loads the extension, its background answers, and its pages open without an error. The first run downloads Playwright and Chromium into~/.config/toolaby/playwright, never into the project. - On Test,
npx -y toolaby@latest test-unlock <tool-id> --plan <plan-id>, thennpx -y toolaby@latest check --browser --as <plan-id>: the extension, signed in as your Test buyer with that plan, allows the paid feature.
test-unlock makes a buyer of your own on Test, at your address with +toolaby-test (you+toolaby-test@example.com), and gives it the plan. It is refused on Live.
check --json answers one object:
{
"ok": false,
"side": "Test",
"folder": "/Users/you/word-count",
"built": null,
"findings": [
{ "code": "CSP_BLOCKS_TOOLABY", "level": "error", "message": "manifest.json's content security policy leaves https://quiet-otter-4172.toolaby.app out of connect-src: every call of Toolaby's fails to fetch. `npx -y toolaby@latest upgrade acme--word-count` adds it.", "file": "manifest.json", "fix": "npx -y toolaby@latest upgrade acme--word-count", "docs": "https://toolaby.app/docs/troubleshooting#in-the-extension" }
]
}For each error finding, an agent runs its fix, a command, when it has one; otherwise it changes what the message says, and reads docs. The codes never change. These are the ones an agent meets most; Command line lists every one.
| Code | Means |
|---|---|
FEATURE_KEY_UNKNOWN | The code gates on a feature key the tool does not have: every buyer is refused. |
BACKGROUND_NOT_STARTED | Nothing starts Toolaby in the background: none is named, it never starts Toolaby, a build's carries none of it, or it did not answer Toolaby's client (--browser). |
EXTERNALLY_CONNECTABLE_MISSING | Toolaby's address is not under externally_connectable: sign-in and the purchase never reach the extension. |
CSP_BLOCKS_TOOLABY | The content security policy's connect-src (or default-src) leaves Toolaby's address out: every call of Toolaby's fails to fetch. |
POPUP_NOT_MODULE | A page loads a script with import or export lines without type="module": Chrome refuses it and the page opens blank. |
PAGE_THREW | A page of the extension threw when it opened (--browser). |
NO_PAYWALL_POSSIBLE | Nothing in the extension can ever ask anyone to pay. An error when the tool sells plans; a warning when it has none. |
TEST_KEY_IN_LIVE_BUILD | A store copy (its manifest has update_url) carries a Test or development key: an error. A production build that carries one: a warning. |
HOST_PERMISSION_LEFT | The manifest gives Toolaby's address, or another side's Test address, a host permission or an entry Toolaby does not need. |
KEY_OUTDATED | The tool key is older than Toolaby's: the Free plan, the plans or the signing key changed since it was written. |
NOT_SIGNED_IN | No session on the side the key is on: the checks that need one were not made. |
CLI_OUTDATED | This command is older than the one Toolaby serves. |
Exit codes
| Code | Means |
|---|---|
0 | Done. check with warnings only exits 0. |
1 | Failed, or check found an error. |
2 | Done, with steps left for a person: wire and upgrade when they end Almost wired. |
MCP tools
npx -y toolaby@latest mcp acts on Test, or on Live when started with --live. Every tool has a title, annotations, an input schema and an output schema, and answers structured content with the same JSON as text. Every tool has a command, below: an agent without MCP runs it with --json.
| Tool | Command | Does |
|---|---|---|
toolaby_whoami | whoami | The signed-in developer and their workspaces. |
toolaby_list_tools | tools | Your tools, with the ids the others take. |
toolaby_get_tool | tool get | One tool: the Free plan, features, plans, the tool key, the extension's id, the checkout page, whether a copy has checked in. |
toolaby_list_customers | customers | The tool's customers, by a search text. |
toolaby_get_customer | customer | One buyer: entitled or not, plan, licences, subscription status and renewal, grants, devices. |
toolaby_analytics | analytics | The tool's Analytics: active devices, the funnel, revenue and MRR, uninstalls; or one table as rows. |
toolaby_docs | docs | A docs page as Markdown, or the index. |
toolaby_search_docs | docs search | The docs pages and passages that match a query. |
toolaby_check | check | A folder's wiring checked, with the findings above. |
toolaby_sign_in | login | A sign-in link and code for you; done once you approve. |
toolaby_create_tool | tool create | A new tool. |
toolaby_update_tool | tool update | The tool's name, line or store listing addresses, Chrome's and Edge's. |
toolaby_set_access | access | What the Free plan holds, and whether an account comes first. |
toolaby_set_features | features | The tool's whole list of features, and the plans that unlock each. Add the plans first. A feature the list leaves out is archived, never deleted: its holders keep it. |
toolaby_add_plan | plan add | A plan, one-time or a subscription, with a trial, a device count, per seat. It answers the plan's id; a tool's first plan is default. |
toolaby_update_plan | plan update | A plan's name, trial, devices or per seat. |
toolaby_retire_plan | plan retire | Takes a plan off sale. Holders keep it. Destructive. |
toolaby_grant | grant | Access without paying, to an address; answers the grant's id. |
toolaby_revoke_grant | grant revoke | Takes a grant back. Destructive. |
toolaby_create_coupon | coupon create | A coupon code for checkout, such as one for a store reviewer. |
toolaby_refund | refund | Refunds a buyer's licence and revokes it. Destructive. |
toolaby_cancel_subscription | cancel | Cancels a buyer's subscription, at the period's end or now. Destructive. |
toolaby_copy_to_live | copy-to-live | Copies the tool from Test to Live: the Free plan, features, plans, versions and the extension's identity. Needs both sessions. |
toolaby_stripe_status | stripe | Whether Stripe is connected, and the link for you to connect it. |
toolaby_create_api_key | api-keys create | A server API key, written into an env file and never shown. |
toolaby_test_unlock | test-unlock | Your Test buyer given a plan, for check --browser --as <plan>. Test only. |
toolaby_list_webhook_events | webhooks events | The events a registered endpoint receives, each with an example of what it carries. |
toolaby_list_webhooks | webhooks endpoints | The webhook endpoints registered, with the events each listens for. |
toolaby_add_webhook | webhooks add | Registers your server's endpoint, and writes its signing secret into an env file without showing it. |
toolaby_send_test_event | webhooks trigger | Sends an event's example to the registered endpoints, as a real delivery. |
toolaby_remove_webhook | webhooks remove | Removes an endpoint: deliveries to it stop at once. Destructive. |
The first eight only read, as do toolaby_stripe_status and the two webhook lists, and say so in their annotations (readOnlyHint). The five marked destructive say so too (destructiveHint), so a client that asks before such a change can ask before these.
When toolaby_set_access or toolaby_add_plan changes what the tool key carries, the answer says keyChanged: run npx -y toolaby@latest upgrade <tool-id>, then build and reload. Installed copies follow a change to the Free plan without a release.
So while copies are installed, toolaby_set_access does not open a Free plan that counts uses: copies that gate their work with a bare gate() would run all of it free, what your plans sell included, until they update. It answers copies_installed with the versions that checked in this week. Ship the build that gates by feature first. Opening the Free plan then is the person's step, once the build is live on the store: the tool's Access card, or access <tool-id> --access open --now in their own terminal. The MCP server never offers now to an agent. Copy to Live keeps Live's Free plan counting uses the same way, and says so.
The server also has resources, toolaby://docs/{page} (Markdown) and toolaby://tools/{tool} (JSON), and prompts: sell-a-feature, move-from-extensionpay, ship-to-store and fix-wiring.
Commands
Every command acts on Test unless given --live, and prints its raw answer as JSON with --json.
# Read
npx -y toolaby@latest whoami
npx -y toolaby@latest tools
npx -y toolaby@latest tool get <tool-id>
npx -y toolaby@latest customers <tool-id> --query <text> --limit 20
npx -y toolaby@latest customer <tool-id> <email>
npx -y toolaby@latest docs gating
npx -y toolaby@latest docs search "free trial"
npx -y toolaby@latest check --json --browser --built <output folder>
# Change
npx -y toolaby@latest tool create --name "Word Counter" --tagline "Counts the words on a page"
npx -y toolaby@latest tool update <tool-id> --store-url <listing address>
npx -y toolaby@latest access <tool-id> --access free_uses --free-uses 10
npx -y toolaby@latest features <tool-id> --features '[{"key":"export","name":"Export to CSV"}]' --plans '[{"id":"default","features":["export"]}]'
npx -y toolaby@latest plan add <tool-id> --billing subscription --interval month --amount 4 --currency usd --name Pro --trial-days 7
npx -y toolaby@latest plan update <tool-id> <plan-id> --devices 3
npx -y toolaby@latest plan retire <tool-id> <plan-id>
npx -y toolaby@latest grant <tool-id> <email> --days 30
npx -y toolaby@latest grant revoke <tool-id> <grant-id>
npx -y toolaby@latest coupon create <tool-id> --percent-off 100 --code REVIEW --max-redemptions 1 --expires-days 30
npx -y toolaby@latest refund <tool-id> <email>
npx -y toolaby@latest cancel <tool-id> <email>
npx -y toolaby@latest api-keys create --env-file .env --name server
# Test and Live
npx -y toolaby@latest test-unlock <tool-id> --plan <plan-id>
npx -y toolaby@latest stripe --live
npx -y toolaby@latest copy-to-live <tool-id>
npx -y toolaby@latest upgrade <tool-id> --live
# Sign-in and setup
npx -y toolaby@latest login --no-wait --json
npx -y toolaby@latest login --poll <deviceCode>
npx -y toolaby@latest agents --client cursor --projectCommand line covers wire, upgrade, create, pack and webhooks.
The docs for agents
/llms.txt: what an agent should know first, when to use Toolaby, and every page with its Markdown address./llms-full.txt: the same, with every page, in one file.- Any page as Markdown: its address with
.md, such as/docs/gating.md. A request for a page withAccept: text/markdowngets the same Markdown, and every page names its copy in aLinkheader (rel="alternate",type="text/markdown"). - On every page, under its title: Copy page, View as Markdown, Open in Claude and Open in ChatGPT.
By address, over MCP
For a client that connects to an MCP server by its address, such as a Claude or ChatGPT connector, the docs are also an MCP server at https://toolaby.app/api/mcp (Streamable HTTP). It has two tools, toolaby_docs and toolaby_search_docs, and reads nothing but these docs, so it asks for no sign-in and holds no key. Where a client asks how to authenticate, choose none.
In Claude on the web, desktop and mobile, it is in the connector directory as Toolaby: browse the connectors, find Toolaby and connect it, with no sign-in.
claude mcp add --transport http toolaby-docs https://toolaby.app/api/mcpIn Cursor: Add the docs server.
The tools that read and change your tools stay with npx -y toolaby@latest mcp on your machine, under your own sign-in.
Safety
- Test by default. Every command and the MCP server act on Test unless told
--live. Test buyers, cards and keys never reach Live by themselves. - Live asks first. On Live, every change through MCP first answers a summary and a
confirmcode, valid for 5 minutes and for those arguments only. The call made again with the code does it. These tools also carry_meta: { "anthropic/requiresUserInteraction": true }. On the command line,refundon Live asks you to confirm. - No secret in a chat or an extension.
api-keys create --env-file .envwritesTOOLABY_API_KEY=…into the file and never prints it. The extension holds the tool key alone (tk_…), which is public. - Your roles hold. Every change goes through the same checks as the dashboard. A member whose role cannot change a tool is refused.
Troubleshooting
| Symptom | Fix |
|---|---|
The agent has no toolaby_* tools | Restart it or reload its MCP servers. npx -y toolaby@latest agents --json says which clients failed. Check Node.js 20 or later. |
| A call answers that you are not signed in | toolaby_sign_in, or login --no-wait --json and then login --poll <deviceCode>. Approve the code in the browser. |
A change on Live answers a confirm code | Show the summary to the person, and call again with the code only on their word. |
An answer says keyChanged | npx -y toolaby@latest upgrade <tool-id>, then build and reload. |
check exits 1 | For each error finding, run its fix, or change what its message says. |
test-unlock is refused | It runs on Test only. A project with the Live key: upgrade <tool-id> writes the Test key; upgrade <tool-id> --live before the store build. |
| The tools act on the wrong side | npx -y toolaby@latest mcp is Test; npx -y toolaby@latest mcp --live is Live. |
npx runs another toolaby | In a repository you did not write, install the command (npm i -g toolaby) and type toolaby-cli. |
See Troubleshoot an extension for what an extension says when something is wrong.