scorecard-ai-mcp 1.0.0-alpha.6 → 1.0.0-alpha.8

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 (195) hide show
  1. package/README.md +63 -35
  2. package/compat.d.mts +2 -0
  3. package/compat.d.mts.map +1 -1
  4. package/compat.d.ts +2 -0
  5. package/compat.d.ts.map +1 -1
  6. package/compat.js +7 -4
  7. package/compat.js.map +1 -1
  8. package/compat.mjs +8 -4
  9. package/compat.mjs.map +1 -1
  10. package/dynamic-tools.d.mts +12 -0
  11. package/dynamic-tools.d.mts.map +1 -0
  12. package/dynamic-tools.d.ts +12 -0
  13. package/dynamic-tools.d.ts.map +1 -0
  14. package/dynamic-tools.js +134 -0
  15. package/dynamic-tools.js.map +1 -0
  16. package/dynamic-tools.mjs +131 -0
  17. package/dynamic-tools.mjs.map +1 -0
  18. package/index.js +15 -18
  19. package/index.js.map +1 -1
  20. package/index.mjs +17 -20
  21. package/index.mjs.map +1 -1
  22. package/options.d.mts +2 -0
  23. package/options.d.mts.map +1 -1
  24. package/options.d.ts +2 -0
  25. package/options.d.ts.map +1 -1
  26. package/options.js +17 -0
  27. package/options.js.map +1 -1
  28. package/options.mjs +17 -0
  29. package/options.mjs.map +1 -1
  30. package/package.json +13 -20
  31. package/server.d.mts +6 -1
  32. package/server.d.mts.map +1 -1
  33. package/server.d.ts +6 -1
  34. package/server.d.ts.map +1 -1
  35. package/server.js +21 -2
  36. package/server.js.map +1 -1
  37. package/server.mjs +22 -4
  38. package/server.mjs.map +1 -1
  39. package/src/compat.ts +13 -4
  40. package/src/dynamic-tools.ts +153 -0
  41. package/src/index.ts +19 -23
  42. package/src/options.ts +22 -0
  43. package/src/server.ts +35 -4
  44. package/src/tools/index.ts +5 -7
  45. package/src/tools/{runs/update-runs.ts → projects/create-projects.ts} +9 -17
  46. package/src/tools/records/create-records.ts +4 -4
  47. package/src/tools/scores/upsert-scores.ts +40 -0
  48. package/src/tools/testcases/create-testcases.ts +0 -2
  49. package/src/tools/testsets/create-testsets.ts +7 -7
  50. package/src/tools/testsets/update-testsets.ts +7 -7
  51. package/tools/index.d.mts.map +1 -1
  52. package/tools/index.d.ts.map +1 -1
  53. package/tools/index.js +5 -6
  54. package/tools/index.js.map +1 -1
  55. package/tools/index.mjs +5 -6
  56. package/tools/index.mjs.map +1 -1
  57. package/tools/projects/create-projects.d.mts +32 -0
  58. package/tools/projects/create-projects.d.mts.map +1 -0
  59. package/tools/projects/create-projects.d.ts +32 -0
  60. package/tools/projects/create-projects.d.ts.map +1 -0
  61. package/tools/{runs/update-runs.js → projects/create-projects.js} +10 -18
  62. package/tools/projects/create-projects.js.map +1 -0
  63. package/tools/projects/create-projects.mjs +29 -0
  64. package/tools/projects/create-projects.mjs.map +1 -0
  65. package/tools/projects/list-projects.d.mts +10 -2
  66. package/tools/projects/list-projects.d.mts.map +1 -1
  67. package/tools/projects/list-projects.d.ts +10 -2
  68. package/tools/projects/list-projects.d.ts.map +1 -1
  69. package/tools/records/create-records.d.mts +8 -0
  70. package/tools/records/create-records.d.mts.map +1 -1
  71. package/tools/records/create-records.d.ts +8 -0
  72. package/tools/records/create-records.d.ts.map +1 -1
  73. package/tools/records/create-records.js +4 -4
  74. package/tools/records/create-records.js.map +1 -1
  75. package/tools/records/create-records.mjs +4 -4
  76. package/tools/records/create-records.mjs.map +1 -1
  77. package/tools/runs/create-runs.d.mts +8 -0
  78. package/tools/runs/create-runs.d.mts.map +1 -1
  79. package/tools/runs/create-runs.d.ts +8 -0
  80. package/tools/runs/create-runs.d.ts.map +1 -1
  81. package/tools/{runs/update-runs.d.mts → scores/upsert-scores.d.mts} +11 -3
  82. package/tools/scores/upsert-scores.d.mts.map +1 -0
  83. package/tools/{runs/update-runs.d.ts → scores/upsert-scores.d.ts} +11 -3
  84. package/tools/scores/upsert-scores.d.ts.map +1 -0
  85. package/tools/scores/upsert-scores.js +35 -0
  86. package/tools/scores/upsert-scores.js.map +1 -0
  87. package/tools/scores/upsert-scores.mjs +31 -0
  88. package/tools/scores/upsert-scores.mjs.map +1 -0
  89. package/tools/system-configs/create-system-configs.d.mts +8 -0
  90. package/tools/system-configs/create-system-configs.d.mts.map +1 -1
  91. package/tools/system-configs/create-system-configs.d.ts +8 -0
  92. package/tools/system-configs/create-system-configs.d.ts.map +1 -1
  93. package/tools/system-configs/get-system-configs.d.mts +8 -0
  94. package/tools/system-configs/get-system-configs.d.mts.map +1 -1
  95. package/tools/system-configs/get-system-configs.d.ts +8 -0
  96. package/tools/system-configs/get-system-configs.d.ts.map +1 -1
  97. package/tools/system-configs/list-system-configs.d.mts +8 -0
  98. package/tools/system-configs/list-system-configs.d.mts.map +1 -1
  99. package/tools/system-configs/list-system-configs.d.ts +8 -0
  100. package/tools/system-configs/list-system-configs.d.ts.map +1 -1
  101. package/tools/systems/create-systems.d.mts +8 -0
  102. package/tools/systems/create-systems.d.mts.map +1 -1
  103. package/tools/systems/create-systems.d.ts +8 -0
  104. package/tools/systems/create-systems.d.ts.map +1 -1
  105. package/tools/systems/delete-systems.d.mts +8 -0
  106. package/tools/systems/delete-systems.d.mts.map +1 -1
  107. package/tools/systems/delete-systems.d.ts +8 -0
  108. package/tools/systems/delete-systems.d.ts.map +1 -1
  109. package/tools/systems/get-systems.d.mts +8 -0
  110. package/tools/systems/get-systems.d.mts.map +1 -1
  111. package/tools/systems/get-systems.d.ts +8 -0
  112. package/tools/systems/get-systems.d.ts.map +1 -1
  113. package/tools/systems/list-systems.d.mts +8 -0
  114. package/tools/systems/list-systems.d.mts.map +1 -1
  115. package/tools/systems/list-systems.d.ts +8 -0
  116. package/tools/systems/list-systems.d.ts.map +1 -1
  117. package/tools/systems/update-systems.d.mts +8 -0
  118. package/tools/systems/update-systems.d.mts.map +1 -1
  119. package/tools/systems/update-systems.d.ts +8 -0
  120. package/tools/systems/update-systems.d.ts.map +1 -1
  121. package/tools/testcases/create-testcases.d.mts +8 -0
  122. package/tools/testcases/create-testcases.d.mts.map +1 -1
  123. package/tools/testcases/create-testcases.d.ts +8 -0
  124. package/tools/testcases/create-testcases.d.ts.map +1 -1
  125. package/tools/testcases/create-testcases.js +0 -1
  126. package/tools/testcases/create-testcases.js.map +1 -1
  127. package/tools/testcases/create-testcases.mjs +0 -1
  128. package/tools/testcases/create-testcases.mjs.map +1 -1
  129. package/tools/testcases/delete-testcases.d.mts +8 -0
  130. package/tools/testcases/delete-testcases.d.mts.map +1 -1
  131. package/tools/testcases/delete-testcases.d.ts +8 -0
  132. package/tools/testcases/delete-testcases.d.ts.map +1 -1
  133. package/tools/testcases/get-testcases.d.mts +8 -0
  134. package/tools/testcases/get-testcases.d.mts.map +1 -1
  135. package/tools/testcases/get-testcases.d.ts +8 -0
  136. package/tools/testcases/get-testcases.d.ts.map +1 -1
  137. package/tools/testcases/list-testcases.d.mts +8 -0
  138. package/tools/testcases/list-testcases.d.mts.map +1 -1
  139. package/tools/testcases/list-testcases.d.ts +8 -0
  140. package/tools/testcases/list-testcases.d.ts.map +1 -1
  141. package/tools/testcases/update-testcases.d.mts +8 -0
  142. package/tools/testcases/update-testcases.d.mts.map +1 -1
  143. package/tools/testcases/update-testcases.d.ts +8 -0
  144. package/tools/testcases/update-testcases.d.ts.map +1 -1
  145. package/tools/testsets/create-testsets.d.mts +8 -0
  146. package/tools/testsets/create-testsets.d.mts.map +1 -1
  147. package/tools/testsets/create-testsets.d.ts +8 -0
  148. package/tools/testsets/create-testsets.d.ts.map +1 -1
  149. package/tools/testsets/create-testsets.js +7 -7
  150. package/tools/testsets/create-testsets.js.map +1 -1
  151. package/tools/testsets/create-testsets.mjs +7 -7
  152. package/tools/testsets/create-testsets.mjs.map +1 -1
  153. package/tools/testsets/delete-testsets.d.mts +8 -0
  154. package/tools/testsets/delete-testsets.d.mts.map +1 -1
  155. package/tools/testsets/delete-testsets.d.ts +8 -0
  156. package/tools/testsets/delete-testsets.d.ts.map +1 -1
  157. package/tools/testsets/get-testsets.d.mts +8 -0
  158. package/tools/testsets/get-testsets.d.mts.map +1 -1
  159. package/tools/testsets/get-testsets.d.ts +8 -0
  160. package/tools/testsets/get-testsets.d.ts.map +1 -1
  161. package/tools/testsets/list-testsets.d.mts +8 -0
  162. package/tools/testsets/list-testsets.d.mts.map +1 -1
  163. package/tools/testsets/list-testsets.d.ts +8 -0
  164. package/tools/testsets/list-testsets.d.ts.map +1 -1
  165. package/tools/testsets/update-testsets.d.mts +8 -0
  166. package/tools/testsets/update-testsets.d.mts.map +1 -1
  167. package/tools/testsets/update-testsets.d.ts +8 -0
  168. package/tools/testsets/update-testsets.d.ts.map +1 -1
  169. package/tools/testsets/update-testsets.js +7 -7
  170. package/tools/testsets/update-testsets.js.map +1 -1
  171. package/tools/testsets/update-testsets.mjs +7 -7
  172. package/tools/testsets/update-testsets.mjs.map +1 -1
  173. package/compat.test.d.mts +0 -2
  174. package/compat.test.d.mts.map +0 -1
  175. package/compat.test.d.ts +0 -2
  176. package/compat.test.d.ts.map +0 -1
  177. package/compat.test.js +0 -950
  178. package/compat.test.js.map +0 -1
  179. package/compat.test.mjs +0 -948
  180. package/compat.test.mjs.map +0 -1
  181. package/options.test.d.mts +0 -2
  182. package/options.test.d.mts.map +0 -1
  183. package/options.test.d.ts +0 -2
  184. package/options.test.d.ts.map +0 -1
  185. package/options.test.js +0 -154
  186. package/options.test.js.map +0 -1
  187. package/options.test.mjs +0 -152
  188. package/options.test.mjs.map +0 -1
  189. package/src/compat.test.ts +0 -1068
  190. package/src/options.test.ts +0 -193
  191. package/tools/runs/update-runs.d.mts.map +0 -1
  192. package/tools/runs/update-runs.d.ts.map +0 -1
  193. package/tools/runs/update-runs.js.map +0 -1
  194. package/tools/runs/update-runs.mjs +0 -37
  195. package/tools/runs/update-runs.mjs.map +0 -1
