@databrainhq/mcp-server 0.3.0-rc.13 → 0.3.0-rc.15

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 (50) hide show
  1. package/.mcp.json +6 -1
  2. package/dist/apps/server.d.ts +102 -389
  3. package/dist/apps/server.js +5 -5
  4. package/dist/apps/stdio.d.ts +1 -2
  5. package/dist/apps/stdio.js +6 -6
  6. package/dist/{bundle-TDQXWIPM.js → bundle-QJNCUMNY.js} +2 -2
  7. package/dist/{chunk-Q5EYDKSA.js → chunk-2F7V6RZR.js} +511 -107
  8. package/dist/chunk-2F7V6RZR.js.map +1 -0
  9. package/dist/chunk-3AH56XX7.js +28 -0
  10. package/dist/chunk-3AH56XX7.js.map +1 -0
  11. package/dist/{chunk-AEQTEE5C.js → chunk-4E57ZRZO.js} +302 -63
  12. package/dist/chunk-4E57ZRZO.js.map +1 -0
  13. package/dist/{chunk-PSJVYD4W.js → chunk-6MD7KOAU.js} +11723 -10560
  14. package/dist/chunk-6MD7KOAU.js.map +1 -0
  15. package/dist/{chunk-HCYZN7I3.js → chunk-FJLRZJ4A.js} +10 -7
  16. package/dist/chunk-FJLRZJ4A.js.map +1 -0
  17. package/dist/{chunk-X44C5GW2.js → chunk-MUZ3KEJX.js} +63 -40
  18. package/dist/chunk-MUZ3KEJX.js.map +1 -0
  19. package/dist/{chunk-DTFYHLYN.js → chunk-NXE2A4WV.js} +26 -11
  20. package/dist/chunk-NXE2A4WV.js.map +1 -0
  21. package/dist/{chunk-233VGFHY.js → chunk-QQ6KNULX.js} +317 -147
  22. package/dist/chunk-QQ6KNULX.js.map +1 -0
  23. package/dist/chunk-V5JINLOA.js +506 -0
  24. package/dist/chunk-V5JINLOA.js.map +1 -0
  25. package/dist/cli.d.ts +16 -15
  26. package/dist/cli.js +134 -36
  27. package/dist/cli.js.map +1 -1
  28. package/dist/custom-chart/custom-runtime.js +6 -6
  29. package/dist/custom-chart/template/chart.ts +116 -28
  30. package/dist/custom-chart/template/icon.svg +1 -1
  31. package/dist/custom-chart/template/manifest.json +66 -12
  32. package/dist/custom-chart/template/sample-data.json +21 -3
  33. package/dist/index.d.ts +1 -2
  34. package/dist/index.js +67 -13
  35. package/dist/index.js.map +1 -1
  36. package/dist/{main-VEKNKWL5.js → main-2FKQQLWX.js} +489 -174
  37. package/dist/main-2FKQQLWX.js.map +1 -0
  38. package/dist/{test-only-LJGOY2QA.js → test-only-VH3FF5ML.js} +15 -9
  39. package/dist/test-only-VH3FF5ML.js.map +1 -0
  40. package/package.json +20 -9
  41. package/dist/chunk-233VGFHY.js.map +0 -1
  42. package/dist/chunk-AEQTEE5C.js.map +0 -1
  43. package/dist/chunk-DTFYHLYN.js.map +0 -1
  44. package/dist/chunk-HCYZN7I3.js.map +0 -1
  45. package/dist/chunk-PSJVYD4W.js.map +0 -1
  46. package/dist/chunk-Q5EYDKSA.js.map +0 -1
  47. package/dist/chunk-X44C5GW2.js.map +0 -1
  48. package/dist/main-VEKNKWL5.js.map +0 -1
  49. package/dist/test-only-LJGOY2QA.js.map +0 -1
  50. /package/dist/{bundle-TDQXWIPM.js.map → bundle-QJNCUMNY.js.map} +0 -0
