@adia-ai/mcp 0.8.37

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/TOOLS.md ADDED
@@ -0,0 +1,565 @@
1
+ # AdiaUI MCP — Tool Reference
2
+
3
+ <!-- GENERATED by scripts/build/generate-mcp-tools-md.mjs from each server's live tools/list.
4
+ Do not hand-edit: run `npm run build:mcp-tools-md`. Tool text lives on the
5
+ server.tool(...) call; grouping lives in each server's own tool-groups.mjs. -->
6
+
7
+ One npm package, two MCP servers (gh#1240) — the ADR-0048 §3 two-server
8
+ decision is unchanged; only the distribution and this reference merged.
9
+ Every tool appears once per section below, and every heading link is
10
+ section-scoped so no two tools — same-named or not — ever resolve to the
11
+ same anchor (gh#1248 renamed the protocol server's 4 formerly-same-named
12
+ tools before it ever published; zero names overlap between the two
13
+ servers as of that change).
14
+
15
+ ## `adia-mcp gen-ui` — generation server
16
+
17
+ The AdiaUI **generation** MCP server (`adia-mcp gen-ui`, `server.js`) exposes the gen-ui compose engine, the training-chunk corpus, retrieval, and the feedback/eval loop — consumed by Claude Desktop, Cursor, and the factory plugin. For installation + configuration see [`README.md`](./README.md).
18
+
19
+ Protocol-only tooling (validate or introspect an A2UI document with no corpus and no model) lives on a separate server, `adia-mcp protocol` — see its section below in this same file. `validate_schema` and `get_component_map` exist on both; the forms here are the catalog-aware ones.
20
+
21
+ This server exposes **30 tools**.
22
+
23
+ ### Tool index
24
+
25
+ | Group | Tools |
26
+ |---|---|
27
+ | **Generation** | [`generate_ui`](#gen-ui-generate_ui), [`refine_ui`](#gen-ui-refine_ui) |
28
+ | **Discovery (catalog + traits + wiring + status)** | [`get_component_map`](#gen-ui-get_component_map), [`lookup_component`](#gen-ui-lookup_component), [`lookup_chunk`](#gen-ui-lookup_chunk), [`get_traits`](#gen-ui-get_traits), [`get_wiring_catalog`](#gen-ui-get_wiring_catalog), [`list_patterns`](#gen-ui-list_patterns), [`server_status`](#gen-ui-server_status) |
29
+ | **Retrieval (chunks + compositions)** | [`search_chunks`](#gen-ui-search_chunks), [`get_chunk`](#gen-ui-get_chunk), [`search_patterns`](#gen-ui-search_patterns), [`get_composition`](#gen-ui-get_composition), [`get_graph`](#gen-ui-get_graph), [`resolve_composition`](#gen-ui-resolve_composition), [`zettel_stats`](#gen-ui-zettel_stats) |
30
+ | **Synthesis + state (zettel two-call chunk workflow)** | [`compose_from_chunks`](#gen-ui-compose_from_chunks), [`refine_composition`](#gen-ui-refine_composition), [`get_state`](#gen-ui-get_state), [`report_issue`](#gen-ui-report_issue) |
31
+ | **Intent + context** | [`plan_app_state`](#gen-ui-plan_app_state), [`classify_intent`](#gen-ui-classify_intent), [`assemble_context`](#gen-ui-assemble_context) |
32
+ | **Validation + conversion** | [`validate_schema`](#gen-ui-validate_schema), [`check_anti_patterns`](#gen-ui-check_anti_patterns), [`convert_html`](#gen-ui-convert_html) |
33
+ | **Feedback + evaluation** | [`submit_feedback`](#gen-ui-submit_feedback), [`get_quality_metrics`](#gen-ui-get_quality_metrics), [`get_training_gaps`](#gen-ui-get_training_gaps), [`run_eval`](#gen-ui-run_eval) |
34
+
35
+ #### Generation
36
+
37
+ <a id="gen-ui-generate_ui"></a>
38
+
39
+ ##### `generate_ui`
40
+
41
+ Generate A2UI components from a natural language description.
42
+
43
+ Engine selection:
44
+ - "monolithic" (default) — pattern-match + adapt. Searches a corpus of 96+ pre-authored monolithic templates and adapts the best match. Battle-tested; highest F1 on held-out intents.
45
+ - "zettel" — fragment-graph composer. Composes UI from named atomic fragments (labeled-input, card-header-with-description, etc.) with a precomputed backlink graph. Higher reusability; supports composition-iterated refinement on multi-turn edits.
46
+
47
+ Mode selection (monolithic only; zettel uses "instant"):
48
+ - "pro" (default) — LLM-powered generation with pattern adaptation.
49
+ - "thinking" — Full LLM-powered generation with semantic search, decomposition, and streaming.
50
+ - "instant" — fast pattern matching, no LLM.
51
+
52
+ The generator knows 96+ UI patterns across 5 domains: forms, data, layout, agent, navigation.
53
+
54
+ | Param | Type | Required | Default | Description |
55
+ |---|---|---|---|---|
56
+ | `intent` | string | yes | — | Description of the UI to generate |
57
+ | `engine` | `monolithic` \| `zettel` | no | — | Generation engine. "monolithic" (default) is pattern-match + adapt. "zettel" is fragment-graph composition. |
58
+ | `mode` | `instant` \| `pro` \| `thinking` | no | — | Generation mode (monolithic). "pro" (default) uses LLM with pattern adaptation. "thinking" uses full LLM generation. "instant" uses fast pattern matching. |
59
+ | `sessionId` | string | no | — | Opaque session identifier for multi-turn iteration (zettel only). When provided, follow-up calls with the same sessionId modify the prior turn's canvas instead of regenerating from scratch. Omit for stateless generation. |
60
+ | `context` | object | no | — | Ontology context parsed by plan_app_state — intent, domain, tasks, experience (REQ-03, gh#1208: all four blocks are accepted and validated here; previously only domain/tasks survived the schema, intent/experience were silently dropped). Per-engine caveat: only the "monolithic" engine's system-prompt injection reads it today, and only five of the schema's leaves (domain.entities, domain.metrics, tasks.primary, experience.mode, experience.shell) — intent.* and tasks.inspection validate but are not yet interpolated into the prompt. The "zettel" engine (and the free-form tier reachable via engine escalation) ignores context entirely; passing it has no effect there. |
61
+
62
+ <a id="gen-ui-refine_ui"></a>
63
+
64
+ ##### `refine_ui`
65
+
66
+ Refine a previous generate_ui result whose validation failed. Pass the messages from the prior result + the validation errors, and the tool produces a corrected version. For monolithic engine; zettel has refine_composition.
67
+
68
+ | Param | Type | Required | Default | Description |
69
+ |---|---|---|---|---|
70
+ | `intent` | string | yes | — | Original intent string |
71
+ | `previousMessages` | any[] | yes | — | Messages from the prior generate_ui call |
72
+ | `validationErrors` | any[] | yes | — | Errors from the prior result.validation.errors |
73
+
74
+ #### Discovery (catalog + traits + wiring + status)
75
+
76
+ <a id="gen-ui-get_component_map"></a>
77
+
78
+ ##### `get_component_map`
79
+
80
+ Get the full AdiaUI component catalog.
81
+
82
+ _No arguments._
83
+
84
+ <a id="gen-ui-lookup_component"></a>
85
+
86
+ ##### `lookup_component`
87
+
88
+ Look up a AdiaUI component by type name.
89
+
90
+ | Param | Type | Required | Default | Description |
91
+ |---|---|---|---|---|
92
+ | `type` | string | yes | — | Component type (e.g., "Card", "Button") |
93
+ | `level` | `index` \| `summary` \| `reference` | no | — | Detail level (default: reference) |
94
+
95
+ <a id="gen-ui-lookup_chunk"></a>
96
+
97
+ ##### `lookup_chunk`
98
+
99
+ List every chunk whose primary element is `<component_name>`.
100
+
101
+ Useful for "show me every page that opens with a `<card-ui raw>`" or "every
102
+ chunk built around a `<grid-ui>` root." Returns chunk names + kinds + sources.
103
+
104
+ Pair with `get_chunk` to fetch full records for any of the returned names.
105
+
106
+ | Param | Type | Required | Default | Description |
107
+ |---|---|---|---|---|
108
+ | `component_name` | string | yes | — | Component tag name, e.g. "card-ui", "grid-ui", "drawer-ui" |
109
+
110
+ <a id="gen-ui-get_traits"></a>
111
+
112
+ ##### `get_traits`
113
+
114
+ Get the trait catalog, optionally filtered by category.
115
+
116
+ | Param | Type | Required | Default | Description |
117
+ |---|---|---|---|---|
118
+ | `category` | string | no | — | Trait category filter (e.g., "input-interaction", "motion-positioning") |
119
+
120
+ <a id="gen-ui-get_wiring_catalog"></a>
121
+
122
+ ##### `get_wiring_catalog`
123
+
124
+ Get the AdiaUI wiring catalog: available controllers, action handlers, refresh strategies, value sources, and association types.
125
+
126
+ _No arguments._
127
+
128
+ <a id="gen-ui-list_patterns"></a>
129
+
130
+ ##### `list_patterns`
131
+
132
+ List all composition patterns in the A2UI corpus. Optional filters narrow by domain (auth, settings, dashboard, etc.) or category (block, page, flow).
133
+
134
+ | Param | Type | Required | Default | Description |
135
+ |---|---|---|---|---|
136
+ | `domain` | string | no | — | Filter by domain (e.g. "forms", "data", "navigation") |
137
+ | `category` | string | no | — | Filter by category ("block", "page", "flow") |
138
+
139
+ <a id="gen-ui-server_status"></a>
140
+
141
+ ##### `server_status`
142
+
143
+ Returns operational status of the MCP server: transport, sampling capability, corpus stats, version.
144
+
145
+ _No arguments._
146
+
147
+ #### Retrieval (chunks + compositions)
148
+
149
+ <a id="gen-ui-search_chunks"></a>
150
+
151
+ ##### `search_chunks`
152
+
153
+ Search the gen-UI training-chunk corpus by keyword.
154
+
155
+ The chunk corpus comes from `packages/gen-ui/corpus/chunks/` — JSON records
156
+ extracted from every `[data-chunk]` element in site/pages/* and the corpus
157
+ exemplars. There are three kinds:
158
+ - block (default): atomic UI fragment (KPI grid, sign-in form, table)
159
+ - panel: tab-panel fragment of a page (e.g. dashboard-overview-panel)
160
+ - page: full-page composition (e.g. dashboard-admin-page)
161
+
162
+ Returns ranked candidates with chunk name, kind, primary tag, and a relevance
163
+ score. Use `get_chunk` to fetch the full record (HTML + slot bindings + nested
164
+ chunks) for a specific name.
165
+
166
+ | Param | Type | Required | Default | Description |
167
+ |---|---|---|---|---|
168
+ | `query` | string | yes | — | Keyword query — chunk name fragment, intent words, primary-tag name |
169
+ | `kind` | `block` \| `panel` \| `page` | no | — | Filter by chunk kind |
170
+ | `limit` | integer | no | `20` | Max results |
171
+
172
+ <a id="gen-ui-get_chunk"></a>
173
+
174
+ ##### `get_chunk`
175
+
176
+ Fetch the full record for a single gen-UI training chunk by name.
177
+
178
+ Returns the chunk's bounding HTML, slot annotations, nested chunk names, and
179
+ metadata (primary tag, kind, source page). For chunks that appear on multiple
180
+ pages (reusable slot chunks like `auth-card-header`, `reg-step-header`),
181
+ returns an `instances` array — one entry per page where the chunk appears.
182
+
183
+ The HTML is suitable for direct rendering / inclusion in an A2UI message
184
+ construction prompt.
185
+
186
+ | Param | Type | Required | Default | Description |
187
+ |---|---|---|---|---|
188
+ | `name` | string | yes | — | The chunk name, e.g. "dashboard-kpi-grid", "auth-signin-card-email", "code-language" |
189
+
190
+ <a id="gen-ui-search_patterns"></a>
191
+
192
+ ##### `search_patterns`
193
+
194
+ Search the composition library for reusable UI templates. Returns matching compositions with full A2UI component trees that can be used directly or adapted.
195
+
196
+ Use this to find a starting point before generating from scratch. If a good composition exists, pass it to generate_ui with instant mode. If no composition matches, use generate_ui with thinking mode.
197
+
198
+ Keyword search only (§64 v0.4.6 migration: now backed by composition-library; the historical "pattern" library and its `semantic` / `remix` params are retired).
199
+
200
+ | Param | Type | Required | Default | Description |
201
+ |---|---|---|---|---|
202
+ | `query` | string | yes | — | Search query (natural language) |
203
+
204
+ <a id="gen-ui-get_composition"></a>
205
+
206
+ ##### `get_composition`
207
+
208
+ Fetch a composition by name. Returns the flat A2UI template (compositions are pre-inlined; no $fragment refs). Zettel-only.
209
+
210
+ | Param | Type | Required | Default | Description |
211
+ |---|---|---|---|---|
212
+ | `name` | string | yes | — | — |
213
+
214
+ <a id="gen-ui-get_graph"></a>
215
+
216
+ ##### `get_graph`
217
+
218
+ Return the composition catalog. Zettel-only. (Backlinks to fragments retired in §37; only composition nodes remain.)
219
+
220
+ _No arguments._
221
+
222
+ <a id="gen-ui-resolve_composition"></a>
223
+
224
+ ##### `resolve_composition`
225
+
226
+ Return the flat A2UI template + updateComponents messages for a composition. Zettel-only. (Pre-inlined since §37 — `resolve` is now a defensive copy + strip pass.)
227
+
228
+ | Param | Type | Required | Default | Description |
229
+ |---|---|---|---|---|
230
+ | `name` | string | yes | — | — |
231
+
232
+ <a id="gen-ui-zettel_stats"></a>
233
+
234
+ ##### `zettel_stats`
235
+
236
+ Zettel corpus stats — composition count + average node count. (Fragment stats retired in §37.)
237
+
238
+ _No arguments._
239
+
240
+ #### Synthesis + state (zettel two-call chunk workflow)
241
+
242
+ <a id="gen-ui-compose_from_chunks"></a>
243
+
244
+ ##### `compose_from_chunks`
245
+
246
+ Compose a UI page from training chunks — retrieval-first, synthesis-fallback.
247
+
248
+ Mix-and-match composition for intents that don't have a 1:1 chunk match. Workflow:
249
+ 1. Pure-retrieval tier: if `search_chunks` returns a strong direct match, return
250
+ that chunk's HTML immediately (no LLM call).
251
+ 2. Synthesis tier: when retrieval is weak, the LLM picks a page-kind chunk and
252
+ binds block/panel chunks to its named slots. Output validated against the
253
+ chunk catalog (slot names exist, bound chunks exist, kinds match).
254
+
255
+ Returns the composed HTML string + a binding plan describing which chunks plug
256
+ where. Useful when the prompt is novel ("dashboard with KPI grid + funnel +
257
+ country list") and no exact chunk has all those parts together — the LLM mixes
258
+ and matches from the corpus.
259
+
260
+ Two-call mode also available via `plan` parameter — pass a pre-baked binding
261
+ plan to skip the LLM call and just materialize HTML.
262
+
263
+ | Param | Type | Required | Default | Description |
264
+ |---|---|---|---|---|
265
+ | `intent` | string | no | — | Natural-language description of what to build (uses LLM synthesis) |
266
+ | `plan` | object | no | — | Pre-baked binding plan (skips LLM, materializes directly) |
267
+ | `max_attempts` | integer | no | `2` | LLM retry budget for synthesis |
268
+
269
+ <a id="gen-ui-refine_composition"></a>
270
+
271
+ ##### `refine_composition`
272
+
273
+ Refine an existing chunk-composed UI based on a natural-language intent or an explicit op-list.
274
+
275
+ Use when the user wants to modify an *existing* UI. Triggers on "change", "update", "modify", "add to", "remove from", "this", "it", "the X". Requires `state_id` from a prior `compose_from_chunks` call.
276
+
277
+ Two modes:
278
+ - **Intent-driven** — pass `intent`. Engine runs two-pass synthesis (locator pass identifies which slots to modify; modifier pass emits chunk-plan ops). Validator-driven retry on op-validation failure.
279
+ - **Explicit ops** — pass `ops` directly. Skips the LLM entirely; engine applies + materializes.
280
+
281
+ Returns a new `state_id` (versioned chain from the parent), the A2UI op-list applied, the post-op HTML, and a delta summary. Failed ops are reported in `ops_failed` with reasons.
282
+
283
+ For *fresh creation* use `compose_from_chunks`, not this tool.
284
+
285
+ | Param | Type | Required | Default | Description |
286
+ |---|---|---|---|---|
287
+ | `state_id` | string | yes | — | State id from a prior compose_from_chunks or refine_composition call |
288
+ | `intent` | string | no | — | Natural-language description of what to change (e.g. "add a country list to page-content") |
289
+ | `ops` | any[] | no | — | Pre-computed chunk-plan ops to apply directly (skips the LLM) |
290
+ | `max_attempts` | integer | no | `2` | Validator retry budget for synthesis |
291
+
292
+ <a id="gen-ui-get_state"></a>
293
+
294
+ ##### `get_state`
295
+
296
+ Inspect a cached composition state by state_id.
297
+
298
+ Returns the full cache entry including the materialized HTML, the chunk binding plan, the chronological ops history (every refinement applied to this state's lineage), and the parent state_id (chain-back to the originating compose_from_chunks call).
299
+
300
+ Useful for debugging refinement sequences, replaying a state's history, or verifying that a state_id is still cached before issuing a refine_composition call.
301
+
302
+ Auto-fires a low-severity `cache-miss-on-known-state` issue when the state_id is not in the cache (the cache is bounded LRU; long-paused conversations may evict their state).
303
+
304
+ | Param | Type | Required | Default | Description |
305
+ |---|---|---|---|---|
306
+ | `state_id` | string | yes | — | State id from a prior compose_from_chunks or refine_composition call |
307
+
308
+ <a id="gen-ui-report_issue"></a>
309
+
310
+ ##### `report_issue`
311
+
312
+ File a structured issue ticket — writes BOTH a machine-readable JSON file AND a human-readable Markdown report containing the full session trace (intent, retrieval log, LLM prompts, every attempt's raw response, composer plan, generated HTML preview, component count, warnings, environment).
313
+
314
+ When to call (any of these is a trigger):
315
+ (a) USER PHRASES — call immediately when the user says any of:
316
+ "file a ticket", "log a ticket", "save a ticket",
317
+ "report this as a bug", "report this issue", "log this issue",
318
+ "save the trace", "capture the session", "save the session for review",
319
+ "create a session ticket", "this is broken — debug it",
320
+ "download the trace", "export this for review",
321
+ "track this regression", "open a ticket for this".
322
+ (b) USER COMPLAINS the output is broken / wrong / missing.
323
+ (c) YOU CANNOT satisfy the user's intent after retrying.
324
+ (d) YOU DETECT a mismatch between requested and produced output you can't fix.
325
+
326
+ ALWAYS pass `state_id` from the most-recent compose_from_chunks or refine_composition call when one exists. The default `trace: "full"` then writes the high-resolution Markdown ticket. (Pass `trace: "summary"` for compact tickets, or `trace: "none"` to suppress the trace entirely.)
327
+
328
+ Do NOT call this for ordinary clarification or for output the user has not yet seen.
329
+
330
+ The tool returns BOTH paths in its response: `path` (.json) and `markdown_path` (.md). Surface BOTH to the user so they can navigate / download either:
331
+
332
+ 📋 Logged ticket `{issue_id}` (`{severity}` · owner: {suggested_owner})
333
+ • Trace report: `{markdown_path}` ← human-readable, scan this first
334
+ • Raw JSON: `{path}` ← machine-readable
335
+
336
+ Issue files land under `qa/findings/issues/` (immutable; resolution lands in a sidecar file). Severity taxonomy matches the project's ui-audit-coherence vocabulary: blocker = contract violation; drift = quality erosion; nit = cosmetic.
337
+
338
+ | Param | Type | Required | Default | Description |
339
+ |---|---|---|---|---|
340
+ | `type` | `bug` \| `training-gap` \| `protocol-gap` \| `ux-feedback` | yes | — | Issue category |
341
+ | `severity` | `blocker` \| `drift` \| `nit` | yes | — | Severity tier |
342
+ | `title` | string | yes | — | One-line title (≤ 80 chars) |
343
+ | `body` | string | yes | — | Markdown body — observed vs expected, repro steps |
344
+ | `state_id` | string | no | — | State id from a prior tool call; auto-attaches the trace |
345
+ | `trace` | `full` \| `summary` \| `none` | no | — | Trace depth — DEFAULT: "full" when state_id is provided (writes both .json + .md ticket with retrieval log, LLM prompts/attempts, plan, HTML preview). Use "summary" for compact tickets; "none" to suppress trace entirely. |
346
+ | `suggested_owner` | `synthesis` \| `retrieval` \| `validator` \| `chunk-corpus` \| `mcp-protocol` \| `unknown` | no | — | Best-guess owner for triage |
347
+ | `tags` | string[] | no | — | Free-form tags for filtering |
348
+
349
+ #### Intent + context
350
+
351
+ <a id="gen-ui-plan_app_state"></a>
352
+
353
+ ##### `plan_app_state`
354
+
355
+ Analyze a natural language prompt and extract the top-level Generative UI Ontology structures (Intent, Domain, Tasks, Experience).
356
+
357
+ Use this tool BEFORE generating UI to ensure you have walked the Reasoning Ladder and properly modeled the nouns and verbs of the feature. This bounds hallucination and forces a focus on tasks over raw layouts.
358
+
359
+ Honesty clause (REQ-03, gh#1208): this tool mechanizes only the Reasoning Ladder's ~Tier 0/1 rungs — one prompt, one LLM pass, no plan a reviewer can gate. It is the agent operator's (P4's) only ladder surface — a persona that cannot preload skills — not a substitute for the full rungs 0-19 walk. For anything past Tier 0/1 (roles, decisions, a scored wireframe checkpoint), use a Domain Plan from app-planning-agent's preloaded ladder skill instead.
360
+
361
+ Output shape — the four ontology blocks generate_ui's context param accepts (ontologyContextSchema, tools/ontology-context.ts): intent (user_goal, product_goal), domain (entities[], metrics[]), tasks (primary[], inspection[]), experience (mode: workspace|dashboard|wizard|chat, shell: admin|chat|editor|simple|embed|none — matches the Orientation Record's own Shell axis). The extracted output is validated against this same schema before being returned (gh#1208 review finding 2): a malformed shell/mode value (or any other schema violation) fails loudly with a typed error instead of passing the raw LLM text through.
362
+
363
+ | Param | Type | Required | Default | Description |
364
+ |---|---|---|---|---|
365
+ | `prompt` | string | yes | — | The natural language request (e.g., "Build a dashboard for incoming sales leads") |
366
+
367
+ <a id="gen-ui-classify_intent"></a>
368
+
369
+ ##### `classify_intent`
370
+
371
+ Classify intent into a UI domain.
372
+
373
+ | Param | Type | Required | Default | Description |
374
+ |---|---|---|---|---|
375
+ | `text` | string | yes | — | Intent text |
376
+
377
+ <a id="gen-ui-assemble_context"></a>
378
+
379
+ ##### `assemble_context`
380
+
381
+ Assemble progressive-disclosure context for a given intent and budget tier. Returns domain-relevant components, matching patterns, and anti-patterns.
382
+
383
+ Tier 0: domain only. Tier 1: components. Tier 2: +patterns. Tier 3: +anti-patterns. Tier 4: full catalog.
384
+
385
+ Use this when you want to manually compose A2UI output rather than using generate_ui. The returned context gives you the building blocks.
386
+
387
+ | Param | Type | Required | Default | Description |
388
+ |---|---|---|---|---|
389
+ | `intent` | string | yes | — | Natural language intent |
390
+ | `tier` | number | no | — | Budget tier 0-4 (default: 1) |
391
+
392
+ #### Validation + conversion
393
+
394
+ <a id="gen-ui-validate_schema"></a>
395
+
396
+ ##### `validate_schema`
397
+
398
+ Validate A2UI messages against schema rules.
399
+
400
+ | Param | Type | Required | Default | Description |
401
+ |---|---|---|---|---|
402
+ | `messages` | string | yes | — | JSON array of A2UI messages |
403
+
404
+ <a id="gen-ui-check_anti_patterns"></a>
405
+
406
+ ##### `check_anti_patterns`
407
+
408
+ Check HTML against all anti-patterns. Returns only violations.
409
+
410
+ | Param | Type | Required | Default | Description |
411
+ |---|---|---|---|---|
412
+ | `html` | string | yes | — | HTML string to check |
413
+
414
+ <a id="gen-ui-convert_html"></a>
415
+
416
+ ##### `convert_html`
417
+
418
+ Convert HTML markup to A2UI flat adjacency component messages. Maps HTML tags to AdiaUI components, infers layout from styles, enforces Card content model.
419
+
420
+ | Param | Type | Required | Default | Description |
421
+ |---|---|---|---|---|
422
+ | `html` | string | yes | — | HTML markup to convert |
423
+ | `mode` | `instant` \| `reasoning` | no | — | instant = rules only, reasoning = LLM for complex layouts |
424
+
425
+ #### Feedback + evaluation
426
+
427
+ <a id="gen-ui-submit_feedback"></a>
428
+
429
+ ##### `submit_feedback`
430
+
431
+ Submit structured feedback for a generation execution. Used by the evolution engine to learn from each generation.
432
+
433
+ Persists the rating to `packages/gen-ui/corpus/feedback/<date>.jsonl` through the shared `submitFeedback` path — the same one the gen-UI gallery's thumbs affordance posts to (gh#668). Optional `engine` / `strategy` / `score` / `source` context is carried onto the stored rating so human signal can rank weak domains.
434
+
435
+ | Param | Type | Required | Default | Description |
436
+ |---|---|---|---|---|
437
+ | `executionId` | string | yes | — | Execution ID from generate_ui |
438
+ | `rating` | number | yes | — | Overall quality 1-5 (>=4 counts as a thumbs-up) |
439
+ | `intent` | string | no | — | — |
440
+ | `domain` | string | no | — | — |
441
+ | `engine` | string | no | — | Engine that produced the output (zettel, free-form, …) |
442
+ | `strategy` | string | no | — | Strategy label from the generation result |
443
+ | `score` | number | no | — | Self-graded validator score at generation time |
444
+ | `source` | string | no | — | Where the rating came from; defaults to "mcp" |
445
+ | `intentAlignment` | number | no | — | — |
446
+ | `visualQuality` | number | no | — | — |
447
+ | `componentChoice` | number | no | — | — |
448
+ | `userEdited` | boolean | no | — | — |
449
+ | `editSummary` | string | no | — | — |
450
+ | `notes` | string | no | — | — |
451
+ | `shouldBePattern` | boolean | no | — | — |
452
+ | `suggestedName` | string | no | — | — |
453
+
454
+ <a id="gen-ui-get_quality_metrics"></a>
455
+
456
+ ##### `get_quality_metrics`
457
+
458
+ Get aggregated quality metrics from the feedback store: avg score, thumb-up rate, per-domain breakdown, training gaps.
459
+
460
+ `thumbUpRate` is a percentage over rating entries alone, reported even when the read window holds no executions (a rated surface whose generation happened offline). Adds a `ratings` summary and `humanRatings` / `thumbUpRate` per domain (gh#668).
461
+
462
+ _No arguments._
463
+
464
+ <a id="gen-ui-get_training_gaps"></a>
465
+
466
+ ##### `get_training_gaps`
467
+
468
+ Get training gap signals: LLM self-critique gaps by type, plus weak domains ranked with human thumbs weighted above the self-grade.
469
+
470
+ Output (gh#668, backward compatible — the gap-type keys stay at the top level): `{ ...gapsByType, gapsByType, weakDomains, weighting }`. `weakDomains` is ranked weakest-first by `blendedScore`: `0.7 * humanScore + 0.3 * selfScore` where a domain has both signals (`signal: "human+self"`), `humanScore` alone where it has no self-grade (`"human"`), `selfScore` alone where it has no thumbs (`"self-only"`). A missing signal is not a zero — a domain with NEITHER (executions logged, none graded, nobody rated) is `signal: "none"` and sorts after every ranked domain rather than at the weak end, ordered by execution count (gh#678). `selfScore` averages execution scores plus any `score` carried inline on a rating (`selfScoreSamples` counts them); `engine` / `strategy` are recorded on ratings for triage but are not ranked on.
471
+
472
+ _No arguments._
473
+
474
+ <a id="gen-ui-run_eval"></a>
475
+
476
+ ##### `run_eval`
477
+
478
+ Run the offline eval harness against the held-out intent set. Returns aggregate scores and per-intent results.
479
+
480
+ | Param | Type | Required | Default | Description |
481
+ |---|---|---|---|---|
482
+ | `domain` | string | no | — | Filter by domain (forms, data, layout, agent, navigation) |
483
+ | `limit` | number | no | — | Max intents to evaluate |
484
+
485
+ Tools on this server (30): `assemble_context`, `check_anti_patterns`, `classify_intent`, `compose_from_chunks`, `convert_html`, `generate_ui`, `get_chunk`, `get_component_map`, `get_composition`, `get_graph`, `get_quality_metrics`, `get_state`, `get_training_gaps`, `get_traits`, `get_wiring_catalog`, `list_patterns`, `lookup_chunk`, `lookup_component`, `plan_app_state`, `refine_composition`, `refine_ui`, `report_issue`, `resolve_composition`, `run_eval`, `search_chunks`, `search_patterns`, `server_status`, `submit_feedback`, `validate_schema`, `zettel_stats`.
486
+
487
+ ---
488
+
489
+ ## `adia-mcp protocol` — A2UI protocol server
490
+
491
+ The A2UI **protocol** MCP server (`adia-mcp protocol`, `server.js`) exposes tooling for the standard itself: validate any A2UI document, and introspect the protocol registry. It has no generation system and no model client in its dependency tree — `@adia-ai/gen-ui` and `@adia-ai/llm` are deliberate non-dependencies (ADR-0048 P4).
492
+
493
+ Looking for generation, retrieval, or the training corpus? That is a different server, `adia-mcp gen-ui` — see its section above in this same file.
494
+
495
+ These four tool names are DISTINCT from the gen-ui server's own tool surface (gh#1248 renamed them off their original same-named forms before this server ever published) but each still serves a narrower, protocol-only counterpart — `validate_document` (schema + runtime registry, no catalog; gen-ui's `validate_schema`) and `get_registry_map` (type → tag, no descriptions or prop schemas; gen-ui's `get_component_map`). `get_wiring_registry` likewise reports the live wiring registry rather than the authoring knowledge base (gen-ui's `get_wiring_catalog`). For installation + configuration see [`README.md`](./README.md).
496
+
497
+ This server exposes **4 tools**.
498
+
499
+ ### Tool index
500
+
501
+ | Group | Tools |
502
+ |---|---|
503
+ | **Validation** | [`validate_document`](#protocol-validate_document) |
504
+ | **Registry introspection** | [`get_registry_map`](#protocol-get_registry_map), [`get_wiring_registry`](#protocol-get_wiring_registry) |
505
+ | **Status** | [`protocol_status`](#protocol-protocol_status) |
506
+
507
+ #### Validation
508
+
509
+ <a id="protocol-validate_document"></a>
510
+
511
+ ##### `validate_document`
512
+
513
+ Validate A2UI messages against the protocol: message envelope shape, flat-adjacency child references, component types resolvable in the runtime registry, and the semantic checks the renderer relies on (Card content model, renderable content, slot addressing).
514
+
515
+ This is the PROTOCOL-side form of validation. It needs no catalog and no corpus, so it validates any A2UI document from any producer. For catalog-aware validation (per-component prop schemas via the v0.9 catalog) plus anti-pattern scoring, use gen-ui-mcp's `validate_schema` instead.
516
+
517
+ | Param | Type | Required | Default | Description |
518
+ |---|---|---|---|---|
519
+ | `messages` | string | yes | — | JSON array of A2UI messages (a single message object is also accepted) |
520
+
521
+ #### Registry introspection
522
+
523
+ <a id="protocol-get_registry_map"></a>
524
+
525
+ ##### `get_registry_map`
526
+
527
+ Get the A2UI protocol registry: every component type name mapped to the custom-element tag that renders it.
528
+
529
+ This is the registry view — the authoritative answer to "what types exist and what does each one render to". It carries no descriptions, categories, or prop schemas: those are catalog data and live on gen-ui-mcp's `get_component_map` tool instead. Alias types (several type names resolving to one tag, e.g. Toggle and Switch both -> switch-ui) are reported as such.
530
+
531
+ _No arguments._
532
+
533
+ <a id="protocol-get_wiring_registry"></a>
534
+
535
+ ##### `get_wiring_registry`
536
+
537
+ Get the A2UI wiring registry: controller types, action-handler names, and data-URI resolver schemes the runtime can resolve.
538
+
539
+ Read live from the runtime's wiringRegistry, so it cannot drift from what the renderer will actually accept. The richer authoring knowledge base (UI event payloads, refresh strategies, value sources, association types) is generation-side — see gen-ui-mcp's `get_wiring_catalog` tool instead.
540
+
541
+ _No arguments._
542
+
543
+ #### Status
544
+
545
+ <a id="protocol-protocol_status"></a>
546
+
547
+ ##### `protocol_status`
548
+
549
+ Returns operational status of this A2UI protocol MCP server: transport and protocol-registry stats. Reports on the protocol server only — gen-ui-mcp's `server_status` tool reports its own corpus-side status separately.
550
+
551
+ _No arguments._
552
+
553
+ Tools on this server (4): `get_registry_map`, `get_wiring_registry`, `protocol_status`, `validate_document`.
554
+
555
+ ---
556
+
557
+ ## Verification
558
+
559
+ Every heading above is derived from a live `tools/list` response, so this page cannot
560
+ claim a tool, a param, or a default a server does not serve. To reproduce:
561
+
562
+ ```bash
563
+ npm run build:mcp-tools-md # regenerate this file (both servers)
564
+ npm run check:mcp-tools-md-fresh # the freshness gate (rides `npm run check`)
565
+ ```
package/bin/adia-mcp ADDED
@@ -0,0 +1,108 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * adia-mcp — the ONE bin for @adia-ai/mcp's two servers (gh#1240).
4
+ *
5
+ * ADR-0048 §3 ruled two distinct MCP servers ("they do different things") and
6
+ * that decision stands; gh#1240 (operator ruling 2026-08-14) unified only the
7
+ * DISTRIBUTION — one npm package, one bin, still two server processes:
8
+ *
9
+ * adia-mcp gen-ui — the generation server (30 tools: compose, corpus,
10
+ * retrieval, feedback/eval loop)
11
+ * adia-mcp protocol — the A2UI protocol server (4 tools: validate + registry
12
+ * introspection; no generation system, no model client)
13
+ * adia-mcp — (bare) prints this menu
14
+ * adia-mcp --help — same menu, exits 0 (an unrecognized subcommand
15
+ * prints the same menu too, but exits 1 — help is
16
+ * never an error)
17
+ *
18
+ * WHY SPAWN RATHER THAN IMPORT
19
+ *
20
+ * The two servers do not share an entry-point contract: gen-ui/server.js calls
21
+ * its own `main()` unconditionally at module scope (so booting it has always
22
+ * meant `node server.js`, not `import`), while protocol/server.js guards
23
+ * `main()` behind an `isEntryPoint()` check comparing `process.argv[1]` to its
24
+ * own resolved path — which would read as "not the entry point" and never
25
+ * start if this dispatcher `import()`ed it in-process instead of spawning it.
26
+ * Neither behavior is a bug to paper over here (server internals are
27
+ * unchanged per the fold's own shape) — spawning a real child process with a
28
+ * real argv[1] is what makes both servers boot exactly as they did standalone,
29
+ * and it is also what an MCP stdio transport needs anyway: the child owns
30
+ * stdin/stdout for the JSON-RPC channel, so `stdio: 'inherit'` hands it over
31
+ * directly rather than proxying it.
32
+ *
33
+ * PACKED-INSTALL SAFE: every path below resolves off THIS FILE's own location
34
+ * (import.meta.url), never off process.cwd() or a workspace-relative guess —
35
+ * so `npx -y @adia-ai/mcp gen-ui` from a real npm install boots the same way
36
+ * as a workspace-local `node packages/mcp/bin/adia-mcp gen-ui`.
37
+ */
38
+
39
+ import { spawn } from 'node:child_process';
40
+ import { fileURLToPath } from 'node:url';
41
+ import { dirname, join } from 'node:path';
42
+
43
+ const __dirname = dirname(fileURLToPath(import.meta.url));
44
+
45
+ const SERVERS = {
46
+ 'gen-ui': {
47
+ path: join(__dirname, '..', 'gen-ui', 'server.js'),
48
+ summary: '30-tool generation server (compose, corpus, retrieval, feedback/eval)',
49
+ },
50
+ protocol: {
51
+ path: join(__dirname, '..', 'protocol', 'server.js'),
52
+ summary: '4-tool protocol server (validate + registry introspection; no gen-ui, no llm)',
53
+ },
54
+ };
55
+
56
+ function printMenu() {
57
+ console.error('adia-mcp — @adia-ai/mcp\'s two MCP servers, one bin.');
58
+ console.error('');
59
+ console.error('Usage: adia-mcp <server>');
60
+ console.error('');
61
+ for (const [name, { summary }] of Object.entries(SERVERS)) {
62
+ console.error(` ${name.padEnd(10)} ${summary}`);
63
+ }
64
+ console.error('');
65
+ console.error('Each server speaks MCP over stdio and takes no CLI flags of its own —');
66
+ console.error('configure via environment (e.g. MCP_HTTP_PORT for gen-ui\'s HTTP transport).');
67
+ }
68
+
69
+ const [sub, ...rest] = process.argv.slice(2);
70
+
71
+ // --help / -h / help print the same menu and exit 0 — asking for help is not
72
+ // an error, unlike an unrecognized subcommand below.
73
+ if (sub === '--help' || sub === '-h' || sub === 'help') {
74
+ printMenu();
75
+ process.exit(0);
76
+ }
77
+
78
+ const target = SERVERS[sub];
79
+
80
+ if (!target) {
81
+ printMenu();
82
+ process.exit(sub ? 1 : 0);
83
+ }
84
+
85
+ const child = spawn(process.execPath, [target.path, ...rest], { stdio: 'inherit' });
86
+
87
+ // Forward the signals a caller sends to THIS wrapper on to the child it
88
+ // spawned — without this, `kill -TERM <wrapper-pid>` (or Ctrl-C reaching only
89
+ // the wrapper in some shells/process-group setups) kills the wrapper and
90
+ // leaves the actual MCP server running with no parent, orphaned (reviewer
91
+ // proved it live on PR #1245). Registered before the child's own 'exit'
92
+ // handler so a signal-caused shutdown is always a forward, never a race.
93
+ for (const sig of ['SIGINT', 'SIGTERM', 'SIGHUP']) {
94
+ process.on(sig, () => child.kill(sig));
95
+ }
96
+
97
+ child.on('error', (err) => {
98
+ console.error(`[adia-mcp] failed to start '${sub}' server: ${err.message}`);
99
+ process.exit(1);
100
+ });
101
+
102
+ child.on('exit', (code, signal) => {
103
+ if (signal) {
104
+ process.kill(process.pid, signal);
105
+ return;
106
+ }
107
+ process.exit(code ?? 0);
108
+ });