@digital-science-dsl/dimensions-analytics-mcp 1.2.0 → 1.3.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.
Files changed (101) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/http-main.js +2 -0
  3. package/dist/http-main.js.map +1 -1
  4. package/dist/main.d.ts +0 -5
  5. package/dist/main.d.ts.map +1 -1
  6. package/dist/main.js +3 -1
  7. package/dist/main.js.map +1 -1
  8. package/dist/mcp/auto-update.d.ts +63 -0
  9. package/dist/mcp/auto-update.d.ts.map +1 -0
  10. package/dist/mcp/auto-update.js +295 -0
  11. package/dist/mcp/auto-update.js.map +1 -0
  12. package/dist/mcp/examples/dsl-examples.d.ts +2 -2
  13. package/dist/mcp/examples/dsl-examples.d.ts.map +1 -1
  14. package/dist/mcp/examples/dsl-examples.js +3 -1
  15. package/dist/mcp/examples/dsl-examples.js.map +1 -1
  16. package/dist/mcp/examples/usage-scenarios.d.ts.map +1 -1
  17. package/dist/mcp/examples/usage-scenarios.js +19 -0
  18. package/dist/mcp/examples/usage-scenarios.js.map +1 -1
  19. package/dist/mcp/http-server.js +3 -3
  20. package/dist/mcp/http-server.js.map +1 -1
  21. package/dist/mcp/middleware/field-aliases.d.ts +1 -1
  22. package/dist/mcp/middleware/field-aliases.d.ts.map +1 -1
  23. package/dist/mcp/middleware/field-aliases.js +0 -6
  24. package/dist/mcp/middleware/field-aliases.js.map +1 -1
  25. package/dist/mcp/resources/schema.d.ts +1 -1
  26. package/dist/mcp/resources/schema.d.ts.map +1 -1
  27. package/dist/mcp/resources/schema.js +11 -11
  28. package/dist/mcp/resources/schema.js.map +1 -1
  29. package/dist/mcp/server.d.ts +2 -2
  30. package/dist/mcp/server.d.ts.map +1 -1
  31. package/dist/mcp/server.js +2 -2
  32. package/dist/mcp/server.js.map +1 -1
  33. package/dist/mcp/tools/analytics.d.ts +1 -1
  34. package/dist/mcp/tools/analytics.d.ts.map +1 -1
  35. package/dist/mcp/tools/analytics.js +21 -21
  36. package/dist/mcp/tools/analytics.js.map +1 -1
  37. package/dist/mcp/tools/fetch-search-pages.d.ts +1 -1
  38. package/dist/mcp/tools/fetch-search-pages.d.ts.map +1 -1
  39. package/dist/mcp/tools/fetch-search-pages.js +4 -9
  40. package/dist/mcp/tools/fetch-search-pages.js.map +1 -1
  41. package/dist/mcp/tools/functions.d.ts +1 -1
  42. package/dist/mcp/tools/functions.d.ts.map +1 -1
  43. package/dist/mcp/tools/functions.js +8 -13
  44. package/dist/mcp/tools/functions.js.map +1 -1
  45. package/dist/mcp/tools/lookup.d.ts +1 -1
  46. package/dist/mcp/tools/lookup.d.ts.map +1 -1
  47. package/dist/mcp/tools/lookup.js +12 -17
  48. package/dist/mcp/tools/lookup.js.map +1 -1
  49. package/dist/mcp/tools/query.d.ts +1 -1
  50. package/dist/mcp/tools/query.d.ts.map +1 -1
  51. package/dist/mcp/tools/query.js +4 -9
  52. package/dist/mcp/tools/query.js.map +1 -1
  53. package/dist/mcp/tools/schema.d.ts +1 -1
  54. package/dist/mcp/tools/schema.d.ts.map +1 -1
  55. package/dist/mcp/tools/schema.js +7 -11
  56. package/dist/mcp/tools/schema.js.map +1 -1
  57. package/dist/mcp/tools/search.d.ts +1 -1
  58. package/dist/mcp/tools/search.d.ts.map +1 -1
  59. package/dist/mcp/tools/search.js +4 -9
  60. package/dist/mcp/tools/search.js.map +1 -1
  61. package/dist/mcp/tools/similar-documents.d.ts +1 -1
  62. package/dist/mcp/tools/similar-documents.d.ts.map +1 -1
  63. package/dist/mcp/tools/similar-documents.js +4 -9
  64. package/dist/mcp/tools/similar-documents.js.map +1 -1
  65. package/dist/mcp/usage-tracking.d.ts +1 -1
  66. package/dist/mcp/usage-tracking.d.ts.map +1 -1
  67. package/dist/mcp/utils.d.ts +1 -2
  68. package/dist/mcp/utils.d.ts.map +1 -1
  69. package/dist/mcp/utils.js +0 -4
  70. package/dist/mcp/utils.js.map +1 -1
  71. package/package.json +6 -2
  72. package/src/http-main.ts +3 -0
  73. package/src/main.ts +4 -2
  74. package/src/mcp/auto-update.ts +379 -0
  75. package/src/mcp/examples/dsl-examples.ts +3 -1
  76. package/src/mcp/examples/usage-scenarios.ts +19 -0
  77. package/src/mcp/http-server.ts +3 -3
  78. package/src/mcp/middleware/field-aliases.ts +1 -2
  79. package/src/mcp/resources/schema.ts +12 -12
  80. package/src/mcp/server.ts +3 -3
  81. package/src/mcp/tools/analytics.ts +26 -26
  82. package/src/mcp/tools/fetch-search-pages.ts +5 -6
  83. package/src/mcp/tools/functions.ts +9 -10
  84. package/src/mcp/tools/lookup.ts +13 -14
  85. package/src/mcp/tools/query.ts +5 -6
  86. package/src/mcp/tools/schema.ts +8 -9
  87. package/src/mcp/tools/search.ts +5 -6
  88. package/src/mcp/tools/similar-documents.ts +5 -6
  89. package/src/mcp/usage-tracking.ts +1 -1
  90. package/src/mcp/utils.ts +1 -3
  91. package/test/examples/dsl-examples.test.ts +8 -0
  92. package/test/examples/usage-scenarios.test.ts +3 -3
  93. package/test/integration/harness.ts +1 -3
  94. package/test/integration/hosted-client.ts +1 -3
  95. package/test/integration/hosted.e2e.test.ts +1 -1
  96. package/test/integration/verify-usage-scenarios.ts +1 -3
  97. package/test/mcp/auto-update.test.ts +347 -0
  98. package/test/middleware/field-aliases.test.ts +1 -1
  99. package/test/resources/schema.test.ts +5 -1
  100. package/test/server.test.ts +15 -3
  101. package/tsconfig.tsbuildinfo +1 -1