@@ -0,0 +1,506 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ READ_ONLY,
4
+ WRITE_CREATE,
5
+ WRITE_IDEMPOTENT
6
+ } from "./chunk-6MD7KOAU.js";
7
+ import {
8
+ DatabrainApiError,
9
+ studioDraftSchema,
10
+ toolError,
11
+ toolSuccess
12
+ } from "./chunk-4E57ZRZO.js";
13
+ import {
14
+ HOSTED_SCOPES
15
+ } from "./chunk-3AH56XX7.js";
16
+
17
+ // src/bryn/catalogue.ts
18
+ import { z } from "zod";
19
+ var surface = z.enum([
20
+ "metric",
21
+ "semantic-model",
22
+ "custom-chart-studio",
23
+ "theme-editor"
24
+ ]);
25
+ var tool = z.object({
26
+ name: z.string().regex(/^[a-z][a-z0-9_]*$/),
27
+ surface,
28
+ description: z.string(),
29
+ inputSchema: z.record(z.string(), z.unknown()),
30
+ contextFields: z.record(
31
+ z.string(),
32
+ z.object({
33
+ schema: z.record(z.string(), z.unknown()),
34
+ required: z.boolean()
35
+ })
36
+ ).optional(),
37
+ requiredScopes: z.array(z.enum(HOSTED_SCOPES)).min(1).optional(),
38
+ opaqueContextFields: z.array(z.string()).optional(),
39
+ effect: z.enum(["read", "view", "commit"]),
40
+ context: z.enum(["none", "metric", "board", "datamart"]),
41
+ modes: z.array(z.enum(["ask", "plan", "build"]))
42
+ });
43
+ var ARGUMENT = /^[a-zA-Z][a-zA-Z0-9]*$/;
44
+ var TURN_ENVELOPE = ["workspaceId", "mode", "message"];
45
+ var TURN_PATH = /^\/(stream\/agent|api\/v2\/[A-Za-z0-9_{}/-]+)$/;
46
+ var turn = z.object({
47
+ // Only the ask_bryn_ namespace. A turn must never share a name with an established tool,
48
+ // because its entry would replace that tool's scope policy.
49
+ name: z.string().regex(/^ask_bryn_[a-z0-9_]+$/),
50
+ surface,
51
+ description: z.string(),
52
+ effect: z.enum(["read", "write"]),
53
+ modes: z.array(z.enum(["ask", "plan", "build"])).min(1),
54
+ path: z.string().regex(TURN_PATH),
55
+ body: z.record(z.string(), z.string()),
56
+ messageMaxLength: z.number().int().min(1).max(1e5),
57
+ contextFields: z.record(
58
+ z.string(),
59
+ z.object({
60
+ schema: z.record(z.string(), z.unknown()),
61
+ required: z.boolean()
62
+ })
63
+ ),
64
+ opaqueContextFields: z.array(z.string()),
65
+ requiredScopes: z.array(z.enum(HOSTED_SCOPES)).min(1),
66
+ timeoutMs: z.number().int().min(1e3).max(3e5)
67
+ });
68
+ var catalogue = z.object({
69
+ tools: z.array(tool).max(100),
70
+ // An issuer from before register-once turns sends none.
71
+ turns: z.array(turn).max(50).default([])
72
+ });
73
+ function turnPathFields(path) {
74
+ return [...path.matchAll(/\{([^{}]*)\}/g)].map((match) => match[1]);
75
+ }
76
+ function assertValidTurn(entry) {
77
+ const fields = Object.keys(entry.contextFields);
78
+ const known = /* @__PURE__ */ new Set([...TURN_ENVELOPE, ...fields]);
79
+ if (fields.some(
80
+ (name) => !ARGUMENT.test(name) || TURN_ENVELOPE.includes(name)
81
+ ) || entry.opaqueContextFields.some((name) => !fields.includes(name)) || Object.values(entry.body).some((source) => !known.has(source)) || Object.keys(entry.body).some((key) => !ARGUMENT.test(key)) || entry.path.includes("..") || // Every placeholder must be a required argument, or the path would be a hole.
82
+ turnPathFields(entry.path).some(
83
+ (name) => entry.contextFields[name]?.required !== true
84
+ ) || entry.path.replace(/\{[^{}]*\}/g, "").match(/[{}]/))
85
+ throw new Error("Invalid Bryn turn");
86
+ }
87
+ function isExecutableBrynTool(entry) {
88
+ const legacy = entry.surface === "custom-chart-studio" || entry.surface === "theme-editor";
89
+ return legacy || entry.requiredScopes !== void 0 && entry.contextFields !== void 0 && entry.opaqueContextFields !== void 0;
90
+ }
91
+ function parseBrynCatalogue(raw) {
92
+ const parsed = catalogue.parse(raw);
93
+ const names = /* @__PURE__ */ new Set();
94
+ for (const entry of parsed.tools) {
95
+ if (names.has(entry.name)) throw new Error("Duplicate Bryn tool name");
96
+ if (entry.opaqueContextFields?.some(
97
+ (name) => !Object.hasOwn(entry.contextFields ?? {}, name) || ["workspaceId", "mode", "input"].includes(name)
98
+ ))
99
+ throw new Error("Invalid Bryn opaque context");
100
+ names.add(entry.name);
101
+ }
102
+ for (const entry of parsed.turns) {
103
+ if (names.has(entry.name)) throw new Error("Duplicate Bryn tool name");
104
+ assertValidTurn(entry);
105
+ names.add(entry.name);
106
+ }
107
+ return parsed;
108
+ }
109
+ async function loadBrynCatalogue(client) {
110
+ try {
111
+ const raw = await client.request({
112
+ method: "GET",
113
+ path: "/api/mcp/bryn/catalog",
114
+ auth: "service",
115
+ timeoutMs: 1e4
116
+ });
117
+ try {
118
+ return parseBrynCatalogue(raw);
119
+ } catch {
120
+ return { tools: [], turns: [] };
121
+ }
122
+ } catch (error) {
123
+ if (error instanceof DatabrainApiError && error.status === 404)
124
+ return { tools: [], turns: [] };
125
+ throw error;
126
+ }
127
+ }
128
+
129
+ // src/bryn/catalogueTurns.ts
130
+ import { z as z2 } from "zod";
131
+ var BUILT_IN_TURNS = /* @__PURE__ */ new Set([
132
+ "ask_bryn_metric",
133
+ "ask_bryn_semantic_model",
134
+ "ask_bryn_theme",
135
+ "ask_bryn_custom_chart"
136
+ ]);
137
+ function catalogueTurnEntry(name, catalogue2) {
138
+ if (BUILT_IN_TURNS.has(name)) return void 0;
139
+ return catalogue2?.turns.find((entry) => entry.name === name);
140
+ }
141
+ function turnPath(entry, args) {
142
+ let valid = true;
143
+ const path = entry.path.replace(/\{([^{}]*)\}/g, (_, name) => {
144
+ const value = args[name];
145
+ if (typeof value !== "string" && typeof value !== "number") valid = false;
146
+ const text = String(value);
147
+ if (text === "" || text === "." || text === "..") valid = false;
148
+ return encodeURIComponent(text);
149
+ });
150
+ return valid ? path : void 0;
151
+ }
152
+ function turnBody(entry, args) {
153
+ const body = {};
154
+ for (const [key, source] of Object.entries(entry.body)) {
155
+ if (args[source] !== void 0) body[key] = args[source];
156
+ }
157
+ return body;
158
+ }
159
+ function registerCatalogueTurns(server, client, catalogue2) {
160
+ for (const entry of catalogue2.turns) {
161
+ if (BUILT_IN_TURNS.has(entry.name)) continue;
162
+ const shape = {
163
+ workspaceId: z2.string().uuid(),
164
+ mode: z2.enum(entry.modes),
165
+ message: z2.string().trim().min(1).max(entry.messageMaxLength)
166
+ };
167
+ try {
168
+ for (const [name, field] of Object.entries(entry.contextFields)) {
169
+ const schema = z2.fromJSONSchema(field.schema);
170
+ shape[name] = field.required ? schema : schema.optional();
171
+ }
172
+ } catch {
173
+ continue;
174
+ }
175
+ server.tool(
176
+ entry.name,
177
+ entry.description,
178
+ shape,
179
+ entry.effect === "read" ? READ_ONLY : WRITE_CREATE,
180
+ async (args) => {
181
+ if (!client.isHosted())
182
+ return toolError(
183
+ "A Bryn turn needs a signed-in user. Service credentials have no user identity or free-turn allowance."
184
+ );
185
+ const path = turnPath(entry, args);
186
+ if (!path) return toolError("This Bryn turn is missing an argument.");
187
+ try {
188
+ const result = await client.request({
189
+ method: "POST",
190
+ path,
191
+ auth: "service",
192
+ body: turnBody(entry, args),
193
+ responseFormat: "bryn-sse",
194
+ timeoutMs: entry.timeoutMs,
195
+ noRetryOnTimeout: true
196
+ });
197
+ return result && typeof result === "object" && "completed" in result && result.completed === false ? toolError(JSON.stringify(result)) : toolSuccess(JSON.stringify(result));
198
+ } catch (error) {
199
+ return error instanceof DatabrainApiError ? error.toToolResponse() : toolError(
200
+ "Bryn did not complete the turn. Review the workspace and retry."
201
+ );
202
+ }
203
+ }
204
+ );
205
+ }
206
+ }
207
+
208
+ // src/bryn/register.ts
209
+ import { z as z3 } from "zod";
210
+ var uuid = z3.string().uuid();
211
+ var mode = z3.enum(["ask", "plan", "build"]);
212
+ var jsonRecord = z3.record(z3.string(), z3.unknown());
213
+ function legacyContext(surface2) {
214
+ if (surface2 === "custom-chart-studio")
215
+ return {
216
+ key: z3.string().regex(/^[a-z][a-z0-9_-]{0,63}$/),
217
+ draft: jsonRecord,
218
+ viewingOldVersion: z3.boolean().optional(),
219
+ followUp: jsonRecord.optional()
220
+ };
221
+ return {
222
+ theme: jsonRecord,
223
+ dark: jsonRecord,
224
+ schema: z3.array(
225
+ z3.object({
226
+ path: z3.string().regex(/^[A-Za-z][A-Za-z0-9]*(\.[A-Za-z][A-Za-z0-9]*)*$/).max(120),
227
+ kind: z3.enum([
228
+ "color",
229
+ "px",
230
+ "number",
231
+ "boolean",
232
+ "enum",
233
+ "text",
234
+ "font",
235
+ "palettes",
236
+ "paletteNames",
237
+ "paletteSelected"
238
+ ]),
239
+ label: z3.string().max(80)
240
+ }).passthrough()
241
+ ).min(1).max(200),
242
+ contrast: z3.array(z3.string().max(240)).max(24).optional()
243
+ };
244
+ }
245
+ function registerBrynTools(server, client, catalogue2) {
246
+ for (const entry of catalogue2.tools) {
247
+ const legacy = entry.surface === "custom-chart-studio" || entry.surface === "theme-editor";
248
+ if (!isExecutableBrynTool(entry)) continue;
249
+ const context = entry.contextFields ? {} : legacy ? legacyContext(entry.surface) : {};
250
+ let input;
251
+ try {
252
+ input = z3.fromJSONSchema(entry.inputSchema);
253
+ for (const [name, field] of Object.entries(entry.contextFields ?? {})) {
254
+ if (!/^[a-zA-Z][a-zA-Z0-9]*$/.test(name) || ["workspaceId", "mode", "input"].includes(name))
255
+ throw new Error("Invalid Bryn context field");
256
+ const schema = z3.fromJSONSchema(field.schema);
257
+ context[name] = field.required ? schema : schema.optional();
258
+ }
259
+ } catch {
260
+ continue;
261
+ }
262
+ const shape = {
263
+ workspaceId: uuid,
264
+ mode,
265
+ input,
266
+ ...context
267
+ };
268
+ server.tool(
269
+ entry.name,
270
+ `${entry.description} Executes the ${entry.surface} Bryn host; returns a draft only.`,
271
+ shape,
272
+ entry.effect === "read" ? READ_ONLY : WRITE_IDEMPOTENT,
273
+ async (args) => {
274
+ try {
275
+ if (!entry.modes.includes(args.mode))
276
+ return toolError("Bryn does not offer this tool in that mode.");
277
+ const result = await client.request({
278
+ method: "POST",
279
+ path: `/api/mcp/bryn/tools/${entry.name}`,
280
+ auth: "service",
281
+ body: args,
282
+ timeoutMs: 45e3,
283
+ noRetryOnTimeout: true
284
+ });
285
+ return toolSuccess(JSON.stringify(result));
286
+ } catch (error) {
287
+ return error instanceof DatabrainApiError ? error.toToolResponse() : toolError("Bryn could not run this tool. No draft was saved.");
288
+ }
289
+ }
290
+ );
291
+ }
292
+ }
293
+
294
+ // src/bryn/turns.ts
295
+ import { z as z4 } from "zod";
296
+ var workspaceId = z4.string().uuid();
297
+ var sessionId = z4.string().uuid().optional();
298
+ var message = z4.string().trim().min(1).max(8e3);
299
+ var mode2 = z4.enum(["ask", "plan"]);
300
+ var themeSnapshot = {
301
+ theme: z4.record(z4.string(), z4.unknown()),
302
+ dark: z4.record(z4.string(), z4.unknown()),
303
+ schema: z4.array(
304
+ z4.object({
305
+ path: z4.string().max(120),
306
+ kind: z4.string(),
307
+ label: z4.string().max(80)
308
+ }).passthrough()
309
+ ).min(1).max(200),
310
+ contrast: z4.array(z4.string().max(240)).max(24).optional()
311
+ };
312
+ var response = (result) => result && typeof result === "object" && "completed" in result && result.completed === false ? toolError(JSON.stringify(result)) : toolSuccess(JSON.stringify(result));
313
+ var failure = (error) => error instanceof DatabrainApiError ? error.toToolResponse() : toolError(
314
+ "Bryn did not complete the turn. Review the workspace and retry."
315
+ );
316
+ function registerBrynTurns(server, client) {
317
+ server.tool(
318
+ "ask_bryn_metric",
319
+ "Ask or plan a metric with the metric Bryn agent in this workspace. This runs a full model turn as the signed-in user and does not apply a metric.",
320
+ { workspaceId, sessionId, message, mode: mode2 },
321
+ READ_ONLY,
322
+ async (input) => {
323
+ if (!client.isHosted())
324
+ return toolError(
325
+ "A Bryn turn needs a signed-in user. Service credentials have no user identity or free-turn allowance."
326
+ );
327
+ try {
328
+ return response(
329
+ await client.request({
330
+ method: "POST",
331
+ path: "/stream/agent",
332
+ auth: "service",
333
+ body: {
334
+ workspaceId: input.workspaceId,
335
+ sessionId: input.sessionId,
336
+ question: input.message,
337
+ mode: input.mode
338
+ },
339
+ responseFormat: "bryn-sse",
340
+ timeoutMs: 18e4,
341
+ noRetryOnTimeout: true
342
+ })
343
+ );
344
+ } catch (error) {
345
+ return failure(error);
346
+ }
347
+ }
348
+ );
349
+ server.tool(
350
+ "ask_bryn_semantic_model",
351
+ "Ask or plan with semantic model Bryn. Supply an existing authoring session and revision, or source and its published base hash to create a draft. A signed-in user and model permission are required.",
352
+ {
353
+ workspaceId,
354
+ datamartId: z4.string().uuid(),
355
+ sessionId,
356
+ revision: z4.number().int().min(0).optional(),
357
+ source: z4.string().max(1e6).optional(),
358
+ baseContentHash: z4.string().nullable().optional(),
359
+ message: z4.string().trim().min(1).max(32e3),
360
+ mode: mode2
361
+ },
362
+ WRITE_CREATE,
363
+ async (input) => {
364
+ if (!client.isHosted())
365
+ return toolError(
366
+ "A Bryn turn needs a signed-in user. Service credentials have no user identity or free-turn allowance."
367
+ );
368
+ try {
369
+ let targetSession = input.sessionId;
370
+ let revision = input.revision;
371
+ if (!targetSession) {
372
+ if (input.source === void 0 || input.baseContentHash === void 0)
373
+ return toolError(
374
+ "source and baseContentHash are required to start a semantic authoring session."
375
+ );
376
+ const draft = await client.request({
377
+ method: "POST",
378
+ auth: "service",
379
+ path: `/api/v2/semantic/${input.datamartId}/authoring`,
380
+ body: {
381
+ source: input.source,
382
+ baseContentHash: input.baseContentHash
383
+ },
384
+ noRetryOnTimeout: true
385
+ });
386
+ targetSession = draft.sessionId;
387
+ revision = draft.revision;
388
+ }
389
+ if (revision === void 0)
390
+ return toolError(
391
+ "revision is required to continue this semantic authoring session."
392
+ );
393
+ const turn2 = await client.request({
394
+ method: "POST",
395
+ auth: "service",
396
+ path: `/api/v2/semantic/${input.datamartId}/authoring/${targetSession}/turn`,
397
+ body: { revision, message: input.message, mode: input.mode },
398
+ responseFormat: "bryn-sse",
399
+ timeoutMs: 18e4,
400
+ noRetryOnTimeout: true
401
+ });
402
+ try {
403
+ const current = await client.request({
404
+ method: "GET",
405
+ auth: "service",
406
+ path: `/api/v2/semantic/${input.datamartId}/authoring/${targetSession}`
407
+ });
408
+ return response({ ...turn2, revision: current.revision });
409
+ } catch {
410
+ return response({
411
+ ...turn2,
412
+ note: "The turn finished, but the latest draft revision could not be read. Fetch it before continuing."
413
+ });
414
+ }
415
+ } catch (error) {
416
+ return failure(error);
417
+ }
418
+ }
419
+ );
420
+ server.tool(
421
+ "ask_bryn_theme",
422
+ "Ask, plan or build a theme draft with theme Bryn. The result is a preview draft; the theme is not saved. A signed-in user is required.",
423
+ {
424
+ workspaceId,
425
+ sessionId,
426
+ message,
427
+ mode: z4.enum(["ask", "plan", "build"]),
428
+ ...themeSnapshot
429
+ },
430
+ WRITE_CREATE,
431
+ async (input) => {
432
+ if (!client.isHosted())
433
+ return toolError(
434
+ "A Bryn turn needs a signed-in user. Service credentials have no user identity or free-turn allowance."
435
+ );
436
+ try {
437
+ return response(
438
+ await client.request({
439
+ method: "POST",
440
+ path: "/api/v2/theme-bryn/turn",
441
+ auth: "service",
442
+ body: input,
443
+ responseFormat: "bryn-sse",
444
+ timeoutMs: 18e4,
445
+ noRetryOnTimeout: true
446
+ })
447
+ );
448
+ } catch (error) {
449
+ return failure(error);
450
+ }
451
+ }
452
+ );
453
+ server.tool(
454
+ "ask_bryn_custom_chart",
455
+ "Ask, plan or build a chart draft with Chart studio Bryn. The result is a draft; no version is saved or published. A signed-in user is required.",
456
+ {
457
+ workspaceId,
458
+ sessionId,
459
+ message,
460
+ mode: z4.enum(["ask", "plan", "build"]),
461
+ key: z4.string().regex(/^[a-z][a-z0-9_-]{0,63}$/),
462
+ draft: studioDraftSchema,
463
+ viewingOldVersion: z4.boolean().default(false)
464
+ },
465
+ WRITE_CREATE,
466
+ async (input) => {
467
+ if (!client.isHosted())
468
+ return toolError(
469
+ "A Bryn turn needs a signed-in user. Service credentials have no user identity or free-turn allowance."
470
+ );
471
+ try {
472
+ return response(
473
+ await client.request({
474
+ method: "POST",
475
+ auth: "service",
476
+ path: `/api/v2/custom-charts/${encodeURIComponent(input.key)}/bryn/turn`,
477
+ body: {
478
+ workspaceId: input.workspaceId,
479
+ sessionId: input.sessionId,
480
+ message: input.message,
481
+ mode: input.mode,
482
+ draft: input.draft,
483
+ viewingOldVersion: input.viewingOldVersion
484
+ },
485
+ responseFormat: "bryn-sse",
486
+ timeoutMs: 18e4,
487
+ noRetryOnTimeout: true
488
+ })
489
+ );
490
+ } catch (error) {
491
+ return failure(error);
492
+ }
493
+ }
494
+ );
495
+ }
496
+
497
+ export {
498
+ isExecutableBrynTool,
499
+ parseBrynCatalogue,
500
+ loadBrynCatalogue,
501
+ catalogueTurnEntry,
502
+ registerCatalogueTurns,
503
+ registerBrynTools,
504
+ registerBrynTurns
505
+ };
506
+ //# sourceMappingURL=chunk-V5JINLOA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/bryn/catalogue.ts","../src/bryn/catalogueTurns.ts","../src/bryn/register.ts","../src/bryn/turns.ts"],"sourcesContent":["import { z } from 'zod';\nimport type { DatabrainClient } from '../client/databrain-client.js';\nimport { HOSTED_SCOPES } from '../hosted/types.js';\nimport { DatabrainApiError } from '../utils/errors.js';\n\nconst surface = z.enum([\n 'metric',\n 'semantic-model',\n 'custom-chart-studio',\n 'theme-editor',\n]);\nconst tool = z.object({\n name: z.string().regex(/^[a-z][a-z0-9_]*$/),\n surface,\n description: z.string(),\n inputSchema: z.record(z.string(), z.unknown()),\n contextFields: z\n .record(\n z.string(),\n z.object({\n schema: z.record(z.string(), z.unknown()),\n required: z.boolean(),\n })\n )\n .optional(),\n requiredScopes: z.array(z.enum(HOSTED_SCOPES)).min(1).optional(),\n opaqueContextFields: z.array(z.string()).optional(),\n effect: z.enum(['read', 'view', 'commit']),\n context: z.enum(['none', 'metric', 'board', 'datamart']),\n modes: z.array(z.enum(['ask', 'plan', 'build'])),\n});\nconst ARGUMENT = /^[a-zA-Z][a-zA-Z0-9]*$/;\n/** Envelope arguments every turn has. A context field may not reuse these names. */\nexport const TURN_ENVELOPE = ['workspaceId', 'mode', 'message'] as const;\n/** A turn path may only reach the Bryn turn routes. Placeholders are `{argument}`. */\nconst TURN_PATH = /^\\/(stream\\/agent|api\\/v2\\/[A-Za-z0-9_{}/-]+)$/;\nconst turn = z.object({\n // Only the ask_bryn_ namespace. A turn must never share a name with an established tool,\n // because its entry would replace that tool's scope policy.\n name: z.string().regex(/^ask_bryn_[a-z0-9_]+$/),\n surface,\n description: z.string(),\n effect: z.enum(['read', 'write']),\n modes: z.array(z.enum(['ask', 'plan', 'build'])).min(1),\n path: z.string().regex(TURN_PATH),\n body: z.record(z.string(), z.string()),\n messageMaxLength: z.number().int().min(1).max(100_000),\n contextFields: z.record(\n z.string(),\n z.object({\n schema: z.record(z.string(), z.unknown()),\n required: z.boolean(),\n })\n ),\n opaqueContextFields: z.array(z.string()),\n requiredScopes: z.array(z.enum(HOSTED_SCOPES)).min(1),\n timeoutMs: z.number().int().min(1000).max(300_000),\n});\nconst catalogue = z.object({\n tools: z.array(tool).max(100),\n // An issuer from before register-once turns sends none.\n turns: z.array(turn).max(50).default([]),\n});\nexport type BrynCatalogue = z.infer<typeof catalogue>;\nexport type BrynTool = z.infer<typeof tool>;\nexport type BrynTurn = z.infer<typeof turn>;\n\n/** Placeholder names in a turn path, in order. */\nexport function turnPathFields(path: string): string[] {\n return [...path.matchAll(/\\{([^{}]*)\\}/g)].map((match) => match[1]);\n}\n\nfunction assertValidTurn(entry: BrynTurn): void {\n const fields = Object.keys(entry.contextFields);\n const known = new Set<string>([...TURN_ENVELOPE, ...fields]);\n if (\n fields.some(\n (name) =>\n !ARGUMENT.test(name) ||\n (TURN_ENVELOPE as readonly string[]).includes(name)\n ) ||\n entry.opaqueContextFields.some((name) => !fields.includes(name)) ||\n Object.values(entry.body).some((source) => !known.has(source)) ||\n Object.keys(entry.body).some((key) => !ARGUMENT.test(key)) ||\n entry.path.includes('..') ||\n // Every placeholder must be a required argument, or the path would be a hole.\n turnPathFields(entry.path).some(\n (name) => entry.contextFields[name]?.required !== true\n ) ||\n entry.path.replace(/\\{[^{}]*\\}/g, '').match(/[{}]/)\n )\n throw new Error('Invalid Bryn turn');\n}\n\nexport function isExecutableBrynTool(entry: BrynTool): boolean {\n const legacy =\n entry.surface === 'custom-chart-studio' || entry.surface === 'theme-editor';\n return (\n legacy ||\n (entry.requiredScopes !== undefined &&\n entry.contextFields !== undefined &&\n entry.opaqueContextFields !== undefined)\n );\n}\n\nexport function parseBrynCatalogue(raw: unknown): BrynCatalogue {\n const parsed = catalogue.parse(raw);\n const names = new Set<string>();\n for (const entry of parsed.tools) {\n if (names.has(entry.name)) throw new Error('Duplicate Bryn tool name');\n if (\n entry.opaqueContextFields?.some(\n (name) =>\n !Object.hasOwn(entry.contextFields ?? {}, name) ||\n ['workspaceId', 'mode', 'input'].includes(name)\n )\n )\n throw new Error('Invalid Bryn opaque context');\n names.add(entry.name);\n }\n for (const entry of parsed.turns) {\n if (names.has(entry.name)) throw new Error('Duplicate Bryn tool name');\n assertValidTurn(entry);\n names.add(entry.name);\n }\n return parsed;\n}\n\n/** A pre-upgrade issuer may lack the route. Existing MCP tools remain available. */\nexport async function loadBrynCatalogue(\n client: DatabrainClient\n): Promise<BrynCatalogue> {\n try {\n const raw = await client.request<unknown>({\n method: 'GET',\n path: '/api/mcp/bryn/catalog',\n auth: 'service',\n timeoutMs: 10_000,\n });\n try {\n return parseBrynCatalogue(raw);\n } catch {\n // A malformed new catalogue cannot disable the established MCP tools.\n return { tools: [], turns: [] };\n }\n } catch (error) {\n if (error instanceof DatabrainApiError && error.status === 404)\n return { tools: [], turns: [] };\n throw error;\n }\n}\n","import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { z } from 'zod';\nimport type { DatabrainClient } from '../client/databrain-client.js';\nimport { READ_ONLY, WRITE_CREATE } from '../tools/annotations.js';\nimport { DatabrainApiError, toolError, toolSuccess } from '../utils/errors.js';\nimport type { BrynCatalogue, BrynTurn } from './catalogue.js';\n\n/** The four turns written by hand. They keep their richer flow when a catalogue entry has the same name. */\nexport const BUILT_IN_TURNS: ReadonlySet<string> = new Set([\n 'ask_bryn_metric',\n 'ask_bryn_semantic_model',\n 'ask_bryn_theme',\n 'ask_bryn_custom_chart',\n]);\n\n/** A turn the catalogue describes and the hand-written wrappers do not cover. */\nexport function catalogueTurnEntry(\n name: string,\n catalogue?: BrynCatalogue\n): BrynTurn | undefined {\n if (BUILT_IN_TURNS.has(name)) return undefined;\n return catalogue?.turns.find((entry) => entry.name === name);\n}\n\n/** The backend path for one call. Each placeholder is a required, URL-encoded argument. */\nexport function turnPath(\n entry: BrynTurn,\n args: Record<string, unknown>\n): string | undefined {\n let valid = true;\n const path = entry.path.replace(/\\{([^{}]*)\\}/g, (_, name: string) => {\n const value = args[name];\n if (typeof value !== 'string' && typeof value !== 'number') valid = false;\n const text = String(value);\n // encodeURIComponent keeps dots, and a dot segment would leave the validated prefix.\n if (text === '' || text === '.' || text === '..') valid = false;\n return encodeURIComponent(text);\n });\n return valid ? path : undefined;\n}\n\n/** The backend body for one call: each body key takes the argument its map names. */\nexport function turnBody(\n entry: BrynTurn,\n args: Record<string, unknown>\n): Record<string, unknown> {\n const body: Record<string, unknown> = {};\n for (const [key, source] of Object.entries(entry.body)) {\n if (args[source] !== undefined) body[key] = args[source];\n }\n return body;\n}\n\n/**\n * Register each turn the backend catalogue lists that no hand-written wrapper\n * covers. A new Bryn surface then needs one backend entry and no MCP code. The\n * route the entry names still decides every gate.\n */\nexport function registerCatalogueTurns(\n server: McpServer,\n client: DatabrainClient,\n catalogue: BrynCatalogue\n): void {\n for (const entry of catalogue.turns) {\n if (BUILT_IN_TURNS.has(entry.name)) continue;\n const shape: Record<string, z.ZodType> = {\n workspaceId: z.string().uuid(),\n mode: z.enum(entry.modes as [string, ...string[]]),\n message: z.string().trim().min(1).max(entry.messageMaxLength),\n };\n try {\n for (const [name, field] of Object.entries(entry.contextFields)) {\n const schema = z.fromJSONSchema(field.schema);\n shape[name] = field.required ? schema : schema.optional();\n }\n } catch {\n // A newer backend schema must not prevent existing MCP tools from loading.\n continue;\n }\n server.tool(\n entry.name,\n entry.description,\n shape,\n entry.effect === 'read' ? READ_ONLY : WRITE_CREATE,\n async (args: Record<string, unknown>) => {\n if (!client.isHosted())\n return toolError(\n 'A Bryn turn needs a signed-in user. Service credentials have no user identity or free-turn allowance.'\n );\n const path = turnPath(entry, args);\n if (!path) return toolError('This Bryn turn is missing an argument.');\n try {\n const result = await client.request<unknown>({\n method: 'POST',\n path,\n auth: 'service',\n body: turnBody(entry, args),\n responseFormat: 'bryn-sse',\n timeoutMs: entry.timeoutMs,\n noRetryOnTimeout: true,\n });\n return result &&\n typeof result === 'object' &&\n 'completed' in result &&\n result.completed === false\n ? toolError(JSON.stringify(result))\n : toolSuccess(JSON.stringify(result));\n } catch (error) {\n return error instanceof DatabrainApiError\n ? error.toToolResponse()\n : toolError(\n 'Bryn did not complete the turn. Review the workspace and retry.'\n );\n }\n }\n );\n }\n}\n","import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { z } from 'zod';\nimport type { DatabrainClient } from '../client/databrain-client.js';\nimport { READ_ONLY, WRITE_IDEMPOTENT } from '../tools/annotations.js';\nimport { DatabrainApiError, toolError, toolSuccess } from '../utils/errors.js';\nimport { type BrynCatalogue, isExecutableBrynTool } from './catalogue.js';\n\nconst uuid = z.string().uuid();\nconst mode = z.enum(['ask', 'plan', 'build']);\nconst jsonRecord = z.record(z.string(), z.unknown());\n\n/** Context contract for the first Bryn catalogue version, before contextFields. */\nfunction legacyContext(\n surface: 'custom-chart-studio' | 'theme-editor'\n): Record<string, z.ZodType> {\n if (surface === 'custom-chart-studio')\n return {\n key: z.string().regex(/^[a-z][a-z0-9_-]{0,63}$/),\n draft: jsonRecord,\n viewingOldVersion: z.boolean().optional(),\n followUp: jsonRecord.optional(),\n };\n return {\n theme: jsonRecord,\n dark: jsonRecord,\n schema: z\n .array(\n z\n .object({\n path: z\n .string()\n .regex(/^[A-Za-z][A-Za-z0-9]*(\\.[A-Za-z][A-Za-z0-9]*)*$/)\n .max(120),\n kind: z.enum([\n 'color',\n 'px',\n 'number',\n 'boolean',\n 'enum',\n 'text',\n 'font',\n 'palettes',\n 'paletteNames',\n 'paletteSelected',\n ]),\n label: z.string().max(80),\n })\n .passthrough()\n )\n .min(1)\n .max(200),\n contrast: z.array(z.string().max(240)).max(24).optional(),\n };\n}\n\n/** Register one MCP call per backend tool; the backend still decides the live gate. */\nexport function registerBrynTools(\n server: McpServer,\n client: DatabrainClient,\n catalogue: BrynCatalogue\n): void {\n for (const entry of catalogue.tools) {\n // A future surface needs a backend host and explicit delegated policy.\n const legacy =\n entry.surface === 'custom-chart-studio' ||\n entry.surface === 'theme-editor';\n if (!isExecutableBrynTool(entry)) continue;\n const context: Record<string, z.ZodType> = entry.contextFields\n ? {}\n : legacy\n ? legacyContext(entry.surface as 'custom-chart-studio' | 'theme-editor')\n : {};\n let input: z.ZodType;\n try {\n input = z.fromJSONSchema(entry.inputSchema);\n for (const [name, field] of Object.entries(entry.contextFields ?? {})) {\n if (\n !/^[a-zA-Z][a-zA-Z0-9]*$/.test(name) ||\n ['workspaceId', 'mode', 'input'].includes(name)\n )\n throw new Error('Invalid Bryn context field');\n const schema = z.fromJSONSchema(field.schema);\n context[name] = field.required ? schema : schema.optional();\n }\n } catch {\n // A newer backend schema must not prevent existing MCP tools from loading.\n continue;\n }\n const shape: Record<string, z.ZodType> = {\n workspaceId: uuid,\n mode,\n input,\n ...context,\n };\n // The exact tool schema comes from Bryn's registry. The envelope carries\n // its required workspace and current editor state to the same host.\n server.tool(\n entry.name,\n `${entry.description} Executes the ${entry.surface} Bryn host; returns a draft only.`,\n shape,\n entry.effect === 'read' ? READ_ONLY : WRITE_IDEMPOTENT,\n async (args) => {\n try {\n if (!entry.modes.includes(args.mode as 'ask' | 'plan' | 'build'))\n return toolError('Bryn does not offer this tool in that mode.');\n const result = await client.request<unknown>({\n method: 'POST',\n path: `/api/mcp/bryn/tools/${entry.name}`,\n auth: 'service',\n body: args,\n timeoutMs: 45_000,\n noRetryOnTimeout: true,\n });\n return toolSuccess(JSON.stringify(result));\n } catch (error) {\n return error instanceof DatabrainApiError\n ? error.toToolResponse()\n : toolError('Bryn could not run this tool. No draft was saved.');\n }\n }\n );\n }\n}\n","import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { z } from 'zod';\nimport type { DatabrainClient } from '../client/databrain-client.js';\nimport { studioDraftSchema } from '../custom-chart/studio.js';\nimport { READ_ONLY, WRITE_CREATE } from '../tools/annotations.js';\nimport { DatabrainApiError, toolError, toolSuccess } from '../utils/errors.js';\n\nconst workspaceId = z.string().uuid();\nconst sessionId = z.string().uuid().optional();\nconst message = z.string().trim().min(1).max(8000);\nconst mode = z.enum(['ask', 'plan']);\nconst themeSnapshot = {\n theme: z.record(z.string(), z.unknown()),\n dark: z.record(z.string(), z.unknown()),\n schema: z\n .array(\n z\n .object({\n path: z.string().max(120),\n kind: z.string(),\n label: z.string().max(80),\n })\n .passthrough()\n )\n .min(1)\n .max(200),\n contrast: z.array(z.string().max(240)).max(24).optional(),\n};\n\nconst response = (result: unknown) =>\n result &&\n typeof result === 'object' &&\n 'completed' in result &&\n result.completed === false\n ? toolError(JSON.stringify(result))\n : toolSuccess(JSON.stringify(result));\nconst failure = (error: unknown) =>\n error instanceof DatabrainApiError\n ? error.toToolResponse()\n : toolError(\n 'Bryn did not complete the turn. Review the workspace and retry.'\n );\n\n/** One full-turn entrypoint per existing Bryn surface, bound to a signed-in user. */\nexport function registerBrynTurns(\n server: McpServer,\n client: DatabrainClient\n): void {\n server.tool(\n 'ask_bryn_metric',\n 'Ask or plan a metric with the metric Bryn agent in this workspace. This runs a full model turn as the signed-in user and does not apply a metric.',\n { workspaceId, sessionId, message, mode },\n READ_ONLY,\n async (input) => {\n if (!client.isHosted())\n return toolError(\n 'A Bryn turn needs a signed-in user. Service credentials have no user identity or free-turn allowance.'\n );\n try {\n return response(\n await client.request({\n method: 'POST',\n path: '/stream/agent',\n auth: 'service',\n body: {\n workspaceId: input.workspaceId,\n sessionId: input.sessionId,\n question: input.message,\n mode: input.mode,\n },\n responseFormat: 'bryn-sse',\n timeoutMs: 180_000,\n noRetryOnTimeout: true,\n })\n );\n } catch (error) {\n return failure(error);\n }\n }\n );\n server.tool(\n 'ask_bryn_semantic_model',\n 'Ask or plan with semantic model Bryn. Supply an existing authoring session and revision, or source and its published base hash to create a draft. A signed-in user and model permission are required.',\n {\n workspaceId,\n datamartId: z.string().uuid(),\n sessionId,\n revision: z.number().int().min(0).optional(),\n source: z.string().max(1_000_000).optional(),\n baseContentHash: z.string().nullable().optional(),\n message: z.string().trim().min(1).max(32000),\n mode,\n },\n WRITE_CREATE,\n async (input) => {\n if (!client.isHosted())\n return toolError(\n 'A Bryn turn needs a signed-in user. Service credentials have no user identity or free-turn allowance.'\n );\n try {\n let targetSession = input.sessionId;\n let revision = input.revision;\n if (!targetSession) {\n if (input.source === undefined || input.baseContentHash === undefined)\n return toolError(\n 'source and baseContentHash are required to start a semantic authoring session.'\n );\n const draft = await client.request<{\n sessionId: string;\n revision: number;\n }>({\n method: 'POST',\n auth: 'service',\n path: `/api/v2/semantic/${input.datamartId}/authoring`,\n body: {\n source: input.source,\n baseContentHash: input.baseContentHash,\n },\n noRetryOnTimeout: true,\n });\n targetSession = draft.sessionId;\n revision = draft.revision;\n }\n if (revision === undefined)\n return toolError(\n 'revision is required to continue this semantic authoring session.'\n );\n const turn = await client.request<Record<string, unknown>>({\n method: 'POST',\n auth: 'service',\n path: `/api/v2/semantic/${input.datamartId}/authoring/${targetSession}/turn`,\n body: { revision, message: input.message, mode: input.mode },\n responseFormat: 'bryn-sse',\n timeoutMs: 180_000,\n noRetryOnTimeout: true,\n });\n try {\n const current = await client.request<{ revision?: number }>({\n method: 'GET',\n auth: 'service',\n path: `/api/v2/semantic/${input.datamartId}/authoring/${targetSession}`,\n });\n return response({ ...turn, revision: current.revision });\n } catch {\n return response({\n ...turn,\n note: 'The turn finished, but the latest draft revision could not be read. Fetch it before continuing.',\n });\n }\n } catch (error) {\n return failure(error);\n }\n }\n );\n server.tool(\n 'ask_bryn_theme',\n 'Ask, plan or build a theme draft with theme Bryn. The result is a preview draft; the theme is not saved. A signed-in user is required.',\n {\n workspaceId,\n sessionId,\n message,\n mode: z.enum(['ask', 'plan', 'build']),\n ...themeSnapshot,\n },\n WRITE_CREATE,\n async (input) => {\n if (!client.isHosted())\n return toolError(\n 'A Bryn turn needs a signed-in user. Service credentials have no user identity or free-turn allowance.'\n );\n try {\n return response(\n await client.request({\n method: 'POST',\n path: '/api/v2/theme-bryn/turn',\n auth: 'service',\n body: input,\n responseFormat: 'bryn-sse',\n timeoutMs: 180_000,\n noRetryOnTimeout: true,\n })\n );\n } catch (error) {\n return failure(error);\n }\n }\n );\n server.tool(\n 'ask_bryn_custom_chart',\n 'Ask, plan or build a chart draft with Chart studio Bryn. The result is a draft; no version is saved or published. A signed-in user is required.',\n {\n workspaceId,\n sessionId,\n message,\n mode: z.enum(['ask', 'plan', 'build']),\n key: z.string().regex(/^[a-z][a-z0-9_-]{0,63}$/),\n draft: studioDraftSchema,\n viewingOldVersion: z.boolean().default(false),\n },\n WRITE_CREATE,\n async (input) => {\n if (!client.isHosted())\n return toolError(\n 'A Bryn turn needs a signed-in user. Service credentials have no user identity or free-turn allowance.'\n );\n try {\n return response(\n await client.request({\n method: 'POST',\n auth: 'service',\n path: `/api/v2/custom-charts/${encodeURIComponent(input.key)}/bryn/turn`,\n body: {\n workspaceId: input.workspaceId,\n sessionId: input.sessionId,\n message: input.message,\n mode: input.mode,\n draft: input.draft,\n viewingOldVersion: input.viewingOldVersion,\n },\n responseFormat: 'bryn-sse',\n timeoutMs: 180_000,\n noRetryOnTimeout: true,\n })\n );\n } catch (error) {\n return failure(error);\n }\n }\n );\n}\n"],"mappings":"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","names":["z","catalogue","z","z","z","surface","catalogue","z","z","mode","turn"]}
package/dist/cli.d.ts CHANGED
@@ -1,15 +1,16 @@
1
- /**
2
- * Shared shapes for the custom chart package pipeline (DAT-925).
3
- * Problem is the one error shape used by the manifest validator, the bundle
4
- * builder, the icon check and the backend API (section 5 of the brief).
5
- */
6
- interface Problem {
7
- code: string;
8
- path: string;
9
- message: string;
10
- }
11
-
12
- declare function formatProblemLines(problems: Problem[]): string[];
13
- declare function runCli(argv: string[]): Promise<number>;
14
-
15
- export { formatProblemLines, runCli };
1
+ export declare function formatProblemLines(problems: Problem[]): string[];
2
+
3
+ /**
4
+ * Shared shapes for the custom chart package pipeline (DAT-925).
5
+ * Problem is the one error shape used by the manifest validator, the bundle
6
+ * builder, the icon check and the backend API (section 5 of the brief).
7
+ */
8
+ declare interface Problem {
9
+ code: string;
10
+ path: string;
11
+ message: string;
12
+ }
13
+
14
+ export declare function runCli(argv: string[]): Promise<number>;
15
+
16
+ export { }