@wootsup/mcp 0.1.0-rc.9 → 0.1.0

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.
Files changed (171) hide show
  1. package/README.md +7 -7
  2. package/dist/index.d.ts +19 -0
  3. package/dist/index.js +71 -5
  4. package/dist/index.js.map +1 -1
  5. package/dist/modules/apimapper/cache.d.ts +2 -2
  6. package/dist/modules/apimapper/cache.js +107 -25
  7. package/dist/modules/apimapper/cache.js.map +1 -1
  8. package/dist/modules/apimapper/client.d.ts +40 -0
  9. package/dist/modules/apimapper/client.js +82 -12
  10. package/dist/modules/apimapper/client.js.map +1 -1
  11. package/dist/modules/apimapper/connections-format.d.ts +51 -0
  12. package/dist/modules/apimapper/connections-format.js +261 -0
  13. package/dist/modules/apimapper/connections-format.js.map +1 -0
  14. package/dist/modules/apimapper/connections-trim.d.ts +82 -0
  15. package/dist/modules/apimapper/connections-trim.js +224 -0
  16. package/dist/modules/apimapper/connections-trim.js.map +1 -0
  17. package/dist/modules/apimapper/connections.d.ts +14 -2
  18. package/dist/modules/apimapper/connections.js +447 -143
  19. package/dist/modules/apimapper/connections.js.map +1 -1
  20. package/dist/modules/apimapper/credentials-format.d.ts +21 -0
  21. package/dist/modules/apimapper/credentials-format.js +145 -0
  22. package/dist/modules/apimapper/credentials-format.js.map +1 -0
  23. package/dist/modules/apimapper/credentials.d.ts +12 -2
  24. package/dist/modules/apimapper/credentials.js +253 -72
  25. package/dist/modules/apimapper/credentials.js.map +1 -1
  26. package/dist/modules/apimapper/diagnose.d.ts +54 -2
  27. package/dist/modules/apimapper/diagnose.js +193 -11
  28. package/dist/modules/apimapper/diagnose.js.map +1 -1
  29. package/dist/modules/apimapper/elicitation.d.ts +54 -0
  30. package/dist/modules/apimapper/elicitation.js +90 -0
  31. package/dist/modules/apimapper/elicitation.js.map +1 -0
  32. package/dist/modules/apimapper/flows-format.d.ts +50 -0
  33. package/dist/modules/apimapper/flows-format.js +318 -0
  34. package/dist/modules/apimapper/flows-format.js.map +1 -0
  35. package/dist/modules/apimapper/flows.d.ts +13 -2
  36. package/dist/modules/apimapper/flows.js +325 -118
  37. package/dist/modules/apimapper/flows.js.map +1 -1
  38. package/dist/modules/apimapper/gateway/advanced-tool.d.ts +9 -0
  39. package/dist/modules/apimapper/gateway/advanced-tool.js +214 -0
  40. package/dist/modules/apimapper/gateway/advanced-tool.js.map +1 -0
  41. package/dist/modules/apimapper/gateway/capturing-server.d.ts +81 -0
  42. package/dist/modules/apimapper/gateway/capturing-server.js +87 -0
  43. package/dist/modules/apimapper/gateway/capturing-server.js.map +1 -0
  44. package/dist/modules/apimapper/gateway/essentials.d.ts +4 -0
  45. package/dist/modules/apimapper/gateway/essentials.js +28 -0
  46. package/dist/modules/apimapper/gateway/essentials.js.map +1 -0
  47. package/dist/modules/apimapper/gateway/test-support.d.ts +17 -0
  48. package/dist/modules/apimapper/gateway/test-support.js +43 -0
  49. package/dist/modules/apimapper/gateway/test-support.js.map +1 -0
  50. package/dist/modules/apimapper/get-skill.d.ts +3 -3
  51. package/dist/modules/apimapper/get-skill.js +4 -2
  52. package/dist/modules/apimapper/get-skill.js.map +1 -1
  53. package/dist/modules/apimapper/graph-builder.js +1 -1
  54. package/dist/modules/apimapper/graph-builder.js.map +1 -1
  55. package/dist/modules/apimapper/graph.d.ts +2 -2
  56. package/dist/modules/apimapper/graph.js +165 -34
  57. package/dist/modules/apimapper/graph.js.map +1 -1
  58. package/dist/modules/apimapper/index.d.ts +17 -1
  59. package/dist/modules/apimapper/index.js +66 -17
  60. package/dist/modules/apimapper/index.js.map +1 -1
  61. package/dist/modules/apimapper/inspect.d.ts +3 -2
  62. package/dist/modules/apimapper/inspect.js +97 -13
  63. package/dist/modules/apimapper/inspect.js.map +1 -1
  64. package/dist/modules/apimapper/library.d.ts +2 -2
  65. package/dist/modules/apimapper/library.js +303 -60
  66. package/dist/modules/apimapper/library.js.map +1 -1
  67. package/dist/modules/apimapper/license-format.d.ts +22 -0
  68. package/dist/modules/apimapper/license-format.js +149 -0
  69. package/dist/modules/apimapper/license-format.js.map +1 -0
  70. package/dist/modules/apimapper/license.d.ts +16 -2
  71. package/dist/modules/apimapper/license.js +85 -37
  72. package/dist/modules/apimapper/license.js.map +1 -1
  73. package/dist/modules/apimapper/local-sources.d.ts +2 -2
  74. package/dist/modules/apimapper/local-sources.js +58 -30
  75. package/dist/modules/apimapper/local-sources.js.map +1 -1
  76. package/dist/modules/apimapper/misc.d.ts +30 -2
  77. package/dist/modules/apimapper/misc.js +129 -50
  78. package/dist/modules/apimapper/misc.js.map +1 -1
  79. package/dist/modules/apimapper/node-schema.d.ts +52 -0
  80. package/dist/modules/apimapper/node-schema.js +70 -2
  81. package/dist/modules/apimapper/node-schema.js.map +1 -1
  82. package/dist/modules/apimapper/normalizers.d.ts +1 -0
  83. package/dist/modules/apimapper/normalizers.js +51 -0
  84. package/dist/modules/apimapper/normalizers.js.map +1 -1
  85. package/dist/modules/apimapper/onboarding.d.ts +48 -2
  86. package/dist/modules/apimapper/onboarding.js +324 -17
  87. package/dist/modules/apimapper/onboarding.js.map +1 -1
  88. package/dist/modules/apimapper/read-cache.d.ts +31 -2
  89. package/dist/modules/apimapper/read-cache.js +20 -6
  90. package/dist/modules/apimapper/read-cache.js.map +1 -1
  91. package/dist/modules/apimapper/render/_shared.d.ts +24 -0
  92. package/dist/modules/apimapper/render/_shared.js +84 -0
  93. package/dist/modules/apimapper/render/_shared.js.map +1 -0
  94. package/dist/modules/apimapper/render/dag.d.ts +18 -0
  95. package/dist/modules/apimapper/render/dag.js +70 -0
  96. package/dist/modules/apimapper/render/dag.js.map +1 -0
  97. package/dist/modules/apimapper/render/index.d.ts +2 -0
  98. package/dist/modules/apimapper/render/index.js +112 -0
  99. package/dist/modules/apimapper/render/index.js.map +1 -0
  100. package/dist/modules/apimapper/render/renderers/chart-bar.d.ts +2 -0
  101. package/dist/modules/apimapper/render/renderers/chart-bar.js +70 -0
  102. package/dist/modules/apimapper/render/renderers/chart-bar.js.map +1 -0
  103. package/dist/modules/apimapper/render/renderers/chart-line.d.ts +2 -0
  104. package/dist/modules/apimapper/render/renderers/chart-line.js +71 -0
  105. package/dist/modules/apimapper/render/renderers/chart-line.js.map +1 -0
  106. package/dist/modules/apimapper/render/renderers/diff.d.ts +2 -0
  107. package/dist/modules/apimapper/render/renderers/diff.js +154 -0
  108. package/dist/modules/apimapper/render/renderers/diff.js.map +1 -0
  109. package/dist/modules/apimapper/render/renderers/flow-diagram.d.ts +1 -0
  110. package/dist/modules/apimapper/render/renderers/flow-diagram.js +180 -0
  111. package/dist/modules/apimapper/render/renderers/flow-diagram.js.map +1 -0
  112. package/dist/modules/apimapper/render/renderers/json-tree.d.ts +2 -0
  113. package/dist/modules/apimapper/render/renderers/json-tree.js +87 -0
  114. package/dist/modules/apimapper/render/renderers/json-tree.js.map +1 -0
  115. package/dist/modules/apimapper/render/renderers/schema-diagram.d.ts +2 -0
  116. package/dist/modules/apimapper/render/renderers/schema-diagram.js +83 -0
  117. package/dist/modules/apimapper/render/renderers/schema-diagram.js.map +1 -0
  118. package/dist/modules/apimapper/render/renderers/table.d.ts +2 -0
  119. package/dist/modules/apimapper/render/renderers/table.js +75 -0
  120. package/dist/modules/apimapper/render/renderers/table.js.map +1 -0
  121. package/dist/modules/apimapper/render/schemas.d.ts +23 -0
  122. package/dist/modules/apimapper/render/schemas.js +56 -0
  123. package/dist/modules/apimapper/render/schemas.js.map +1 -0
  124. package/dist/modules/apimapper/render/secret-masking.d.ts +5 -0
  125. package/dist/modules/apimapper/render/secret-masking.js +51 -0
  126. package/dist/modules/apimapper/render/secret-masking.js.map +1 -0
  127. package/dist/modules/apimapper/render/sidecar.d.ts +21 -0
  128. package/dist/modules/apimapper/render/sidecar.js +66 -0
  129. package/dist/modules/apimapper/render/sidecar.js.map +1 -0
  130. package/dist/modules/apimapper/render/token-cap.d.ts +21 -0
  131. package/dist/modules/apimapper/render/token-cap.js +57 -0
  132. package/dist/modules/apimapper/render/token-cap.js.map +1 -0
  133. package/dist/modules/apimapper/schema.d.ts +2 -2
  134. package/dist/modules/apimapper/schema.js +100 -32
  135. package/dist/modules/apimapper/schema.js.map +1 -1
  136. package/dist/modules/apimapper/settings-format.d.ts +23 -0
  137. package/dist/modules/apimapper/settings-format.js +135 -0
  138. package/dist/modules/apimapper/settings-format.js.map +1 -0
  139. package/dist/modules/apimapper/settings.d.ts +2 -2
  140. package/dist/modules/apimapper/settings.js +101 -40
  141. package/dist/modules/apimapper/settings.js.map +1 -1
  142. package/dist/modules/apimapper/skill-resources.d.ts +2 -2
  143. package/dist/modules/apimapper/skill-resources.js.map +1 -1
  144. package/dist/modules/apimapper/token-baseline.harness.d.ts +91 -0
  145. package/dist/modules/apimapper/token-baseline.harness.js +291 -0
  146. package/dist/modules/apimapper/token-baseline.harness.js.map +1 -0
  147. package/dist/modules/apimapper/toolslist-size.d.ts +55 -0
  148. package/dist/modules/apimapper/toolslist-size.js +190 -0
  149. package/dist/modules/apimapper/toolslist-size.js.map +1 -0
  150. package/dist/modules/apimapper/types.d.ts +23 -8
  151. package/dist/modules/apimapper/types.js +26 -1
  152. package/dist/modules/apimapper/types.js.map +1 -1
  153. package/dist/modules/apimapper/use-profile.d.ts +21 -0
  154. package/dist/modules/apimapper/use-profile.js +56 -2
  155. package/dist/modules/apimapper/use-profile.js.map +1 -1
  156. package/dist/modules/apimapper/workflows.d.ts +2 -2
  157. package/dist/modules/apimapper/workflows.js +143 -16
  158. package/dist/modules/apimapper/workflows.js.map +1 -1
  159. package/dist/platform/index.js +44 -5
  160. package/dist/platform/index.js.map +1 -1
  161. package/dist/setup-cli.d.ts +53 -0
  162. package/dist/setup-cli.js +126 -4
  163. package/dist/setup-cli.js.map +1 -1
  164. package/docs/architecture.md +1 -1
  165. package/docs/tools.md +1 -1
  166. package/manifest.json +12 -3
  167. package/package.json +9 -4
  168. package/skills/apimapper/SKILL.md +1 -1
  169. package/skills/apimapper/reference/render.md +132 -0
  170. package/skills/apimapper/reference/troubleshooting.md +1 -1
  171. package/skills/apimapper/reference/yootheme.md +1 -1
