@lightsage/mcp 0.4.23 → 0.4.24

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 (96) hide show
  1. package/README.md +2 -2
  2. package/api/mcp.js +3 -0
  3. package/bin/mcp-server.js +357 -168
  4. package/bin/mcp-server.js.map +24 -18
  5. package/esm/funcs/pluginEvalsResultsList.d.ts +16 -0
  6. package/esm/funcs/pluginEvalsResultsList.d.ts.map +1 -0
  7. package/esm/funcs/pluginEvalsResultsList.js +86 -0
  8. package/esm/funcs/pluginEvalsResultsList.js.map +1 -0
  9. package/esm/landing-page.js +1 -1
  10. package/esm/lib/config.d.ts +2 -2
  11. package/esm/lib/config.js +2 -2
  12. package/esm/mcp-server/mcp-server.js +1 -1
  13. package/esm/mcp-server/server.d.ts.map +1 -1
  14. package/esm/mcp-server/server.js +3 -1
  15. package/esm/mcp-server/server.js.map +1 -1
  16. package/esm/mcp-server/tools/pluginEvalsResultsList.d.ts +7 -0
  17. package/esm/mcp-server/tools/pluginEvalsResultsList.d.ts.map +1 -0
  18. package/esm/mcp-server/tools/pluginEvalsResultsList.js +35 -0
  19. package/esm/mcp-server/tools/pluginEvalsResultsList.js.map +1 -0
  20. package/esm/models/createv2evalrequest.d.ts +1 -0
  21. package/esm/models/createv2evalrequest.d.ts.map +1 -1
  22. package/esm/models/createv2evalrequest.js +1 -0
  23. package/esm/models/createv2evalrequest.js.map +1 -1
  24. package/esm/models/createv2evalrunrequest.d.ts +1 -0
  25. package/esm/models/createv2evalrunrequest.d.ts.map +1 -1
  26. package/esm/models/createv2evalrunrequest.js +1 -0
  27. package/esm/models/createv2evalrunrequest.js.map +1 -1
  28. package/esm/models/graderdefinition.d.ts +1 -0
  29. package/esm/models/graderdefinition.d.ts.map +1 -1
  30. package/esm/models/graderdefinition.js +1 -0
  31. package/esm/models/graderdefinition.js.map +1 -1
  32. package/esm/models/publiccriterionverdict.d.ts +4 -2
  33. package/esm/models/publiccriterionverdict.d.ts.map +1 -1
  34. package/esm/models/publiccriterionverdict.js +5 -3
  35. package/esm/models/publiccriterionverdict.js.map +1 -1
  36. package/esm/models/publicgraderresult.d.ts +1 -0
  37. package/esm/models/publicgraderresult.d.ts.map +1 -1
  38. package/esm/models/publicgraderresult.js +1 -0
  39. package/esm/models/publicgraderresult.js.map +1 -1
  40. package/esm/models/publicpluginevalresultsdownload.d.ts +11 -0
  41. package/esm/models/publicpluginevalresultsdownload.d.ts.map +1 -0
  42. package/esm/models/publicpluginevalresultsdownload.js +14 -0
  43. package/esm/models/publicpluginevalresultsdownload.js.map +1 -0
  44. package/esm/models/publicpluginevalresultsresponse.d.ts +8 -0
  45. package/esm/models/publicpluginevalresultsresponse.d.ts.map +1 -0
  46. package/esm/models/publicpluginevalresultsresponse.js +11 -0
  47. package/esm/models/publicpluginevalresultsresponse.js.map +1 -0
  48. package/esm/models/updatev2evalrequest.d.ts +1 -0
  49. package/esm/models/updatev2evalrequest.d.ts.map +1 -1
  50. package/esm/models/updatev2evalrequest.js +1 -0
  51. package/esm/models/updatev2evalrequest.js.map +1 -1
  52. package/esm/models/v2eval.d.ts +1 -0
  53. package/esm/models/v2eval.d.ts.map +1 -1
  54. package/esm/models/v2eval.js +1 -0
  55. package/esm/models/v2eval.js.map +1 -1
  56. package/esm/models/v2evalresultsummary.d.ts +2 -0
  57. package/esm/models/v2evalresultsummary.d.ts.map +1 -1
  58. package/esm/models/v2evalresultsummary.js +2 -0
  59. package/esm/models/v2evalresultsummary.js.map +1 -1
  60. package/esm/models/v2pluginevalsresultslistop.d.ts +10 -0
  61. package/esm/models/v2pluginevalsresultslistop.d.ts.map +1 -0
  62. package/esm/models/v2pluginevalsresultslistop.js +15 -0
  63. package/esm/models/v2pluginevalsresultslistop.js.map +1 -0
  64. package/esm/models/v2promptrunjobresponse.js +1 -1
  65. package/esm/models/v2promptrunjobresponse.js.map +1 -1
  66. package/esm/models/v2setupcommandoutput.d.ts +10 -0
  67. package/esm/models/v2setupcommandoutput.d.ts.map +1 -0
  68. package/esm/models/v2setupcommandoutput.js +14 -0
  69. package/esm/models/v2setupcommandoutput.js.map +1 -0
  70. package/esm/tool-names.d.ts.map +1 -1
  71. package/esm/tool-names.js +4 -0
  72. package/esm/tool-names.js.map +1 -1
  73. package/lib/tool-overrides.js +66 -0
  74. package/package.json +1 -1
  75. package/src/funcs/pluginEvalsResultsList.ts +148 -0
  76. package/src/landing-page.ts +1 -1
  77. package/src/lib/config.ts +2 -2
  78. package/src/mcp-server/mcp-server.ts +1 -1
  79. package/src/mcp-server/server.ts +3 -1
  80. package/src/mcp-server/tools/pluginEvalsResultsList.ts +43 -0
  81. package/src/models/createv2evalrequest.ts +4 -0
  82. package/src/models/createv2evalrunrequest.ts +4 -0
  83. package/src/models/graderdefinition.ts +2 -0
  84. package/src/models/publiccriterionverdict.ts +6 -4
  85. package/src/models/publicgraderresult.ts +4 -0
  86. package/src/models/publicpluginevalresultsdownload.ts +34 -0
  87. package/src/models/publicpluginevalresultsresponse.ts +24 -0
  88. package/src/models/updatev2evalrequest.ts +4 -0
  89. package/src/models/v2eval.ts +4 -0
  90. package/src/models/v2evalresultsummary.ts +8 -0
  91. package/src/models/v2pluginevalsresultslistop.ts +35 -0
  92. package/src/models/v2promptrunjobresponse.ts +1 -1
  93. package/src/models/v2setupcommandoutput.ts +31 -0
  94. package/src/tool-names.ts +4 -0
  95. package/test/simulations.test.js +2 -1
  96. package/test/tool-overrides.test.js +70 -0
