@lightsage/mcp 0.4.18 → 0.4.19
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/README.md +2 -2
- package/api/mcp.js +4 -1
- package/bin/mcp-server.js +440 -116
- package/bin/mcp-server.js.map +23 -14
- package/esm/funcs/agentsList.d.ts +1 -1
- package/esm/funcs/agentsList.js +1 -1
- package/esm/funcs/promptsRun.d.ts +2 -1
- package/esm/funcs/promptsRun.d.ts.map +1 -1
- package/esm/funcs/promptsRun.js +2 -1
- package/esm/funcs/promptsRun.js.map +1 -1
- package/esm/funcs/promptsTargetsList.d.ts +16 -0
- package/esm/funcs/promptsTargetsList.d.ts.map +1 -0
- package/esm/funcs/promptsTargetsList.js +86 -0
- package/esm/funcs/promptsTargetsList.js.map +1 -0
- package/esm/funcs/promptsTargetsSet.d.ts +16 -0
- package/esm/funcs/promptsTargetsSet.d.ts.map +1 -0
- package/esm/funcs/promptsTargetsSet.js +83 -0
- package/esm/funcs/promptsTargetsSet.js.map +1 -0
- package/esm/landing-page.js +1 -1
- package/esm/lib/config.d.ts +2 -2
- package/esm/lib/config.js +2 -2
- package/esm/mcp-server/mcp-server.js +1 -1
- package/esm/mcp-server/server.d.ts.map +1 -1
- package/esm/mcp-server/server.js +5 -1
- package/esm/mcp-server/server.js.map +1 -1
- package/esm/mcp-server/tools/agentsList.js +1 -1
- package/esm/mcp-server/tools/agentsList.js.map +1 -1
- package/esm/mcp-server/tools/promptsRun.d.ts.map +1 -1
- package/esm/mcp-server/tools/promptsRun.js +2 -1
- package/esm/mcp-server/tools/promptsRun.js.map +1 -1
- package/esm/mcp-server/tools/promptsTargetsList.d.ts +7 -0
- package/esm/mcp-server/tools/promptsTargetsList.d.ts.map +1 -0
- package/esm/mcp-server/tools/promptsTargetsList.js +35 -0
- package/esm/mcp-server/tools/promptsTargetsList.js.map +1 -0
- package/esm/mcp-server/tools/promptsTargetsSet.d.ts +7 -0
- package/esm/mcp-server/tools/promptsTargetsSet.d.ts.map +1 -0
- package/esm/mcp-server/tools/promptsTargetsSet.js +35 -0
- package/esm/mcp-server/tools/promptsTargetsSet.js.map +1 -0
- package/esm/models/createv2promptrunrequest.js +1 -1
- package/esm/models/createv2promptrunrequest.js.map +1 -1
- package/esm/models/evaltemplateschedule.d.ts +4 -4
- package/esm/models/evaltemplateschedule.d.ts.map +1 -1
- package/esm/models/evaltemplateschedule.js +4 -3
- package/esm/models/evaltemplateschedule.js.map +1 -1
- package/esm/models/setv2prompttargetsrequest.d.ts +8 -0
- package/esm/models/setv2prompttargetsrequest.d.ts.map +1 -0
- package/esm/models/setv2prompttargetsrequest.js +11 -0
- package/esm/models/setv2prompttargetsrequest.js.map +1 -0
- package/esm/models/setv2prompttargetsresponse.d.ts +9 -0
- package/esm/models/setv2prompttargetsresponse.d.ts.map +1 -0
- package/esm/models/setv2prompttargetsresponse.js +12 -0
- package/esm/models/setv2prompttargetsresponse.js.map +1 -0
- package/esm/models/v2prompttarget.d.ts +44 -0
- package/esm/models/v2prompttarget.d.ts.map +1 -0
- package/esm/models/v2prompttarget.js +41 -0
- package/esm/models/v2prompttarget.js.map +1 -0
- package/esm/models/v2prompttargetinput.d.ts +47 -0
- package/esm/models/v2prompttargetinput.d.ts.map +1 -0
- package/esm/models/v2prompttargetinput.js +45 -0
- package/esm/models/v2prompttargetinput.js.map +1 -0
- package/esm/models/v2prompttargetslistop.d.ts +10 -0
- package/esm/models/v2prompttargetslistop.d.ts.map +1 -0
- package/esm/models/v2prompttargetslistop.js +15 -0
- package/esm/models/v2prompttargetslistop.js.map +1 -0
- package/esm/models/v2prompttargetsresponse.d.ts +8 -0
- package/esm/models/v2prompttargetsresponse.d.ts.map +1 -0
- package/esm/models/v2prompttargetsresponse.js +11 -0
- package/esm/models/v2prompttargetsresponse.js.map +1 -0
- package/esm/models/v2prompttargetssetop.d.ts +6 -0
- package/esm/models/v2prompttargetssetop.d.ts.map +1 -0
- package/esm/models/v2prompttargetssetop.js +12 -0
- package/esm/models/v2prompttargetssetop.js.map +1 -0
- package/esm/tool-names.d.ts.map +1 -1
- package/esm/tool-names.js +10 -2
- package/esm/tool-names.js.map +1 -1
- package/lib/feedback.js +47 -0
- package/lib/tracker.js +4 -2
- package/package.json +5 -4
- package/src/funcs/agentsList.ts +1 -1
- package/src/funcs/promptsRun.ts +2 -1
- package/src/funcs/promptsTargetsList.ts +148 -0
- package/src/funcs/promptsTargetsSet.ts +145 -0
- package/src/landing-page.ts +1 -1
- package/src/lib/config.ts +2 -2
- package/src/mcp-server/mcp-server.ts +1 -1
- package/src/mcp-server/server.ts +5 -1
- package/src/mcp-server/tools/agentsList.ts +1 -1
- package/src/mcp-server/tools/promptsRun.ts +2 -1
- package/src/mcp-server/tools/promptsTargetsList.ts +43 -0
- package/src/mcp-server/tools/promptsTargetsSet.ts +43 -0
- package/src/models/createv2promptrunrequest.ts +1 -1
- package/src/models/evaltemplateschedule.ts +8 -7
- package/src/models/setv2prompttargetsrequest.ts +26 -0
- package/src/models/setv2prompttargetsresponse.ts +23 -0
- package/src/models/v2prompttarget.ts +79 -0
- package/src/models/v2prompttargetinput.ts +72 -0
- package/src/models/v2prompttargetslistop.ts +33 -0
- package/src/models/v2prompttargetsresponse.ts +19 -0
- package/src/models/v2prompttargetssetop.ts +25 -0
- package/src/tool-names.ts +10 -2
- package/test/tracker.test.js +83 -1
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.
|
|
3
|
+
* @generated-id: 69ccb1989872
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import * as z from "zod";
|
|
7
|
+
import { ClosedEnum } from "../types/enums.js";
|
|
8
|
+
|
|
9
|
+
export const AnswerEngine = {
|
|
10
|
+
Chatgpt: "chatgpt",
|
|
11
|
+
GoogleAiOverviews: "google-ai-overviews",
|
|
12
|
+
GoogleAiMode: "google-ai-mode",
|
|
13
|
+
GeminiSearch: "gemini-search",
|
|
14
|
+
Perplexity: "perplexity",
|
|
15
|
+
Claude: "claude",
|
|
16
|
+
MicrosoftCopilot: "microsoft-copilot",
|
|
17
|
+
} as const;
|
|
18
|
+
export type AnswerEngine = ClosedEnum<typeof AnswerEngine>;
|
|
19
|
+
|
|
20
|
+
export const AnswerEngine$zodSchema = z.enum([
|
|
21
|
+
"chatgpt",
|
|
22
|
+
"google-ai-overviews",
|
|
23
|
+
"google-ai-mode",
|
|
24
|
+
"gemini-search",
|
|
25
|
+
"perplexity",
|
|
26
|
+
"claude",
|
|
27
|
+
"microsoft-copilot",
|
|
28
|
+
]);
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* How often this target runs on schedule. `manual` keeps it for runs you start yourself. Frequencies other than `daily` require custom prompt scheduling on the organization.
|
|
32
|
+
*/
|
|
33
|
+
export const V2PromptTargetInputFrequency = {
|
|
34
|
+
Daily: "daily",
|
|
35
|
+
EveryOtherDay: "every_other_day",
|
|
36
|
+
Weekly: "weekly",
|
|
37
|
+
Manual: "manual",
|
|
38
|
+
} as const;
|
|
39
|
+
/**
|
|
40
|
+
* How often this target runs on schedule. `manual` keeps it for runs you start yourself. Frequencies other than `daily` require custom prompt scheduling on the organization.
|
|
41
|
+
*/
|
|
42
|
+
export type V2PromptTargetInputFrequency = ClosedEnum<
|
|
43
|
+
typeof V2PromptTargetInputFrequency
|
|
44
|
+
>;
|
|
45
|
+
|
|
46
|
+
export const V2PromptTargetInputFrequency$zodSchema = z.enum([
|
|
47
|
+
"daily",
|
|
48
|
+
"every_other_day",
|
|
49
|
+
"weekly",
|
|
50
|
+
"manual",
|
|
51
|
+
]).describe(
|
|
52
|
+
"How often this target runs on schedule. `manual` keeps it for runs you start yourself. Frequencies other than `daily` require custom prompt scheduling on the organization.",
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
export type V2PromptTargetInput = {
|
|
56
|
+
answer_engine?: AnswerEngine | null | undefined;
|
|
57
|
+
agent?: string | null | undefined;
|
|
58
|
+
frequency?: V2PromptTargetInputFrequency | undefined;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export const V2PromptTargetInput$zodSchema: z.ZodType<V2PromptTargetInput> = z
|
|
62
|
+
.object({
|
|
63
|
+
agent: z.string().nullable().optional().describe(
|
|
64
|
+
"Runnable agent from `GET /v2/agents`, a coding-agent harness and model such as `claude-code:claude-opus-5-5`. Set this or `answer_engine`, not both.",
|
|
65
|
+
),
|
|
66
|
+
answer_engine: AnswerEngine$zodSchema.nullable().optional().describe(
|
|
67
|
+
"Answer engine to run the topic's prompts on. Set this or `agent`, not both.",
|
|
68
|
+
),
|
|
69
|
+
frequency: V2PromptTargetInputFrequency$zodSchema.default("daily").describe(
|
|
70
|
+
"How often this target runs on schedule. `manual` keeps it for runs you start yourself. Frequencies other than `daily` require custom prompt scheduling on the organization.",
|
|
71
|
+
),
|
|
72
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.
|
|
3
|
+
* @generated-id: 31f493d5ba11
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import * as z from "zod";
|
|
7
|
+
import {
|
|
8
|
+
HTTPValidationError,
|
|
9
|
+
HTTPValidationError$zodSchema,
|
|
10
|
+
} from "./httpvalidationerror.js";
|
|
11
|
+
import {
|
|
12
|
+
V2PromptTargetsResponse,
|
|
13
|
+
V2PromptTargetsResponse$zodSchema,
|
|
14
|
+
} from "./v2prompttargetsresponse.js";
|
|
15
|
+
|
|
16
|
+
export type V2PromptTargetsListRequest = { topic_id?: string | undefined };
|
|
17
|
+
|
|
18
|
+
export const V2PromptTargetsListRequest$zodSchema: z.ZodType<
|
|
19
|
+
V2PromptTargetsListRequest
|
|
20
|
+
> = z.object({
|
|
21
|
+
topic_id: z.string().describe("Optional prompt topic ID.").optional(),
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
export type V2PromptTargetsListResponse =
|
|
25
|
+
| V2PromptTargetsResponse
|
|
26
|
+
| HTTPValidationError;
|
|
27
|
+
|
|
28
|
+
export const V2PromptTargetsListResponse$zodSchema: z.ZodType<
|
|
29
|
+
V2PromptTargetsListResponse
|
|
30
|
+
> = z.union([
|
|
31
|
+
V2PromptTargetsResponse$zodSchema,
|
|
32
|
+
HTTPValidationError$zodSchema,
|
|
33
|
+
]);
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.
|
|
3
|
+
* @generated-id: 25379b3b6438
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import * as z from "zod";
|
|
7
|
+
import { V2PromptTarget, V2PromptTarget$zodSchema } from "./v2prompttarget.js";
|
|
8
|
+
|
|
9
|
+
export type V2PromptTargetsResponse = {
|
|
10
|
+
data?: Array<V2PromptTarget> | undefined;
|
|
11
|
+
count: number;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export const V2PromptTargetsResponse$zodSchema: z.ZodType<
|
|
15
|
+
V2PromptTargetsResponse
|
|
16
|
+
> = z.object({
|
|
17
|
+
count: z.int(),
|
|
18
|
+
data: z.array(V2PromptTarget$zodSchema).optional(),
|
|
19
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.
|
|
3
|
+
* @generated-id: 4187502eab53
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import * as z from "zod";
|
|
7
|
+
import {
|
|
8
|
+
HTTPValidationError,
|
|
9
|
+
HTTPValidationError$zodSchema,
|
|
10
|
+
} from "./httpvalidationerror.js";
|
|
11
|
+
import {
|
|
12
|
+
SetV2PromptTargetsResponse,
|
|
13
|
+
SetV2PromptTargetsResponse$zodSchema,
|
|
14
|
+
} from "./setv2prompttargetsresponse.js";
|
|
15
|
+
|
|
16
|
+
export type V2PromptTargetsSetResponse =
|
|
17
|
+
| SetV2PromptTargetsResponse
|
|
18
|
+
| HTTPValidationError;
|
|
19
|
+
|
|
20
|
+
export const V2PromptTargetsSetResponse$zodSchema: z.ZodType<
|
|
21
|
+
V2PromptTargetsSetResponse
|
|
22
|
+
> = z.union([
|
|
23
|
+
SetV2PromptTargetsResponse$zodSchema,
|
|
24
|
+
HTTPValidationError$zodSchema,
|
|
25
|
+
]);
|
package/src/tool-names.ts
CHANGED
|
@@ -52,6 +52,14 @@ export const toolNames: Array<{ name: string; description: string }>= [
|
|
|
52
52
|
"name": "prompts-topics-delete",
|
|
53
53
|
"description": "Delete Topic\n\nArchives a prompt topic. Set `archive_prompts` to archive remaining prompts; otherwise the request fails with `400` if prompts remain."
|
|
54
54
|
},
|
|
55
|
+
{
|
|
56
|
+
"name": "prompts-targets-list",
|
|
57
|
+
"description": "List Targets\n\nReturns the answer engines and coding agents that run the organization's prompts on schedule, with each target's topic and frequency. Provide `topic_id` to list one topic's targets."
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"name": "prompts-targets-set",
|
|
61
|
+
"description": "Set Targets\n\nSets which answer engines and coding agents run a topic's prompts on schedule, the same way the prompt editor does. The list replaces the topic's targets: targets you leave out stop running. Every prompt in the topic is set to exactly these platforms; you can still narrow one prompt afterwards with `platform_ids`. Name coding agents with IDs from `GET /v2/agents`, and list a harness more than once to run it on several models. To pick agents for a single run without changing the schedule, pass `agent` to `POST /v2/prompts/runs` instead."
|
|
62
|
+
},
|
|
55
63
|
{
|
|
56
64
|
"name": "prompts-runs-list",
|
|
57
65
|
"description": "List Prompt Runs\n\nReturns stored prompt runs with limit-and-offset pagination, without exposing raw runtime or provider configuration. Filter by prompt, platform, or date range."
|
|
@@ -74,7 +82,7 @@ export const toolNames: Array<{ name: string; description: string }>= [
|
|
|
74
82
|
},
|
|
75
83
|
{
|
|
76
84
|
"name": "prompts-run",
|
|
77
|
-
"description": "Run Prompts\n\nQueue saved prompts on answer engines and coding agents.\n\nProvide `prompt_ids` to run selected prompts, or omit them to run all active\nprompts. By default the run uses the organization's configured targets
|
|
85
|
+
"description": "Run Prompts\n\nQueue saved prompts on answer engines and coding agents.\n\nProvide `prompt_ids` to run selected prompts, or omit them to run all active\nprompts. By default the run uses the organization's configured targets,\nlisted by `GET /v2/prompts/targets`.\nProvide `agent` with IDs from `GET /v2/agents` to run the prompts on\nspecific coding-agent harnesses and models instead, for example to compare\nhow several coding tools answer the same developer question. Results\ninclude mentions and citations. Saved prompt run settings apply to\ncoding-agent targets. The response returns a run ID to poll with\n`GET /v2/prompts/runs/{run_id}/status`."
|
|
78
86
|
},
|
|
79
87
|
{
|
|
80
88
|
"name": "prompts-run-status",
|
|
@@ -258,7 +266,7 @@ export const toolNames: Array<{ name: string; description: string }>= [
|
|
|
258
266
|
},
|
|
259
267
|
{
|
|
260
268
|
"name": "agents-list",
|
|
261
|
-
"description": "List Agents\n\nReturns the coding-agent harness-and-model combinations your plan can run, as single agent IDs. Pass them as `agent` to `POST /v2/prompts/runs` to see how coding agents answer your prompts, with mentions and citations; to `POST /v2/agent-preference/evals` to see whether agents recommend your company over one competitor; or to `POST /v2/evals` and `POST /v2/eval-runs` to measure how well agents complete tasks with your product."
|
|
269
|
+
"description": "List Agents\n\nReturns the coding-agent harness-and-model combinations your plan can run, as single agent IDs. Pass them as `agent` to `POST /v2/prompts/runs` to see how coding agents answer your prompts, with mentions and citations, or to `PUT /v2/prompts/targets` to run them on a schedule; to `POST /v2/agent-preference/evals` to see whether agents recommend your company over one competitor; or to `POST /v2/evals` and `POST /v2/eval-runs` to measure how well agents complete tasks with your product."
|
|
262
270
|
},
|
|
263
271
|
{
|
|
264
272
|
"name": "repositories-list",
|
package/test/tracker.test.js
CHANGED
|
@@ -313,11 +313,93 @@ test("OAuth sessions follow the user, not the token", async () => {
|
|
|
313
313
|
});
|
|
314
314
|
|
|
315
315
|
|
|
316
|
-
test("only failed calls
|
|
316
|
+
test("only failed calls, catalog tool results and feedback confirmations are stored", async () => {
|
|
317
317
|
const { shouldStoreResponse } = await import("../lib/tracker.js");
|
|
318
318
|
assert.equal(shouldStoreResponse({ toolName: "list_tools", isError: false }), true);
|
|
319
319
|
assert.equal(shouldStoreResponse({ toolName: "describe_tool_input", isError: false }), true);
|
|
320
320
|
assert.equal(shouldStoreResponse({ toolName: "execute_tool", isError: false }), false);
|
|
321
321
|
assert.equal(shouldStoreResponse({ toolName: "get_profile", isError: false }), false);
|
|
322
322
|
assert.equal(shouldStoreResponse({ toolName: "execute_tool", isError: true }), true);
|
|
323
|
+
assert.equal(shouldStoreResponse({ toolName: "send_feedback", isError: false }), true);
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
async function connectedClient(url, apiKey) {
|
|
327
|
+
const client = new Client({ name: "feedback-test", version: "1.0.0" });
|
|
328
|
+
await client.connect(
|
|
329
|
+
new StreamableHTTPClientTransport(url, {
|
|
330
|
+
fetch: realFetch,
|
|
331
|
+
requestInit: { headers: { "lightsage-api-key-auth": apiKey } },
|
|
332
|
+
}),
|
|
333
|
+
);
|
|
334
|
+
return client;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
test("a recorded caller can send feedback, and MCP Analytics keeps its input and output", async () => {
|
|
338
|
+
await withServer(async (url) => {
|
|
339
|
+
const client = await connectedClient(new URL(url), "ls_feedback_key");
|
|
340
|
+
try {
|
|
341
|
+
const { tools } = await client.listTools();
|
|
342
|
+
const tool = tools.find((t) => t.name === "send_feedback");
|
|
343
|
+
assert.ok(tool, "send_feedback is listed");
|
|
344
|
+
assert.equal(tool.annotations.readOnlyHint, false);
|
|
345
|
+
assert.equal(tool.annotations.destructiveHint, false);
|
|
346
|
+
assert.deepEqual(tool.inputSchema.required, ["feedback"]);
|
|
347
|
+
assert.equal(tool.inputSchema.additionalProperties, false);
|
|
348
|
+
|
|
349
|
+
const before = sentEvents().length;
|
|
350
|
+
const result = await client.callTool({
|
|
351
|
+
name: "send_feedback",
|
|
352
|
+
arguments: { feedback: " list_tools missed the visibility tools " },
|
|
353
|
+
});
|
|
354
|
+
assert.ok(!result.isError);
|
|
355
|
+
assert.equal(result.content[0].text, "Feedback received. Thank you!");
|
|
356
|
+
|
|
357
|
+
const call = sentEvents().slice(before).find((e) =>
|
|
358
|
+
e.event === "$mcp_tool_call" && e.tool_name === "send_feedback"
|
|
359
|
+
);
|
|
360
|
+
assert.equal(call.parameters.feedback, " list_tools missed the visibility tools ");
|
|
361
|
+
assert.equal(call.response.content[0].text, "Feedback received. Thank you!");
|
|
362
|
+
assert.ok(!JSON.stringify(call).includes("ls_feedback_key"));
|
|
363
|
+
} finally {
|
|
364
|
+
await client.close();
|
|
365
|
+
}
|
|
366
|
+
});
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
test("feedback must be text within the limit, with no other fields", async () => {
|
|
370
|
+
const { MAX_FEEDBACK_LENGTH } = await import("../lib/feedback.js");
|
|
371
|
+
await withServer(async (url) => {
|
|
372
|
+
const client = await connectedClient(new URL(url), "ls_feedback_key");
|
|
373
|
+
try {
|
|
374
|
+
for (const args of [
|
|
375
|
+
{},
|
|
376
|
+
{ feedback: " " },
|
|
377
|
+
{ feedback: "x".repeat(MAX_FEEDBACK_LENGTH + 1) },
|
|
378
|
+
{ feedback: "ok", email: "a@example.com" },
|
|
379
|
+
]) {
|
|
380
|
+
const result = await client.callTool({ name: "send_feedback", arguments: args });
|
|
381
|
+
assert.equal(result.isError, true, JSON.stringify(args).slice(0, 60));
|
|
382
|
+
}
|
|
383
|
+
const result = await client.callTool({
|
|
384
|
+
name: "send_feedback",
|
|
385
|
+
arguments: { feedback: "x".repeat(MAX_FEEDBACK_LENGTH) },
|
|
386
|
+
});
|
|
387
|
+
assert.ok(!result.isError);
|
|
388
|
+
} finally {
|
|
389
|
+
await client.close();
|
|
390
|
+
}
|
|
391
|
+
});
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
test("callers who are not recorded are not offered the feedback tool", async () => {
|
|
395
|
+
await withServer(async (url) => {
|
|
396
|
+
const client = await connectedClient(new URL(url), "ls_bad_unrecorded");
|
|
397
|
+
try {
|
|
398
|
+
const { tools } = await client.listTools();
|
|
399
|
+
assert.ok(tools.length > 0);
|
|
400
|
+
assert.ok(!tools.some((t) => t.name === "send_feedback"));
|
|
401
|
+
} finally {
|
|
402
|
+
await client.close();
|
|
403
|
+
}
|
|
404
|
+
});
|
|
323
405
|
});
|