@@ -0,0 +1,291 @@
1
+ // token-baseline.harness.ts — W3.0.C
2
+ //
3
+ // Deterministic, offline token-output measurement for the canonical API
4
+ // Mapper tool-call sequence. The SAME harness is re-run after Welle 3 ships;
5
+ // the before/after delta is what proves the ≥40% token-reduction goal, so
6
+ // consistency between runs matters more than the absolute number.
7
+ //
8
+ // How it works:
9
+ // 1. The caller passes the registered apimapper tools map (the live
10
+ // `registerTool` config + handler for every tool) and a `fetchResponder`
11
+ // that maps an upstream URL to a canned real-shape REST response.
12
+ // 2. `runTokenBaseline` installs the responder as `globalThis.fetch`,
13
+ // replays the 8-call canonical sequence against the real tool handlers
14
+ // with canned real-shape inputs, sums the UTF-8 byte length of every
15
+ // result's `content[].text` block, and restores `globalThis.fetch`.
16
+ // 3. It returns `{ sequence: [{ tool, bytes }], totalBytes }`.
17
+ //
18
+ // No network, no child process — the tool handlers run in-process and the
19
+ // REST layer is the supplied responder. Given the same tools map and the
20
+ // same responder, the result is byte-for-byte identical (determinism is
21
+ // pinned by token-baseline.test.ts).
22
+ /**
23
+ * The canonical 8-call walkthrough (the Maria mixed-feed flow): a fresh user
24
+ * discovers the install, activates a library template, inspects a connection,
25
+ * builds and validates a flow, then compiles it. Inputs are real-shape and
26
+ * fixed so the measurement is reproducible.
27
+ */
28
+ export const CANONICAL_SEQUENCE = [
29
+ { tool: "apimapper_onboarding", args: {} },
30
+ { tool: "apimapper_library_list", args: { limit: 25 } },
31
+ {
32
+ tool: "apimapper_library_activate",
33
+ args: { id: "pexels", extra_fields: { api_key: "demo-key" } },
34
+ },
35
+ { tool: "apimapper_connection_list", args: {} },
36
+ { tool: "apimapper_connection_data", args: { id: "con_pexels", limit: 10 } },
37
+ {
38
+ tool: "apimapper_flow_create",
39
+ args: {
40
+ name: "Maria Mixed Feed",
41
+ nodes: [
42
+ {
43
+ id: "src1",
44
+ type: "source",
45
+ position: { x: 0, y: 0 },
46
+ data: { connectionId: "con_pexels" },
47
+ },
48
+ {
49
+ id: "out1",
50
+ type: "output-yootheme",
51
+ position: { x: 300, y: 0 },
52
+ data: { name: "Mixed Feed" },
53
+ },
54
+ ],
55
+ edges: [{ id: "e1", source: "src1", target: "out1" }],
56
+ },
57
+ },
58
+ {
59
+ tool: "apimapper_graph_validate",
60
+ args: {
61
+ nodes: [
62
+ {
63
+ id: "src1",
64
+ type: "source",
65
+ position: { x: 0, y: 0 },
66
+ data: { connectionId: "con_pexels" },
67
+ },
68
+ {
69
+ id: "out1",
70
+ type: "output-yootheme",
71
+ position: { x: 300, y: 0 },
72
+ data: { name: "Mixed Feed" },
73
+ },
74
+ ],
75
+ edges: [{ id: "e1", source: "src1", target: "out1" }],
76
+ },
77
+ },
78
+ { tool: "apimapper_flow_compile", args: { id: "flow_maria01" } },
79
+ ];
80
+ /** The tool names the canonical sequence exercises, in call order. */
81
+ export const CANONICAL_TOOLS = CANONICAL_SEQUENCE.map((s) => s.tool);
82
+ // ── Canonical real-shape REST fixtures ──────────────────────────────────
83
+ //
84
+ // One fixture per upstream endpoint the canonical sequence touches. Shapes
85
+ // mirror the actual PHP wire responses (the same shapes the per-module test
86
+ // files assert against). Keeping them here — alongside the sequence — means
87
+ // the determinism test and the scripts/token-baseline.mjs runner measure the
88
+ // exact same byte budget; the responder is a single source of truth.
89
+ // `provider` mirrors the real library.test.ts fixtures — the library_list
90
+ // handler reads it for the client-side provider filter, so shipping it keeps
91
+ // the measured shape faithful to the live PHP wire response.
92
+ const LIBRARY_ITEMS = [
93
+ {
94
+ id: "pexels",
95
+ name: "Pexels",
96
+ provider: "pexels",
97
+ category: "media",
98
+ description: "Free stock photos and videos via the Pexels REST API.",
99
+ auth_type: "apikey",
100
+ popular: true,
101
+ },
102
+ {
103
+ id: "google-sheets",
104
+ name: "Google Sheets",
105
+ provider: "google",
106
+ category: "productivity",
107
+ description: "Read rows from a Google Sheets spreadsheet.",
108
+ auth_type: "oauth2_authcode",
109
+ popular: true,
110
+ },
111
+ {
112
+ id: "instagram",
113
+ name: "Instagram Graph",
114
+ provider: "instagram",
115
+ category: "social",
116
+ description: "Fetch media from an Instagram Business account.",
117
+ auth_type: "oauth2_authcode",
118
+ popular: false,
119
+ },
120
+ ];
121
+ const CONNECTIONS = [
122
+ {
123
+ id: "con_pexels",
124
+ name: "Pexels — Curated",
125
+ source_type: "pexels",
126
+ status: "active",
127
+ credential_id: "cred_pexels1",
128
+ },
129
+ ];
130
+ const PEXELS_ROWS = Array.from({ length: 10 }, (_, i) => ({
131
+ id: 1000 + i,
132
+ title: `Curated photo ${i + 1}`,
133
+ photographer: `Photographer ${i + 1}`,
134
+ image: { url: `https://images.pexels.com/photos/${1000 + i}/photo.jpg` },
135
+ width: 1920,
136
+ height: 1280,
137
+ }));
138
+ const FLOW_OBJECT = {
139
+ id: "flow_maria01",
140
+ name: "Maria Mixed Feed",
141
+ node_count: 2,
142
+ is_compiled: false,
143
+ };
144
+ /**
145
+ * Canonical fetch responder — routes an upstream URL to its real-shape
146
+ * fixture. Anything unmatched returns an empty-success envelope, which is the
147
+ * benign default for the optional sub-calls inside `apimapper_onboarding`.
148
+ */
149
+ export function canonicalFetchResponder(url) {
150
+ if (url.includes("/library/popular")) {
151
+ return { body: { connections: LIBRARY_ITEMS.filter((i) => i.popular) } };
152
+ }
153
+ if (url.includes("/library/featured")) {
154
+ return { body: { connections: LIBRARY_ITEMS.slice(0, 2) } };
155
+ }
156
+ if (url.includes("/library/categories")) {
157
+ return {
158
+ body: {
159
+ categories: [
160
+ { id: "media", name: "Media", count: 4 },
161
+ { id: "social", name: "Social", count: 3 },
162
+ ],
163
+ },
164
+ };
165
+ }
166
+ if (url.includes("/library/pexels/activate")) {
167
+ return {
168
+ body: {
169
+ success: true,
170
+ connection: { id: "con_pexels", name: "Pexels", source_type: "pexels" },
171
+ reused: false,
172
+ },
173
+ };
174
+ }
175
+ if (url.includes("/library")) {
176
+ return { body: { connections: LIBRARY_ITEMS, total: LIBRARY_ITEMS.length } };
177
+ }
178
+ if (url.includes("/connections/con_pexels/data")) {
179
+ // Real backend returns the connection as an OBJECT, not a bare id —
180
+ // mirrors the {data, connection:{…}} envelope the connections.test.ts
181
+ // fixtures assert against, so the byte measurement stays realistic.
182
+ return {
183
+ body: {
184
+ data: PEXELS_ROWS,
185
+ connection: {
186
+ id: "con_pexels",
187
+ name: "Pexels — Curated",
188
+ source_type: "pexels",
189
+ },
190
+ },
191
+ };
192
+ }
193
+ if (url.includes("/connections")) {
194
+ return { body: { connections: CONNECTIONS } };
195
+ }
196
+ if (url.includes("/flows/flow_maria01/compile")) {
197
+ return { body: { compiled: {}, flowId: "flow_maria01" } };
198
+ }
199
+ if (url.includes("/flows")) {
200
+ return { body: { success: true, flow: FLOW_OBJECT } };
201
+ }
202
+ if (url.includes("/graph/validate")) {
203
+ return {
204
+ body: { valid: true, warnings: [], nodeCount: 2, edgeCount: 1 },
205
+ };
206
+ }
207
+ if (url.includes("/health")) {
208
+ return {
209
+ body: { plugin_version: "2.0.7", api_version: "v1", status: "ok" },
210
+ };
211
+ }
212
+ if (url.includes("/license")) {
213
+ return { body: { tier: "pro", status: "active" } };
214
+ }
215
+ // Benign default for any onboarding sub-call without a dedicated fixture.
216
+ return { body: {} };
217
+ }
218
+ /**
219
+ * Matches the toolkit's embedded structured-meta marker — a trailing
220
+ * `\n\n<!-- structured-meta:<base64> -->` block appended by the
221
+ * `tableResult` / `detailResult` / … builders so `_meta.ui` survives
222
+ * `@ai-sdk/mcp`'s conversion (see @getimo/mcp-toolkit `embedStructuredMeta`).
223
+ * The `[A-Za-z0-9+/=]*` body is base64; `g` strips every occurrence.
224
+ */
225
+ const STRUCTURED_META_MARKER = /\n\n<!-- structured-meta:[A-Za-z0-9+/=]*? -->/g;
226
+ /**
227
+ * Strip every embedded structured-meta marker from a text block. What remains
228
+ * is the human/LLM-readable text a marker-aware host (the WootsUp Chat UI)
229
+ * presents after extracting the marker into a Rich Card.
230
+ */
231
+ export function stripStructuredMeta(text) {
232
+ return text.replace(STRUCTURED_META_MARKER, "");
233
+ }
234
+ /**
235
+ * Sum the UTF-8 byte length of every text block in a tool result — both the
236
+ * raw bytes (`bytes`) and the marker-stripped, LLM-visible bytes
237
+ * (`visibleBytes`). The raw figure is the token-baseline metric; the visible
238
+ * figure is what a marker-stripping host actually feeds the model.
239
+ */
240
+ function resultBytes(result) {
241
+ const blocks = Array.isArray(result.content) ? result.content : [];
242
+ let bytes = 0;
243
+ let visibleBytes = 0;
244
+ for (const block of blocks) {
245
+ if (typeof block.text === "string") {
246
+ bytes += Buffer.byteLength(block.text, "utf8");
247
+ visibleBytes += Buffer.byteLength(stripStructuredMeta(block.text), "utf8");
248
+ }
249
+ }
250
+ return { bytes, visibleBytes };
251
+ }
252
+ /**
253
+ * Replay the canonical sequence and measure total token output.
254
+ *
255
+ * @param tools the registered apimapper tools map (name → tool)
256
+ * @param fetchResponder maps each upstream URL to a canned REST response
257
+ * @returns per-tool byte tally + `totalBytes` across the whole sequence
258
+ */
259
+ export async function runTokenBaseline(tools, fetchResponder) {
260
+ const originalFetch = globalThis.fetch;
261
+ globalThis.fetch = (async (input, init) => {
262
+ const url = String(input);
263
+ const canned = fetchResponder(url, init);
264
+ const body = typeof canned.body === "string"
265
+ ? canned.body
266
+ : JSON.stringify(canned.body);
267
+ return new Response(body, {
268
+ status: canned.status ?? 200,
269
+ headers: { "Content-Type": "application/json" },
270
+ });
271
+ });
272
+ try {
273
+ const sequence = [];
274
+ for (const step of CANONICAL_SEQUENCE) {
275
+ const tool = tools[step.tool];
276
+ if (!tool) {
277
+ throw new Error(`token-baseline: tool "${step.tool}" is not registered`);
278
+ }
279
+ const result = await tool.handler(step.args);
280
+ const { bytes, visibleBytes } = resultBytes(result);
281
+ sequence.push({ tool: step.tool, bytes, visibleBytes });
282
+ }
283
+ const totalBytes = sequence.reduce((sum, e) => sum + e.bytes, 0);
284
+ const totalVisibleBytes = sequence.reduce((sum, e) => sum + e.visibleBytes, 0);
285
+ return { sequence, totalBytes, totalVisibleBytes };
286
+ }
287
+ finally {
288
+ globalThis.fetch = originalFetch;
289
+ }
290
+ }
291
+ //# sourceMappingURL=token-baseline.harness.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-baseline.harness.js","sourceRoot":"","sources":["../../../src/modules/apimapper/token-baseline.harness.ts"],"names":[],"mappings":"AAAA,qCAAqC;AACrC,EAAE;AACF,wEAAwE;AACxE,6EAA6E;AAC7E,0EAA0E;AAC1E,kEAAkE;AAClE,EAAE;AACF,gBAAgB;AAChB,sEAAsE;AACtE,8EAA8E;AAC9E,uEAAuE;AACvE,wEAAwE;AACxE,4EAA4E;AAC5E,0EAA0E;AAC1E,yEAAyE;AACzE,iEAAiE;AACjE,EAAE;AACF,0EAA0E;AAC1E,yEAAyE;AACzE,wEAAwE;AACxE,qCAAqC;AA0ErC;;;;;GAKG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAA4B;IACzD,EAAE,IAAI,EAAE,sBAAsB,EAAE,IAAI,EAAE,EAAE,EAAE;IAC1C,EAAE,IAAI,EAAE,wBAAwB,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE;IACvD;QACE,IAAI,EAAE,4BAA4B;QAClC,IAAI,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,YAAY,EAAE,EAAE,OAAO,EAAE,UAAU,EAAE,EAAE;KAC9D;IACD,EAAE,IAAI,EAAE,2BAA2B,EAAE,IAAI,EAAE,EAAE,EAAE;IAC/C,EAAE,IAAI,EAAE,2BAA2B,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE;IAC5E;QACE,IAAI,EAAE,uBAAuB;QAC7B,IAAI,EAAE;YACJ,IAAI,EAAE,kBAAkB;YACxB,KAAK,EAAE;gBACL;oBACE,EAAE,EAAE,MAAM;oBACV,IAAI,EAAE,QAAQ;oBACd,QAAQ,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;oBACxB,IAAI,EAAE,EAAE,YAAY,EAAE,YAAY,EAAE;iBACrC;gBACD;oBACE,EAAE,EAAE,MAAM;oBACV,IAAI,EAAE,iBAAiB;oBACvB,QAAQ,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE;oBAC1B,IAAI,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE;iBAC7B;aACF;YACD,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;SACtD;KACF;IACD;QACE,IAAI,EAAE,0BAA0B;QAChC,IAAI,EAAE;YACJ,KAAK,EAAE;gBACL;oBACE,EAAE,EAAE,MAAM;oBACV,IAAI,EAAE,QAAQ;oBACd,QAAQ,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;oBACxB,IAAI,EAAE,EAAE,YAAY,EAAE,YAAY,EAAE;iBACrC;gBACD;oBACE,EAAE,EAAE,MAAM;oBACV,IAAI,EAAE,iBAAiB;oBACvB,QAAQ,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE;oBAC1B,IAAI,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE;iBAC7B;aACF;YACD,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;SACtD;KACF;IACD,EAAE,IAAI,EAAE,wBAAwB,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,cAAc,EAAE,EAAE;CACxD,CAAC;AAEX,sEAAsE;AACtE,MAAM,CAAC,MAAM,eAAe,GAAsB,kBAAkB,CAAC,GAAG,CACtE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CACd,CAAC;AAEF,2EAA2E;AAC3E,EAAE;AACF,2EAA2E;AAC3E,4EAA4E;AAC5E,4EAA4E;AAC5E,6EAA6E;AAC7E,qEAAqE;AAErE,0EAA0E;AAC1E,6EAA6E;AAC7E,6DAA6D;AAC7D,MAAM,aAAa,GAAG;IACpB;QACE,EAAE,EAAE,QAAQ;QACZ,IAAI,EAAE,QAAQ;QACd,QAAQ,EAAE,QAAQ;QAClB,QAAQ,EAAE,OAAO;QACjB,WAAW,EAAE,uDAAuD;QACpE,SAAS,EAAE,QAAQ;QACnB,OAAO,EAAE,IAAI;KACd;IACD;QACE,EAAE,EAAE,eAAe;QACnB,IAAI,EAAE,eAAe;QACrB,QAAQ,EAAE,QAAQ;QAClB,QAAQ,EAAE,cAAc;QACxB,WAAW,EAAE,6CAA6C;QAC1D,SAAS,EAAE,iBAAiB;QAC5B,OAAO,EAAE,IAAI;KACd;IACD;QACE,EAAE,EAAE,WAAW;QACf,IAAI,EAAE,iBAAiB;QACvB,QAAQ,EAAE,WAAW;QACrB,QAAQ,EAAE,QAAQ;QAClB,WAAW,EAAE,iDAAiD;QAC9D,SAAS,EAAE,iBAAiB;QAC5B,OAAO,EAAE,KAAK;KACf;CACF,CAAC;AAEF,MAAM,WAAW,GAAG;IAClB;QACE,EAAE,EAAE,YAAY;QAChB,IAAI,EAAE,kBAAkB;QACxB,WAAW,EAAE,QAAQ;QACrB,MAAM,EAAE,QAAQ;QAChB,aAAa,EAAE,cAAc;KAC9B;CACF,CAAC;AAEF,MAAM,WAAW,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;IACxD,EAAE,EAAE,IAAI,GAAG,CAAC;IACZ,KAAK,EAAE,iBAAiB,CAAC,GAAG,CAAC,EAAE;IAC/B,YAAY,EAAE,gBAAgB,CAAC,GAAG,CAAC,EAAE;IACrC,KAAK,EAAE,EAAE,GAAG,EAAE,oCAAoC,IAAI,GAAG,CAAC,YAAY,EAAE;IACxE,KAAK,EAAE,IAAI;IACX,MAAM,EAAE,IAAI;CACb,CAAC,CAAC,CAAC;AAEJ,MAAM,WAAW,GAAG;IAClB,EAAE,EAAE,cAAc;IAClB,IAAI,EAAE,kBAAkB;IACxB,UAAU,EAAE,CAAC;IACb,WAAW,EAAE,KAAK;CACnB,CAAC;AAEF;;;;GAIG;AACH,MAAM,UAAU,uBAAuB,CAAC,GAAW;IACjD,IAAI,GAAG,CAAC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,CAAC;QACrC,OAAO,EAAE,IAAI,EAAE,EAAE,WAAW,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC;IAC3E,CAAC;IACD,IAAI,GAAG,CAAC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAAC;QACtC,OAAO,EAAE,IAAI,EAAE,EAAE,WAAW,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC;IAC9D,CAAC;IACD,IAAI,GAAG,CAAC,QAAQ,CAAC,qBAAqB,CAAC,EAAE,CAAC;QACxC,OAAO;YACL,IAAI,EAAE;gBACJ,UAAU,EAAE;oBACV,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE;oBACxC,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,EAAE;iBAC3C;aACF;SACF,CAAC;IACJ,CAAC;IACD,IAAI,GAAG,CAAC,QAAQ,CAAC,0BAA0B,CAAC,EAAE,CAAC;QAC7C,OAAO;YACL,IAAI,EAAE;gBACJ,OAAO,EAAE,IAAI;gBACb,UAAU,EAAE,EAAE,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE;gBACvE,MAAM,EAAE,KAAK;aACd;SACF,CAAC;IACJ,CAAC;IACD,IAAI,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;QAC7B,OAAO,EAAE,IAAI,EAAE,EAAE,WAAW,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,CAAC,MAAM,EAAE,EAAE,CAAC;IAC/E,CAAC;IACD,IAAI,GAAG,CAAC,QAAQ,CAAC,8BAA8B,CAAC,EAAE,CAAC;QACjD,oEAAoE;QACpE,sEAAsE;QACtE,oEAAoE;QACpE,OAAO;YACL,IAAI,EAAE;gBACJ,IAAI,EAAE,WAAW;gBACjB,UAAU,EAAE;oBACV,EAAE,EAAE,YAAY;oBAChB,IAAI,EAAE,kBAAkB;oBACxB,WAAW,EAAE,QAAQ;iBACtB;aACF;SACF,CAAC;IACJ,CAAC;IACD,IAAI,GAAG,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;QACjC,OAAO,EAAE,IAAI,EAAE,EAAE,WAAW,EAAE,WAAW,EAAE,EAAE,CAAC;IAChD,CAAC;IACD,IAAI,GAAG,CAAC,QAAQ,CAAC,6BAA6B,CAAC,EAAE,CAAC;QAChD,OAAO,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,cAAc,EAAE,EAAE,CAAC;IAC5D,CAAC;IACD,IAAI,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC3B,OAAO,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,CAAC;IACxD,CAAC;IACD,IAAI,GAAG,CAAC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,CAAC;QACpC,OAAO;YACL,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE;SAChE,CAAC;IACJ,CAAC;IACD,IAAI,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QAC5B,OAAO;YACL,IAAI,EAAE,EAAE,cAAc,EAAE,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE;SACnE,CAAC;IACJ,CAAC;IACD,IAAI,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;QAC7B,OAAO,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,CAAC;IACrD,CAAC;IACD,0EAA0E;IAC1E,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;AACtB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,sBAAsB,GAC1B,gDAAgD,CAAC;AAEnD;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC9C,OAAO,IAAI,CAAC,OAAO,CAAC,sBAAsB,EAAE,EAAE,CAAC,CAAC;AAClD,CAAC;AAED;;;;;GAKG;AACH,SAAS,WAAW,CAAC,MAAsB;IAIzC,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;IACnE,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,YAAY,GAAG,CAAC,CAAC;IACrB,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACnC,KAAK,IAAI,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YAC/C,YAAY,IAAI,MAAM,CAAC,UAAU,CAC/B,mBAAmB,CAAC,KAAK,CAAC,IAAI,CAAC,EAC/B,MAAM,CACP,CAAC;QACJ,CAAC;IACH,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC;AACjC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,KAA4C,EAC5C,cAA8B;IAE9B,MAAM,aAAa,GAAG,UAAU,CAAC,KAAK,CAAC;IACvC,UAAU,CAAC,KAAK,GAAG,CAAC,KAAK,EACvB,KAAwB,EACxB,IAAkB,EACC,EAAE;QACrB,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;QAC1B,MAAM,MAAM,GAAG,cAAc,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QACzC,MAAM,IAAI,GACR,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ;YAC7B,CAAC,CAAC,MAAM,CAAC,IAAI;YACb,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAClC,OAAO,IAAI,QAAQ,CAAC,IAAI,EAAE;YACxB,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,GAAG;YAC5B,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;SAChD,CAAC,CAAC;IACL,CAAC,CAAiB,CAAC;IAEnB,IAAI,CAAC;QACH,MAAM,QAAQ,GAAoB,EAAE,CAAC;QACrC,KAAK,MAAM,IAAI,IAAI,kBAAkB,EAAE,CAAC;YACtC,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC9B,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,MAAM,IAAI,KAAK,CACb,yBAAyB,IAAI,CAAC,IAAI,qBAAqB,CACxD,CAAC;YACJ,CAAC;YACD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC7C,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;YACpD,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC,CAAC;QAC1D,CAAC;QACD,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QACjE,MAAM,iBAAiB,GAAG,QAAQ,CAAC,MAAM,CACvC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,YAAY,EAChC,CAAC,CACF,CAAC;QACF,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,iBAAiB,EAAE,CAAC;IACrD,CAAC;YAAS,CAAC;QACT,UAAU,CAAC,KAAK,GAAG,aAAa,CAAC;IACnC,CAAC;AACH,CAAC"}
@@ -0,0 +1,55 @@
1
+ import { type CollectedTool } from "./gateway/test-support.js";
2
+ /**
3
+ * The minimal `tools/list`-relevant slice of a registered tool: the fields the
4
+ * MCP client receives and the LLM reads as part of the static catalog.
5
+ */
6
+ export interface ToolCatalogEntry {
7
+ name: string;
8
+ description?: string;
9
+ inputSchema?: unknown;
10
+ annotations?: Record<string, unknown>;
11
+ }
12
+ /** One side of the measurement: its tool count and total serialized bytes. */
13
+ export interface ToolsListMeasurement {
14
+ /** Number of tools in this `tools/list` surface. */
15
+ toolCount: number;
16
+ /** Sum of `Buffer.byteLength(JSON.stringify(entry))` across all tools. */
17
+ totalBytes: number;
18
+ /** Per-tool byte tally, sorted by name, for the breakdown table. */
19
+ perTool: Array<{
20
+ name: string;
21
+ bytes: number;
22
+ }>;
23
+ }
24
+ /** The full Task-B result: the post-W3 and pre-W3-equivalent surfaces. */
25
+ export interface ToolsListComparison {
26
+ /** Post-W3 `tools/list` — the 17 surface tools the server exposes today. */
27
+ postW3: ToolsListMeasurement;
28
+ /** Pre-W3-equivalent `tools/list` — all 76 tools exposed flat (no gateway). */
29
+ preW3Flat: ToolsListMeasurement;
30
+ /** Absolute byte reduction (preW3Flat.totalBytes − postW3.totalBytes). */
31
+ bytesSaved: number;
32
+ /** Reduction as a fraction of the pre-W3-equivalent total (0..1). */
33
+ fractionSaved: number;
34
+ }
35
+ /**
36
+ * Projects one tool to its `tools/list` JSON-Schema-bearing catalog entry.
37
+ * The `inputSchema` is JSON-Schema-projected the same way the SDK and the
38
+ * gateway's discovery mode do, so the byte count reflects the real wire shape.
39
+ */
40
+ export declare function toCatalogEntry(name: string, tool: Pick<CollectedTool, "description" | "inputSchema" | "annotations">): ToolCatalogEntry;
41
+ /**
42
+ * Builds the full 77-tool catalog from the current build and measures the
43
+ * post-W3 vs pre-W3-equivalent `tools/list` payload sizes.
44
+ *
45
+ * Surface composition (verified against `gateway/essentials.ts` + `src/index.ts`):
46
+ * - module tools : 13 essentials + `apimapper_advanced` = 14 (on the real
47
+ * McpServer) + 60 advanced (gateway registry) = 74
48
+ * - top-level tools: rest_modules_status + use_profile + list_profiles = 3
49
+ * total = 77
50
+ *
51
+ * POST-W3 `tools/list` = the 14 module-real tools + the 3 top-level tools = 17.
52
+ * PRE-W3 flat `tools/list` = the 16 non-gateway surface tools + the 60 advanced
53
+ * tools = 76 (the `apimapper_advanced` gateway did not exist pre-W3).
54
+ */
55
+ export declare function measureToolsList(): Promise<ToolsListComparison>;
@@ -0,0 +1,190 @@
1
+ // toolslist-size.ts — W3 Stage-5 token-Δ measurement (Task B)
2
+ //
3
+ // Measures the `tools/list` catalog overhead — the static tool descriptions +
4
+ // JSON schemas an MCP client receives once per session, before any tool is
5
+ // called. This is the DOMINANT token cost center of an API Mapper session.
6
+ //
7
+ // Two figures, both derived from the CURRENT build:
8
+ //
9
+ // - POST-W3 `tools/list` — the 17 surface tools the server now exposes
10
+ // (13 module essentials + `apimapper_advanced`
11
+ // + the 3 src/index.ts top-level tools).
12
+ // - PRE-W3-equivalent `tools/list` — what `tools/list` WOULD be if all 77
13
+ // tools were exposed flat (the pre-Gateway
14
+ // state): the 17 surface tools minus the
15
+ // gateway tool, plus the 60 advanced-registry
16
+ // tool configs — 76 flat tools. (Pre-W3 the
17
+ // `apimapper_advanced` gateway did not exist.)
18
+ //
19
+ // Per-tool serialization mirrors what the MCP SDK puts on the wire for one
20
+ // `tools/list` entry: `{ name, description, inputSchema, annotations }`, where
21
+ // `inputSchema` is the JSON Schema projected from the tool's Zod raw-shape
22
+ // (the same `z.toJSONSchema` projection `gateway/advanced-tool.ts` uses for
23
+ // discovery mode). `title` and `_meta` are omitted: they are small, present on
24
+ // both sides, and cancel out in the delta — keeping the measurement focused on
25
+ // the description + schema payload that actually scales with the tool count.
26
+ //
27
+ // Determinism: given the same build, every figure is byte-for-byte identical.
28
+ // Pinned by toolslist-size.test.ts.
29
+ import * as os from "node:os";
30
+ import * as path from "node:path";
31
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
32
+ import { loadModules } from "@getimo/mcp-toolkit";
33
+ import { z } from "zod";
34
+ import { apimapperRestModule } from "./index.js";
35
+ import { collectModuleTools } from "./gateway/test-support.js";
36
+ import { registerListProfilesTool, registerUseProfileTool, } from "./use-profile.js";
37
+ import { ProfileStore } from "../../auth/profiles.js";
38
+ /**
39
+ * Reads a tool config's `inputSchema` as a Zod raw-shape. Mirrors `shapeOf`
40
+ * in `gateway/advanced-tool.ts` — a registered `inputSchema` is the raw shape
41
+ * object; a zero-arg tool has none.
42
+ */
43
+ function shapeOf(inputSchema) {
44
+ if (inputSchema && typeof inputSchema === "object") {
45
+ return inputSchema;
46
+ }
47
+ return {};
48
+ }
49
+ /**
50
+ * Projects one tool to its `tools/list` JSON-Schema-bearing catalog entry.
51
+ * The `inputSchema` is JSON-Schema-projected the same way the SDK and the
52
+ * gateway's discovery mode do, so the byte count reflects the real wire shape.
53
+ */
54
+ export function toCatalogEntry(name, tool) {
55
+ let inputSchema;
56
+ try {
57
+ inputSchema = z.toJSONSchema(z.object(shapeOf(tool.inputSchema)));
58
+ }
59
+ catch {
60
+ // A schema that cannot be JSON-projected still yields a usable entry; the
61
+ // description carries the rest. Matches the gateway discovery-mode guard.
62
+ inputSchema = { type: "object" };
63
+ }
64
+ return {
65
+ name,
66
+ description: tool.description,
67
+ inputSchema,
68
+ annotations: tool.annotations,
69
+ };
70
+ }
71
+ /**
72
+ * Serializes a list of catalog entries and tallies the UTF-8 byte length of
73
+ * each entry's `JSON.stringify`. The total is the `tools/list` payload size
74
+ * for that surface.
75
+ */
76
+ function measure(entries) {
77
+ const perTool = entries
78
+ .map((entry) => ({
79
+ name: entry.name,
80
+ bytes: Buffer.byteLength(JSON.stringify(entry), "utf8"),
81
+ }))
82
+ .sort((a, b) => a.name.localeCompare(b.name));
83
+ const totalBytes = perTool.reduce((sum, t) => sum + t.bytes, 0);
84
+ return { toolCount: perTool.length, totalBytes, perTool };
85
+ }
86
+ /** A no-op keychain: registration stores the dep but never invokes it here. */
87
+ const STUB_KEYCHAIN = {
88
+ set: async () => undefined,
89
+ get: async () => null,
90
+ delete: async () => undefined,
91
+ };
92
+ /**
93
+ * Captures the 3 top-level tools registered in `src/index.ts` —
94
+ * `apimapper_rest_modules_status`, `apimapper_use_profile`,
95
+ * `apimapper_list_profiles` — by replaying their registration against a
96
+ * recording registrar. `src/index.ts` registers these directly on the
97
+ * McpServer (not via the module / CapturingServer), so they must be added to
98
+ * the catalog explicitly for an accurate `tools/list` count.
99
+ *
100
+ * The use-profile registrations only *store* their `{ store, keychain }` deps;
101
+ * they are never invoked at registration time, so a real `ProfileStore` over a
102
+ * throwaway dir + a stub keychain is sufficient to capture the configs.
103
+ */
104
+ function captureTopLevelTools() {
105
+ const captured = new Map();
106
+ const recorder = {
107
+ registerTool(name, config) {
108
+ const cfg = config;
109
+ captured.set(name, {
110
+ handler: () => ({ content: [] }),
111
+ description: cfg.description,
112
+ inputSchema: cfg.inputSchema,
113
+ annotations: cfg.annotations,
114
+ });
115
+ },
116
+ };
117
+ // apimapper_rest_modules_status — registered inline in src/index.ts. Its
118
+ // config is replicated here verbatim (zero-arg readOnly status tool). The
119
+ // toolslist-size.test.ts cross-checks the captured name set, so drift
120
+ // between this replica and src/index.ts surfaces as a failing pin.
121
+ recorder.registerTool("apimapper_rest_modules_status", {
122
+ title: "Adapter Modules Status",
123
+ description: "Module-loading status for this MCP adapter (which sub-modules registered cleanly). " +
124
+ "For runtime connectivity + auth checks against the API Mapper REST surface, use apimapper_health.",
125
+ inputSchema: {},
126
+ annotations: { readOnlyHint: true, openWorldHint: false, title: "MCP Modules Status" },
127
+ });
128
+ // apimapper_use_profile + apimapper_list_profiles — registered via the
129
+ // use-profile module functions. Replaying the real registration functions
130
+ // captures their exact live config (description + Zod inputSchema).
131
+ // F-1.1 (Pass-1 consolidation): platform-portable temp path. The store is a
132
+ // throwaway used purely for tool-list shape capture during the measurement.
133
+ const store = new ProfileStore(path.join(os.tmpdir(), "__w3_toolslist_measure__"));
134
+ registerUseProfileTool(recorder, { store, keychain: STUB_KEYCHAIN });
135
+ registerListProfilesTool(recorder, { store, keychain: STUB_KEYCHAIN });
136
+ return captured;
137
+ }
138
+ /**
139
+ * Builds the full 77-tool catalog from the current build and measures the
140
+ * post-W3 vs pre-W3-equivalent `tools/list` payload sizes.
141
+ *
142
+ * Surface composition (verified against `gateway/essentials.ts` + `src/index.ts`):
143
+ * - module tools : 13 essentials + `apimapper_advanced` = 14 (on the real
144
+ * McpServer) + 60 advanced (gateway registry) = 74
145
+ * - top-level tools: rest_modules_status + use_profile + list_profiles = 3
146
+ * total = 77
147
+ *
148
+ * POST-W3 `tools/list` = the 14 module-real tools + the 3 top-level tools = 17.
149
+ * PRE-W3 flat `tools/list` = the 16 non-gateway surface tools + the 60 advanced
150
+ * tools = 76 (the `apimapper_advanced` gateway did not exist pre-W3).
151
+ */
152
+ export async function measureToolsList() {
153
+ const server = new McpServer({
154
+ name: "toolslist-size-measure",
155
+ version: "0.0.0",
156
+ });
157
+ await loadModules(server, [apimapperRestModule]);
158
+ // collectModuleTools unifies the real-server essentials (incl. the gateway
159
+ // tool) with the captured advanced-registry tools.
160
+ const moduleTools = collectModuleTools(server, apimapperRestModule);
161
+ const topLevelTools = captureTopLevelTools();
162
+ const advancedRegistry = apimapperRestModule.getAdvancedRegistry();
163
+ const advancedNames = new Set(advancedRegistry ? advancedRegistry.keys() : []);
164
+ // POST-W3 surface: every tool in `tools/list` today — module-real tools that
165
+ // are NOT in the advanced registry (i.e. essentials + the gateway) plus the
166
+ // 3 top-level tools.
167
+ const postEntries = [];
168
+ for (const [name, tool] of Object.entries(moduleTools)) {
169
+ if (advancedNames.has(name))
170
+ continue; // advanced — gated behind the gateway
171
+ postEntries.push(toCatalogEntry(name, tool));
172
+ }
173
+ for (const [name, tool] of topLevelTools) {
174
+ postEntries.push(toCatalogEntry(name, tool));
175
+ }
176
+ // PRE-W3-equivalent flat surface: the post-W3 surface MINUS the gateway tool
177
+ // (it did not exist pre-W3) PLUS every advanced tool exposed flat.
178
+ const preEntries = postEntries.filter((e) => e.name !== "apimapper_advanced");
179
+ for (const [name, tool] of Object.entries(moduleTools)) {
180
+ if (!advancedNames.has(name))
181
+ continue; // only the advanced tools
182
+ preEntries.push(toCatalogEntry(name, tool));
183
+ }
184
+ const postW3 = measure(postEntries);
185
+ const preW3Flat = measure(preEntries);
186
+ const bytesSaved = preW3Flat.totalBytes - postW3.totalBytes;
187
+ const fractionSaved = preW3Flat.totalBytes > 0 ? bytesSaved / preW3Flat.totalBytes : 0;
188
+ return { postW3, preW3Flat, bytesSaved, fractionSaved };
189
+ }
190
+ //# sourceMappingURL=toolslist-size.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toolslist-size.js","sourceRoot":"","sources":["../../../src/modules/apimapper/toolslist-size.ts"],"names":[],"mappings":"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"}
@@ -53,14 +53,8 @@ export interface FlowNode {
53
53
  data?: Record<string, unknown>;
54
54
  [k: string]: unknown;
55
55
  }