@@ -27,6 +27,7 @@ export type GraderDefinition = {
27
27
  pattern?: string | null | undefined;
28
28
  case_sensitive?: boolean | undefined;
29
29
  criteria?: string | null | undefined;
30
+ plugin?: string | null | undefined;
30
31
  metric?: Metric | null | undefined;
31
32
  min_score?: number | null | undefined;
32
33
  max_value?: number | null | undefined;
@@ -48,6 +49,7 @@ export const GraderDefinition$zodSchema: z.ZodType<GraderDefinition> = z.object(
48
49
  needle: z.string().nullable().optional(),
49
50
  needles: z.array(z.string()).nullable().optional(),
50
51
  pattern: z.string().nullable().optional(),
52
+ plugin: z.string().nullable().optional(),
51
53
  type: z.string(),
52
54
  weight: z.number().default(1),
53
55
  },
@@ -7,15 +7,16 @@ import * as z from "zod";
7
7
  import { ClosedEnum } from "../types/enums.js";
8
8
 
9
9
  /**
10
- * `PASS` when the evidence shows the requirement was met, `FAIL` when it shows it was not, and `NOT_VERIFIED` when the evidence cannot confirm it. Any `FAIL` or `NOT_VERIFIED` fails the run, whatever the score.
10
+ * `PASS` when the evidence shows the requirement was met, `FAIL` when it shows it was not, and `NOT_VERIFIED` when the evidence cannot confirm it. Any `FAIL` or `NOT_VERIFIED` fails the run, whatever the score. `NOT_APPLICABLE` when the requirement states its own condition ("If X is used, ...") and that condition did not occur; it neither passes nor fails the run.
11
11
  */
12
12
  export const Verdict = {
13
13
  Pass: "PASS",
14
14
  Fail: "FAIL",
15
15
  NotVerified: "NOT_VERIFIED",
16
+ NotApplicable: "NOT_APPLICABLE",
16
17
  } as const;
17
18
  /**
18
- * `PASS` when the evidence shows the requirement was met, `FAIL` when it shows it was not, and `NOT_VERIFIED` when the evidence cannot confirm it. Any `FAIL` or `NOT_VERIFIED` fails the run, whatever the score.
19
+ * `PASS` when the evidence shows the requirement was met, `FAIL` when it shows it was not, and `NOT_VERIFIED` when the evidence cannot confirm it. Any `FAIL` or `NOT_VERIFIED` fails the run, whatever the score. `NOT_APPLICABLE` when the requirement states its own condition ("If X is used, ...") and that condition did not occur; it neither passes nor fails the run.
19
20
  */
20
21
  export type Verdict = ClosedEnum<typeof Verdict>;
21
22
 
@@ -23,8 +24,9 @@ export const Verdict$zodSchema = z.enum([
23
24
  "PASS",
24
25
  "FAIL",
25
26
  "NOT_VERIFIED",
27
+ "NOT_APPLICABLE",
26
28
  ]).describe(
27
- "`PASS` when the evidence shows the requirement was met, `FAIL` when it shows it was not, and `NOT_VERIFIED` when the evidence cannot confirm it. Any `FAIL` or `NOT_VERIFIED` fails the run, whatever the score.",
29
+ "`PASS` when the evidence shows the requirement was met, `FAIL` when it shows it was not, and `NOT_VERIFIED` when the evidence cannot confirm it. Any `FAIL` or `NOT_VERIFIED` fails the run, whatever the score. `NOT_APPLICABLE` when the requirement states its own condition (\"If X is used, ...\") and that condition did not occur; it neither passes nor fails the run.",
28
30
  );
29
31
 
30
32
  export type PublicCriterionVerdict = {
@@ -43,6 +45,6 @@ export const PublicCriterionVerdict$zodSchema: z.ZodType<
43
45
  "Short evidence the judge gave for the verdict.",
44
46
  ),
45
47
  verdict: Verdict$zodSchema.describe(
46
- "`PASS` when the evidence shows the requirement was met, `FAIL` when it shows it was not, and `NOT_VERIFIED` when the evidence cannot confirm it. Any `FAIL` or `NOT_VERIFIED` fails the run, whatever the score.",
48
+ "`PASS` when the evidence shows the requirement was met, `FAIL` when it shows it was not, and `NOT_VERIFIED` when the evidence cannot confirm it. Any `FAIL` or `NOT_VERIFIED` fails the run, whatever the score. `NOT_APPLICABLE` when the requirement states its own condition (\"If X is used, ...\") and that condition did not occur; it neither passes nor fails the run.",
47
49
  ),
48
50
  });