@@ -1,1068 +0,0 @@
1
- import {
2
- truncateToolNames,
3
- removeTopLevelUnions,
4
- removeAnyOf,
5
- inlineRefs,
6
- applyCompatibilityTransformations,
7
- removeFormats,
8
- } from './compat';
9
- import { Tool } from '@modelcontextprotocol/sdk/types.js';
10
- import { JSONSchema } from './compat';
11
- import { Endpoint } from './tools';
12
-
13
- describe('truncateToolNames', () => {
14
- it('should return original names when maxLength is 0 or negative', () => {
15
- const names = ['tool1', 'tool2', 'tool3'];
16
- expect(truncateToolNames(names, 0)).toEqual(new Map());
17
- expect(truncateToolNames(names, -1)).toEqual(new Map());
18
- });
19
-
20
- it('should return original names when all names are shorter than maxLength', () => {
21
- const names = ['tool1', 'tool2', 'tool3'];
22
- expect(truncateToolNames(names, 10)).toEqual(new Map());
23
- });
24
-
25
- it('should truncate names longer than maxLength', () => {
26
- const names = ['very-long-tool-name', 'another-long-tool-name', 'short'];
27
- expect(truncateToolNames(names, 10)).toEqual(
28
- new Map([
29
- ['very-long-tool-name', 'very-long-'],
30
- ['another-long-tool-name', 'another-lo'],
31
- ]),
32
- );
33
- });
34
-
35
- it('should handle duplicate truncated names by appending numbers', () => {
36
- const names = ['tool-name-a', 'tool-name-b', 'tool-name-c'];
37
- expect(truncateToolNames(names, 8)).toEqual(
38
- new Map([
39
- ['tool-name-a', 'tool-na1'],
40
- ['tool-name-b', 'tool-na2'],
41
- ['tool-name-c', 'tool-na3'],
42
- ]),
43
- );
44
- });
45
- });
46
-
47
- describe('removeTopLevelUnions', () => {
48
- const createTestTool = (overrides = {}): Tool => ({
49
- name: 'test-tool',
50
- description: 'Test tool',
51
- inputSchema: {
52
- type: 'object',
53
- properties: {},
54
- },
55
- ...overrides,
56
- });
57
-
58
- it('should return the original tool if it has no anyOf at the top level', () => {
59
- const tool = createTestTool({
60
- inputSchema: {
61
- type: 'object',
62
- properties: {
63
- foo: { type: 'string' },
64
- },
65
- },
66
- });
67
-
68
- expect(removeTopLevelUnions(tool)).toEqual([tool]);
69
- });
70
-
71
- it('should split a tool with top-level anyOf into multiple tools', () => {
72
- const tool = createTestTool({
73
- name: 'union-tool',
74
- description: 'A tool with unions',
75
- inputSchema: {
76
- type: 'object',
77
- properties: {
78
- common: { type: 'string' },
79
- },
80
- anyOf: [
81
- {
82
- title: 'first variant',
83
- description: 'Its the first variant',
84
- properties: {
85
- variant1: { type: 'string' },
86
- },
87
- required: ['variant1'],
88
- },
89
- {
90
- title: 'second variant',
91
- properties: {
92
- variant2: { type: 'number' },
93
- },
94
- required: ['variant2'],
95
- },
96
- ],
97
- },
98
- });
99
-
100
- const result = removeTopLevelUnions(tool);
101
-
102
- expect(result).toEqual([
103
- {
104
- name: 'union-tool_first_variant',
105
- description: 'Its the first variant',
106
- inputSchema: {
107
- type: 'object',
108
- title: 'first variant',
109
- description: 'Its the first variant',
110
- properties: {
111
- common: { type: 'string' },
112
- variant1: { type: 'string' },
113
- },
114
- required: ['variant1'],
115
- },
116
- },
117
- {
118
- name: 'union-tool_second_variant',
119
- description: 'A tool with unions',
120
- inputSchema: {
121
- type: 'object',
122
- title: 'second variant',
123
- description: 'A tool with unions',
124
- properties: {
125
- common: { type: 'string' },
126
- variant2: { type: 'number' },
127
- },
128
- required: ['variant2'],
129
- },
130
- },
131
- ]);
132
- });
133
-
134
- it('should handle $defs and only include those used by the variant', () => {
135
- const tool = createTestTool({
136
- name: 'defs-tool',
137
- description: 'A tool with $defs',
138
- inputSchema: {
139
- type: 'object',
140
- properties: {
141
- common: { type: 'string' },
142
- },
143
- $defs: {
144
- def1: { type: 'string', format: 'email' },
145
- def2: { type: 'number', minimum: 0 },
146
- unused: { type: 'boolean' },
147
- },
148
- anyOf: [
149
- {
150
- properties: {
151
- email: { $ref: '#/$defs/def1' },
152
- },
153
- },
154
- {
155
- properties: {
156
- count: { $ref: '#/$defs/def2' },
157
- },
158
- },
159
- ],
160
- },
161
- });
162
-
163
- const result = removeTopLevelUnions(tool);
164
-
165
- expect(result).toEqual([
166
- {
167
- name: 'defs-tool_variant1',
168
- description: 'A tool with $defs',
169
- inputSchema: {
170
- type: 'object',
171
- description: 'A tool with $defs',
172
- properties: {
173
- common: { type: 'string' },
174
- email: { $ref: '#/$defs/def1' },
175
- },
176
- $defs: {
177
- def1: { type: 'string', format: 'email' },
178
- },
179
- },
180
- },
181
- {
182
- name: 'defs-tool_variant2',
183
- description: 'A tool with $defs',
184
- inputSchema: {
185
- type: 'object',
186
- description: 'A tool with $defs',
187
- properties: {
188
- common: { type: 'string' },
189
- count: { $ref: '#/$defs/def2' },
190
- },
191
- $defs: {
192
- def2: { type: 'number', minimum: 0 },
193
- },
194
- },
195
- },
196
- ]);
197
- });
198
- });
199
-
200
- describe('removeAnyOf', () => {
201
- it('should return original schema if it has no anyOf', () => {
202
- const schema = {
203
- type: 'object',
204
- properties: {
205
- foo: { type: 'string' },
206
- bar: { type: 'number' },
207
- },
208
- };
209
-
210
- expect(removeAnyOf(schema)).toEqual(schema);
211
- });
212
-
213
- it('should remove anyOf field and use the first variant', () => {
214
- const schema = {
215
- type: 'object',
216
- properties: {
217
- common: { type: 'string' },
218
- },
219
- anyOf: [
220
- {
221
- properties: {
222
- variant1: { type: 'string' },
223
- },
224
- required: ['variant1'],
225
- },
226
- {
227
- properties: {
228
- variant2: { type: 'number' },
229
- },
230
- required: ['variant2'],
231
- },
232
- ],
233
- };
234
-
235
- const expected = {
236
- type: 'object',
237
- properties: {
238
- common: { type: 'string' },
239
- variant1: { type: 'string' },
240
- },
241
- required: ['variant1'],
242
- };
243
-
244
- expect(removeAnyOf(schema)).toEqual(expected);
245
- });
246
-
247
- it('should recursively remove anyOf fields from nested properties', () => {
248
- const schema = {
249
- type: 'object',
250
- properties: {
251
- foo: { type: 'string' },
252
- nested: {
253
- type: 'object',
254
- properties: {
255
- bar: { type: 'number' },
256
- },
257
- anyOf: [
258
- {
259
- properties: {
260
- option1: { type: 'boolean' },
261
- },
262
- },
263
- {
264
- properties: {
265
- option2: { type: 'array' },
266
- },
267
- },
268
- ],
269
- },
270
- },
271
- };
272
-
273
- const expected = {
274
- type: 'object',
275
- properties: {
276
- foo: { type: 'string' },
277
- nested: {
278
- type: 'object',
279
- properties: {
280
- bar: { type: 'number' },
281
- option1: { type: 'boolean' },
282
- },
283
- },
284
- },
285
- };
286
-
287
- expect(removeAnyOf(schema)).toEqual(expected);
288
- });
289
-
290
- it('should handle arrays', () => {
291
- const schema = {
292
- type: 'object',
293
- properties: {
294
- items: {
295
- type: 'array',
296
- items: {
297
- anyOf: [{ type: 'string' }, { type: 'number' }],
298
- },
299
- },
300
- },
301
- };
302
-
303
- const expected = {
304
- type: 'object',
305
- properties: {
306
- items: {
307
- type: 'array',
308
- items: {
309
- type: 'string',
310
- },
311
- },
312
- },
313
- };
314
-
315
- expect(removeAnyOf(schema)).toEqual(expected);
316
- });
317
- });
318
-
319
- describe('inlineRefs', () => {
320
- it('should return the original schema if it does not contain $refs', () => {
321
- const schema: JSONSchema = {
322
- type: 'object',
323
- properties: {
324
- name: { type: 'string' },
325
- age: { type: 'number' },
326
- },
327
- };
328
-
329
- expect(inlineRefs(schema)).toEqual(schema);
330
- });
331
-
332
- it('should inline simple $refs', () => {
333
- const schema: JSONSchema = {
334
- type: 'object',
335
- properties: {
336
- user: { $ref: '#/$defs/user' },
337
- },
338
- $defs: {
339
- user: {
340
- type: 'object',
341
- properties: {
342
- name: { type: 'string' },
343
- email: { type: 'string' },
344
- },
345
- },
346
- },
347
- };
348
-
349
- const expected: JSONSchema = {
350
- type: 'object',
351
- properties: {
352
- user: {
353
- type: 'object',
354
- properties: {
355
- name: { type: 'string' },
356
- email: { type: 'string' },
357
- },
358
- },
359
- },
360
- };
361
-
362
- expect(inlineRefs(schema)).toEqual(expected);
363
- });
364
-
365
- it('should inline nested $refs', () => {
366
- const schema: JSONSchema = {
367
- type: 'object',
368
- properties: {
369
- order: { $ref: '#/$defs/order' },
370
- },
371
- $defs: {
372
- order: {
373
- type: 'object',
374
- properties: {
375
- id: { type: 'string' },
376
- items: { type: 'array', items: { $ref: '#/$defs/item' } },
377
- },
378
- },
379
- item: {
380
- type: 'object',
381
- properties: {
382
- product: { type: 'string' },
383
- quantity: { type: 'integer' },
384
- },
385
- },
386
- },
387
- };
388
-
389
- const expected: JSONSchema = {
390
- type: 'object',
391
- properties: {
392
- order: {
393
- type: 'object',
394
- properties: {
395
- id: { type: 'string' },
396
- items: {
397
- type: 'array',
398
- items: {
399
- type: 'object',
400
- properties: {
401
- product: { type: 'string' },
402
- quantity: { type: 'integer' },
403
- },
404
- },
405
- },
406
- },
407
- },
408
- },
409
- };
410
-
411
- expect(inlineRefs(schema)).toEqual(expected);
412
- });
413
-
414
- it('should handle circular references by removing the circular part', () => {
415
- const schema: JSONSchema = {
416
- type: 'object',
417
- properties: {
418
- person: { $ref: '#/$defs/person' },
419
- },
420
- $defs: {
421
- person: {
422
- type: 'object',
423
- properties: {
424
- name: { type: 'string' },
425
- friend: { $ref: '#/$defs/person' }, // Circular reference
426
- },
427
- },
428
- },
429
- };
430
-
431
- const expected: JSONSchema = {
432
- type: 'object',
433
- properties: {
434
- person: {
435
- type: 'object',
436
- properties: {
437
- name: { type: 'string' },
438
- // friend property is removed to break the circular reference
439
- },
440
- },
441
- },
442
- };
443
-
444
- expect(inlineRefs(schema)).toEqual(expected);
445
- });
446
-
447
- it('should handle indirect circular references', () => {
448
- const schema: JSONSchema = {
449
- type: 'object',
450
- properties: {
451
- node: { $ref: '#/$defs/node' },
452
- },
453
- $defs: {
454
- node: {
455
- type: 'object',
456
- properties: {
457
- value: { type: 'string' },
458
- child: { $ref: '#/$defs/childNode' },
459
- },
460
- },
461
- childNode: {
462
- type: 'object',
463
- properties: {
464
- value: { type: 'string' },
465
- parent: { $ref: '#/$defs/node' }, // Circular reference through childNode
466
- },
467
- },
468
- },
469
- };
470
-
471
- const expected: JSONSchema = {
472
- type: 'object',
473
- properties: {
474
- node: {
475
- type: 'object',
476
- properties: {
477
- value: { type: 'string' },
478
- child: {
479
- type: 'object',
480
- properties: {
481
- value: { type: 'string' },
482
- // parent property is removed to break the circular reference
483
- },
484
- },
485
- },
486
- },
487
- },
488
- };
489
-
490
- expect(inlineRefs(schema)).toEqual(expected);
491
- });
492
-
493
- it('should preserve other properties when inlining references', () => {
494
- const schema: JSONSchema = {
495
- type: 'object',
496
- properties: {
497
- address: { $ref: '#/$defs/address', description: 'User address' },
498
- },
499
- $defs: {
500
- address: {
501
- type: 'object',
502
- properties: {
503
- street: { type: 'string' },
504
- city: { type: 'string' },
505
- },
506
- required: ['street'],
507
- },
508
- },
509
- };
510
-
511
- const expected: JSONSchema = {
512
- type: 'object',
513
- properties: {
514
- address: {
515
- type: 'object',
516
- description: 'User address',
517
- properties: {
518
- street: { type: 'string' },
519
- city: { type: 'string' },
520
- },
521
- required: ['street'],
522
- },
523
- },
524
- };
525
-
526
- expect(inlineRefs(schema)).toEqual(expected);
527
- });
528
- });
529
-
530
- describe('removeFormats', () => {
531
- it('should return original schema if formats capability is true', () => {
532
- const schema = {
533
- type: 'object',
534
- properties: {
535
- date: { type: 'string', description: 'A date field', format: 'date' },
536
- email: { type: 'string', description: 'An email field', format: 'email' },
537
- },
538
- };
539
-
540
- expect(removeFormats(schema, true)).toEqual(schema);
541
- });
542
-
543
- it('should move format to description when formats capability is false', () => {
544
- const schema = {
545
- type: 'object',
546
- properties: {
547
- date: { type: 'string', description: 'A date field', format: 'date' },
548
- email: { type: 'string', description: 'An email field', format: 'email' },
549
- },
550
- };
551
-
552
- const expected = {
553
- type: 'object',
554
- properties: {
555
- date: { type: 'string', description: 'A date field (format: "date")' },
556
- email: { type: 'string', description: 'An email field (format: "email")' },
557
- },
558
- };
559
-
560
- expect(removeFormats(schema, false)).toEqual(expected);
561
- });
562
-
563
- it('should handle properties without description', () => {
564
- const schema = {
565
- type: 'object',
566
- properties: {
567
- date: { type: 'string', format: 'date' },
568
- },
569
- };
570
-
571
- const expected = {
572
- type: 'object',
573
- properties: {
574
- date: { type: 'string', description: '(format: "date")' },
575
- },
576
- };
577
-
578
- expect(removeFormats(schema, false)).toEqual(expected);
579
- });
580
-
581
- it('should handle nested properties', () => {
582
- const schema = {
583
- type: 'object',
584
- properties: {
585
- user: {
586
- type: 'object',
587
- properties: {
588
- created_at: { type: 'string', description: 'Creation date', format: 'date-time' },
589
- },
590
- },
591
- },
592
- };
593
-
594
- const expected = {
595
- type: 'object',
596
- properties: {
597
- user: {
598
- type: 'object',
599
- properties: {
600
- created_at: { type: 'string', description: 'Creation date (format: "date-time")' },
601
- },
602
- },
603
- },
604
- };
605
-
606
- expect(removeFormats(schema, false)).toEqual(expected);
607
- });
608
-
609
- it('should handle arrays of objects', () => {
610
- const schema = {
611
- type: 'object',
612
- properties: {
613
- dates: {
614
- type: 'array',
615
- items: {
616
- type: 'object',
617
- properties: {
618
- start: { type: 'string', description: 'Start date', format: 'date' },
619
- end: { type: 'string', description: 'End date', format: 'date' },
620
- },
621
- },
622
- },
623
- },
624
- };
625
-
626
- const expected = {
627
- type: 'object',
628
- properties: {
629
- dates: {
630
- type: 'array',
631
- items: {
632
- type: 'object',
633
- properties: {
634
- start: { type: 'string', description: 'Start date (format: "date")' },
635
- end: { type: 'string', description: 'End date (format: "date")' },
636
- },
637
- },
638
- },
639
- },
640
- };
641
-
642
- expect(removeFormats(schema, false)).toEqual(expected);
643
- });
644
-
645
- it('should handle schemas with $defs', () => {
646
- const schema = {
647
- type: 'object',
648
- properties: {
649
- date: { type: 'string', description: 'A date field', format: 'date' },
650
- },
651
- $defs: {
652
- timestamp: {
653
- type: 'string',
654
- description: 'A timestamp field',
655
- format: 'date-time',
656
- },
657
- },
658
- };
659
-
660
- const expected = {
661
- type: 'object',
662
- properties: {
663
- date: { type: 'string', description: 'A date field (format: "date")' },
664
- },
665
- $defs: {
666
- timestamp: {
667
- type: 'string',
668
- description: 'A timestamp field (format: "date-time")',
669
- },
670
- },
671
- };
672
-
673
- expect(removeFormats(schema, false)).toEqual(expected);
674
- });
675
- });
676
-
677
- describe('applyCompatibilityTransformations', () => {
678
- const createTestTool = (name: string, overrides = {}): Tool => ({
679
- name,
680
- description: 'Test tool',
681
- inputSchema: {
682
- type: 'object',
683
- properties: {},
684
- },
685
- ...overrides,
686
- });
687
-
688
- const createTestEndpoint = (tool: Tool): Endpoint => ({
689
- tool,
690
- handler: jest.fn(),
691
- metadata: {
692
- resource: 'test',
693
- operation: 'read' as const,
694
- tags: [],
695
- },
696
- });
697
-
698
- it('should not modify endpoints when all capabilities are enabled', () => {
699
- const tool = createTestTool('test-tool');
700
- const endpoints = [createTestEndpoint(tool)];
701
-
702
- const capabilities = {
703
- topLevelUnions: true,
704
- validJson: true,
705
- refs: true,
706
- unions: true,
707
- formats: true,
708
- toolNameLength: undefined,
709
- };
710
-
711
- const transformed = applyCompatibilityTransformations(endpoints, capabilities);
712
- expect(transformed).toEqual(endpoints);
713
- });
714
-
715
- it('should split tools with top-level unions when topLevelUnions is disabled', () => {
716
- const tool = createTestTool('union-tool', {
717
- inputSchema: {
718
- type: 'object',
719
- properties: {
720
- common: { type: 'string' },
721
- },
722
- anyOf: [
723
- {
724
- title: 'first variant',
725
- properties: {
726
- variant1: { type: 'string' },
727
- },
728
- },
729
- {
730
- title: 'second variant',
731
- properties: {
732
- variant2: { type: 'number' },
733
- },
734
- },
735
- ],
736
- },
737
- });
738
-
739
- const endpoints = [createTestEndpoint(tool)];
740
-
741
- const capabilities = {
742
- topLevelUnions: false,
743
- validJson: true,
744
- refs: true,
745
- unions: true,
746
- formats: true,
747
- toolNameLength: undefined,
748
- };
749
-
750
- const transformed = applyCompatibilityTransformations(endpoints, capabilities);
751
- expect(transformed.length).toBe(2);
752
- expect(transformed[0]!.tool.name).toBe('union-tool_first_variant');
753
- expect(transformed[1]!.tool.name).toBe('union-tool_second_variant');
754
- });
755
-
756
- it('should handle variants without titles in removeTopLevelUnions', () => {
757
- const tool = createTestTool('union-tool', {
758
- inputSchema: {
759
- type: 'object',
760
- properties: {
761
- common: { type: 'string' },
762
- },
763
- anyOf: [
764
- {
765
- properties: {
766
- variant1: { type: 'string' },
767
- },
768
- },
769
- {
770
- properties: {
771
- variant2: { type: 'number' },
772
- },
773
- },
774
- ],
775
- },
776
- });
777
-
778
- const endpoints = [createTestEndpoint(tool)];
779
-
780
- const capabilities = {
781
- topLevelUnions: false,
782
- validJson: true,
783
- refs: true,
784
- unions: true,
785
- formats: true,
786
- toolNameLength: undefined,
787
- };
788
-
789
- const transformed = applyCompatibilityTransformations(endpoints, capabilities);
790
- expect(transformed.length).toBe(2);
791
- expect(transformed[0]!.tool.name).toBe('union-tool_variant1');
792
- expect(transformed[1]!.tool.name).toBe('union-tool_variant2');
793
- });
794
-
795
- it('should truncate tool names when toolNameLength is set', () => {
796
- const tools = [
797
- createTestTool('very-long-tool-name-that-exceeds-limit'),
798
- createTestTool('another-long-tool-name-to-truncate'),
799
- createTestTool('short-name'),
800
- ];
801
-
802
- const endpoints = tools.map(createTestEndpoint);
803
-
804
- const capabilities = {
805
- topLevelUnions: true,
806
- validJson: true,
807
- refs: true,
808
- unions: true,
809
- formats: true,
810
- toolNameLength: 20,
811
- };
812
-
813
- const transformed = applyCompatibilityTransformations(endpoints, capabilities);
814
- expect(transformed[0]!.tool.name).toBe('very-long-tool-name-');
815
- expect(transformed[1]!.tool.name).toBe('another-long-tool-na');
816
- expect(transformed[2]!.tool.name).toBe('short-name');
817
- });
818
-
819
- it('should inline refs when refs capability is disabled', () => {
820
- const tool = createTestTool('ref-tool', {
821
- inputSchema: {
822
- type: 'object',
823
- properties: {
824
- user: { $ref: '#/$defs/user' },
825
- },
826
- $defs: {
827
- user: {
828
- type: 'object',
829
- properties: {
830
- name: { type: 'string' },
831
- email: { type: 'string' },
832
- },
833
- },
834
- },
835
- },
836
- });
837
-
838
- const endpoints = [createTestEndpoint(tool)];
839
-
840
- const capabilities = {
841
- topLevelUnions: true,
842
- validJson: true,
843
- refs: false,
844
- unions: true,
845
- formats: true,
846
- toolNameLength: undefined,
847
- };
848
-
849
- const transformed = applyCompatibilityTransformations(endpoints, capabilities);
850
- const schema = transformed[0]!.tool.inputSchema as JSONSchema;
851
- expect(schema.$defs).toBeUndefined();
852
-
853
- if (schema.properties) {
854
- expect(schema.properties['user']).toEqual({
855
- type: 'object',
856
- properties: {
857
- name: { type: 'string' },
858
- email: { type: 'string' },
859
- },
860
- });
861
- }
862
- });
863
-
864
- it('should preserve external refs when inlining', () => {
865
- const tool = createTestTool('ref-tool', {
866
- inputSchema: {
867
- type: 'object',
868
- properties: {
869
- internal: { $ref: '#/$defs/internal' },
870
- external: { $ref: 'https://example.com/schemas/external.json' },
871
- },
872
- $defs: {
873
- internal: {
874
- type: 'object',
875
- properties: {
876
- name: { type: 'string' },
877
- },
878
- },
879
- },
880
- },
881
- });
882
-
883
- const endpoints = [createTestEndpoint(tool)];
884
-
885
- const capabilities = {
886
- topLevelUnions: true,
887
- validJson: true,
888
- refs: false,
889
- unions: true,
890
- formats: true,
891
- toolNameLength: undefined,
892
- };
893
-
894
- const transformed = applyCompatibilityTransformations(endpoints, capabilities);
895
- const schema = transformed[0]!.tool.inputSchema as JSONSchema;
896
-
897
- if (schema.properties) {
898
- expect(schema.properties['internal']).toEqual({
899
- type: 'object',
900
- properties: {
901
- name: { type: 'string' },
902
- },
903
- });
904
- expect(schema.properties['external']).toEqual({
905
- $ref: 'https://example.com/schemas/external.json',
906
- });
907
- }
908
- });
909
-
910
- it('should remove anyOf fields when unions capability is disabled', () => {
911
- const tool = createTestTool('union-tool', {
912
- inputSchema: {
913
- type: 'object',
914
- properties: {
915
- field: {
916
- anyOf: [{ type: 'string' }, { type: 'number' }],
917
- },
918
- },
919
- },
920
- });
921
-
922
- const endpoints = [createTestEndpoint(tool)];
923
-
924
- const capabilities = {
925
- topLevelUnions: true,
926
- validJson: true,
927
- refs: true,
928
- unions: false,
929
- formats: true,
930
- toolNameLength: undefined,
931
- };
932
-
933
- const transformed = applyCompatibilityTransformations(endpoints, capabilities);
934
- const schema = transformed[0]!.tool.inputSchema as JSONSchema;
935
-
936
- if (schema.properties && schema.properties['field']) {
937
- const field = schema.properties['field'];
938
- expect(field.anyOf).toBeUndefined();
939
- expect(field.type).toBe('string');
940
- }
941
- });
942
-
943
- it('should correctly combine topLevelUnions and toolNameLength transformations', () => {
944
- const tool = createTestTool('very-long-union-tool-name', {
945
- inputSchema: {
946
- type: 'object',
947
- properties: {
948
- common: { type: 'string' },
949
- },
950
- anyOf: [
951
- {
952
- title: 'first variant',
953
- properties: {
954
- variant1: { type: 'string' },
955
- },
956
- },
957
- {
958
- title: 'second variant',
959
- properties: {
960
- variant2: { type: 'number' },
961
- },
962
- },
963
- ],
964
- },
965
- });
966
-
967
- const endpoints = [createTestEndpoint(tool)];
968
-
969
- const capabilities = {
970
- topLevelUnions: false,
971
- validJson: true,
972
- refs: true,
973
- unions: true,
974
- formats: true,
975
- toolNameLength: 20,
976
- };
977
-
978
- const transformed = applyCompatibilityTransformations(endpoints, capabilities);
979
- expect(transformed.length).toBe(2);
980
-
981
- // Both names should be truncated because they exceed 20 characters
982
- expect(transformed[0]!.tool.name).toBe('very-long-union-too1');
983
- expect(transformed[1]!.tool.name).toBe('very-long-union-too2');
984
- });
985
-
986
- it('should correctly combine refs and unions transformations', () => {
987
- const tool = createTestTool('complex-tool', {
988
- inputSchema: {
989
- type: 'object',
990
- properties: {
991
- user: { $ref: '#/$defs/user' },
992
- },
993
- $defs: {
994
- user: {
995
- type: 'object',
996
- properties: {
997
- preference: {
998
- anyOf: [{ type: 'string' }, { type: 'number' }],
999
- },
1000
- },
1001
- },
1002
- },
1003
- },
1004
- });
1005
-
1006
- const endpoints = [createTestEndpoint(tool)];
1007
-
1008
- const capabilities = {
1009
- topLevelUnions: true,
1010
- validJson: true,
1011
- refs: false,
1012
- unions: false,
1013
- formats: true,
1014
- toolNameLength: undefined,
1015
- };
1016
-
1017
- const transformed = applyCompatibilityTransformations(endpoints, capabilities);
1018
- const schema = transformed[0]!.tool.inputSchema as JSONSchema;
1019
-
1020
- // Refs should be inlined
1021
- expect(schema.$defs).toBeUndefined();
1022
-
1023
- // Safely access nested properties
1024
- if (schema.properties && schema.properties['user']) {
1025
- const user = schema.properties['user'];
1026
- // User should be inlined
1027
- expect(user.type).toBe('object');
1028
-
1029
- // AnyOf in the inlined user.preference should be removed
1030
- if (user.properties && user.properties['preference']) {
1031
- const preference = user.properties['preference'];
1032
- expect(preference.anyOf).toBeUndefined();
1033
- expect(preference.type).toBe('string');
1034
- }
1035
- }
1036
- });
1037
-
1038
- it('should handle formats capability being false', () => {
1039
- const tool = createTestTool('format-tool', {
1040
- inputSchema: {
1041
- type: 'object',
1042
- properties: {
1043
- date: { type: 'string', description: 'A date', format: 'date' },
1044
- },
1045
- },
1046
- });
1047
-
1048
- const endpoints = [createTestEndpoint(tool)];
1049
-
1050
- const capabilities = {
1051
- topLevelUnions: true,
1052
- validJson: true,
1053
- refs: true,
1054
- unions: true,
1055
- formats: false,
1056
- toolNameLength: undefined,
1057
- };
1058
-
1059
- const transformed = applyCompatibilityTransformations(endpoints, capabilities);
1060
- const schema = transformed[0]!.tool.inputSchema as JSONSchema;
1061
-
1062
- if (schema.properties && schema.properties['date']) {
1063
- const dateField = schema.properties['date'];
1064
- expect(dateField['format']).toBeUndefined();
1065
- expect(dateField['description']).toBe('A date (format: "date")');
1066
- }
1067
- });
1068
- });