@@ -0,0 +1,347 @@
1
+ /**
2
+ * @module test/mcp/auto-update
3
+ */
4
+
5
+ import { join } from "node:path";
6
+ import { afterEach, describe, expect, it, vi } from "vitest";
7
+ import {
8
+ type AutoUpdateIo,
9
+ DEFAULT_UPDATE_INTERVAL_MS,
10
+ detectInstallLayout,
11
+ envFlagOff,
12
+ type InstallLayout,
13
+ NPM_PACKAGE,
14
+ PREFIX_DIR_NAME,
15
+ parseSemver,
16
+ readCurrentVersion,
17
+ resolveNpmBin,
18
+ resolvePackageRoot,
19
+ runUpdateCheck,
20
+ stampPathFor,
21
+ UPDATING_DOCS_URL,
22
+ type UpdateStamp,
23
+ upgradeGuidance,
24
+ upgradeRecipe,
25
+ versionRelation,
26
+ } from "../../src/mcp/auto-update.js";
27
+
28
+ const HOME = "/Users/test";
29
+ const PREFIX_ROOT = join(
30
+ HOME,
31
+ PREFIX_DIR_NAME,
32
+ "node_modules",
33
+ "@digital-science-dsl",
34
+ "dimensions-analytics-mcp",
35
+ );
36
+
37
+ function fakeIo(overrides: Partial<AutoUpdateIo> & { stamps?: Map<string, UpdateStamp> } = {}): {
38
+ io: AutoUpdateIo;
39
+ logs: string[];
40
+ stamps: Map<string, UpdateStamp>;
41
+ reexec: ReturnType<typeof vi.fn>;
42
+ npmInstall: ReturnType<typeof vi.fn>;
43
+ } {
44
+ const logs: string[] = [];
45
+ const stamps = overrides.stamps ?? new Map<string, UpdateStamp>();
46
+ const reexec = vi.fn();
47
+ const npmInstall = vi.fn<(version: string) => boolean>().mockReturnValue(true);
48
+ const stampPath = join(HOME, PREFIX_DIR_NAME, ".auto-update.json");
49
+
50
+ const io: AutoUpdateIo = {
51
+ now: () => 1_000_000,
52
+ env: {},
53
+ layout: "prefix",
54
+ currentVersion: "1.2.0",
55
+ allowInstall: true,
56
+ stampPath,
57
+ readStamp: (path) => stamps.get(path),
58
+ writeStamp: (path, stamp) => {
59
+ stamps.set(path, stamp);
60
+ },
61
+ npmView: () => "1.3.0",
62
+ npmInstall,
63
+ log: (message) => {
64
+ logs.push(message);
65
+ },
66
+ reexec,
67
+ ...overrides,
68
+ };
69
+
70
+ return { io, logs, stamps, reexec, npmInstall };
71
+ }
72
+
73
+ describe("envFlagOff", () => {
74
+ it("treats 0/false/off/no as off", () => {
75
+ expect(envFlagOff("0")).toBe(true);
76
+ expect(envFlagOff("false")).toBe(true);
77
+ expect(envFlagOff("OFF")).toBe(true);
78
+ expect(envFlagOff("no")).toBe(true);
79
+ expect(envFlagOff("1")).toBe(false);
80
+ expect(envFlagOff(undefined)).toBe(false);
81
+ });
82
+ });
83
+
84
+ describe("detectInstallLayout", () => {
85
+ it("detects the guided prefix install", () => {
86
+ expect(detectInstallLayout(PREFIX_ROOT, HOME)).toBe("prefix");
87
+ expect(detectInstallLayout(`${PREFIX_ROOT}/dist`, HOME)).toBe("prefix");
88
+ });
89
+
90
+ it("detects npx cache paths", () => {
91
+ expect(
92
+ detectInstallLayout(
93
+ "/Users/test/.npm/_npx/abc123/node_modules/@digital-science-dsl/dimensions-analytics-mcp",
94
+ HOME,
95
+ ),
96
+ ).toBe("npx");
97
+ });
98
+
99
+ it("detects global installs", () => {
100
+ expect(
101
+ detectInstallLayout(
102
+ "/usr/local/lib/node_modules/@digital-science-dsl/dimensions-analytics-mcp",
103
+ HOME,
104
+ ),
105
+ ).toBe("global");
106
+ });
107
+
108
+ it("detects source / workspace checkouts", () => {
109
+ expect(
110
+ detectInstallLayout("/Users/akovari/devel/dimensions-analytics-mcp/apps/mcp", HOME),
111
+ ).toBe("source");
112
+ });
113
+
114
+ it("normalizes Windows prefix paths", () => {
115
+ expect(
116
+ detectInstallLayout(
117
+ "C:\\Users\\test\\.dimensions-analytics-mcp\\node_modules\\@digital-science-dsl\\dimensions-analytics-mcp",
118
+ "C:\\Users\\test",
119
+ ),
120
+ ).toBe("prefix");
121
+ });
122
+ });
123
+
124
+ describe("versionRelation", () => {
125
+ it("classifies same, patch/minor, and major", () => {
126
+ expect(versionRelation("1.2.0", "1.2.0")).toBe("same");
127
+ expect(versionRelation("1.2.0", "1.2.1")).toBe("newer-same-major");
128
+ expect(versionRelation("1.2.0", "1.3.0")).toBe("newer-same-major");
129
+ expect(versionRelation("1.2.0", "2.0.0")).toBe("newer-major");
130
+ expect(versionRelation("1.3.0", "1.2.0")).toBe("older");
131
+ expect(versionRelation("nope", "1.0.0")).toBe("incomparable");
132
+ });
133
+ });
134
+
135
+ describe("parseSemver", () => {
136
+ it("reads leading v and ignores pre-release suffix for the numeric core", () => {
137
+ expect(parseSemver("v1.2.3")).toEqual({ major: 1, minor: 2, patch: 3 });
138
+ expect(parseSemver("1.2.3-beta.1")).toEqual({ major: 1, minor: 2, patch: 3 });
139
+ });
140
+ });
141
+
142
+ describe("upgradeGuidance", () => {
143
+ const layouts: InstallLayout[] = ["prefix", "npx", "global", "source", "hosted"];
144
+
145
+ it.each(layouts)("includes docs link and a recipe for %s", (layout) => {
146
+ const text = upgradeGuidance(layout, "1.0.3", "1.3.0");
147
+ expect(text).toContain("1.0.3");
148
+ expect(text).toContain("1.3.0");
149
+ expect(text).toContain(UPDATING_DOCS_URL);
150
+ expect(text).toContain(upgradeRecipe(layout).split("\n")[0]);
151
+ });
152
+
153
+ it("tells prefix users to re-run the installer or npm --prefix", () => {
154
+ const text = upgradeGuidance("prefix", "1.0.3", "1.3.0");
155
+ expect(text).toContain("install.sh");
156
+ expect(text).toContain("install.ps1");
157
+ expect(text).toContain(`npm install ${NPM_PACKAGE}@latest --prefix ~/${PREFIX_DIR_NAME}`);
158
+ });
159
+
160
+ it("tells npx users to pin @latest", () => {
161
+ expect(upgradeGuidance("npx", "1.0.3", "1.3.0")).toContain(`${NPM_PACKAGE}@latest`);
162
+ expect(upgradeGuidance("npx", "1.0.3", "1.3.0")).toContain("npx cache");
163
+ });
164
+
165
+ it("tells global users to npm install -g @latest", () => {
166
+ expect(upgradeGuidance("global", "1.0.3", "1.3.0")).toContain(
167
+ `npm install -g ${NPM_PACKAGE}@latest`,
168
+ );
169
+ });
170
+
171
+ it("tells source checkouts to pull and rebuild", () => {
172
+ expect(upgradeGuidance("source", "1.0.3", "1.3.0")).toContain(
173
+ "git pull && pnpm install && pnpm run build",
174
+ );
175
+ });
176
+
177
+ it("tells hosted operators to bump the pin, not run the stdio installer", () => {
178
+ const text = upgradeGuidance("hosted", "1.0.3", "1.3.0");
179
+ expect(text).toContain("deployed image");
180
+ expect(text).toContain("Do not run the stdio installer");
181
+ });
182
+
183
+ it("notes that majors are not auto-applied", () => {
184
+ expect(upgradeGuidance("prefix", "1.2.0", "2.0.0", { major: true })).toContain(
185
+ "auto-update will not apply it",
186
+ );
187
+ });
188
+ });
189
+
190
+ describe("stampPathFor", () => {
191
+ it("uses the prefix dir for stdio and tmpdir for hosted", () => {
192
+ expect(stampPathFor("prefix", HOME, "/tmp")).toBe(
193
+ join(HOME, PREFIX_DIR_NAME, ".auto-update.json"),
194
+ );
195
+ expect(stampPathFor("hosted", HOME, "/tmp")).toBe(
196
+ "/tmp/dimensions-analytics-mcp-auto-update.json",
197
+ );
198
+ });
199
+ });
200
+
201
+ describe("resolveNpmBin", () => {
202
+ it("prefers npm next to node", () => {
203
+ expect(resolveNpmBin("/usr/local/bin/node", "darwin", (p) => p === "/usr/local/bin/npm")).toBe(
204
+ "/usr/local/bin/npm",
205
+ );
206
+ });
207
+
208
+ it("falls back to npm.cmd on Windows", () => {
209
+ expect(resolveNpmBin("C:\\Program Files\\nodejs\\node.exe", "win32", () => false)).toBe(
210
+ "npm.cmd",
211
+ );
212
+ });
213
+ });
214
+
215
+ describe("resolvePackageRoot / readCurrentVersion", () => {
216
+ it("reads this workspace package version from import.meta.url", () => {
217
+ const root = resolvePackageRoot();
218
+ expect(readCurrentVersion(root)).toMatch(/^\d+\.\d+\.\d+/);
219
+ });
220
+ });
221
+
222
+ describe("runUpdateCheck", () => {
223
+ afterEach(() => {
224
+ vi.restoreAllMocks();
225
+ });
226
+
227
+ it("skips when DIMENSIONS_MCP_UPDATED=1", () => {
228
+ const { io, logs, stamps } = fakeIo({ env: { DIMENSIONS_MCP_UPDATED: "1" } });
229
+ expect(runUpdateCheck(io)).toBe("skipped");
230
+ expect(logs).toEqual([]);
231
+ expect(stamps.size).toBe(0);
232
+ });
233
+
234
+ it("skips when DIMENSIONS_MCP_UPDATE_CHECK is off", () => {
235
+ const { io, logs } = fakeIo({ env: { DIMENSIONS_MCP_UPDATE_CHECK: "0" } });
236
+ expect(runUpdateCheck(io)).toBe("skipped");
237
+ expect(logs).toEqual([]);
238
+ });
239
+
240
+ it("skips when the stamp is still fresh", () => {
241
+ const stampPath = join(HOME, PREFIX_DIR_NAME, ".auto-update.json");
242
+ const { io, logs } = fakeIo({
243
+ now: () => 50_000,
244
+ stamps: new Map([[stampPath, { checkedAt: 40_000 }]]),
245
+ env: { DIMENSIONS_MCP_AUTO_UPDATE_INTERVAL_MS: String(DEFAULT_UPDATE_INTERVAL_MS) },
246
+ });
247
+ expect(runUpdateCheck(io)).toBe("skipped");
248
+ expect(logs).toEqual([]);
249
+ });
250
+
251
+ it("does not warn when npm view fails", () => {
252
+ const { io, logs, stamps } = fakeIo({ npmView: () => undefined });
253
+ expect(runUpdateCheck(io)).toBe("current");
254
+ expect(logs).toEqual([]);
255
+ expect([...stamps.values()][0]?.skippedReason).toBe("view-failed");
256
+ });
257
+
258
+ it("does not warn when already on latest", () => {
259
+ const { io, logs, reexec } = fakeIo({ npmView: () => "1.2.0", currentVersion: "1.2.0" });
260
+ expect(runUpdateCheck(io)).toBe("current");
261
+ expect(logs).toEqual([]);
262
+ expect(reexec).not.toHaveBeenCalled();
263
+ });
264
+
265
+ it("installs and re-execs for prefix same-major updates", () => {
266
+ const { io, logs, reexec, npmInstall, stamps } = fakeIo();
267
+ expect(runUpdateCheck(io)).toBe("updated");
268
+ expect(npmInstall).toHaveBeenCalledWith("1.3.0");
269
+ expect(reexec).toHaveBeenCalledOnce();
270
+ expect(logs).toEqual([]);
271
+ expect([...stamps.values()][0]).toMatchObject({ from: "1.2.0", to: "1.3.0" });
272
+ });
273
+
274
+ it("writes the stamp before re-exec on success", () => {
275
+ const order: string[] = [];
276
+ const { io } = fakeIo({
277
+ writeStamp: () => {
278
+ order.push("stamp");
279
+ },
280
+ reexec: () => {
281
+ order.push("reexec");
282
+ },
283
+ });
284
+ runUpdateCheck(io);
285
+ expect(order).toEqual(["stamp", "reexec"]);
286
+ });
287
+
288
+ it("warns and does not install when auto-update is disabled", () => {
289
+ const { io, logs, reexec, npmInstall } = fakeIo({
290
+ env: { DIMENSIONS_MCP_AUTO_UPDATE: "0" },
291
+ });
292
+ expect(runUpdateCheck(io)).toBe("warned");
293
+ expect(npmInstall).not.toHaveBeenCalled();
294
+ expect(reexec).not.toHaveBeenCalled();
295
+ expect(logs[0]).toContain("install.sh");
296
+ });
297
+
298
+ it("warns on major versions and does not install", () => {
299
+ const { io, logs, npmInstall, reexec } = fakeIo({ npmView: () => "2.0.0" });
300
+ expect(runUpdateCheck(io)).toBe("warned");
301
+ expect(npmInstall).not.toHaveBeenCalled();
302
+ expect(reexec).not.toHaveBeenCalled();
303
+ expect(logs[0]).toContain("auto-update will not apply it");
304
+ });
305
+
306
+ it("warns with the npx recipe and never installs", () => {
307
+ const { io, logs, npmInstall, reexec } = fakeIo({ layout: "npx", allowInstall: true });
308
+ expect(runUpdateCheck(io)).toBe("warned");
309
+ expect(npmInstall).not.toHaveBeenCalled();
310
+ expect(reexec).not.toHaveBeenCalled();
311
+ expect(logs[0]).toContain("@latest");
312
+ expect(logs[0]).toContain("npx cache");
313
+ });
314
+
315
+ it("warns with the global recipe", () => {
316
+ const { io, logs, npmInstall } = fakeIo({ layout: "global" });
317
+ expect(runUpdateCheck(io)).toBe("warned");
318
+ expect(npmInstall).not.toHaveBeenCalled();
319
+ expect(logs[0]).toContain("npm install -g");
320
+ });
321
+
322
+ it("warns with the source recipe", () => {
323
+ const { io, logs, npmInstall } = fakeIo({ layout: "source" });
324
+ expect(runUpdateCheck(io)).toBe("warned");
325
+ expect(npmInstall).not.toHaveBeenCalled();
326
+ expect(logs[0]).toContain("git pull && pnpm install && pnpm run build");
327
+ });
328
+
329
+ it("hosted layout never installs or re-execs", () => {
330
+ const { io, logs, npmInstall, reexec } = fakeIo({
331
+ layout: "hosted",
332
+ allowInstall: false,
333
+ });
334
+ expect(runUpdateCheck(io)).toBe("warned");
335
+ expect(npmInstall).not.toHaveBeenCalled();
336
+ expect(reexec).not.toHaveBeenCalled();
337
+ expect(logs[0]).toContain("deployed image");
338
+ });
339
+
340
+ it("warns when prefix install fails", () => {
341
+ const { io, logs, reexec, npmInstall } = fakeIo();
342
+ npmInstall.mockReturnValue(false);
343
+ expect(runUpdateCheck(io)).toBe("warned");
344
+ expect(reexec).not.toHaveBeenCalled();
345
+ expect(logs[0]).toContain("Automatic update failed");
346
+ });
347
+ });
@@ -1,4 +1,4 @@
1
- import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
1
+ import type { CallToolResult } from "@modelcontextprotocol/server";
2
2
  import { describe, expect, it } from "vitest";
