@adia-ai/mcp 0.8.38 → 0.8.39
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/CHANGELOG.md +8 -0
- package/README.md +4 -4
- package/TOOLS.md +21 -3
- package/bin/adia-mcp +2 -2
- package/package.json +2 -2
- package/protocol/server.d.ts +3 -2
- package/protocol/server.js +1 -1
- package/protocol/tools/protocol.js +123 -0
package/CHANGELOG.md
CHANGED
|
@@ -9,6 +9,14 @@
|
|
|
9
9
|
> entire changelog was still `[Unreleased]` at fold time (minted at ADR-0048 P4,
|
|
10
10
|
> never released under its own name) and is merged into the section below.
|
|
11
11
|
|
|
12
|
+
## [0.8.39] — 2026-08-15
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
- **`get_catalog_ladder` on the `protocol` server (ADR-0050, gh#1291 phase 3) — 4 → 5 tools there (all-server total 43: gen-ui 31 · protocol 5 · factory 7).** ADR-0050's serving map gives the protocol server L0+L1; phase 1 held it at four tools because an L0-only enumerate tool duplicates `get_registry_map`. With L1 populated (44 curated widgets) the tool earns its place: an L1 entry carries its A2UI `template`, so a chat agent can enumerate a widget and emit it with no generation system and no corpus. No arguments returns the ladder summary — all five rungs with unit/composesTier/status/count plus a `servedHere` flag and the serving map in prose, so a client learns where L2–L4 live; `tier` (a two-value enum, `L0`|`L1`, so an unserved rung is refused at the schema rather than answered emptily) lists that rung's entry names; `tier` + `name` returns one entry's full record. **Isolation is unchanged by construction** — the tier index is data inside the zero-dependency `@adia-ai/a2ui` (`./catalog/tiers`), so the P4 module-graph walk still proves zero reach into `@adia-ai/gen-ui`/`@adia-ai/llm`/`@adia-ai/agent`. Zero tool-name overlap across the three servers (the factory smoke's ADR-0051 §4 assertion). **Purely additive** — no existing tool's input or output shape changed, so no versioning event; `protocol_status` deliberately did not grow catalog counters, which would have been an output-contract change for cosmetic value. gen-ui's `get_catalog_tiers` (all five rungs, for retrieval) is unchanged.
|
|
16
|
+
|
|
17
|
+
### Maintenance
|
|
18
|
+
- **`bin/` touched in this release window** (1 file(s), e.g. `bin/adia-mcp`) — carried by the entries above.
|
|
19
|
+
|
|
12
20
|
## [0.8.38] — 2026-08-15
|
|
13
21
|
|
|
14
22
|
### Added
|
package/README.md
CHANGED
|
@@ -152,13 +152,13 @@ Wraps [`@adia-ai/a2ui`](../a2ui) and nothing else. `@adia-ai/gen-ui` and
|
|
|
152
152
|
`@adia-ai/llm` are deliberate **non**-dependencies of this surface — see
|
|
153
153
|
[Why a separate server](#why-a-separate-server-not-just-a-shared-one).
|
|
154
154
|
|
|
155
|
-
|
|
155
|
+
Five tools, no API key, no `.env`, **stdio only** (no HTTP mode — express and
|
|
156
156
|
session-sweep belong to `gen-ui`): `validate_document` · `get_registry_map` ·
|
|
157
|
-
`get_wiring_registry` · `protocol_status`.
|
|
157
|
+
`get_wiring_registry` · `get_catalog_ladder` · `protocol_status`.
|
|
158
158
|
|
|
159
159
|
```bash
|
|
160
160
|
node packages/gen-ui/mcp/protocol/server.js # stdio only
|
|
161
|
-
npm run mcp:protocol:smoke # boot + exercise all
|
|
161
|
+
npm run mcp:protocol:smoke # boot + exercise all 5 tools + isolation proof
|
|
162
162
|
```
|
|
163
163
|
|
|
164
164
|
### Tool name disambiguation
|
|
@@ -265,7 +265,7 @@ npm run build:protocol-mcp-server # protocol: server.ts + tools/*.ts -> .js (e
|
|
|
265
265
|
npm run build:factory-mcp-server # factory: server.ts + tools/*.ts -> .js (esbuild)
|
|
266
266
|
npm run build:factory-mcp-assets # factory: re-vendor scripts + re-derive doctrine resources from the plugin
|
|
267
267
|
npm run mcp:smoke # gen-ui: boot over stdio, exercise all 31 tools
|
|
268
|
-
npm run mcp:protocol:smoke # protocol: boot over stdio, exercise all
|
|
268
|
+
npm run mcp:protocol:smoke # protocol: boot over stdio, exercise all 5 tools + isolation proof
|
|
269
269
|
npm run mcp:factory:smoke # factory: asset freshness + boot + tools + zero-overlap/parity/isolation proofs
|
|
270
270
|
npm run build:mcp-tools-md # regenerate TOOLS.md (all three servers, sectioned) from the live tool lists
|
|
271
271
|
```
|
package/TOOLS.md
CHANGED
|
@@ -509,9 +509,9 @@ The A2UI **protocol** MCP server (`adia-mcp protocol`, `server.js`) exposes tool
|
|
|
509
509
|
|
|
510
510
|
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.
|
|
511
511
|
|
|
512
|
-
|
|
512
|
+
Every tool name here is DISTINCT from the gen-ui and factory servers' surfaces (gh#1248 renamed the original four off their 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`), `get_registry_map` (type → tag, no descriptions or prop schemas; gen-ui's `get_component_map`), and `get_catalog_ladder` (the L0+L1 rungs ADR-0050's serving map puts on this server; gen-ui's `get_catalog_tiers` serves the whole ladder for retrieval). `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).
|
|
513
513
|
|
|
514
|
-
This server exposes **
|
|
514
|
+
This server exposes **5 tools**.
|
|
515
515
|
|
|
516
516
|
### Tool index
|
|
517
517
|
|
|
@@ -519,6 +519,7 @@ This server exposes **4 tools**.
|
|
|
519
519
|
|---|---|
|
|
520
520
|
| **Validation** | [`validate_document`](#protocol-validate_document) |
|
|
521
521
|
| **Registry introspection** | [`get_registry_map`](#protocol-get_registry_map), [`get_wiring_registry`](#protocol-get_wiring_registry) |
|
|
522
|
+
| **Catalog contract** | [`get_catalog_ladder`](#protocol-get_catalog_ladder) |
|
|
522
523
|
| **Status** | [`protocol_status`](#protocol-protocol_status) |
|
|
523
524
|
|
|
524
525
|
#### Validation
|
|
@@ -557,6 +558,23 @@ Read live from the runtime's wiringRegistry, so it cannot drift from what the re
|
|
|
557
558
|
|
|
558
559
|
_No arguments._
|
|
559
560
|
|
|
561
|
+
#### Catalog contract
|
|
562
|
+
|
|
563
|
+
<a id="protocol-get_catalog_ladder"></a>
|
|
564
|
+
|
|
565
|
+
##### `get_catalog_ladder`
|
|
566
|
+
|
|
567
|
+
Enumerate the AdiaUI catalog contract's served rungs: L0 primitives (component vocabulary) and L1 widgets (named, versioned, chat-scale functional units — a Row of stat cards, a sign-in card, a tool-call accordion). An L1 entry carries its A2UI `template`, so this is the tool to call before generating a document by hand: find the widget, take its template, fill in the copy.
|
|
568
|
+
|
|
569
|
+
Called with no arguments it returns the ladder summary — every rung with its entry unit, the rung it composes, populated/reserved status, and entry count. Pass `tier` ("L0" or "L1") for that rung's entry names; pass `tier` + `name` for one entry's full record (`composes`, `template`, `keywords`, `domain`, provenance).
|
|
570
|
+
|
|
571
|
+
Scope, per ADR-0050's serving map: this server serves **L0 + L1** — the rungs a chat agent enumerates to emit A2UI. L2 layouts, L3 shells, and L4 flows are developer-facing and belong to the factory surface; `adia-mcp gen-ui`'s `get_catalog_tiers` serves the whole ladder for retrieval. The ladder's one law is that every tier-N entry is a declared composition of tier-(N-1) entries, so `composes` is the edge you follow down a rung — an L1 entry's `composes` names L0 types you can validate with `validate_document`.
|
|
572
|
+
|
|
573
|
+
| Param | Type | Required | Default | Description |
|
|
574
|
+
|---|---|---|---|---|
|
|
575
|
+
| `tier` | `L0` \| `L1` | no | — | List one served rung's entry names instead of the ladder summary |
|
|
576
|
+
| `name` | string | no | — | With `tier` (required alongside it), return this single entry's full record |
|
|
577
|
+
|
|
560
578
|
#### Status
|
|
561
579
|
|
|
562
580
|
<a id="protocol-protocol_status"></a>
|
|
@@ -567,7 +585,7 @@ Returns operational status of this A2UI protocol MCP server: transport and proto
|
|
|
567
585
|
|
|
568
586
|
_No arguments._
|
|
569
587
|
|
|
570
|
-
Tools on this server (
|
|
588
|
+
Tools on this server (5): `get_catalog_ladder`, `get_registry_map`, `get_wiring_registry`, `protocol_status`, `validate_document`.
|
|
571
589
|
|
|
572
590
|
---
|
|
573
591
|
|
package/bin/adia-mcp
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*
|
|
11
11
|
* adia-mcp gen-ui — the generation server (31 tools: compose, corpus,
|
|
12
12
|
* retrieval, feedback/eval loop)
|
|
13
|
-
* adia-mcp protocol — the A2UI protocol server (
|
|
13
|
+
* adia-mcp protocol — the A2UI protocol server (5 tools: validate + registry
|
|
14
14
|
* introspection; no generation system, no model client)
|
|
15
15
|
* adia-mcp factory — the adia-factory server (7 tools: orient, scaffold,
|
|
16
16
|
* audit, surface QA — the factory plugin's gated
|
|
@@ -54,7 +54,7 @@ const SERVERS = {
|
|
|
54
54
|
},
|
|
55
55
|
protocol: {
|
|
56
56
|
path: join(__dirname, '..', 'protocol', 'server.js'),
|
|
57
|
-
summary: '
|
|
57
|
+
summary: '5-tool protocol server (validate + registry introspection + L0/L1 catalog rungs; no gen-ui, no llm)',
|
|
58
58
|
},
|
|
59
59
|
factory: {
|
|
60
60
|
path: join(__dirname, '..', 'factory', 'server.js'),
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adia-ai/mcp",
|
|
3
|
-
"version": "0.8.
|
|
4
|
-
"description": "AdiaUI's three MCP servers, one npm package (gh#1240, ADR-0051). `adia-mcp gen-ui` — the
|
|
3
|
+
"version": "0.8.39",
|
|
4
|
+
"description": "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 introspection + the L0/L1 catalog-contract rungs, no generation system, no model client). `adia-mcp factory` — the 7-tool adia-factory server (orient, scaffold, audit, surface QA for building adia-ui apps from any MCP harness; no generation system, no model client). ADR-0048 §3's distinct-server decision is unchanged; only the distribution unified.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"adia-mcp": "./bin/adia-mcp"
|
package/protocol/server.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Builds the A2UI protocol MCP server (
|
|
5
|
-
* get_registry_map, get_wiring_registry, protocol_status)
|
|
4
|
+
* Builds the A2UI protocol MCP server (5 tools: validate_document,
|
|
5
|
+
* get_registry_map, get_wiring_registry, get_catalog_ladder, protocol_status)
|
|
6
|
+
* with no transport
|
|
6
7
|
* attached. Exported for tests and for `scripts/build/generate-mcp-tools-md.mjs`;
|
|
7
8
|
* the module's own top-level `isEntryPoint()` guard is what actually starts a
|
|
8
9
|
* stdio transport when this file is run directly (`node server.js`), not when
|
package/protocol/server.js
CHANGED
|
@@ -16,7 +16,7 @@ async function main() {
|
|
|
16
16
|
const server = createServer();
|
|
17
17
|
const transport = new StdioServerTransport();
|
|
18
18
|
await server.connect(transport);
|
|
19
|
-
console.error("[a2ui-protocol-mcp] stdio transport ready (
|
|
19
|
+
console.error("[a2ui-protocol-mcp] stdio transport ready (5 protocol tools)");
|
|
20
20
|
}
|
|
21
21
|
function isEntryPoint() {
|
|
22
22
|
if (typeof process === "undefined" || !process.argv[1]) return false;
|
|
@@ -10,6 +10,11 @@ This is the registry view \u2014 the authoritative answer to "what types exist a
|
|
|
10
10
|
const GET_WIRING_REGISTRY_DESCRIPTION = `Get the A2UI wiring registry: controller types, action-handler names, and data-URI resolver schemes the runtime can resolve.
|
|
11
11
|
|
|
12
12
|
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 \u2014 see gen-ui-mcp's \`get_wiring_catalog\` tool instead.`;
|
|
13
|
+
const GET_CATALOG_LADDER_DESCRIPTION = `Enumerate the AdiaUI catalog contract's served rungs: L0 primitives (component vocabulary) and L1 widgets (named, versioned, chat-scale functional units \u2014 a Row of stat cards, a sign-in card, a tool-call accordion). An L1 entry carries its A2UI \`template\`, so this is the tool to call before generating a document by hand: find the widget, take its template, fill in the copy.
|
|
14
|
+
|
|
15
|
+
Called with no arguments it returns the ladder summary \u2014 every rung with its entry unit, the rung it composes, populated/reserved status, and entry count. Pass \`tier\` ("L0" or "L1") for that rung's entry names; pass \`tier\` + \`name\` for one entry's full record (\`composes\`, \`template\`, \`keywords\`, \`domain\`, provenance).
|
|
16
|
+
|
|
17
|
+
Scope, per ADR-0050's serving map: this server serves **L0 + L1** \u2014 the rungs a chat agent enumerates to emit A2UI. L2 layouts, L3 shells, and L4 flows are developer-facing and belong to the factory surface; \`adia-mcp gen-ui\`'s \`get_catalog_tiers\` serves the whole ladder for retrieval. The ladder's one law is that every tier-N entry is a declared composition of tier-(N-1) entries, so \`composes\` is the edge you follow down a rung \u2014 an L1 entry's \`composes\` names L0 types you can validate with \`validate_document\`.`;
|
|
13
18
|
const PROTOCOL_STATUS_DESCRIPTION = `Returns operational status of this A2UI protocol MCP server: transport and protocol-registry stats. Reports on the protocol server only \u2014 gen-ui-mcp's \`server_status\` tool reports its own corpus-side status separately.`;
|
|
14
19
|
function buildRegistryView() {
|
|
15
20
|
const byTag = /* @__PURE__ */ new Map();
|
|
@@ -25,6 +30,14 @@ function buildRegistryView() {
|
|
|
25
30
|
})).sort((a, b) => a.type.localeCompare(b.type));
|
|
26
31
|
return { totalTypes: registry.size, totalTags: byTag.size, entries };
|
|
27
32
|
}
|
|
33
|
+
const SERVED_TIERS = ["L0", "L1"];
|
|
34
|
+
let _tierIndex = null;
|
|
35
|
+
async function loadTierIndex() {
|
|
36
|
+
if (_tierIndex) return _tierIndex;
|
|
37
|
+
const mod = await import("@adia-ai/a2ui/catalog/tiers", { with: { type: "json" } });
|
|
38
|
+
_tierIndex = mod.default ?? mod;
|
|
39
|
+
return _tierIndex;
|
|
40
|
+
}
|
|
28
41
|
function buildWiringView() {
|
|
29
42
|
return {
|
|
30
43
|
controllers: [...wiringRegistry.controllers.keys()].sort(),
|
|
@@ -68,6 +81,116 @@ function registerProtocolTools(server) {
|
|
|
68
81
|
return { content: [{ type: "text", text: JSON.stringify(buildWiringView(), null, 2) }] };
|
|
69
82
|
}
|
|
70
83
|
);
|
|
84
|
+
server.tool(
|
|
85
|
+
"get_catalog_ladder",
|
|
86
|
+
GET_CATALOG_LADDER_DESCRIPTION,
|
|
87
|
+
{
|
|
88
|
+
tier: z.enum(["L0", "L1"]).optional().describe("List one served rung's entry names instead of the ladder summary"),
|
|
89
|
+
name: z.string().optional().describe("With `tier` (required alongside it), return this single entry's full record")
|
|
90
|
+
},
|
|
91
|
+
async ({ tier, name }) => {
|
|
92
|
+
if (name && !tier) {
|
|
93
|
+
return {
|
|
94
|
+
content: [
|
|
95
|
+
{
|
|
96
|
+
type: "text",
|
|
97
|
+
text: `\`name\` needs a \`tier\`: entry names are unique only within a rung. Retry with { tier: "L1", name: "${name}" } (or "L0"), or omit \`name\` for the ladder summary.`
|
|
98
|
+
}
|
|
99
|
+
],
|
|
100
|
+
isError: true
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
let index;
|
|
104
|
+
try {
|
|
105
|
+
index = await loadTierIndex();
|
|
106
|
+
} catch (err) {
|
|
107
|
+
const e = err instanceof Error ? err : new Error(String(err));
|
|
108
|
+
return {
|
|
109
|
+
content: [{ type: "text", text: `Catalog tier index unavailable: ${e.message}` }],
|
|
110
|
+
isError: true
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
if (!tier) {
|
|
114
|
+
const ladder = Object.fromEntries(
|
|
115
|
+
Object.entries(index.tiers).map(([id, t]) => [
|
|
116
|
+
id,
|
|
117
|
+
{
|
|
118
|
+
unit: t.unit,
|
|
119
|
+
composesTier: t.composesTier,
|
|
120
|
+
status: t.status,
|
|
121
|
+
count: t.count,
|
|
122
|
+
servedHere: SERVED_TIERS.includes(id)
|
|
123
|
+
}
|
|
124
|
+
])
|
|
125
|
+
);
|
|
126
|
+
return {
|
|
127
|
+
content: [
|
|
128
|
+
{
|
|
129
|
+
type: "text",
|
|
130
|
+
text: JSON.stringify(
|
|
131
|
+
{
|
|
132
|
+
catalogId: index.catalogId,
|
|
133
|
+
servedTiers: [...SERVED_TIERS],
|
|
134
|
+
servingMap: "protocol server: L0+L1 (this tool) \xB7 gen-ui server: all tiers, for retrieval (get_catalog_tiers) \xB7 factory server: L2-L4, developer-facing",
|
|
135
|
+
ladder
|
|
136
|
+
},
|
|
137
|
+
null,
|
|
138
|
+
2
|
|
139
|
+
)
|
|
140
|
+
}
|
|
141
|
+
]
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
const rung = index.tiers[tier];
|
|
145
|
+
if (!rung) {
|
|
146
|
+
return {
|
|
147
|
+
content: [
|
|
148
|
+
{
|
|
149
|
+
type: "text",
|
|
150
|
+
text: `Tier "${tier}" is absent from the catalog tier index (${Object.keys(index.tiers).join(", ")} present) \u2014 the index may predate it.`
|
|
151
|
+
}
|
|
152
|
+
],
|
|
153
|
+
isError: true
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
if (name) {
|
|
157
|
+
const entry = rung.entries[name];
|
|
158
|
+
if (!entry) {
|
|
159
|
+
return {
|
|
160
|
+
content: [
|
|
161
|
+
{
|
|
162
|
+
type: "text",
|
|
163
|
+
text: `No ${tier} entry named "${name}". ${rung.count} entries in this tier \u2014 call this tool with just \`tier\` for the names.`
|
|
164
|
+
}
|
|
165
|
+
],
|
|
166
|
+
isError: true
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
return {
|
|
170
|
+
content: [{ type: "text", text: JSON.stringify({ tier, name, entry }, null, 2) }]
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
return {
|
|
174
|
+
content: [
|
|
175
|
+
{
|
|
176
|
+
type: "text",
|
|
177
|
+
text: JSON.stringify(
|
|
178
|
+
{
|
|
179
|
+
tier,
|
|
180
|
+
unit: rung.unit,
|
|
181
|
+
composesTier: rung.composesTier,
|
|
182
|
+
status: rung.status,
|
|
183
|
+
count: rung.count,
|
|
184
|
+
entries: Object.keys(rung.entries).sort()
|
|
185
|
+
},
|
|
186
|
+
null,
|
|
187
|
+
2
|
|
188
|
+
)
|
|
189
|
+
}
|
|
190
|
+
]
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
);
|
|
71
194
|
server.tool(
|
|
72
195
|
"protocol_status",
|
|
73
196
|
PROTOCOL_STATUS_DESCRIPTION,
|