@webmcp-auto-ui/sdk 2.5.32 → 2.5.34

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webmcp-auto-ui/sdk",
3
- "version": "2.5.32",
3
+ "version": "2.5.34",
4
4
  "description": "Skills CRUD, HyperSkill format, Svelte 5 stores",
5
5
  "license": "AGPL-3.0-or-later",
6
6
  "type": "module",
package/src/index.ts CHANGED
@@ -96,3 +96,6 @@ export type { ParsedSegment, RunResult, RunLog, RunTab, RecipeData } from './rec
96
96
 
97
97
  // Short URL — domain-dependent compact token
98
98
  export { buildShortUrl, getShortToken } from './short-url.js';
99
+
100
+ // Widget sample-data extractor — parses the `## Example` block of a recipe
101
+ export { extractSampleData } from './widget-sample-data.js';
@@ -80,7 +80,6 @@ function createCanvas() {
80
80
  // Setters (kept for backward compat)
81
81
  setMode(m: Mode) { canvasVanilla.setMode(m); },
82
82
  setLlm(l: LLMId) { canvasVanilla.setLlm(l); },
83
- setMcpUrl(u: string) { canvasVanilla.setMcpUrl(u); },
84
83
  setGenerating(g: boolean) { canvasVanilla.setGenerating(g); },
85
84
 
86
85
  // Widget actions (primary name)
@@ -101,11 +100,6 @@ function createCanvas() {
101
100
  updateMsg: canvasVanilla.updateMsg.bind(canvasVanilla),
102
101
  clearMessages: canvasVanilla.clearMessages.bind(canvasVanilla),
103
102
 
104
- // MCP
105
- setMcpConnecting: canvasVanilla.setMcpConnecting.bind(canvasVanilla),
106
- setMcpConnected: canvasVanilla.setMcpConnected.bind(canvasVanilla),
107
- setMcpError: canvasVanilla.setMcpError.bind(canvasVanilla),
108
-
109
103
  // Theme
110
104
  get themeOverrides() { return themeOverrides; },
111
105
  setThemeOverrides: canvasVanilla.setThemeOverrides.bind(canvasVanilla),
@@ -118,6 +112,7 @@ function createCanvas() {
118
112
  get dataServers() { return dataServers; },
119
113
  set dataServers(v: DataServer[]) { canvasVanilla.dataServers = v; },
120
114
  addDataServer: canvasVanilla.addDataServer.bind(canvasVanilla),
115
+ addMcpServer: canvasVanilla.addMcpServer.bind(canvasVanilla),
121
116
  removeDataServer: canvasVanilla.removeDataServer.bind(canvasVanilla),
122
117
  getDataServer: canvasVanilla.getDataServer.bind(canvasVanilla),
123
118
  setDataServerMeta: canvasVanilla.setDataServerMeta.bind(canvasVanilla),
@@ -10,17 +10,15 @@
10
10
  *
11
11
  * Historically this store had TWO parallel surfaces for MCP servers:
12
12
  * - `mcpUrl` / `mcpName` / `mcpConnected` / `mcpConnecting` / `mcpTools`
13
- * (flat, single-server or comma-joined multi)
13
+ * (flat, single-server or comma-joined multi) driven by legacy
14
+ * `setMcpConnected`/`setMcpConnecting`/`setMcpError` setters.
14
15
  * - `dataServers: DataServer[]` (list, managed by MultiMcpBridge)
15
16
  *
16
- * They were actually the same concept. This file now stores a single list
17
- * (`_servers`) and derives the flat `mcp*` fields from it. All writes (via
18
- * `setMcpConnected`, `addDataServer`, etc.) mutate the same underlying list,
19
- * so tools populated by the agent-MCP path are visible to the notebook / data
20
- * server consumers and vice-versa.
21
- *
22
- * The public API shape is preserved (both `mcp*` and `dataServers` / `addDataServer`)
23
- * so existing apps keep working without modification.
17
+ * They were the same concept. The legacy setters and the `primary` flag have
18
+ * been removed; writes go through `addDataServer` / `setDataServerMeta` /
19
+ * `setDataServerEnabled` / `addMcpServer` (url shorthand) exclusively. Flat
20
+ * getters (`mcpConnected`, `mcpName`, `mcpUrl`, `mcpConnecting`, `mcpTools`)
21
+ * remain as read-only derivations over the server list for UI back-compat.
24
22
  */
25
23
 
26
24
  import { encode, decode } from '../hyperskills.js';
@@ -62,9 +60,8 @@ export interface McpToolInfo {
62
60
 
63
61
  /**
64
62
  * Single MCP server entry — the one true shape.
65
- * `primary: true` marks the "agent MCP" (used by the chat/tool-call path) —
66
- * at most one server may be primary. Additional servers (data-only) are
67
- * non-primary but otherwise identical.
63
+ * All servers are equal; there is no "primary" concept. The MultiMcpBridge
64
+ * singleton reconciles connection state across all entries.
68
65
  */
69
66
  export interface DataServer {
70
67
  name: string; // user-chosen label
@@ -73,10 +70,12 @@ export interface DataServer {
73
70
  enabled: boolean; // user intent
74
71
  connected: boolean; // handshake completed
75
72
  connecting?: boolean;
76
- primary?: boolean; // agent MCP when true
77
73
  tools?: McpToolInfo[];
78
74
  recipes?: { name: string; description?: string; body?: string }[];
79
75
  error?: string;
76
+ /** Real server name from MCP handshake (initResult.serverInfo.name, aliased).
77
+ * Canvas `.name` is URL-host; `.serverName` is what to display. */
78
+ serverName?: string;
80
79
  }
81
80
 
82
81
  export interface CanvasSnapshot {
@@ -124,9 +123,6 @@ function createCanvasVanilla() {
124
123
  let _servers: DataServer[] = [];
125
124
 
126
125
  // ── Helpers over _servers ──────────────────────────────────────────────
127
- function primaryServer(): DataServer | undefined {
128
- return _servers.find((s) => s.primary);
129
- }
130
126
  function connectedServers(): DataServer[] {
131
127
  return _servers.filter((s) => s.connected);
132
128
  }
@@ -162,33 +158,35 @@ function createCanvasVanilla() {
162
158
  }
163
159
 
164
160
  // ── Server list actions (public, stable) ───────────────────────────────
165
- function addDataServer(desc: { name: string; url: string; primary?: boolean }): DataServer {
161
+ function addDataServer(desc: { name: string; url: string }): DataServer {
166
162
  const existing = _servers.find((s) => s.name === desc.name);
167
- if (existing) {
168
- if (desc.primary && !existing.primary) {
169
- // Promote: there's only one primary. Demote others.
170
- _servers = _servers.map((s) => ({ ...s, primary: s.name === desc.name }));
171
- notify();
172
- }
173
- return existing;
174
- }
163
+ if (existing) return existing;
175
164
  const srv: DataServer = {
176
165
  name: desc.name,
177
166
  url: desc.url,
178
167
  kind: 'data',
179
168
  enabled: true,
180
169
  connected: false,
181
- primary: !!desc.primary,
182
170
  };
183
- if (srv.primary) {
184
- // Demote any existing primary before inserting.
185
- _servers = _servers.map((s) => ({ ...s, primary: false }));
186
- }
187
171
  _servers = [..._servers, srv];
188
172
  notify();
189
173
  return srv;
190
174
  }
191
175
 
176
+ /**
177
+ * Add a server by URL alone (derives name from the URL host). Returns the
178
+ * canvas name so callers can reference it later.
179
+ */
180
+ function addMcpServer(url: string): string {
181
+ if (!url) return '';
182
+ let name: string;
183
+ try { name = new URL(url, 'http://local').host || url; }
184
+ catch { name = url; }
185
+ addDataServer({ name, url });
186
+ setDataServerEnabled(name, true);
187
+ return name;
188
+ }
189
+
192
190
  function removeDataServer(name: string): boolean {
193
191
  const before = _servers.length;
194
192
  _servers = _servers.filter((s) => s.name !== name);
@@ -222,74 +220,6 @@ function createCanvasVanilla() {
222
220
  return setDataServerEnabled(name, !s.enabled);
223
221
  }
224
222
 
225
- // ── Agent-MCP compatibility layer ──────────────────────────────────────
226
- // All these mutate the SAME _servers list; `mcpUrl` targets the primary
227
- // entry, creating one if none exists. Apps can equivalently call
228
- // addDataServer({primary: true}) + setDataServerMeta(name, ...) directly.
229
- function ensurePrimary(url?: string): DataServer | undefined {
230
- let p = primaryServer();
231
- if (p) {
232
- if (url && p.url !== url) {
233
- _servers = _servers.map((s) => s.name === p!.name ? { ...s, url } : s);
234
- }
235
- return _servers.find((s) => s.primary)!;
236
- }
237
- // Refuse to create a placeholder primary without a real URL — empty-URL
238
- // ghosts caused MultiMcpBridge to POST to the current page origin, yielding
239
- // a 405 storm (SvelteKit treats POST / as a form action).
240
- if (!url) return undefined;
241
- const nm = new URL(url, 'http://local').host || url;
242
- _servers = [..._servers, {
243
- name: nm, url, kind: 'data', enabled: true, connected: false, primary: true,
244
- }];
245
- return _servers[_servers.length - 1]!;
246
- }
247
-
248
- function setMcpUrl(u: string): void {
249
- // Update the primary server's URL (create one if none).
250
- ensurePrimary(u);
251
- notify();
252
- }
253
-
254
- function setMcpConnecting(connecting: boolean): void {
255
- const p = ensurePrimary();
256
- if (!p) return;
257
- _servers = _servers.map((s) => s.name === p.name ? { ...s, connecting } : s);
258
- notify();
259
- }
260
-
261
- function setMcpConnected(connected: boolean, name?: string, tools?: McpToolInfo[]): void {
262
- if (!connected) {
263
- // Disconnect all — agent-level disconnect affects the primary and
264
- // traditionally cleared the flat tools. Mirror that by disconnecting
265
- // all primary-flagged servers.
266
- const p = primaryServer();
267
- if (p) {
268
- _servers = _servers.map((s) => s.primary
269
- ? { ...s, connected: false, connecting: false, tools: [], error: undefined }
270
- : s);
271
- }
272
- notify();
273
- return;
274
- }
275
- const p = ensurePrimary();
276
- if (!p) return;
277
- const newName = name && name.length > 0 ? name : p.name;
278
- _servers = _servers.map((s) => s.name === p.name
279
- ? { ...s, name: newName, connected: true, connecting: false, tools: tools ?? s.tools ?? [], error: undefined }
280
- : s);
281
- notify();
282
- }
283
-
284
- function setMcpError(err: string): void {
285
- const p = ensurePrimary();
286
- if (!p) return;
287
- _servers = _servers.map((s) => s.name === p.name
288
- ? { ...s, connected: false, connecting: false, error: err }
289
- : s);
290
- notify();
291
- }
292
-
293
223
  // ── Widget actions ─────────────────────────────────────────────────────
294
224
  function addWidget(type: WidgetType, data: Record<string, unknown> = {}): Widget {
295
225
  const widget: Widget = { id: uuid(), type, data };
@@ -346,12 +276,12 @@ function createCanvasVanilla() {
346
276
 
347
277
  // ── HyperSkill ─────────────────────────────────────────────────────────
348
278
  function buildSkillJSON() {
349
- const p = primaryServer();
279
+ const first = connectedServers()[0] ?? _servers[0];
350
280
  const skill: Record<string, unknown> = {
351
281
  version: '1.0',
352
282
  name: 'skill-' + Date.now(),
353
283
  created: new Date().toISOString(),
354
- mcp: p?.url ?? '',
284
+ mcp: first?.url ?? '',
355
285
  llm: _llm,
356
286
  blocks: _blocks.map((b) => ({ type: b.type, data: JSON.parse(JSON.stringify(b.data)) })),
357
287
  };
@@ -374,7 +304,7 @@ function createCanvasVanilla() {
374
304
  servers?: string[];
375
305
  blocks?: { type: WidgetType; data: Record<string, unknown> }[];
376
306
  }) {
377
- if (skill.mcp) ensurePrimary(skill.mcp);
307
+ if (skill.mcp) addMcpServer(skill.mcp);
378
308
  if (skill.llm) _llm = skill.llm;
379
309
  if (skill.theme) _themeOverrides = skill.theme;
380
310
  if (skill.servers) _enabledServerIds = skill.servers;
@@ -407,7 +337,7 @@ function createCanvasVanilla() {
407
337
  content?: { blocks?: { type: WidgetType; data: Record<string, unknown> }[] };
408
338
  servers?: string[];
409
339
  };
410
- if (decoded.meta?.mcp) ensurePrimary(decoded.meta.mcp as string);
340
+ if (decoded.meta?.mcp) addMcpServer(decoded.meta.mcp as string);
411
341
  if (decoded.meta?.llm) _llm = decoded.meta.llm as LLMId;
412
342
  if (decoded.meta?.theme) _themeOverrides = decoded.meta.theme as Record<string, string>;
413
343
  const servers = (decoded.servers ?? (decoded.meta?.servers as string[] | undefined));
@@ -422,15 +352,15 @@ function createCanvasVanilla() {
422
352
 
423
353
  // ── Snapshot (fields kept for API stability) ───────────────────────────
424
354
  function getSnapshot(): CanvasSnapshot {
425
- const p = primaryServer();
355
+ const first = connectedServers()[0] ?? _servers[0];
426
356
  return {
427
357
  blocks: _blocks,
428
358
  mode: _mode,
429
359
  llm: _llm,
430
- mcpUrl: p?.url ?? '',
431
- mcpConnected: p?.connected ?? false,
360
+ mcpUrl: first?.url ?? '',
361
+ mcpConnected: _servers.some((s) => s.connected),
432
362
  mcpConnecting: anyConnecting(),
433
- mcpName: displayName(),
363
+ mcpName: first && first.connected ? aliasName(first.serverName ?? first.name) : '',
434
364
  mcpTools: unionTools(),
435
365
  messages: _messages,
436
366
  generating: _generating,
@@ -456,11 +386,14 @@ function createCanvasVanilla() {
456
386
  set mode(v: Mode) { _mode = v; notify(); },
457
387
  get llm() { return _llm; },
458
388
  set llm(v: LLMId) { _llm = v; notify(); },
459
- get mcpUrl() { return primaryServer()?.url ?? ''; },
460
- set mcpUrl(v: string) { setMcpUrl(v); },
389
+ get mcpUrl() { return (connectedServers()[0] ?? _servers[0])?.url ?? ''; },
390
+ set mcpUrl(v: string) { addMcpServer(v); },
461
391
  get mcpConnected() { return _servers.some((s) => s.connected); },
462
392
  get mcpConnecting() { return anyConnecting(); },
463
- get mcpName() { return displayName(); },
393
+ get mcpName() {
394
+ const s = connectedServers()[0];
395
+ return s ? aliasName(s.serverName ?? s.name) : '';
396
+ },
464
397
  get mcpTools() { return unionTools(); },
465
398
  get messages() { return _messages; },
466
399
  get generating() { return _generating; },
@@ -472,15 +405,12 @@ function createCanvasVanilla() {
472
405
 
473
406
  setMode(m: Mode) { _mode = m; notify(); },
474
407
  setLlm(l: LLMId) { _llm = l; notify(); },
475
- setMcpUrl,
476
408
  setGenerating(g: boolean) { _generating = g; notify(); },
477
409
 
478
410
  addWidget, addBlock,
479
411
  removeBlock, updateBlock, moveBlock, clearBlocks, setBlocks,
480
412
  addMsg, updateMsg, clearMessages,
481
413
 
482
- setMcpConnecting, setMcpConnected, setMcpError,
483
-
484
414
  get themeOverrides() { return _themeOverrides; },
485
415
  setThemeOverrides,
486
416
 
@@ -492,6 +422,7 @@ function createCanvasVanilla() {
492
422
  get dataServers() { return _servers; },
493
423
  set dataServers(v: DataServer[]) { _servers = Array.isArray(v) ? v : []; notify(); },
494
424
  addDataServer,
425
+ addMcpServer,
495
426
  removeDataServer,
496
427
  getDataServer,
497
428
  setDataServerMeta,
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Extract sample `params` data from a widget recipe's `## Example` block.
3
+ *
4
+ * Recipes have shape:
5
+ * ## Example
6
+ * ```
7
+ * <server>_webmcp_widget_display({name: "<widget>", params: { ... }})
8
+ * ```
9
+ *
10
+ * Recipes are bundled at build time from our own source — `new Function`
11
+ * eval is acceptable here (not user input).
12
+ */
13
+
14
+ function findBalancedBraces(text: string, fromIndex: number): string | null {
15
+ let depth = 0;
16
+ let start = -1;
17
+ for (let i = fromIndex; i < text.length; i++) {
18
+ const ch = text[i];
19
+ if (ch === '{') {
20
+ if (start === -1) start = i;
21
+ depth++;
22
+ } else if (ch === '}') {
23
+ depth--;
24
+ if (depth === 0 && start !== -1) return text.slice(start, i + 1);
25
+ }
26
+ }
27
+ return null;
28
+ }
29
+
30
+ export function extractSampleData(recipe: string | undefined | null): Record<string, unknown> | null {
31
+ if (!recipe) return null;
32
+ const exampleHeader = recipe.search(/^##\s*Example/m);
33
+ if (exampleHeader === -1) return null;
34
+ const after = recipe.slice(exampleHeader);
35
+ const paramsIdx = after.search(/params\s*:/);
36
+ if (paramsIdx === -1) return null;
37
+ const objStart = after.indexOf('{', paramsIdx);
38
+ if (objStart === -1) return null;
39
+ const objLiteral = findBalancedBraces(after, objStart);
40
+ if (!objLiteral) return null;
41
+ try {
42
+ const fn = new Function(`return (${objLiteral});`);
43
+ const value = fn();
44
+ if (value && typeof value === 'object') return value as Record<string, unknown>;
45
+ } catch { /* parse error — fall through */ }
46
+ return null;
47
+ }
package/tsconfig.json CHANGED
@@ -16,7 +16,6 @@
16
16
  "declaration": true
17
17
  },
18
18
  "include": [
19
- "src/**/*.ts",
20
- "src/**/*.svelte"
19
+ "src/**/*.ts"
21
20
  ]
22
21
  }
package/src/Index.svelte DELETED
@@ -1,5 +0,0 @@
1
- <!-- @webmcp-auto-ui/sdk — browser components stub -->
2
- <script lang="ts">
3
- // This file exists to satisfy svelte-check tooling.
4
- // Import canvas store via: import { canvas } from '@webmcp-auto-ui/sdk/canvas'
5
- </script>