3
3
  import {
4
4
  buildReverseAliasMap,
@@ -12,7 +12,11 @@ describe("registerSchemaResources", () => {
12
12
  const context = { store: testSchemaStore() };
13
13
  const resources: Array<{ name: string; uri: string | { uriTemplate?: string } }> = [];
14
14
  const server = {
15
- resource: (name: string, uri: string | { uriTemplate?: string }, ..._rest: unknown[]) => {
15
+ registerResource: (
16
+ name: string,
17
+ uri: string | { uriTemplate?: string },
18
+ ..._rest: unknown[]
19
+ ) => {
16
20
  resources.push({ name, uri });
17
21
  },
18
22
  };
@@ -2,9 +2,7 @@
2
2
  * Tests for the MCP server factory function and startup lifecycle.
3
3
  * @module test/server
4
4
  */
5
-
6
- import { Client } from "@modelcontextprotocol/sdk/client/index.js";
7
- import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js";
5
+ import { Client, InMemoryTransport } from "@modelcontextprotocol/client";
8
6
  import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
9
7
  import {
10
8
  buildServerInstructions,
@@ -142,6 +140,20 @@ describe("MCP protocol", () => {
142
140
  expect(toolNames).toContain("execute_dsl");
143
141
  expect(toolNames).not.toContain("validate_dsl");
144
142
 
143
+ const jsonSchema2020 = "https://json-schema.org/draft/2020-12/schema";
144
+ for (const tool of tools.tools) {
145
+ const inputSchema = tool.inputSchema as { $schema?: string } | undefined;
146
+ const outputSchema = tool.outputSchema as { $schema?: string } | undefined;
147
+ expect(inputSchema?.$schema ?? jsonSchema2020).not.toContain("draft-07");
148
+ expect(outputSchema?.$schema ?? jsonSchema2020).not.toContain("draft-07");
149
+ }
150
+ for (const name of ["search_publications", "execute_dsl", "facet_query"]) {
151
+ const tool = tools.tools.find((t) => t.name === name);
152
+ const outputSchema = tool?.outputSchema as { $schema?: string } | undefined;
153
+ expect(outputSchema, `${name} should advertise outputSchema`).toBeDefined();
154
+ expect(outputSchema?.$schema).toBe(jsonSchema2020);
155
+ }
156
+
145
157
  const resources = await client.listResources();
146
158
  const uris = resources.resources.map((r) => r.uri);
147
159
  expect(uris.some((u) => u.startsWith("dimensions://schema"))).toBe(true);
@@ -1 +1 @@
1
- {"root":["./src/http-main.ts","./src/index.ts","./src/main.ts","./src/client/command.ts","./src/client/config.ts","./src/client/deployment-config.ts","./src/client/errors.ts","./src/client/http-client.ts","./src/client/index.ts","./src/client/internal-dsl-client.ts","./src/client/rate-limiter.ts","./src/client/request-retry.ts","./src/client/resolve-api-key-user.ts","./src/client/types.ts","./src/client/usage-context.ts","./src/client/usage-headers.ts","./src/client/auth/config-loaders.ts","./src/client/auth/factory.ts","./src/client/auth/index.ts","./src/client/auth/jwt-utils.ts","./src/client/auth/node.ts","./src/client/auth/schemas.ts","./src/client/auth/types.ts","./src/client/auth/decorators/index.ts","./src/client/auth/decorators/with-caching.ts","./src/client/auth/providers/index.ts","./src/client/auth/providers/jwt-auth-provider.ts","./src/client/config/index.ts","./src/client/config/loader.ts","./src/client/config/node.ts","./src/client/config/schemas.ts","./src/client/config/types.ts","./src/client/config/unified-loader.ts","./src/dsl/client.ts","./src/dsl/create-client.ts","./src/dsl/fluent-query-builder.ts","./src/dsl/index.ts","./src/dsl/pagination.ts","./src/dsl/query-builder.ts","./src/dsl/response-parser.ts","./src/dsl/usage-policy.ts","./src/dsl/commands/apply-filters.ts","./src/dsl/commands/index.ts","./src/dsl/commands/validate-input.ts","./src/dsl/commands/facet/index.ts","./src/dsl/commands/facet/schemas.ts","./src/dsl/commands/functions/ClassifyCommand.ts","./src/dsl/commands/functions/ExtractAffiliationsCommand.ts","./src/dsl/commands/functions/ExtractConceptsCommand.ts","./src/dsl/commands/functions/ExtractGrantsCommand.ts","./src/dsl/commands/functions/index.ts","./src/dsl/schema/cache.ts","./src/dsl/schema/extract.ts","./src/dsl/schema/index.ts","./src/dsl/schema/load.ts","./src/dsl/schema/store.ts","./src/dsl/schema/structured-entities.ts","./src/dsl/schema/summary.ts","./src/dsl/schema/types.ts","./src/dsl/schema/validation.ts","./src/dsl/types/buckets.ts","./src/dsl/types/common.ts","./src/dsl/types/entities.ts","./src/dsl/types/index.ts","./src/dsl/types/return-clauses.ts","./src/dsl/types/special-functions.ts","./src/dsl/types/vocabulary.ts","./src/dsl/utils/escape.ts","./src/dsl/utils/sanitize.ts","./src/dsl/utils/string-utils.ts","./src/dsl/utils/validate-field-name.ts","./src/mcp/batch-fetch.ts","./src/mcp/export-format.ts","./src/mcp/funder-org-names.ts","./src/mcp/http-server.ts","./src/mcp/server.ts","./src/mcp/shared-schema.ts","./src/mcp/usage-tracking.ts","./src/mcp/utils.ts","./src/mcp/examples/dsl-examples.ts","./src/mcp/examples/usage-scenarios.ts","./src/mcp/middleware/field-aliases.ts","./src/mcp/resources/schema.ts","./src/mcp/schema/context.ts","./src/mcp/schema/index.ts","./src/mcp/tools/analytics-filters.ts","./src/mcp/tools/analytics.ts","./src/mcp/tools/fetch-search-pages.ts","./src/mcp/tools/functions.ts","./src/mcp/tools/lookup.ts","./src/mcp/tools/query.ts","./src/mcp/tools/schema.ts","./src/mcp/tools/search-entity-metadata.ts","./src/mcp/tools/search-input.ts","./src/mcp/tools/search.ts","./src/mcp/tools/similar-documents.ts"],"version":"5.9.3"}
1
+ {"root":["./src/http-main.ts","./src/index.ts","./src/main.ts","./src/client/command.ts","./src/client/config.ts","./src/client/deployment-config.ts","./src/client/errors.ts","./src/client/http-client.ts","./src/client/index.ts","./src/client/internal-dsl-client.ts","./src/client/rate-limiter.ts","./src/client/request-retry.ts","./src/client/resolve-api-key-user.ts","./src/client/types.ts","./src/client/usage-context.ts","./src/client/usage-headers.ts","./src/client/auth/config-loaders.ts","./src/client/auth/factory.ts","./src/client/auth/index.ts","./src/client/auth/jwt-utils.ts","./src/client/auth/node.ts","./src/client/auth/schemas.ts","./src/client/auth/types.ts","./src/client/auth/decorators/index.ts","./src/client/auth/decorators/with-caching.ts","./src/client/auth/providers/index.ts","./src/client/auth/providers/jwt-auth-provider.ts","./src/client/config/index.ts","./src/client/config/loader.ts","./src/client/config/node.ts","./src/client/config/schemas.ts","./src/client/config/types.ts","./src/client/config/unified-loader.ts","./src/dsl/client.ts","./src/dsl/create-client.ts","./src/dsl/fluent-query-builder.ts","./src/dsl/index.ts","./src/dsl/pagination.ts","./src/dsl/query-builder.ts","./src/dsl/response-parser.ts","./src/dsl/usage-policy.ts","./src/dsl/commands/apply-filters.ts","./src/dsl/commands/index.ts","./src/dsl/commands/validate-input.ts","./src/dsl/commands/facet/index.ts","./src/dsl/commands/facet/schemas.ts","./src/dsl/commands/functions/ClassifyCommand.ts","./src/dsl/commands/functions/ExtractAffiliationsCommand.ts","./src/dsl/commands/functions/ExtractConceptsCommand.ts","./src/dsl/commands/functions/ExtractGrantsCommand.ts","./src/dsl/commands/functions/index.ts","./src/dsl/schema/cache.ts","./src/dsl/schema/extract.ts","./src/dsl/schema/index.ts","./src/dsl/schema/load.ts","./src/dsl/schema/store.ts","./src/dsl/schema/structured-entities.ts","./src/dsl/schema/summary.ts","./src/dsl/schema/types.ts","./src/dsl/schema/validation.ts","./src/dsl/types/buckets.ts","./src/dsl/types/common.ts","./src/dsl/types/entities.ts","./src/dsl/types/index.ts","./src/dsl/types/return-clauses.ts","./src/dsl/types/special-functions.ts","./src/dsl/types/vocabulary.ts","./src/dsl/utils/escape.ts","./src/dsl/utils/sanitize.ts","./src/dsl/utils/string-utils.ts","./src/dsl/utils/validate-field-name.ts","./src/mcp/auto-update.ts","./src/mcp/batch-fetch.ts","./src/mcp/export-format.ts","./src/mcp/funder-org-names.ts","./src/mcp/http-server.ts","./src/mcp/server.ts","./src/mcp/shared-schema.ts","./src/mcp/usage-tracking.ts","./src/mcp/utils.ts","./src/mcp/examples/dsl-examples.ts","./src/mcp/examples/usage-scenarios.ts","./src/mcp/middleware/field-aliases.ts","./src/mcp/resources/schema.ts","./src/mcp/schema/context.ts","./src/mcp/schema/index.ts","./src/mcp/tools/analytics-filters.ts","./src/mcp/tools/analytics.ts","./src/mcp/tools/fetch-search-pages.ts","./src/mcp/tools/functions.ts","./src/mcp/tools/lookup.ts","./src/mcp/tools/query.ts","./src/mcp/tools/schema.ts","./src/mcp/tools/search-entity-metadata.ts","./src/mcp/tools/search-input.ts","./src/mcp/tools/search.ts","./src/mcp/tools/similar-documents.ts"],"version":"5.9.3"}