56
- export interface FlowEdge {
57
- id: string;
58
- source: string;
59
- target: string;
60
- sourceHandle?: string;
61
- targetHandle?: string;
62
- [k: string]: unknown;
63
- }
56
+ import type { FlowEdge } from "./node-schema.js";
57
+ export type { FlowEdge };
64
58
  export interface Flow {
65
59
  id: string;
66
60
  name: string;
@@ -109,3 +103,24 @@ export interface LicenseStatus {
109
103
  activation_count?: number;
110
104
  max_activations?: number;
111
105
  }
106
+ /**
107
+ * Bridge a typed-domain array to the toolkit's structurally-typed table-row
108
+ * shape.
109
+ *
110
+ * The mcp-core `tableResult()` (and other table builders) accept
111
+ * `Record<string, unknown>[]` for ASCII-table serialization. Our domain
112
+ * interfaces (`Connection`, `Credential`, `Flow`, `LibraryItem`, …) are
113
+ * nominal types without an index signature, so they are not structurally
114
+ * assignable to `Record<string, unknown>` even though every concrete row
115
+ * happens to satisfy it at runtime.
116
+ *
117
+ * Rather than scatter `items as unknown as Record<string, unknown>[]`
118
+ * across call-sites — each one looking like a code smell — this is the
119
+ * single documented interop point. Call-sites stay cast-free and the
120
+ * narrowing decision lives in ONE place that reviewers can audit.
121
+ *
122
+ * This is NOT a license to widen domain types — fields used downstream
123
+ * (column `key`s in the table config) are still type-checked against the
124
+ * domain interface separately.
125
+ */
126
+ export declare function toRows<T extends object>(items: readonly T[]): Record<string, unknown>[];
@@ -10,5 +10,30 @@
10
10
  // - LocalSource wire fmt = camelCase (contentType) with "platform/type" id ("wordpress/posts")
11
11
  //
12
12
  // These types reflect the actual REST contract verified against the PHP controllers.
13
- export {};
13
+ // =============================================================================
14
+ // Domain → toolkit interop bridge (F-1.2 — Pass-1 consolidation)
15
+ // =============================================================================
16
+ /**
17
+ * Bridge a typed-domain array to the toolkit's structurally-typed table-row
18
+ * shape.
19
+ *
20
+ * The mcp-core `tableResult()` (and other table builders) accept
21
+ * `Record<string, unknown>[]` for ASCII-table serialization. Our domain
22
+ * interfaces (`Connection`, `Credential`, `Flow`, `LibraryItem`, …) are
23
+ * nominal types without an index signature, so they are not structurally
24
+ * assignable to `Record<string, unknown>` even though every concrete row
25
+ * happens to satisfy it at runtime.
26
+ *
27
+ * Rather than scatter `items as unknown as Record<string, unknown>[]`
28
+ * across call-sites — each one looking like a code smell — this is the
29
+ * single documented interop point. Call-sites stay cast-free and the
30
+ * narrowing decision lives in ONE place that reviewers can audit.
31
+ *
32
+ * This is NOT a license to widen domain types — fields used downstream
33
+ * (column `key`s in the table config) are still type-checked against the
34
+ * domain interface separately.
35
+ */
36
+ export function toRows(items) {
37
+ return items;
38
+ }
14
39
  //# sourceMappingURL=types.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/modules/apimapper/types.ts"],"names":[],"mappings":"AAAA,oFAAoF;AACpF,EAAE;AACF,yEAAyE;AACzE,iGAAiG;AACjG,oFAAoF;AACpF,wEAAwE;AACxE,iFAAiF;AACjF,sEAAsE;AACtE,6EAA6E;AAC7E,mGAAmG;AACnG,EAAE;AACF,qFAAqF"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/modules/apimapper/types.ts"],"names":[],"mappings":"AAAA,oFAAoF;AACpF,EAAE;AACF,yEAAyE;AACzE,iGAAiG;AACjG,oFAAoF;AACpF,wEAAwE;AACxE,iFAAiF;AACjF,sEAAsE;AACtE,6EAA6E;AAC7E,mGAAmG;AACnG,EAAE;AACF,qFAAqF;AA8HrF,gFAAgF;AAChF,iEAAiE;AACjE,gFAAgF;AAEhF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,MAAM,CAAmB,KAAmB;IAC1D,OAAO,KAAwD,CAAC;AAClE,CAAC"}