@sentientui/mcp 0.14.1 → 0.15.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.
- package/dist/{chunk-O335LMWF.js → chunk-3RJUYHO7.js} +255 -224
- package/dist/index.cjs +66 -34
- package/dist/index.js +1 -1
- package/dist/lib.cjs +68 -34
- package/dist/lib.d.cts +12 -1
- package/dist/lib.d.ts +12 -1
- package/dist/lib.js +3 -1
- package/package.json +1 -1
|
@@ -65,196 +65,6 @@ var ApiClient = class {
|
|
|
65
65
|
}
|
|
66
66
|
};
|
|
67
67
|
|
|
68
|
-
// src/server.ts
|
|
69
|
-
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
70
|
-
|
|
71
|
-
// src/tools/projects.ts
|
|
72
|
-
import { z as z2 } from "zod";
|
|
73
|
-
|
|
74
|
-
// src/tools/common.ts
|
|
75
|
-
import { z } from "zod";
|
|
76
|
-
var projectIdSchema = z.string().uuid().describe("The project UUID");
|
|
77
|
-
function apiErrorGuidance(err, extra) {
|
|
78
|
-
if (extra && Object.prototype.hasOwnProperty.call(extra, err.message)) {
|
|
79
|
-
return extra[err.message];
|
|
80
|
-
}
|
|
81
|
-
switch (err.message) {
|
|
82
|
-
case "insufficient_scope":
|
|
83
|
-
return "This action needs an account login. Connect via the hosted MCP URL (https://api.sentient-ui.com/mcp) and sign in \u2014 a project-scoped server key (sk_\u2026) or anonymous demo token cannot do this.";
|
|
84
|
-
case "demo_read_only":
|
|
85
|
-
return "Demo mode is read-only. Create a SentientUI account and sign in (or use a project server key) to make changes.";
|
|
86
|
-
case "insufficient_role":
|
|
87
|
-
return "Your account role does not permit this action \u2014 it needs the account owner or an admin.";
|
|
88
|
-
default:
|
|
89
|
-
break;
|
|
90
|
-
}
|
|
91
|
-
if (err.status === 402) {
|
|
92
|
-
return `This feature requires a higher plan (${err.message}). Upgrade your SentientUI plan, then try again.`;
|
|
93
|
-
}
|
|
94
|
-
if (err.status === 403) {
|
|
95
|
-
return `Access denied (${err.message}). Check that your key or login has access to this project.`;
|
|
96
|
-
}
|
|
97
|
-
return null;
|
|
98
|
-
}
|
|
99
|
-
function withApiErrorGuidance(fn, extra) {
|
|
100
|
-
return async (args) => {
|
|
101
|
-
try {
|
|
102
|
-
return await fn(args);
|
|
103
|
-
} catch (err) {
|
|
104
|
-
if (err instanceof ApiError) {
|
|
105
|
-
const guidance = apiErrorGuidance(err, extra);
|
|
106
|
-
if (guidance) {
|
|
107
|
-
return { content: [{ type: "text", text: guidance }], isError: true };
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
throw err;
|
|
111
|
-
}
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// src/tools/projects.ts
|
|
116
|
-
var CREATE_PROJECT_GUIDANCE = {
|
|
117
|
-
project_limit_reached: "You've reached your plan's project limit. Upgrade your plan or remove an existing project, then try again.",
|
|
118
|
-
name_required: "A project name is required to create a project."
|
|
119
|
-
};
|
|
120
|
-
function registerProjectTools(server, client) {
|
|
121
|
-
server.registerTool(
|
|
122
|
-
"create_project",
|
|
123
|
-
{
|
|
124
|
-
title: "Create project",
|
|
125
|
-
description: "Create a NEW SentientUI project (onboarding). Returns the project id and its pk_ public key for the SDK. Requires an account login: this works when connected via OAuth (the hosted MCP URL) but NOT with a project-scoped sk_ server key or an anonymous demo token. After it succeeds, call get_integration_guide and help the user install @sentientui/react with the returned key.",
|
|
126
|
-
inputSchema: {
|
|
127
|
-
name: z2.string().min(1).describe("Human-readable project name"),
|
|
128
|
-
contextType: z2.enum(["saas", "ecommerce", "marketing", "landing", "internal"]).optional().describe("What kind of product this is; defaults to saas"),
|
|
129
|
-
framework: z2.enum(["next", "react", "core"]).optional().describe("How the site is built \u2014 next, react, or core (website builder/CMS); defaults to next"),
|
|
130
|
-
websiteUrl: z2.string().optional().describe("Production site origin to allow-list so the SDK's events aren't origin-blocked on day one")
|
|
131
|
-
},
|
|
132
|
-
outputSchema: {
|
|
133
|
-
projectId: z2.string().describe("The new project UUID"),
|
|
134
|
-
publicKey: z2.string().describe("The pk_ public key to configure the SDK with"),
|
|
135
|
-
name: z2.string().describe("The project name"),
|
|
136
|
-
contextType: z2.string().describe("The resolved context type")
|
|
137
|
-
},
|
|
138
|
-
annotations: {
|
|
139
|
-
readOnlyHint: false,
|
|
140
|
-
destructiveHint: false,
|
|
141
|
-
idempotentHint: false,
|
|
142
|
-
openWorldHint: false
|
|
143
|
-
}
|
|
144
|
-
},
|
|
145
|
-
withApiErrorGuidance(async ({ name, contextType, framework, websiteUrl }) => {
|
|
146
|
-
const created = await client.post("/projects", {
|
|
147
|
-
name,
|
|
148
|
-
contextType,
|
|
149
|
-
framework,
|
|
150
|
-
origin: websiteUrl
|
|
151
|
-
});
|
|
152
|
-
const resolvedContextType = contextType != null ? contextType : "saas";
|
|
153
|
-
return {
|
|
154
|
-
content: [{
|
|
155
|
-
type: "text",
|
|
156
|
-
text: [
|
|
157
|
-
`Created project "${name}" (id: ${created.id}, type: ${resolvedContextType}).`,
|
|
158
|
-
`Public key: ${created.apiKey}`,
|
|
159
|
-
`Next: install @sentientui/react with this key. Ask me to pull the setup guide (get_integration_guide) and I'll wrap your first component.`
|
|
160
|
-
].join("\n")
|
|
161
|
-
}],
|
|
162
|
-
structuredContent: {
|
|
163
|
-
projectId: created.id,
|
|
164
|
-
publicKey: created.apiKey,
|
|
165
|
-
name,
|
|
166
|
-
contextType: resolvedContextType
|
|
167
|
-
}
|
|
168
|
-
};
|
|
169
|
-
}, CREATE_PROJECT_GUIDANCE)
|
|
170
|
-
);
|
|
171
|
-
server.registerTool(
|
|
172
|
-
"list_projects",
|
|
173
|
-
{
|
|
174
|
-
title: "List projects",
|
|
175
|
-
description: "List all SentientUI projects for the authenticated account.",
|
|
176
|
-
inputSchema: {},
|
|
177
|
-
outputSchema: {
|
|
178
|
-
projects: z2.array(
|
|
179
|
-
z2.object({
|
|
180
|
-
id: z2.string().describe("Project UUID"),
|
|
181
|
-
name: z2.string(),
|
|
182
|
-
contextType: z2.string(),
|
|
183
|
-
createdAt: z2.string().describe("ISO date (YYYY-MM-DD)")
|
|
184
|
-
})
|
|
185
|
-
).describe("All projects for the account (empty if none)")
|
|
186
|
-
},
|
|
187
|
-
annotations: {
|
|
188
|
-
readOnlyHint: true,
|
|
189
|
-
idempotentHint: true,
|
|
190
|
-
openWorldHint: false
|
|
191
|
-
}
|
|
192
|
-
},
|
|
193
|
-
withApiErrorGuidance(async () => {
|
|
194
|
-
const projects = await client.get("/projects");
|
|
195
|
-
const text = projects.length === 0 ? "No projects found." : projects.map(
|
|
196
|
-
(p) => `- ${p.name} (id: ${p.id}, type: ${p.context_type}, created: ${p.created_at.slice(0, 10)})`
|
|
197
|
-
).join("\n");
|
|
198
|
-
return {
|
|
199
|
-
content: [{ type: "text", text }],
|
|
200
|
-
structuredContent: {
|
|
201
|
-
projects: projects.map((p) => ({
|
|
202
|
-
id: p.id,
|
|
203
|
-
name: p.name,
|
|
204
|
-
contextType: p.context_type,
|
|
205
|
-
createdAt: p.created_at.slice(0, 10)
|
|
206
|
-
}))
|
|
207
|
-
}
|
|
208
|
-
};
|
|
209
|
-
})
|
|
210
|
-
);
|
|
211
|
-
server.registerTool(
|
|
212
|
-
"get_project_stats",
|
|
213
|
-
{
|
|
214
|
-
title: "Project health stats",
|
|
215
|
-
description: "Get health stats for a project: event volume, session count, agent calls, and status.",
|
|
216
|
-
inputSchema: { projectId: projectIdSchema },
|
|
217
|
-
outputSchema: {
|
|
218
|
-
status: z2.string().describe("Overall project health status"),
|
|
219
|
-
events24h: z2.number().describe("Events in the last 24 hours"),
|
|
220
|
-
sessions24h: z2.number().describe("Sessions in the last 24 hours"),
|
|
221
|
-
agentCalls: z2.number().describe("Total agent (MCP/API) calls"),
|
|
222
|
-
lastEventAt: z2.string().nullable().describe("ISO timestamp of the last event, or null")
|
|
223
|
-
},
|
|
224
|
-
annotations: {
|
|
225
|
-
readOnlyHint: true,
|
|
226
|
-
idempotentHint: true,
|
|
227
|
-
openWorldHint: false
|
|
228
|
-
}
|
|
229
|
-
},
|
|
230
|
-
withApiErrorGuidance(async ({ projectId }) => {
|
|
231
|
-
var _a;
|
|
232
|
-
const id = encodeURIComponent(projectId);
|
|
233
|
-
const stats = await client.get(`/projects/${id}/health`);
|
|
234
|
-
const text = [
|
|
235
|
-
`Status: ${stats.status}`,
|
|
236
|
-
`Events (24h): ${stats.events24h}`,
|
|
237
|
-
`Sessions (24h): ${stats.sessions24h}`,
|
|
238
|
-
`Agent calls (total): ${stats.agentCalls}`,
|
|
239
|
-
`Last event: ${(_a = stats.lastEventAt) != null ? _a : "never"}`
|
|
240
|
-
].join("\n");
|
|
241
|
-
return {
|
|
242
|
-
content: [{ type: "text", text }],
|
|
243
|
-
structuredContent: {
|
|
244
|
-
status: stats.status,
|
|
245
|
-
events24h: stats.events24h,
|
|
246
|
-
sessions24h: stats.sessions24h,
|
|
247
|
-
agentCalls: stats.agentCalls,
|
|
248
|
-
lastEventAt: stats.lastEventAt
|
|
249
|
-
}
|
|
250
|
-
};
|
|
251
|
-
})
|
|
252
|
-
);
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
// src/tools/components.ts
|
|
256
|
-
import { z as z3 } from "zod";
|
|
257
|
-
|
|
258
68
|
// src/ui/templates.ts
|
|
259
69
|
var VIZ_TITLES = {
|
|
260
70
|
"persona-breakdown": "Persona breakdown",
|
|
@@ -488,6 +298,7 @@ function uiMeta(id) {
|
|
|
488
298
|
"openai/outputTemplate": uri
|
|
489
299
|
};
|
|
490
300
|
}
|
|
301
|
+
var PUBLIC_UI_RESOURCE_URIS = Object.values(UI_TOOL_VIZ).map(uiResourceUri);
|
|
491
302
|
function registerUiResources(server) {
|
|
492
303
|
for (const id of Object.values(UI_TOOL_VIZ)) {
|
|
493
304
|
server.registerResource(
|
|
@@ -511,7 +322,195 @@ function registerUiResources(server) {
|
|
|
511
322
|
}
|
|
512
323
|
}
|
|
513
324
|
|
|
325
|
+
// src/server.ts
|
|
326
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
327
|
+
|
|
328
|
+
// src/tools/projects.ts
|
|
329
|
+
import { z as z2 } from "zod";
|
|
330
|
+
|
|
331
|
+
// src/tools/common.ts
|
|
332
|
+
import { z } from "zod";
|
|
333
|
+
var projectIdSchema = z.string().uuid().describe("The project UUID");
|
|
334
|
+
function apiErrorGuidance(err, extra) {
|
|
335
|
+
if (extra && Object.prototype.hasOwnProperty.call(extra, err.message)) {
|
|
336
|
+
return extra[err.message];
|
|
337
|
+
}
|
|
338
|
+
switch (err.message) {
|
|
339
|
+
case "insufficient_scope":
|
|
340
|
+
return "This action needs an account login. Connect via the hosted MCP URL (https://api.sentient-ui.com/mcp) and sign in \u2014 a project-scoped server key (sk_\u2026) or anonymous demo token cannot do this.";
|
|
341
|
+
case "demo_read_only":
|
|
342
|
+
return "Demo mode is read-only. Create a SentientUI account and sign in (or use a project server key) to make changes.";
|
|
343
|
+
case "insufficient_role":
|
|
344
|
+
return "Your account role does not permit this action \u2014 it needs the account owner or an admin.";
|
|
345
|
+
default:
|
|
346
|
+
break;
|
|
347
|
+
}
|
|
348
|
+
if (err.status === 402) {
|
|
349
|
+
return `This feature requires a higher plan (${err.message}). Upgrade your SentientUI plan, then try again.`;
|
|
350
|
+
}
|
|
351
|
+
if (err.status === 403) {
|
|
352
|
+
return `Access denied (${err.message}). Check that your key or login has access to this project.`;
|
|
353
|
+
}
|
|
354
|
+
return null;
|
|
355
|
+
}
|
|
356
|
+
function withApiErrorGuidance(fn, extra) {
|
|
357
|
+
return async (args) => {
|
|
358
|
+
try {
|
|
359
|
+
return await fn(args);
|
|
360
|
+
} catch (err) {
|
|
361
|
+
if (err instanceof ApiError) {
|
|
362
|
+
const guidance = apiErrorGuidance(err, extra);
|
|
363
|
+
if (guidance) {
|
|
364
|
+
return { content: [{ type: "text", text: guidance }], isError: true };
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
throw err;
|
|
368
|
+
}
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// src/tools/projects.ts
|
|
373
|
+
var CREATE_PROJECT_GUIDANCE = {
|
|
374
|
+
project_limit_reached: "You've reached your plan's project limit. Upgrade your plan or remove an existing project, then try again.",
|
|
375
|
+
name_required: "A project name is required to create a project."
|
|
376
|
+
};
|
|
377
|
+
function registerProjectTools(server, client) {
|
|
378
|
+
server.registerTool(
|
|
379
|
+
"create_project",
|
|
380
|
+
{
|
|
381
|
+
title: "Create project",
|
|
382
|
+
description: "Create a NEW SentientUI project (onboarding). Returns the project id and its pk_ public key for the SDK. Requires an account login: this works when connected via OAuth (the hosted MCP URL) but NOT with a project-scoped sk_ server key or an anonymous demo token. After it succeeds, call get_integration_guide and help the user install @sentientui/react with the returned key.",
|
|
383
|
+
inputSchema: {
|
|
384
|
+
name: z2.string().min(1).describe("Human-readable project name"),
|
|
385
|
+
contextType: z2.enum(["saas", "ecommerce", "marketing", "landing", "internal"]).optional().describe("What kind of product this is; defaults to saas"),
|
|
386
|
+
framework: z2.enum(["next", "react", "core"]).optional().describe("How the site is built \u2014 next, react, or core (website builder/CMS); defaults to next"),
|
|
387
|
+
websiteUrl: z2.string().optional().describe("Production site origin to allow-list so the SDK's events aren't origin-blocked on day one")
|
|
388
|
+
},
|
|
389
|
+
outputSchema: {
|
|
390
|
+
projectId: z2.string().describe("The new project UUID"),
|
|
391
|
+
publicKey: z2.string().describe("The pk_ public key to configure the SDK with"),
|
|
392
|
+
name: z2.string().describe("The project name"),
|
|
393
|
+
contextType: z2.string().describe("The resolved context type")
|
|
394
|
+
},
|
|
395
|
+
annotations: {
|
|
396
|
+
readOnlyHint: false,
|
|
397
|
+
destructiveHint: false,
|
|
398
|
+
idempotentHint: false,
|
|
399
|
+
openWorldHint: false
|
|
400
|
+
}
|
|
401
|
+
},
|
|
402
|
+
withApiErrorGuidance(async ({ name, contextType, framework, websiteUrl }) => {
|
|
403
|
+
const created = await client.post("/projects", {
|
|
404
|
+
name,
|
|
405
|
+
contextType,
|
|
406
|
+
framework,
|
|
407
|
+
origin: websiteUrl
|
|
408
|
+
});
|
|
409
|
+
const resolvedContextType = contextType != null ? contextType : "saas";
|
|
410
|
+
return {
|
|
411
|
+
content: [{
|
|
412
|
+
type: "text",
|
|
413
|
+
text: [
|
|
414
|
+
`Created project "${name}" (id: ${created.id}, type: ${resolvedContextType}).`,
|
|
415
|
+
`Public key: ${created.apiKey}`,
|
|
416
|
+
`Next: install @sentientui/react with this key. Ask me to pull the setup guide (get_integration_guide) and I'll wrap your first component.`
|
|
417
|
+
].join("\n")
|
|
418
|
+
}],
|
|
419
|
+
structuredContent: {
|
|
420
|
+
projectId: created.id,
|
|
421
|
+
publicKey: created.apiKey,
|
|
422
|
+
name,
|
|
423
|
+
contextType: resolvedContextType
|
|
424
|
+
}
|
|
425
|
+
};
|
|
426
|
+
}, CREATE_PROJECT_GUIDANCE)
|
|
427
|
+
);
|
|
428
|
+
server.registerTool(
|
|
429
|
+
"list_projects",
|
|
430
|
+
{
|
|
431
|
+
title: "List projects",
|
|
432
|
+
description: "List all SentientUI projects for the authenticated account.",
|
|
433
|
+
inputSchema: {},
|
|
434
|
+
outputSchema: {
|
|
435
|
+
projects: z2.array(
|
|
436
|
+
z2.object({
|
|
437
|
+
id: z2.string().describe("Project UUID"),
|
|
438
|
+
name: z2.string(),
|
|
439
|
+
contextType: z2.string(),
|
|
440
|
+
createdAt: z2.string().describe("ISO date (YYYY-MM-DD)")
|
|
441
|
+
})
|
|
442
|
+
).describe("All projects for the account (empty if none)")
|
|
443
|
+
},
|
|
444
|
+
annotations: {
|
|
445
|
+
readOnlyHint: true,
|
|
446
|
+
idempotentHint: true,
|
|
447
|
+
openWorldHint: false
|
|
448
|
+
}
|
|
449
|
+
},
|
|
450
|
+
withApiErrorGuidance(async () => {
|
|
451
|
+
const projects = await client.get("/projects");
|
|
452
|
+
const text = projects.length === 0 ? "No projects found." : projects.map(
|
|
453
|
+
(p) => `- ${p.name} (id: ${p.id}, type: ${p.context_type}, created: ${p.created_at.slice(0, 10)})`
|
|
454
|
+
).join("\n");
|
|
455
|
+
return {
|
|
456
|
+
content: [{ type: "text", text }],
|
|
457
|
+
structuredContent: {
|
|
458
|
+
projects: projects.map((p) => ({
|
|
459
|
+
id: p.id,
|
|
460
|
+
name: p.name,
|
|
461
|
+
contextType: p.context_type,
|
|
462
|
+
createdAt: p.created_at.slice(0, 10)
|
|
463
|
+
}))
|
|
464
|
+
}
|
|
465
|
+
};
|
|
466
|
+
})
|
|
467
|
+
);
|
|
468
|
+
server.registerTool(
|
|
469
|
+
"get_project_stats",
|
|
470
|
+
{
|
|
471
|
+
title: "Project health stats",
|
|
472
|
+
description: "Get health stats for a project: event volume, session count, agent calls, and status.",
|
|
473
|
+
inputSchema: { projectId: projectIdSchema },
|
|
474
|
+
outputSchema: {
|
|
475
|
+
status: z2.string().describe("Overall project health status"),
|
|
476
|
+
events24h: z2.number().describe("Events in the last 24 hours"),
|
|
477
|
+
sessions24h: z2.number().describe("Sessions in the last 24 hours"),
|
|
478
|
+
agentCalls: z2.number().describe("Total agent (MCP/API) calls"),
|
|
479
|
+
lastEventAt: z2.string().nullable().describe("ISO timestamp of the last event, or null")
|
|
480
|
+
},
|
|
481
|
+
annotations: {
|
|
482
|
+
readOnlyHint: true,
|
|
483
|
+
idempotentHint: true,
|
|
484
|
+
openWorldHint: false
|
|
485
|
+
}
|
|
486
|
+
},
|
|
487
|
+
withApiErrorGuidance(async ({ projectId }) => {
|
|
488
|
+
var _a;
|
|
489
|
+
const id = encodeURIComponent(projectId);
|
|
490
|
+
const stats = await client.get(`/projects/${id}/health`);
|
|
491
|
+
const text = [
|
|
492
|
+
`Status: ${stats.status}`,
|
|
493
|
+
`Events (24h): ${stats.events24h}`,
|
|
494
|
+
`Sessions (24h): ${stats.sessions24h}`,
|
|
495
|
+
`Agent calls (total): ${stats.agentCalls}`,
|
|
496
|
+
`Last event: ${(_a = stats.lastEventAt) != null ? _a : "never"}`
|
|
497
|
+
].join("\n");
|
|
498
|
+
return {
|
|
499
|
+
content: [{ type: "text", text }],
|
|
500
|
+
structuredContent: {
|
|
501
|
+
status: stats.status,
|
|
502
|
+
events24h: stats.events24h,
|
|
503
|
+
sessions24h: stats.sessions24h,
|
|
504
|
+
agentCalls: stats.agentCalls,
|
|
505
|
+
lastEventAt: stats.lastEventAt
|
|
506
|
+
}
|
|
507
|
+
};
|
|
508
|
+
})
|
|
509
|
+
);
|
|
510
|
+
}
|
|
511
|
+
|
|
514
512
|
// src/tools/components.ts
|
|
513
|
+
import { z as z3 } from "zod";
|
|
515
514
|
function registerComponentTools(server, client) {
|
|
516
515
|
server.registerTool(
|
|
517
516
|
"list_components",
|
|
@@ -619,19 +618,38 @@ function registerComponentTools(server, client) {
|
|
|
619
618
|
|
|
620
619
|
// src/tools/insights.ts
|
|
621
620
|
import { z as z4 } from "zod";
|
|
621
|
+
var EMPTY_REASON_TEXT = {
|
|
622
|
+
no_events: "The snippet has not fired yet \u2014 nothing has reached us.",
|
|
623
|
+
no_traffic_yet: "Test traffic only so far; no genuine visitors yet.",
|
|
624
|
+
awaiting_profiles: "Still building visitor profiles before visitors can be grouped.",
|
|
625
|
+
no_variants: "Nothing to compare yet \u2014 no adaptive component is running.",
|
|
626
|
+
nothing_moved: "Enough data, and nothing moved this period. That is a result.",
|
|
627
|
+
job_never_ran: "The analysis job has not run yet.",
|
|
628
|
+
job_stale: "These numbers are out of date \u2014 the analysis job has not run recently."
|
|
629
|
+
};
|
|
622
630
|
function registerInsightTools(server, client) {
|
|
623
631
|
server.registerTool(
|
|
624
632
|
"get_insights",
|
|
625
633
|
{
|
|
626
634
|
title: "Get insights",
|
|
627
|
-
description: "
|
|
635
|
+
description: "What is known about this project right now: ranked findings with the evidence behind each one, plus (Growth tier) advisor recommendations. Says why it is empty when it is.",
|
|
628
636
|
inputSchema: { projectId: projectIdSchema },
|
|
629
637
|
outputSchema: {
|
|
630
|
-
status: z4.enum(["ok", "empty"]).describe("Whether
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
638
|
+
status: z4.enum(["ok", "empty"]).describe("Whether any findings exist yet"),
|
|
639
|
+
reached: z4.string().describe("Highest confidence tier earned: observed | patterned | tested"),
|
|
640
|
+
findings: z4.array(z4.object({
|
|
641
|
+
tier: z4.string().describe("observed | patterned | tested"),
|
|
642
|
+
kind: z4.string(),
|
|
643
|
+
headline: z4.string(),
|
|
644
|
+
audience: z4.string().nullable(),
|
|
645
|
+
sample: z4.number().describe("How many the finding is based on"),
|
|
646
|
+
coverage: z4.number().nullable().describe("Fraction of traffic this finding describes, when applicable")
|
|
647
|
+
})).describe("Ranked findings, each with the evidence behind it"),
|
|
648
|
+
emptyReason: z4.string().nullable().describe("Why there is nothing to report, when there is nothing"),
|
|
649
|
+
observations: z4.array(z4.string()).describe("Headlines of measured findings"),
|
|
650
|
+
recommendations: z4.array(z4.string()).describe("Headlines of interpreted findings (Growth tier)"),
|
|
651
|
+
isStale: z4.boolean().describe("True when the analysis has not run recently"),
|
|
652
|
+
generatedAt: z4.string().nullable().describe("ISO timestamp, or null")
|
|
635
653
|
},
|
|
636
654
|
annotations: {
|
|
637
655
|
readOnlyHint: true,
|
|
@@ -640,42 +658,54 @@ function registerInsightTools(server, client) {
|
|
|
640
658
|
}
|
|
641
659
|
},
|
|
642
660
|
withApiErrorGuidance(async ({ projectId }) => {
|
|
643
|
-
var _a, _b, _c, _d;
|
|
661
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
|
|
644
662
|
const id = encodeURIComponent(projectId);
|
|
645
|
-
const data = await client.get(`/projects/${id}/
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
isStale: false,
|
|
654
|
-
generatedAt: null
|
|
655
|
-
}
|
|
656
|
-
};
|
|
657
|
-
}
|
|
658
|
-
const observations = (_a = data.narratorBullets) != null ? _a : [];
|
|
659
|
-
const recommendations = (_b = data.advisorBullets) != null ? _b : [];
|
|
663
|
+
const data = await client.get(`/projects/${id}/evidence-report`);
|
|
664
|
+
const findings = (_a = data.findings) != null ? _a : [];
|
|
665
|
+
const measured = findings.filter((f) => !f.interpreted);
|
|
666
|
+
const interpreted = findings.filter((f) => f.interpreted);
|
|
667
|
+
const observations = measured.map((f) => f.headline);
|
|
668
|
+
const recommendations = interpreted.map((f) => f.headline);
|
|
669
|
+
const isStale = (_c = (_b = data.freshness) == null ? void 0 : _b.isStale) != null ? _c : false;
|
|
670
|
+
const emptyReason = (_d = data.emptyReason) != null ? _d : null;
|
|
660
671
|
const lines = [];
|
|
661
|
-
if (
|
|
672
|
+
if (emptyReason) lines.push((_e = EMPTY_REASON_TEXT[emptyReason]) != null ? _e : emptyReason);
|
|
673
|
+
if (isStale) lines.push("\u26A0 The analysis job has not run recently, so these numbers may have moved.");
|
|
674
|
+
if ((_f = data.interpretation) == null ? void 0 : _f.locked) {
|
|
675
|
+
lines.push(`${data.interpretation.count || "Some"} recommendations are available on the Growth plan.`);
|
|
676
|
+
} else if (((_g = data.interpretation) == null ? void 0 : _g.emptyReason) && !emptyReason) {
|
|
677
|
+
lines.push(`Recommendations: ${(_h = EMPTY_REASON_TEXT[data.interpretation.emptyReason]) != null ? _h : data.interpretation.emptyReason}`);
|
|
678
|
+
}
|
|
662
679
|
if (data.generatedAt) lines.push(`Generated: ${new Date(data.generatedAt).toUTCString()}`);
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
680
|
+
if (measured.length) {
|
|
681
|
+
lines.push("", "Findings:");
|
|
682
|
+
for (const f of measured) {
|
|
683
|
+
const cov = f.provenance.coverage !== null && f.provenance.coverage < 0.999 ? `, covering ${Math.round(f.provenance.coverage * 100)}% of visitors` : "";
|
|
684
|
+
lines.push(`- [${f.tier}] ${f.headline} (${f.provenance.sample} ${f.provenance.denominatorLabel}${cov})`);
|
|
685
|
+
}
|
|
686
|
+
}
|
|
666
687
|
if (recommendations.length) {
|
|
667
|
-
lines.push("");
|
|
668
|
-
lines.push(
|
|
669
|
-
recommendations.forEach((b) => lines.push(`- ${b}`));
|
|
688
|
+
lines.push("", "Recommendations:");
|
|
689
|
+
for (const r of recommendations) lines.push(`- ${r}`);
|
|
670
690
|
}
|
|
671
691
|
return {
|
|
672
|
-
content: [{ type: "text", text: lines.join("\n") }],
|
|
692
|
+
content: [{ type: "text", text: lines.join("\n").trim() || "No findings yet." }],
|
|
673
693
|
structuredContent: {
|
|
674
|
-
status: "ok",
|
|
694
|
+
status: findings.length ? "ok" : "empty",
|
|
695
|
+
reached: (_i = data.reached) != null ? _i : "observed",
|
|
696
|
+
findings: findings.map((f) => ({
|
|
697
|
+
tier: f.tier,
|
|
698
|
+
kind: f.kind,
|
|
699
|
+
headline: f.headline,
|
|
700
|
+
audience: f.audience,
|
|
701
|
+
sample: f.provenance.sample,
|
|
702
|
+
coverage: f.provenance.coverage
|
|
703
|
+
})),
|
|
704
|
+
emptyReason,
|
|
675
705
|
observations,
|
|
676
706
|
recommendations,
|
|
677
|
-
isStale
|
|
678
|
-
generatedAt: (
|
|
707
|
+
isStale,
|
|
708
|
+
generatedAt: (_j = data.generatedAt) != null ? _j : null
|
|
679
709
|
}
|
|
680
710
|
};
|
|
681
711
|
})
|
|
@@ -1772,7 +1802,7 @@ function registerAgentTrafficTools(server, client) {
|
|
|
1772
1802
|
}
|
|
1773
1803
|
|
|
1774
1804
|
// src/server.ts
|
|
1775
|
-
var PKG_VERSION = true ? "0.
|
|
1805
|
+
var PKG_VERSION = true ? "0.15.0" : "0.0.0-dev";
|
|
1776
1806
|
function createMcpServer(client) {
|
|
1777
1807
|
const server = new McpServer(
|
|
1778
1808
|
{
|
|
@@ -1813,5 +1843,6 @@ function createMcpServer(client) {
|
|
|
1813
1843
|
export {
|
|
1814
1844
|
ApiError,
|
|
1815
1845
|
ApiClient,
|
|
1846
|
+
PUBLIC_UI_RESOURCE_URIS,
|
|
1816
1847
|
createMcpServer
|
|
1817
1848
|
};
|
package/dist/index.cjs
CHANGED
|
@@ -492,6 +492,7 @@ function uiMeta(id) {
|
|
|
492
492
|
"openai/outputTemplate": uri
|
|
493
493
|
};
|
|
494
494
|
}
|
|
495
|
+
var PUBLIC_UI_RESOURCE_URIS = Object.values(UI_TOOL_VIZ).map(uiResourceUri);
|
|
495
496
|
function registerUiResources(server) {
|
|
496
497
|
for (const id of Object.values(UI_TOOL_VIZ)) {
|
|
497
498
|
server.registerResource(
|
|
@@ -623,19 +624,38 @@ function registerComponentTools(server, client) {
|
|
|
623
624
|
|
|
624
625
|
// src/tools/insights.ts
|
|
625
626
|
var import_zod4 = require("zod");
|
|
627
|
+
var EMPTY_REASON_TEXT = {
|
|
628
|
+
no_events: "The snippet has not fired yet \u2014 nothing has reached us.",
|
|
629
|
+
no_traffic_yet: "Test traffic only so far; no genuine visitors yet.",
|
|
630
|
+
awaiting_profiles: "Still building visitor profiles before visitors can be grouped.",
|
|
631
|
+
no_variants: "Nothing to compare yet \u2014 no adaptive component is running.",
|
|
632
|
+
nothing_moved: "Enough data, and nothing moved this period. That is a result.",
|
|
633
|
+
job_never_ran: "The analysis job has not run yet.",
|
|
634
|
+
job_stale: "These numbers are out of date \u2014 the analysis job has not run recently."
|
|
635
|
+
};
|
|
626
636
|
function registerInsightTools(server, client) {
|
|
627
637
|
server.registerTool(
|
|
628
638
|
"get_insights",
|
|
629
639
|
{
|
|
630
640
|
title: "Get insights",
|
|
631
|
-
description: "
|
|
641
|
+
description: "What is known about this project right now: ranked findings with the evidence behind each one, plus (Growth tier) advisor recommendations. Says why it is empty when it is.",
|
|
632
642
|
inputSchema: { projectId: projectIdSchema },
|
|
633
643
|
outputSchema: {
|
|
634
|
-
status: import_zod4.z.enum(["ok", "empty"]).describe("Whether
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
644
|
+
status: import_zod4.z.enum(["ok", "empty"]).describe("Whether any findings exist yet"),
|
|
645
|
+
reached: import_zod4.z.string().describe("Highest confidence tier earned: observed | patterned | tested"),
|
|
646
|
+
findings: import_zod4.z.array(import_zod4.z.object({
|
|
647
|
+
tier: import_zod4.z.string().describe("observed | patterned | tested"),
|
|
648
|
+
kind: import_zod4.z.string(),
|
|
649
|
+
headline: import_zod4.z.string(),
|
|
650
|
+
audience: import_zod4.z.string().nullable(),
|
|
651
|
+
sample: import_zod4.z.number().describe("How many the finding is based on"),
|
|
652
|
+
coverage: import_zod4.z.number().nullable().describe("Fraction of traffic this finding describes, when applicable")
|
|
653
|
+
})).describe("Ranked findings, each with the evidence behind it"),
|
|
654
|
+
emptyReason: import_zod4.z.string().nullable().describe("Why there is nothing to report, when there is nothing"),
|
|
655
|
+
observations: import_zod4.z.array(import_zod4.z.string()).describe("Headlines of measured findings"),
|
|
656
|
+
recommendations: import_zod4.z.array(import_zod4.z.string()).describe("Headlines of interpreted findings (Growth tier)"),
|
|
657
|
+
isStale: import_zod4.z.boolean().describe("True when the analysis has not run recently"),
|
|
658
|
+
generatedAt: import_zod4.z.string().nullable().describe("ISO timestamp, or null")
|
|
639
659
|
},
|
|
640
660
|
annotations: {
|
|
641
661
|
readOnlyHint: true,
|
|
@@ -644,42 +664,54 @@ function registerInsightTools(server, client) {
|
|
|
644
664
|
}
|
|
645
665
|
},
|
|
646
666
|
withApiErrorGuidance(async ({ projectId }) => {
|
|
647
|
-
var _a2, _b, _c, _d;
|
|
667
|
+
var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j;
|
|
648
668
|
const id = encodeURIComponent(projectId);
|
|
649
|
-
const data = await client.get(`/projects/${id}/
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
isStale: false,
|
|
658
|
-
generatedAt: null
|
|
659
|
-
}
|
|
660
|
-
};
|
|
661
|
-
}
|
|
662
|
-
const observations = (_a2 = data.narratorBullets) != null ? _a2 : [];
|
|
663
|
-
const recommendations = (_b = data.advisorBullets) != null ? _b : [];
|
|
669
|
+
const data = await client.get(`/projects/${id}/evidence-report`);
|
|
670
|
+
const findings = (_a2 = data.findings) != null ? _a2 : [];
|
|
671
|
+
const measured = findings.filter((f) => !f.interpreted);
|
|
672
|
+
const interpreted = findings.filter((f) => f.interpreted);
|
|
673
|
+
const observations = measured.map((f) => f.headline);
|
|
674
|
+
const recommendations = interpreted.map((f) => f.headline);
|
|
675
|
+
const isStale = (_c = (_b = data.freshness) == null ? void 0 : _b.isStale) != null ? _c : false;
|
|
676
|
+
const emptyReason = (_d = data.emptyReason) != null ? _d : null;
|
|
664
677
|
const lines = [];
|
|
665
|
-
if (
|
|
678
|
+
if (emptyReason) lines.push((_e = EMPTY_REASON_TEXT[emptyReason]) != null ? _e : emptyReason);
|
|
679
|
+
if (isStale) lines.push("\u26A0 The analysis job has not run recently, so these numbers may have moved.");
|
|
680
|
+
if ((_f = data.interpretation) == null ? void 0 : _f.locked) {
|
|
681
|
+
lines.push(`${data.interpretation.count || "Some"} recommendations are available on the Growth plan.`);
|
|
682
|
+
} else if (((_g = data.interpretation) == null ? void 0 : _g.emptyReason) && !emptyReason) {
|
|
683
|
+
lines.push(`Recommendations: ${(_h = EMPTY_REASON_TEXT[data.interpretation.emptyReason]) != null ? _h : data.interpretation.emptyReason}`);
|
|
684
|
+
}
|
|
666
685
|
if (data.generatedAt) lines.push(`Generated: ${new Date(data.generatedAt).toUTCString()}`);
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
686
|
+
if (measured.length) {
|
|
687
|
+
lines.push("", "Findings:");
|
|
688
|
+
for (const f of measured) {
|
|
689
|
+
const cov = f.provenance.coverage !== null && f.provenance.coverage < 0.999 ? `, covering ${Math.round(f.provenance.coverage * 100)}% of visitors` : "";
|
|
690
|
+
lines.push(`- [${f.tier}] ${f.headline} (${f.provenance.sample} ${f.provenance.denominatorLabel}${cov})`);
|
|
691
|
+
}
|
|
692
|
+
}
|
|
670
693
|
if (recommendations.length) {
|
|
671
|
-
lines.push("");
|
|
672
|
-
lines.push(
|
|
673
|
-
recommendations.forEach((b) => lines.push(`- ${b}`));
|
|
694
|
+
lines.push("", "Recommendations:");
|
|
695
|
+
for (const r of recommendations) lines.push(`- ${r}`);
|
|
674
696
|
}
|
|
675
697
|
return {
|
|
676
|
-
content: [{ type: "text", text: lines.join("\n") }],
|
|
698
|
+
content: [{ type: "text", text: lines.join("\n").trim() || "No findings yet." }],
|
|
677
699
|
structuredContent: {
|
|
678
|
-
status: "ok",
|
|
700
|
+
status: findings.length ? "ok" : "empty",
|
|
701
|
+
reached: (_i = data.reached) != null ? _i : "observed",
|
|
702
|
+
findings: findings.map((f) => ({
|
|
703
|
+
tier: f.tier,
|
|
704
|
+
kind: f.kind,
|
|
705
|
+
headline: f.headline,
|
|
706
|
+
audience: f.audience,
|
|
707
|
+
sample: f.provenance.sample,
|
|
708
|
+
coverage: f.provenance.coverage
|
|
709
|
+
})),
|
|
710
|
+
emptyReason,
|
|
679
711
|
observations,
|
|
680
712
|
recommendations,
|
|
681
|
-
isStale
|
|
682
|
-
generatedAt: (
|
|
713
|
+
isStale,
|
|
714
|
+
generatedAt: (_j = data.generatedAt) != null ? _j : null
|
|
683
715
|
}
|
|
684
716
|
};
|
|
685
717
|
})
|
|
@@ -1776,7 +1808,7 @@ function registerAgentTrafficTools(server, client) {
|
|
|
1776
1808
|
}
|
|
1777
1809
|
|
|
1778
1810
|
// src/server.ts
|
|
1779
|
-
var PKG_VERSION = true ? "0.
|
|
1811
|
+
var PKG_VERSION = true ? "0.15.0" : "0.0.0-dev";
|
|
1780
1812
|
function createMcpServer(client) {
|
|
1781
1813
|
const server = new import_mcp.McpServer(
|
|
1782
1814
|
{
|
package/dist/index.js
CHANGED
package/dist/lib.cjs
CHANGED
|
@@ -40,6 +40,7 @@ var lib_exports = {};
|
|
|
40
40
|
__export(lib_exports, {
|
|
41
41
|
ApiClient: () => ApiClient,
|
|
42
42
|
ApiError: () => ApiError,
|
|
43
|
+
PUBLIC_UI_RESOURCE_URIS: () => PUBLIC_UI_RESOURCE_URIS,
|
|
43
44
|
createMcpServer: () => createMcpServer
|
|
44
45
|
});
|
|
45
46
|
module.exports = __toCommonJS(lib_exports);
|
|
@@ -515,6 +516,7 @@ function uiMeta(id) {
|
|
|
515
516
|
"openai/outputTemplate": uri
|
|
516
517
|
};
|
|
517
518
|
}
|
|
519
|
+
var PUBLIC_UI_RESOURCE_URIS = Object.values(UI_TOOL_VIZ).map(uiResourceUri);
|
|
518
520
|
function registerUiResources(server) {
|
|
519
521
|
for (const id of Object.values(UI_TOOL_VIZ)) {
|
|
520
522
|
server.registerResource(
|
|
@@ -646,19 +648,38 @@ function registerComponentTools(server, client) {
|
|
|
646
648
|
|
|
647
649
|
// src/tools/insights.ts
|
|
648
650
|
var import_zod4 = require("zod");
|
|
651
|
+
var EMPTY_REASON_TEXT = {
|
|
652
|
+
no_events: "The snippet has not fired yet \u2014 nothing has reached us.",
|
|
653
|
+
no_traffic_yet: "Test traffic only so far; no genuine visitors yet.",
|
|
654
|
+
awaiting_profiles: "Still building visitor profiles before visitors can be grouped.",
|
|
655
|
+
no_variants: "Nothing to compare yet \u2014 no adaptive component is running.",
|
|
656
|
+
nothing_moved: "Enough data, and nothing moved this period. That is a result.",
|
|
657
|
+
job_never_ran: "The analysis job has not run yet.",
|
|
658
|
+
job_stale: "These numbers are out of date \u2014 the analysis job has not run recently."
|
|
659
|
+
};
|
|
649
660
|
function registerInsightTools(server, client) {
|
|
650
661
|
server.registerTool(
|
|
651
662
|
"get_insights",
|
|
652
663
|
{
|
|
653
664
|
title: "Get insights",
|
|
654
|
-
description: "
|
|
665
|
+
description: "What is known about this project right now: ranked findings with the evidence behind each one, plus (Growth tier) advisor recommendations. Says why it is empty when it is.",
|
|
655
666
|
inputSchema: { projectId: projectIdSchema },
|
|
656
667
|
outputSchema: {
|
|
657
|
-
status: import_zod4.z.enum(["ok", "empty"]).describe("Whether
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
668
|
+
status: import_zod4.z.enum(["ok", "empty"]).describe("Whether any findings exist yet"),
|
|
669
|
+
reached: import_zod4.z.string().describe("Highest confidence tier earned: observed | patterned | tested"),
|
|
670
|
+
findings: import_zod4.z.array(import_zod4.z.object({
|
|
671
|
+
tier: import_zod4.z.string().describe("observed | patterned | tested"),
|
|
672
|
+
kind: import_zod4.z.string(),
|
|
673
|
+
headline: import_zod4.z.string(),
|
|
674
|
+
audience: import_zod4.z.string().nullable(),
|
|
675
|
+
sample: import_zod4.z.number().describe("How many the finding is based on"),
|
|
676
|
+
coverage: import_zod4.z.number().nullable().describe("Fraction of traffic this finding describes, when applicable")
|
|
677
|
+
})).describe("Ranked findings, each with the evidence behind it"),
|
|
678
|
+
emptyReason: import_zod4.z.string().nullable().describe("Why there is nothing to report, when there is nothing"),
|
|
679
|
+
observations: import_zod4.z.array(import_zod4.z.string()).describe("Headlines of measured findings"),
|
|
680
|
+
recommendations: import_zod4.z.array(import_zod4.z.string()).describe("Headlines of interpreted findings (Growth tier)"),
|
|
681
|
+
isStale: import_zod4.z.boolean().describe("True when the analysis has not run recently"),
|
|
682
|
+
generatedAt: import_zod4.z.string().nullable().describe("ISO timestamp, or null")
|
|
662
683
|
},
|
|
663
684
|
annotations: {
|
|
664
685
|
readOnlyHint: true,
|
|
@@ -667,42 +688,54 @@ function registerInsightTools(server, client) {
|
|
|
667
688
|
}
|
|
668
689
|
},
|
|
669
690
|
withApiErrorGuidance(async ({ projectId }) => {
|
|
670
|
-
var _a, _b, _c, _d;
|
|
691
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
|
|
671
692
|
const id = encodeURIComponent(projectId);
|
|
672
|
-
const data = await client.get(`/projects/${id}/
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
isStale: false,
|
|
681
|
-
generatedAt: null
|
|
682
|
-
}
|
|
683
|
-
};
|
|
684
|
-
}
|
|
685
|
-
const observations = (_a = data.narratorBullets) != null ? _a : [];
|
|
686
|
-
const recommendations = (_b = data.advisorBullets) != null ? _b : [];
|
|
693
|
+
const data = await client.get(`/projects/${id}/evidence-report`);
|
|
694
|
+
const findings = (_a = data.findings) != null ? _a : [];
|
|
695
|
+
const measured = findings.filter((f) => !f.interpreted);
|
|
696
|
+
const interpreted = findings.filter((f) => f.interpreted);
|
|
697
|
+
const observations = measured.map((f) => f.headline);
|
|
698
|
+
const recommendations = interpreted.map((f) => f.headline);
|
|
699
|
+
const isStale = (_c = (_b = data.freshness) == null ? void 0 : _b.isStale) != null ? _c : false;
|
|
700
|
+
const emptyReason = (_d = data.emptyReason) != null ? _d : null;
|
|
687
701
|
const lines = [];
|
|
688
|
-
if (
|
|
702
|
+
if (emptyReason) lines.push((_e = EMPTY_REASON_TEXT[emptyReason]) != null ? _e : emptyReason);
|
|
703
|
+
if (isStale) lines.push("\u26A0 The analysis job has not run recently, so these numbers may have moved.");
|
|
704
|
+
if ((_f = data.interpretation) == null ? void 0 : _f.locked) {
|
|
705
|
+
lines.push(`${data.interpretation.count || "Some"} recommendations are available on the Growth plan.`);
|
|
706
|
+
} else if (((_g = data.interpretation) == null ? void 0 : _g.emptyReason) && !emptyReason) {
|
|
707
|
+
lines.push(`Recommendations: ${(_h = EMPTY_REASON_TEXT[data.interpretation.emptyReason]) != null ? _h : data.interpretation.emptyReason}`);
|
|
708
|
+
}
|
|
689
709
|
if (data.generatedAt) lines.push(`Generated: ${new Date(data.generatedAt).toUTCString()}`);
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
710
|
+
if (measured.length) {
|
|
711
|
+
lines.push("", "Findings:");
|
|
712
|
+
for (const f of measured) {
|
|
713
|
+
const cov = f.provenance.coverage !== null && f.provenance.coverage < 0.999 ? `, covering ${Math.round(f.provenance.coverage * 100)}% of visitors` : "";
|
|
714
|
+
lines.push(`- [${f.tier}] ${f.headline} (${f.provenance.sample} ${f.provenance.denominatorLabel}${cov})`);
|
|
715
|
+
}
|
|
716
|
+
}
|
|
693
717
|
if (recommendations.length) {
|
|
694
|
-
lines.push("");
|
|
695
|
-
lines.push(
|
|
696
|
-
recommendations.forEach((b) => lines.push(`- ${b}`));
|
|
718
|
+
lines.push("", "Recommendations:");
|
|
719
|
+
for (const r of recommendations) lines.push(`- ${r}`);
|
|
697
720
|
}
|
|
698
721
|
return {
|
|
699
|
-
content: [{ type: "text", text: lines.join("\n") }],
|
|
722
|
+
content: [{ type: "text", text: lines.join("\n").trim() || "No findings yet." }],
|
|
700
723
|
structuredContent: {
|
|
701
|
-
status: "ok",
|
|
724
|
+
status: findings.length ? "ok" : "empty",
|
|
725
|
+
reached: (_i = data.reached) != null ? _i : "observed",
|
|
726
|
+
findings: findings.map((f) => ({
|
|
727
|
+
tier: f.tier,
|
|
728
|
+
kind: f.kind,
|
|
729
|
+
headline: f.headline,
|
|
730
|
+
audience: f.audience,
|
|
731
|
+
sample: f.provenance.sample,
|
|
732
|
+
coverage: f.provenance.coverage
|
|
733
|
+
})),
|
|
734
|
+
emptyReason,
|
|
702
735
|
observations,
|
|
703
736
|
recommendations,
|
|
704
|
-
isStale
|
|
705
|
-
generatedAt: (
|
|
737
|
+
isStale,
|
|
738
|
+
generatedAt: (_j = data.generatedAt) != null ? _j : null
|
|
706
739
|
}
|
|
707
740
|
};
|
|
708
741
|
})
|
|
@@ -1799,7 +1832,7 @@ function registerAgentTrafficTools(server, client) {
|
|
|
1799
1832
|
}
|
|
1800
1833
|
|
|
1801
1834
|
// src/server.ts
|
|
1802
|
-
var PKG_VERSION = true ? "0.
|
|
1835
|
+
var PKG_VERSION = true ? "0.15.0" : "0.0.0-dev";
|
|
1803
1836
|
function createMcpServer(client) {
|
|
1804
1837
|
const server = new import_mcp.McpServer(
|
|
1805
1838
|
{
|
|
@@ -1840,5 +1873,6 @@ function createMcpServer(client) {
|
|
|
1840
1873
|
0 && (module.exports = {
|
|
1841
1874
|
ApiClient,
|
|
1842
1875
|
ApiError,
|
|
1876
|
+
PUBLIC_UI_RESOURCE_URIS,
|
|
1843
1877
|
createMcpServer
|
|
1844
1878
|
});
|
package/dist/lib.d.cts
CHANGED
|
@@ -17,4 +17,15 @@ declare class ApiClient {
|
|
|
17
17
|
|
|
18
18
|
declare function createMcpServer(client: ApiClient): McpServer;
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
/**
|
|
21
|
+
* Every `ui://` resource this server registers. These templates are static HTML
|
|
22
|
+
* — no project data, no API call — so a host may read them before the user has
|
|
23
|
+
* authenticated. The remote /mcp endpoint uses this set to allow an
|
|
24
|
+
* unauthenticated `resources/read` for exactly these URIs (see
|
|
25
|
+
* apps/api/src/routes/mcp.ts): without it, `resources/list` advertised four
|
|
26
|
+
* resources that every reader got a 401 for, which reads to an agent as a
|
|
27
|
+
* server whose resources are all broken.
|
|
28
|
+
*/
|
|
29
|
+
declare const PUBLIC_UI_RESOURCE_URIS: readonly string[];
|
|
30
|
+
|
|
31
|
+
export { ApiClient, ApiError, PUBLIC_UI_RESOURCE_URIS, createMcpServer };
|
package/dist/lib.d.ts
CHANGED
|
@@ -17,4 +17,15 @@ declare class ApiClient {
|
|
|
17
17
|
|
|
18
18
|
declare function createMcpServer(client: ApiClient): McpServer;
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
/**
|
|
21
|
+
* Every `ui://` resource this server registers. These templates are static HTML
|
|
22
|
+
* — no project data, no API call — so a host may read them before the user has
|
|
23
|
+
* authenticated. The remote /mcp endpoint uses this set to allow an
|
|
24
|
+
* unauthenticated `resources/read` for exactly these URIs (see
|
|
25
|
+
* apps/api/src/routes/mcp.ts): without it, `resources/list` advertised four
|
|
26
|
+
* resources that every reader got a 401 for, which reads to an agent as a
|
|
27
|
+
* server whose resources are all broken.
|
|
28
|
+
*/
|
|
29
|
+
declare const PUBLIC_UI_RESOURCE_URIS: readonly string[];
|
|
30
|
+
|
|
31
|
+
export { ApiClient, ApiError, PUBLIC_UI_RESOURCE_URIS, createMcpServer };
|
package/dist/lib.js
CHANGED