Generating MCP tools

An app can expose a set of MCP tools — named actions an agent calls, like purchase_order.create, instead of driving your interface. WAID drafts those tools from your source. Nothing becomes callable until you say so.

text
waid new → waid app generate-mcp → review → waid app sync

That is the whole pipeline. waid new scaffolds the agent runtime and generate-mcp scans your source itself, so there is no init or scan command in between.

The CLI reference has the flags. This page is about what the steps mean and where the safety boundary sits.

Generation never exposes a tool. Every newly generated tool is recorded as denied, and only a person changes that. Nothing is sent anywhere until sync.

1. Generate#

bash
waid app generate-mcp --in ./frontend
waid app generate-mcp --in ./frontend --agent claude

There is no separate setup or scan step to run first. generate-mcp does the whole thing in five stages:

StageWhat happens
1Prepares source evidence: scaffolds the agent runtime if missing, then scans your source for candidates.
2Hands that evidence to a local coding agent — codex or claude, auto-selected if you don't choose — to author real MCP handlers.
3Re-scans the source the agent wrote.
4Validates the generated catalog against the snapshot contract.
5Builds and tests the project.

What you get is a worktree diff to review. No session is required, because nothing leaves your machine.

Two files matter afterwards:

FileWhat it is
waid/mcp/generated/tools.jsonThe verified inventory: every tool generation produced.
waid/mcp/curation.jsonThe review ledger: your decision about each tool.

The agent runtime under src/waid/agent/ is scaffolded by waid new, and generate-mcp re-creates it if it is missing, so neither waid actions init nor waid app scan is a step you need to run. waid app scan --check remains useful on its own: it reports whether the candidate list still matches your source.

2. Review#

Every new tool arrives in curation.json as denied. Open it and promote the ones you have actually read:

json
{
"tools": [
{ "name": "purchase_order.create", "state": "exposed" },
{ "name": "admin.reset_tenant", "state": "denied" }
]
}

Generation never changes a decision you have already made. Re-running generate-mcp cannot quietly re-expose something you denied, and cannot withdraw something you approved — it only appends tools that are new, denied.

This is the human boundary in the pipeline. A tool an agent can reach is one a person deliberately allowed.

3. Sync#

bash
waid login --env local --tenant <tenant-key>
waid app sync --in ./frontend

Submits an immutable candidate to ICE Develop. Only tools marked exposed are projected; denied ones are not sent.

Sync needs a session, and the mode follows it: local → development, staging → staging, prod → production. An incompatible explicit --mode is rejected. The app's hosted URL comes from WAID_WEB_URL in that mode — see Modes and env files.

Sync is not publication. Publishing a candidate, installing it for a tenant, and granting access are separate, deliberate steps in ICE. A successful sync does not make anything live.

Services#

A JVM service follows the same steps with the same guarantees, and the same absorption — waid service generate-mcp scans the Java source itself, so waid service scan is not a step you run first:

bash
waid service generate-mcp --in ./my-service --agent codex
waid service sync --in ./my-service
waid service sync --in ./my-service --release 2026.10.1

The origin comes from splenta.service.public-base-url in the service's application-<env>.properties; --url overrides it. Staging sync needs a --release.