@@ -17,6 +17,7 @@ export type PublicGraderResult = {
17
17
  deductions?: Array<string> | undefined;
18
18
  details?: string | null | undefined;
19
19
  criteria_verdicts?: Array<PublicCriterionVerdict> | undefined;
20
+ not_applicable?: boolean | undefined;
20
21
  };
21
22
 
22
23
  export const PublicGraderResult$zodSchema: z.ZodType<PublicGraderResult> = z
@@ -35,6 +36,9 @@ export const PublicGraderResult$zodSchema: z.ZodType<PublicGraderResult> = z
35
36
  "Display name for the check, when the grader sets one.",
36
37
  ),
37
38
  name: z.string().describe("Grader name as configured on the eval."),
39
+ not_applicable: z.boolean().default(false).describe(
40
+ "Judges only: true when every requirement was `NOT_APPLICABLE`. The check is left out of the run's score and does not fail the run.",
41
+ ),
38
42
  passed: z.boolean().nullable().optional().describe(
39
43
  "Whether this check passed.",
40
44
  ),
@@ -0,0 +1,34 @@
1
+ /*
2
+ * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.
3
+ * @generated-id: 56e8f4aa6dc9
4
+ */
5
+
6
+ import * as z from "zod";
7
+
8
+ export type PublicPluginEvalResultsDownload = {
9
+ plugin: string;
10
+ runs?: number | null | undefined;
11
+ prompts?: number | null | undefined;
12
+ filename?: string | null | undefined;
13
+ download_url: string;
14
+ created_at?: string | null | undefined;
15
+ };
16
+
17
+ export const PublicPluginEvalResultsDownload$zodSchema: z.ZodType<
18
+ PublicPluginEvalResultsDownload
19
+ > = z.object({
20
+ created_at: z.iso.datetime({ offset: true }).nullable().optional().describe(
21
+ "When the results were prepared.",
22
+ ),
23
+ download_url: z.string().describe(
24
+ "Downloads the zip of the day's runs and their insights report. Call it with the same API key.",
25
+ ),
26
+ filename: z.string().nullable().optional().describe("The zip file's name."),
27
+ plugin: z.string().describe("The plugin's slug, such as `firecrawl`."),
28
+ prompts: z.int().nullable().optional().describe(
29
+ "Distinct prompts included in the download.",
30
+ ),
31
+ runs: z.int().nullable().optional().describe(
32
+ "Runs included in the download.",
33
+ ),
34
+ });
@@ -0,0 +1,24 @@
1
+ /*
2
+ * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.
3
+ * @generated-id: f47fd4bfe2d1
4
+ */
5
+
6
+ import * as z from "zod";
7
+ import {
8
+ PublicPluginEvalResultsDownload,
9
+ PublicPluginEvalResultsDownload$zodSchema,
10
+ } from "./publicpluginevalresultsdownload.js";
11
+
12
+ export type PublicPluginEvalResultsResponse = {
13
+ date: string;
14
+ results: Array<PublicPluginEvalResultsDownload>;
15
+ };
16
+
17
+ export const PublicPluginEvalResultsResponse$zodSchema: z.ZodType<
18
+ PublicPluginEvalResultsResponse
19
+ > = z.object({
20
+ date: z.string().describe("The day the results cover, as YYYY-MM-DD."),
21
+ results: z.array(PublicPluginEvalResultsDownload$zodSchema).describe(
22
+ "One download per plugin with results on that day.",
23
+ ),
24
+ });
@@ -34,6 +34,7 @@ export type UpdateV2EvalRequest = {
34
34
  judges?: Array<string> | null | undefined;
35
35
  agent?: Array<string> | null | undefined;
36
36
  persona?: string | undefined;
37
+ include_env_vars?: boolean | undefined;
37
38
  clis?: Array<string> | null | undefined;
38
39
  mcps?: Array<V2InlineMcpDefinition | V2SavedMcpReference> | null | undefined;
39
40
  setup_commands?: Array<string> | null | undefined;
@@ -52,6 +53,9 @@ export const UpdateV2EvalRequest$zodSchema: z.ZodType<UpdateV2EvalRequest> = z
52
53
  clis: z.array(z.string()).nullable().optional().describe(
53
54
  "Replacement saved CLI IDs or shell installation commands. UUID values resolve saved CLIs; every other value is an installation command. Pass an empty array to clear all CLIs.",
54
55
  ),
56
+ include_env_vars: z.boolean().optional().describe(
57
+ "Replacement environment setting. false runs the eval with no environment; omit it to keep the saved value.",
58
+ ),
55
59
  judges: z.array(z.string()).nullable().optional().describe(
56
60
  "Replacement success criteria for the eval.",
57
61
  ),
@@ -45,6 +45,7 @@ export type V2Eval = {
45
45
  prompts?: Array<string> | undefined;
46
46
  judges?: Array<string> | undefined;
47
47
  agent?: Array<string> | undefined;
48
+ include_env_vars?: boolean | undefined;
48
49
  persona?: string | null | undefined;
49
50
  clis?: Array<V2SavedCliReference | V2InlineCliReference> | undefined;
50
51
  mcps?: Array<V2InlineMcpDefinition | V2SavedMcpReference> | undefined;
@@ -66,6 +67,9 @@ export const V2Eval$zodSchema: z.ZodType<V2Eval> = z.object({
66
67
  ])).optional(),
67
68
  created_at: z.string().nullable().optional(),
68
69
  id: z.string(),
70
+ include_env_vars: z.boolean().default(true).describe(
71
+ "Whether runs get environment variables. false means runs use no environment, as Environment: Off in the app.",
72
+ ),
69
73
  judges: z.array(z.string()).optional(),
70
74
  mcps: z.array(z.union([
71
75
  V2InlineMcpDefinition$zodSchema,
@@ -24,6 +24,10 @@ import {
24
24
  V2PreferenceResult,
25
25
  V2PreferenceResult$zodSchema,
26
26
  } from "./v2preferenceresult.js";
27
+ import {
28
+ V2SetupCommandOutput,
29
+ V2SetupCommandOutput$zodSchema,
30
+ } from "./v2setupcommandoutput.js";
27
31
 
28
32
  export type V2EvalResultSummary = {
29
33
  id: string;
@@ -46,6 +50,7 @@ export type V2EvalResultSummary = {
46
50
  grounding_qualification_reason?: string | null | undefined;
47
51
  created_at?: string | null | undefined;
48
52
  environment?: PublicEvalRunEnvironment | null | undefined;
53
+ setup_output?: Array<V2SetupCommandOutput> | undefined;
49
54
  };
50
55
 
51
56
  export const V2EvalResultSummary$zodSchema: z.ZodType<V2EvalResultSummary> = z
@@ -82,6 +87,9 @@ export const V2EvalResultSummary$zodSchema: z.ZodType<V2EvalResultSummary> = z
82
87
  score: z.number().nullable().optional().describe("Score from 0 to 1."),
83
88
  search_grounding: SearchGroundingMode$zodSchema.nullable().optional(),
84
89
  search_observed: z.boolean().nullable().optional(),
90
+ setup_output: z.array(V2SetupCommandOutput$zodSchema).optional().describe(
91
+ "Setup commands run before the agent started, in order, with the end of what each printed. Secret values are redacted. Empty when the eval has no setup commands or the attempt ran before setup output was recorded.",
92
+ ),
85
93
  tool_calls: z.array(V2EvalResultToolCall$zodSchema).optional().describe(
86
94
  "Every tool call the agent made, in order, with how long each took. Empty when the agent made no tool calls or the model does not use tools.",
87
95
  ),
@@ -0,0 +1,35 @@
1
+ /*
2
+ * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.
3
+ * @generated-id: 4edf2fbdf8be
4
+ */
5
+
6
+ import * as z from "zod";
7
+ import {
8
+ HTTPValidationError,
9
+ HTTPValidationError$zodSchema,
10
+ } from "./httpvalidationerror.js";
11
+ import {
12
+ PublicPluginEvalResultsResponse,
13
+ PublicPluginEvalResultsResponse$zodSchema,
14
+ } from "./publicpluginevalresultsresponse.js";
15
+
16
+ export type V2PluginEvalsResultsListRequest = { date: string };
17
+
18
+ export const V2PluginEvalsResultsListRequest$zodSchema: z.ZodType<
19
+ V2PluginEvalsResultsListRequest
20
+ > = z.object({
21
+ date: z.string().date().describe(
22
+ "The day to get results for, as YYYY-MM-DD (UTC).",
23
+ ),
24
+ });
25
+
26
+ export type V2PluginEvalsResultsListResponse =
27
+ | PublicPluginEvalResultsResponse
28
+ | HTTPValidationError;
29
+
30
+ export const V2PluginEvalsResultsListResponse$zodSchema: z.ZodType<
31
+ V2PluginEvalsResultsListResponse
32
+ > = z.union([
33
+ PublicPluginEvalResultsResponse$zodSchema,
34
+ HTTPValidationError$zodSchema,
35
+ ]);
@@ -73,7 +73,7 @@ export const V2PromptRunJobResponse$zodSchema: z.ZodType<
73
73
  dispatch_id: z.string().nullable().optional(),
74
74
  error: z.string().nullable().optional(),
75
75
  estimated_cost: z.number().nullable().optional().describe(
76
- "The estimated credit cost for prompt jobs or estimated USD cost for API Performance jobs. Null when no estimate is available.",
76
+ "Estimated credits for the run, worked out when it was queued. Credits actually used can differ by agent and model. Null when no estimate is available.",
77
77
  ),
78
78
  eval_count: z.int().nullable().optional(),
79
79
  id: z.string().describe(
@@ -0,0 +1,31 @@
1
+ /*
2
+ * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.
3
+ * @generated-id: cee0aa951ed5
4
+ */
5
+
6
+ import * as z from "zod";
7
+
8
+ export type V2SetupCommandOutput = {
9
+ command: string;
10
+ exit_code?: number | null | undefined;
11
+ status?: string | null | undefined;
12
+ output?: string | null | undefined;
13
+ output_truncated?: boolean | undefined;
14
+ };
15
+
16
+ export const V2SetupCommandOutput$zodSchema: z.ZodType<V2SetupCommandOutput> = z
17
+ .object({
18
+ command: z.string().describe("The setup command as saved on the eval."),
19
+ exit_code: z.int().nullable().optional().describe(
20
+ "The command's exit code.",
21
+ ),
22
+ output: z.string().nullable().optional().describe(
23
+ "The end of what the command printed (up to 4,000 characters), with secret values redacted.",
24
+ ),
25
+ output_truncated: z.boolean().default(false).describe(
26
+ "True when earlier output was cut off.",
27
+ ),
28
+ status: z.string().nullable().optional().describe(
29
+ "`succeeded` for a completed command.",
30
+ ),
31
+ });
package/src/tool-names.ts CHANGED
@@ -264,6 +264,10 @@ export const toolNames: Array<{ name: string; description: string }>= [
264
264
  "name": "agent-preference-evals-results-list",
265
265
  "description": "List Results\n\nReturns recorded attempts for an Agent Preference eval, newest first, each with whether your company won, lost, or tied against the competitor."
266
266
  },
267
+ {
268
+ "name": "plugin-evals-results-list",
269
+ "description": "List Plugin Eval Results\n\nReturns a day's plugin eval results, one per plugin with results that day. Each has a `download_url` for a zip of every run with and without the plugin installed, plus the insights report written from them. Call `download_url` with the same API key. Returns 404 when no results exist for the date."
270
+ },
267
271
  {
268
272
  "name": "agents-list",
269
273
  "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."
@@ -174,7 +174,8 @@ test("MCP tools forward canonical eval resources unchanged", async () => {
174
174
  method: "POST",
175
175
  url: "/v2/evals",
176
176
  apiKey: "ls_simulation_test",
177
- body: createRequest,
177
+ // The schema fills in include_env_vars' default (true) on create.
178
+ body: { ...createRequest, include_env_vars: true },
178
179
  },
179
180
  {
180
181
  method: "POST",
@@ -0,0 +1,70 @@
1
+ import assert from "node:assert/strict";
2
+ import test from "node:test";
3
+
4
+ const { Client } = await import("@modelcontextprotocol/sdk/client/index.js");
5
+ const { InMemoryTransport } = await import(
6
+ "@modelcontextprotocol/sdk/inMemory.js"
7
+ );
8
+ const { createConsoleLogger } = await import(
9
+ "../esm/mcp-server/console-logger.js"
10
+ );
11
+ const { createMCPServer } = await import("../esm/mcp-server/server.js");
12
+ const { ANNOTATION_OVERRIDES, TOOL_RENAMES, applyToolOverrides } = await import(
13
+ "../lib/tool-overrides.js"
14
+ );
15
+
16
+ async function listTools(allowedTools) {
17
+ const { server } = createMCPServer({
18
+ logger: createConsoleLogger("error"),
19
+ allowedTools,
20
+ dynamic: false,
21
+ serverURL: "https://api.lightsage.com",
22
+ getSDK: () => {
23
+ throw new Error("not called when listing tools");
24
+ },
25
+ });
26
+ applyToolOverrides(server);
27
+
28
+ const [clientTransport, serverTransport] =
29
+ InMemoryTransport.createLinkedPair();
30
+ const client = new Client({ name: "test", version: "1.0.0" });
31
+ await Promise.all([
32
+ server.connect(serverTransport),
33
+ client.connect(clientTransport),
34
+ ]);
35
+ const { tools } = await client.listTools();
36
+ await client.close();
37
+ return new Map(tools.map((tool) => [tool.name, tool]));
38
+ }
39
+
40
+ test("corrected tools carry the overridden hints", async () => {
41
+ const tools = await listTools(undefined);
42
+ for (const [name, overrides] of Object.entries(ANNOTATION_OVERRIDES)) {
43
+ const tool = tools.get(name);
44
+ assert.ok(tool, `${name} is listed`);
45
+ for (const [hint, value] of Object.entries(overrides)) {
46
+ assert.equal(tool.annotations?.[hint], value, `${name}.${hint}`);
47
+ }
48
+ for (const hint of ["readOnlyHint", "destructiveHint", "openWorldHint"]) {
49
+ assert.equal(typeof tool.annotations?.[hint], "boolean", `${name}.${hint}`);
50
+ }
51
+ }
52
+ });
53
+
54
+ test("unclear generated names are listed under their new names", async () => {
55
+ const tools = await listTools(undefined);
56
+ for (const [from, to] of Object.entries(TOOL_RENAMES)) {
57
+ assert.equal(tools.has(from), false, `${from} is gone`);
58
+ assert.ok(tools.has(to), `${to} is listed`);
59
+ }
60
+ });
61
+
62
+ test("renames apply to tools kept by the allowlist", async () => {
63
+ const tools = await listTools(["CL-is-list", "prompts-list"]);
64
+ assert.deepEqual([...tools.keys()].sort(), ["clis-list", "prompts-list"]);
65
+ });
66
+
67
+ test("tools without overrides keep their generated hints", async () => {
68
+ const tools = await listTools(["prompts-list"]);
69
+ assert.equal(tools.get("prompts-list").annotations.readOnlyHint, true);
70
+ });