@adia-ai/mcp
v0.8.50
Published
AdiaUI's three MCP servers, one npm package (gh#1240, ADR-0051). `adia-mcp gen-ui` — the 31-tool generation server (compose engine, corpus, retrieval, feedback/eval loop). `adia-mcp protocol` — the 5-tool A2UI protocol server (validate + registry introspe
Readme
@adia-ai/mcp
Three MCP servers, one npm package, one bin. ADR-0048 §3 ruled distinct
servers ("they do different things"); gh#1240 (operator ruling 2026-08-14)
unified only the distribution — before either predecessor name
(@adia-ai/gen-ui-mcp, @adia-ai/a2ui-protocol-mcp) ever published a 0.8.x —
into this one package. ADR-0051 (gh#1241) added the third server, factory,
as a third subcommand under the same one-package ruling.
| You want to… | Run |
|---|---|
| Generate UI from an intent, search the training corpus, run evals, catalog-aware validation + anti-pattern scoring | adia-mcp gen-ui |
| Check that an A2UI document is well-formed, whoever produced it; see which component types/wiring exist with no corpus and no model | adia-mcp protocol |
| Build adia-ui APPS from any MCP harness — orient, scaffold, structural audit, the surface-qa browser gate, doctrine resources | adia-mcp factory |
| See the three-server menu | adia-mcp (bare) |
The protocol server's four tool names are distinct from the gen-ui
server's (gh#1248 renamed them off their original same-named forms before
the protocol server ever published) — each still has a narrower,
protocol-only counterpart on gen-ui; see
Tool name disambiguation for the mapping if you
have both servers installed.
Install
npm install -g @adia-ai/mcp # global — exposes the `adia-mcp` bin
# OR
npm install @adia-ai/mcp # local — invoke via npxClaude Desktop / Cursor / any MCP host, mcpServers block:
{
"mcpServers": {
"adia-ui": {
"command": "npx",
"args": ["-y", "@adia-ai/mcp", "gen-ui"]
},
"a2ui-protocol": {
"command": "npx",
"args": ["-y", "@adia-ai/mcp", "protocol"]
},
"adia-factory": {
"command": "npx",
"args": ["-y", "@adia-ai/mcp", "factory"]
}
}
}(adia-factory is the reserved config key for the factory server —
ADR-0051's config-key ruling, 2026-08-14.)
From a local checkout:
node packages/gen-ui/mcp/bin/adia-mcp gen-ui # stdio, local IDE
node packages/gen-ui/mcp/bin/adia-mcp protocol # stdio, protocol-only
node packages/gen-ui/mcp/bin/adia-mcp factory # stdio, factory toolbox
MCP_HTTP_PORT=3460 node packages/gen-ui/mcp/bin/adia-mcp gen-ui # HTTP transport (gen-ui only)gen-ui — the generation server
Wraps @adia-ai/gen-ui. Exposes the generation engine,
component catalog, pattern library, validator, and training feedback loop as
30 MCP tools for Claude Desktop, Claude Code, Cursor, Windsurf, and any
deployed MCP-capable host.
Runtime only. Generation logic lives in
@adia-ai/gen-ui; UI atoms in@adia-ai/web-components; the A2UI protocol runtime (renderer, registry, streams, wiring) in@adia-ai/a2ui; corpus in@adia-ai/gen-ui/corpus.
Two transports, one tool surface
| Mode | When | LLM source |
|---|---|---|
| stdio (default) | Local IDE tools — Claude Code, Cursor, Hermes | Host's LLM via MCP sampling (no API key needed) |
| HTTP (MCP_HTTP_PORT) | Deployed web service, remote MCP clients | .env API key required |
stdio requests LLM inference from the host via MCP sampling/createMessage
— no separate API key, same model, same token budget the user is already
paying for. HTTP gives each session its own transport and its own
McpServer (the SDK binds one transport per server instance); corpus,
catalog and chunk index stay process-wide and shared.
Session idle TTL (HTTP only)
| Env | Default | Meaning |
|---|---|---|
| MCP_SESSION_TTL_MS | 1800000 (30 min) | Idle time before a session is evicted. 0 or negative disables eviction entirely. |
Every request refreshes a session's last-activity stamp; an idle-evicted
session's next request gets the same -32001 an unknown session id gets —
re-initialize to continue. stdio has no sessions and is unaffected.
Quick start
export ANTHROPIC_API_KEY=sk-ant-… # at least one provider key, for generate_ui
adia-mcp gen-ui # global install, stdio
npx @adia-ai/mcp gen-ui # via npx
node packages/gen-ui/mcp/gen-ui/server.js # from local checkout
MCP_HTTP_PORT=3460 node packages/gen-ui/mcp/gen-ui/server.js # HTTP → 0.0.0.0:3460/mcpTools
See TOOLS.md for the full reference (all three servers,
sectioned) — tool names, descriptions, grouping, argument schemas. Quick map
for gen-ui:
| Group | Tools |
|---|---|
| Generation | generate_ui, refine_ui |
| Discovery | get_component_map, lookup_component, lookup_chunk, get_traits, get_wiring_catalog, list_patterns, server_status |
| Retrieval | search_chunks, get_chunk, search_patterns, get_composition, get_graph, resolve_composition, zettel_stats |
| Synthesis + state | compose_from_chunks, refine_composition, get_state, report_issue |
| Intent + context | plan_app_state, classify_intent, assemble_context |
| Validation + conversion | validate_schema, check_anti_patterns, convert_html |
| Feedback + evaluation | submit_feedback, get_quality_metrics, get_training_gaps, run_eval |
Layout
gen-ui/
├── server.js MCP bootstrap — registers tools inline; the rest live in tools/ modules
├── scripts/ Standalone runners (smoke tests, eval diffs, visual validate)
├── tools/ tool modules: synthesis · validation · feedback · corpus · zettel · discovery · refine
└── evals/ held-out eval fixturesGotchas
- Corpus load is noisy. The zettel composer prints stats to stderr on first invocation. Callers expecting silent MCP should swallow stderr.
- API keys must be set before the server starts. Changing env vars mid-session doesn't hot-reload adapters.
- Engine selector is internal. Don't pass
engine: 'mcp'— the generator picksmonolithicvszettelfrom intent + mode. - Multi-turn state is per-process, in-memory, ephemeral. Restarting the
server drops every multi-turn chain in flight. Checkpoint the canvas to your
own store between turns and pass
currentCanvason resume rather than relying onexecutionId/sessionIdfor durability.
protocol — the A2UI protocol server
Wraps @adia-ai/a2ui and nothing else. @adia-ai/gen-ui and
@adia-ai/llm are deliberate non-dependencies of this surface — see
Why a separate server.
Five tools, no API key, no .env, stdio only (no HTTP mode — express and
session-sweep belong to gen-ui): validate_document · get_registry_map ·
get_wiring_registry · get_catalog_ladder · protocol_status.
node packages/gen-ui/mcp/protocol/server.js # stdio only
npm run mcp:protocol:smoke # boot + exercise all 5 tools + isolation proofTool name disambiguation
Until gh#1248, all four of these tool names were shared with gen-ui, each
returning a different shape depending on which server answered — a host with
both installed saw each name twice. The protocol server had never
published, so gh#1248 (adversarial-review finding F7, 2026-08-14) renamed all
four off their original same-named forms while the cost was still zero. Each
renamed tool keeps its narrower, protocol-only counterpart on gen-ui:
| Tool (protocol) | Counterpart (gen-ui) | protocol shape | gen-ui shape |
|---|---|---|---|
| validate_document | validate_schema | protocol verdict only | same verdict plus a catalog key (AJV against the v0.9 catalog) and anti-pattern scoring |
| get_registry_map | get_component_map | { totalTypes, totalTags, entries: [{ type, tag, aliases }] } | newline-delimited Type -> <tag>: description text from the catalog |
| get_wiring_registry | get_wiring_catalog | { controllers, handlers, uriSchemes } — names only, read live from the runtime registry | the full authoring knowledge base: UI event payloads, refresh strategies, value sources, association types, per-controller config/commands/bind |
| protocol_status | server_status | transport + protocol-registry stats | transport, sampling capability, corpus stats |
That asymmetry is the point — protocol answers questions about the standard
itself (any producer's document), gen-ui answers questions about this
producer's catalog. The rename only changed how a client asks; it changed
neither shape.
factory — the adia-factory server
The developer toolbox (ADR-0051, gh#1241): build adia-ui apps from any
MCP-speaking harness (Claude Code, Hermes, Pi, …) — the adia-ui-factory
plugin's capabilities without Claude-Code-specific skills/commands/agents.
MCP config key: adia-factory (reserved).
Seven tools, no API key, no .env, stdio only: orient_app ·
scaffold_app · scaffold_page · scaffold_component · audit_structure ·
verify_surface · factory_status. See TOOLS.md for the
full reference.
Every tool wraps an existing gated script (ADR-0051 §2 — the server adds
no business logic): the factory plugin's adia-info, record-lint,
adia-lint, adia-scaffold, adia-contract-check, and adia-probe,
vendored verbatim into factory/vendor/ by
npm run build:factory-mcp-assets (the plugin's own files stay the single
source; the vendor manifest + mcp:factory:smoke keep the copies honest).
Doctrine ships as MCP resources generated from the skill files at build
time (ADR-0051 §3), never hand-copied:
adia://factory/{shell-selection,data-wiring,token-pairing-laws,pattern-index}.
Runtime needs:
- python3 — four of the wrapped scripts are stdlib-only Python 3.8+. Absent, the affected tools return an actionable install message.
- Playwright is NOT a dependency (ADR-0051 §6):
verify_surfacelazy-loads it from the target project (npm i -D playwrightthere); every other tool works without it. Keepsnpx -y @adia-ai/mcpinstalls light.
Deliberate non-dependencies, same posture as protocol (ADR-0051 §5):
@adia-ai/gen-ui and @adia-ai/llm never appear in this server's runtime
module graph — a developer wanting generation talks to adia-mcp gen-ui.
mcp:factory:smoke walks the module graph from factory/server.js and
fails on any reach, proves zero tool-name overlap with both sibling servers
(ADR-0051 §4), and asserts tool-name/resource-URI conformance against
factory/public-surface.json — the
checked-in surface definition minted for the adia-factory-public (remote
claude.ai connector) reconciliation. Scope, honestly: this is
local-surface conformance — the remote publishes no machine-readable
manifest yet, so remote divergence is not detectable until that export
exists (the file's $comment rules that its rosters then become an import
of it, never a fork).
node packages/gen-ui/mcp/factory/server.js # stdio only
npm run mcp:factory:smoke # boot + exercise tools + freshness, zero-overlap, parity, isolation proofsWhy a separate server (not just a shared one)
ADR-0048 Decision §3 and .claude/docs/specs/a2ui-gen-ui-split.md ## Interfaces
▸ MCP partition: the MCP SDK and zod would otherwise become dependencies of
every embedding host that only needs to render a canvas and validate
documents against the standard, with no need for the generation engine or a
model client. Two servers keep that boundary at the process level, not just
the package level; gh#1240 only moved where the two servers' code and npm
manifest live, not that boundary.
Package exports
package.json's exports map declares three subpaths — ./gen-ui/server.js,
./protocol/server.js, and ./factory/server.js (added by ADR-0051/gh#1241;
adding a subpath is the safe direction). The first two are the entry points the packed-boot probe (and
the published @adia-ai/[email protected] bridge shim, frozen on the registry)
reach by deep import (@adia-ai/mcp/gen-ui/server.js). This is an explicit
invariant, not an accident of omission: without a declared exports map
every file in files is deep-importable by default, which is what let that
resolution work before this map existed. Adding ANY future subpath key here is
fine; removing or renarrowing either of the first two silently breaks the
published shim for anyone still on the retired, deprecated
@adia-ai/a2ui-mcp name. Re-run npm run probe:packed-boot after touching
this map.
Local development
npm run build:mcp-server # gen-ui: server.ts + tools/*.ts -> .js (esbuild)
npm run build:protocol-mcp-server # protocol: server.ts + tools/*.ts -> .js (esbuild)
npm run build:factory-mcp-server # factory: server.ts + tools/*.ts -> .js (esbuild)
npm run build:factory-mcp-assets # factory: re-vendor scripts + re-derive doctrine resources from the plugin
npm run mcp:smoke # gen-ui: boot over stdio, exercise all 31 tools
npm run mcp:protocol:smoke # protocol: boot over stdio, exercise all 5 tools + isolation proof
npm run mcp:factory:smoke # factory: asset freshness + boot + tools + zero-overlap/parity/isolation proofs
npm run build:mcp-tools-md # regenerate TOOLS.md (all three servers, sectioned) from the live tool listsLicense
MIT
