mcp-meilisearch 1.4.7 → 1.4.9

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 CHANGED
@@ -354,18 +354,131 @@ The MCP server exposes various tools that allow you to interact with Meilisearch
354
354
  - **Parameters**:
355
355
  - `indexUid` (string, required): Unique identifier of the index.
356
356
 
357
- #### get-searchable-attributes / get-displayed-attributes / get-filterable-attributes / get-sortable-attributes / get-ranking-rules / get-stop-words / get-synonyms / get-distinct-attribute / get-typo-tolerance / get-faceting / get-pagination
357
+ #### Get Settings Tools
358
+
359
+ The following tools retrieve specific settings for a Meilisearch index:
360
+
361
+ - **get-displayed-attributes**
362
+ - **get-searchable-attributes**
363
+ - **get-filterable-attributes**
364
+ - **get-sortable-attributes**
365
+ - **get-ranking-rules**
366
+ - **get-stop-words**
367
+ - **get-synonyms**
368
+ - **get-typo-tolerance**
369
+ - **get-pagination**
370
+ - **get-faceting**
371
+ - **get-dictionary**
372
+ - **get-proximity-precision**
373
+ - **get-separator-tokens**
374
+ - **get-non-separator-tokens**
375
+ - **get-word-dictionary**
376
+
377
+ All these tools have the same parameter:
378
+
379
+ - `indexUid` (string, required): Unique identifier of the index.
380
+
381
+ #### Update Settings Tools
382
+
383
+ The following tools update specific settings for a Meilisearch index:
384
+
385
+ - **update-displayed-attributes**
358
386
 
359
- - **Description**: Get the specific setting for an index.
360
- - **Parameters**:
361
387
  - `indexUid` (string, required): Unique identifier of the index.
388
+ - `displayedAttributes` (string, required): JSON array of attributes to display, e.g. ["title", "description"].
362
389
 
363
- #### update-searchable-attributes / update-displayed-attributes / update-filterable-attributes / update-sortable-attributes / update-ranking-rules / update-stop-words / update-synonyms / update-distinct-attribute / update-typo-tolerance / update-faceting / update-pagination
390
+ - **update-searchable-attributes**
364
391
 
365
- - **Description**: Update a specific setting for an index.
366
- - **Parameters**:
367
392
  - `indexUid` (string, required): Unique identifier of the index.
368
- - `value` (string, required): JSON value for the setting.
393
+ - `searchableAttributes` (string, required): JSON array of attributes that can be searched, e.g. ["title", "description"].
394
+
395
+ - **update-filterable-attributes**
396
+
397
+ - `indexUid` (string, required): Unique identifier of the index.
398
+ - `filterableAttributes` (string, required): JSON array of attributes that can be used as filters, e.g. ["genre", "director"].
399
+
400
+ - **update-sortable-attributes**
401
+
402
+ - `indexUid` (string, required): Unique identifier of the index.
403
+ - `sortableAttributes` (string, required): JSON array of attributes that can be used for sorting, e.g. ["price", "date"].
404
+
405
+ - **update-ranking-rules**
406
+
407
+ - `indexUid` (string, required): Unique identifier of the index.
408
+ - `rankingRules` (string, required): JSON array of ranking rules, e.g. ["typo", "words", "proximity", "attribute", "sort", "exactness"].
409
+
410
+ - **update-stop-words**
411
+
412
+ - `indexUid` (string, required): Unique identifier of the index.
413
+ - `stopWords` (string, required): JSON array of words to ignore in search queries, e.g. ["the", "a", "an"].
414
+
415
+ - **update-synonyms**
416
+
417
+ - `indexUid` (string, required): Unique identifier of the index.
418
+ - `synonyms` (string, required): JSON object mapping words to their synonyms, e.g. {"movie": ["film"]}.
419
+
420
+ - **update-typo-tolerance**
421
+
422
+ - `indexUid` (string, required): Unique identifier of the index.
423
+ - `typoTolerance` (string, required): JSON object with typo tolerance configuration, e.g. {"enabled": true, "minWordSizeForTypos": {"oneTypo": 5, "twoTypos": 9}}.
424
+
425
+ - **update-pagination**
426
+
427
+ - `indexUid` (string, required): Unique identifier of the index.
428
+ - `pagination` (string, required): JSON object with pagination configuration, e.g. {"maxTotalHits": 1000}.
429
+
430
+ - **update-faceting**
431
+
432
+ - `indexUid` (string, required): Unique identifier of the index.
433
+ - `faceting` (string, required): JSON object with faceting configuration, e.g. {"maxValuesPerFacet": 100}.
434
+
435
+ - **update-dictionary**
436
+
437
+ - `indexUid` (string, required): Unique identifier of the index.
438
+ - `dictionary` (string, required): JSON array of words to consider as a single word, e.g. ["San Francisco", "New York"].
439
+
440
+ - **update-proximity-precision**
441
+
442
+ - `indexUid` (string, required): Unique identifier of the index.
443
+ - `proximityPrecision` (string, required): String with proximity precision value, can be 'byWord' or 'byAttribute'.
444
+
445
+ - **update-separator-tokens**
446
+
447
+ - `indexUid` (string, required): Unique identifier of the index.
448
+ - `separatorTokens` (string, required): JSON array of tokens that should be considered as word separators, e.g. ["-", "_"].
449
+
450
+ - **update-non-separator-tokens**
451
+
452
+ - `indexUid` (string, required): Unique identifier of the index.
453
+ - `nonSeparatorTokens` (string, required): JSON array of tokens that should not be considered as word separators, e.g. ["@", "."].
454
+
455
+ - **update-word-dictionary**
456
+ - `indexUid` (string, required): Unique identifier of the index.
457
+ - `wordDictionary` (string, required): JSON array of custom words to add to the dictionary, e.g. ["cbuilder", "meilisearch"].
458
+
459
+ #### Reset Settings Tools
460
+
461
+ The following tools reset specific settings for a Meilisearch index to their default values:
462
+
463
+ - **reset-displayed-attributes**
464
+ - **reset-searchable-attributes**
465
+ - **reset-filterable-attributes**
466
+ - **reset-sortable-attributes**
467
+ - **reset-ranking-rules**
468
+ - **reset-stop-words**
469
+ - **reset-synonyms**
470
+ - **reset-typo-tolerance**
471
+ - **reset-pagination**
472
+ - **reset-faceting**
473
+ - **reset-dictionary**
474
+ - **reset-proximity-precision**
475
+ - **reset-separator-tokens**
476
+ - **reset-non-separator-tokens**
477
+ - **reset-word-dictionary**
478
+
479
+ All these reset tools have the same parameter:
480
+
481
+ - `indexUid` (string, required): Unique identifier of the index.
369
482
 
370
483
  ### Task Tools
371
484
 
package/dist/index.js CHANGED
@@ -21,7 +21,7 @@ export async function mcpMeilisearchServer(options = defaultOptions) {
21
21
  aiService.initialize(apiKey, aiProviderName, llmModel);
22
22
  }
23
23
  else {
24
- console.warn("AI provider API key not found. AI will not be available");
24
+ console.warn("AI provider API key not found. Continuing without it.");
25
25
  }
26
26
  let mcpServerInstance = null;
27
27
  const transport = options.transport;
package/dist/server.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { IncomingMessage, ServerResponse } from "http";
2
2
  import { ServerOptions } from "./types/options.js";
3
- import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { McpServer as McpServerInstance } from "@modelcontextprotocol/sdk/server/mcp.js";
4
4
  /**
5
5
  * Return type for the initServer function
6
6
  */
@@ -21,8 +21,8 @@ export declare const defaultOptions: {
21
21
  export declare class MCPServer {
22
22
  private readonly JSON_RPC;
23
23
  private readonly SESSION_ID_HEADER_NAME;
24
- private server;
25
24
  private config;
25
+ private server;
26
26
  private cleanupInterval;
27
27
  private sessions;
28
28
  /**
@@ -30,7 +30,7 @@ export declare class MCPServer {
30
30
  * @param server The underlying MCP server implementation
31
31
  * @param config Configuration options
32
32
  */
33
- constructor(server: McpServer, config?: Partial<ServerOptions>);
33
+ constructor(server: McpServerInstance, config?: Partial<ServerOptions>);
34
34
  /**
35
35
  * Handles an HTTP request and routes it to the appropriate handler
36
36
  * @param req The HTTP request
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,MAAM,CAAC;AAOvD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAInD,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAUpE;;GAEG;AACH,UAAU,cAAc;IACtB,SAAS,EAAE,SAAS,CAAC;CACtB;AASD,eAAO,MAAM,cAAc;;;;;;;CAO1B,CAAC;AAEF;;GAEG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAoB;IAE3D,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,eAAe,CAA+B;IACtD,OAAO,CAAC,QAAQ,CAAuC;IAEvD;;;;OAIG;gBACS,MAAM,EAAE,SAAS,EAAE,MAAM,GAAE,OAAO,CAAC,aAAa,CAAM;IAOlE;;;;;OAKG;IACG,iBAAiB,CACrB,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,EACnB,WAAW,GAAE,MAAmC,GAC/C,OAAO,CAAC,IAAI,CAAC;IA+ChB;;;;OAIG;IACG,gBAAgB,CACpB,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,GAClB,OAAO,CAAC,IAAI,CAAC;IA+BhB;;;;;OAKG;IACG,iBAAiB,CACrB,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,EACnB,IAAI,EAAE,GAAG,GACR,OAAO,CAAC,IAAI,CAAC;IA+BhB;;OAEG;IACH,QAAQ,IAAI,IAAI;IAqBhB;;;;;OAKG;YACW,uBAAuB;IAuCrC;;OAEG;IACH,OAAO,CAAC,+BAA+B;IAWvC;;OAEG;YACW,gBAAgB;IAmB9B;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAa3B;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAKxB;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAO7B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAUzB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAQ3B;;OAEG;IACH,OAAO,CAAC,sBAAsB;CA2B/B;AA+DD;;;;;;GAMG;AACH,eAAO,MAAM,UAAU,GACrB,YAAW,MAAM,GAAG,OAAgB,EACpC,SAAS,OAAO,CAAC,aAAa,CAAC,KAC9B,OAAO,CAAC,cAAc,CAcxB,CAAC"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,MAAM,CAAC;AAOvD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAWnD,OAAO,EAAE,SAAS,IAAI,iBAAiB,EAAE,MAAM,yCAAyC,CAAC;AAGzF;;GAEG;AACH,UAAU,cAAc;IACtB,SAAS,EAAE,SAAS,CAAC;CACtB;AASD,eAAO,MAAM,cAAc;;;;;;;CAO1B,CAAC;AAEF;;GAEG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAoB;IAE3D,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,eAAe,CAA+B;IACtD,OAAO,CAAC,QAAQ,CAAuC;IAEvD;;;;OAIG;gBACS,MAAM,EAAE,iBAAiB,EAAE,MAAM,GAAE,OAAO,CAAC,aAAa,CAAM;IAO1E;;;;;OAKG;IACG,iBAAiB,CACrB,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,EACnB,WAAW,GAAE,MAAmC,GAC/C,OAAO,CAAC,IAAI,CAAC;IA+ChB;;;;OAIG;IACG,gBAAgB,CACpB,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,GAClB,OAAO,CAAC,IAAI,CAAC;IA+BhB;;;;;OAKG;IACG,iBAAiB,CACrB,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,EACnB,IAAI,EAAE,GAAG,GACR,OAAO,CAAC,IAAI,CAAC;IA+BhB;;OAEG;IACH,QAAQ,IAAI,IAAI;IAqBhB;;;;;OAKG;YACW,uBAAuB;IAuCrC;;OAEG;IACH,OAAO,CAAC,+BAA+B;IAWvC;;OAEG;YACW,gBAAgB;IAmB9B;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAa3B;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAKxB;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAO7B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAUzB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAQ3B;;OAEG;IACH,OAAO,CAAC,sBAAsB;CA2B/B;AAyDD;;;;;;GAMG;AACH,eAAO,MAAM,UAAU,GACrB,YAAW,MAAM,GAAG,OAAgB,EACpC,SAAS,OAAO,CAAC,aAAa,CAAC,KAC9B,OAAO,CAAC,cAAc,CAcxB,CAAC"}
package/dist/server.js CHANGED
@@ -3,7 +3,6 @@ import { InitializeRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
3
3
  import registerAITools from "./tools/core/ai-tools.js";
4
4
  import { createErrorResponse } from "./utils/error-handler.js";
5
5
  import registerTaskTools from "./tools/meilisearch/task-tools.js";
6
- import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
7
6
  import registerIndexTools from "./tools/meilisearch/index-tools.js";
8
7
  import registerSearchTools from "./tools/meilisearch/search-tools.js";
9
8
  import registerSystemTools from "./tools/meilisearch/system-tools.js";
@@ -11,6 +10,7 @@ import registerVectorTools from "./tools/meilisearch/vector-tools.js";
11
10
  import registerDocumentTools from "./tools/meilisearch/document-tools.js";
12
11
  import registerSettingsTools from "./tools/meilisearch/settings-tools.js";
13
12
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
13
+ import { McpServer as McpServerInstance } from "@modelcontextprotocol/sdk/server/mcp.js";
14
14
  import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
15
15
  export const defaultOptions = {
16
16
  httpPort: 4995,
@@ -26,8 +26,8 @@ export const defaultOptions = {
26
26
  export class MCPServer {
27
27
  JSON_RPC = "2.0";
28
28
  SESSION_ID_HEADER_NAME = "mcp-session-id";
29
- server;
30
29
  config;
30
+ server;
31
31
  cleanupInterval = null;
32
32
  sessions = new Map();
33
33
  /**
@@ -293,10 +293,11 @@ export class MCPServer {
293
293
  }
294
294
  }
295
295
  /**
296
- * Initialize the MCP server with HTTP transport
296
+ * Create a new MCP server instance
297
+ * @returns MCP server instance
297
298
  */
298
- const initServerHTTPTransport = async (customConfig) => {
299
- const serverInstance = new McpServer({
299
+ const createServerInstance = () => {
300
+ const serverInstance = new McpServerInstance({
300
301
  version: "1.0.0",
301
302
  name: "mcp-meilisearch",
302
303
  });
@@ -308,6 +309,13 @@ const initServerHTTPTransport = async (customConfig) => {
308
309
  registerSystemTools(serverInstance);
309
310
  registerTaskTools(serverInstance);
310
311
  registerAITools(serverInstance);
312
+ return serverInstance;
313
+ };
314
+ /**
315
+ * Initialize the MCP server with HTTP transport
316
+ */
317
+ const initServerHTTPTransport = async (customConfig) => {
318
+ const serverInstance = createServerInstance();
311
319
  const server = new MCPServer(serverInstance, customConfig);
312
320
  return { mcpServer: server };
313
321
  };
@@ -316,22 +324,10 @@ const initServerHTTPTransport = async (customConfig) => {
316
324
  * @returns MCP server instance
317
325
  */
318
326
  const initServerStdioTransport = async (customConfig) => {
319
- const serverInstance = new McpServer({
320
- version: "1.0.0",
321
- name: "mcp-meilisearch",
322
- });
323
- registerIndexTools(serverInstance);
324
- registerDocumentTools(serverInstance);
325
- registerSearchTools(serverInstance);
326
- registerSettingsTools(serverInstance);
327
- registerVectorTools(serverInstance);
328
- registerSystemTools(serverInstance);
329
- registerTaskTools(serverInstance);
330
- registerAITools(serverInstance);
327
+ const serverInstance = createServerInstance();
331
328
  const server = new MCPServer(serverInstance, customConfig);
332
329
  const transport = new StdioServerTransport();
333
330
  await serverInstance.connect(transport);
334
- console.info("Meilisearch MCP Server is running on stdio transport");
335
331
  process.on("SIGINT", () => {
336
332
  console.info("Shutting down stdio server...");
337
333
  process.exit(0);
@@ -1 +1 @@
1
- {"version":3,"file":"ai-tools.d.ts","sourceRoot":"","sources":["../../../src/tools/core/ai-tools.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAapE;;;GAGG;AACH,eAAO,MAAM,eAAe,GAAI,QAAQ,SAAS,SAoDhD,CAAC;AAEF,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"ai-tools.d.ts","sourceRoot":"","sources":["../../../src/tools/core/ai-tools.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAqBpE;;;GAGG;AACH,eAAO,MAAM,eAAe,GAAI,QAAQ,SAAS,SA2DhD,CAAC;AAEF,eAAe,eAAe,CAAC"}
@@ -1,8 +1,8 @@
1
1
  import { z } from "zod";
2
2
  import { zodToJsonSchema } from "zod-to-json-schema";
3
3
  import { AIService } from "../../utils/ai-handler.js";
4
- import { cleanNullValues } from "../../utils/response-handler.js";
5
4
  import { createErrorResponse } from "../../utils/error-handler.js";
5
+ import { convertNullToUndefined } from "../../utils/response-handler.js";
6
6
  /**
7
7
  * Register AI tools with the MCP server
8
8
  * @param server - The MCP server instance
@@ -17,7 +17,8 @@ export const registerAITools = (server) => {
17
17
  }, { category: "core" }, async ({ query, specificTools }) => {
18
18
  try {
19
19
  const aiService = AIService.getInstance();
20
- const availableTools = Object.entries(server._registeredTools)
20
+ const registeredTools = Object.entries(server._registeredTools);
21
+ const availableTools = registeredTools
21
22
  .filter(([_, { annotations }]) => annotations?.category !== "core")
22
23
  .map(([name, { description, inputSchema }]) => {
23
24
  const { definitions } = zodToJsonSchema(inputSchema, "parameters");
@@ -28,17 +29,18 @@ export const registerAITools = (server) => {
28
29
  };
29
30
  });
30
31
  aiService.setAvailableTools(availableTools);
31
- const result = await aiService.processQuery(query, specificTools);
32
- if (result.error)
33
- return createErrorResponse(result.error);
32
+ const response = await aiService.processQuery(query, specificTools);
33
+ if (response.error)
34
+ return createErrorResponse(response.error);
34
35
  return {
36
+ isError: false,
35
37
  content: [
36
38
  {
37
39
  type: "text",
38
40
  text: JSON.stringify({
39
- toolName: result.toolName,
40
- reasoning: result.reasoning,
41
- parameters: cleanNullValues(result.parameters),
41
+ toolName: response.toolName,
42
+ reasoning: response.reasoning,
43
+ parameters: convertNullToUndefined(response.parameters),
42
44
  }, null, 2),
43
45
  },
44
46
  ],
@@ -1 +1 @@
1
- {"version":3,"file":"settings-tools.d.ts","sourceRoot":"","sources":["../../../src/tools/meilisearch/settings-tools.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE;;;;GAIG;AAEH;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,GAAI,QAAQ,SAAS,SAgqCtD,CAAC;AAEF,eAAe,qBAAqB,CAAC"}
1
+ {"version":3,"file":"settings-tools.d.ts","sourceRoot":"","sources":["../../../src/tools/meilisearch/settings-tools.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE;;;;GAIG;AAEH;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,GAAI,QAAQ,SAAS,SA2uCtD,CAAC;AAEF,eAAe,qBAAqB,CAAC"}
@@ -93,6 +93,9 @@ export const registerSettingsTools = (server) => {
93
93
  // Update displayed attributes setting
94
94
  server.tool("update-displayed-attributes", "Update the displayed attributes setting for a Meilisearch index", {
95
95
  indexUid: z.string().describe("Unique identifier of the index"),
96
+ displayedAttributes: z
97
+ .string()
98
+ .describe('JSON array of attributes to display, e.g. ["title", "description"]'),
96
99
  }, { category: "meilisearch" }, async ({ indexUid, displayedAttributes }) => {
97
100
  try {
98
101
  const response = await apiClient.put(`/indexes/${indexUid}/settings/displayed-attributes`, displayedAttributes);
@@ -141,6 +144,9 @@ export const registerSettingsTools = (server) => {
141
144
  // Update filterable attributes setting
142
145
  server.tool("update-filterable-attributes", "Update the filterable attributes setting for a Meilisearch index", {
143
146
  indexUid: z.string().describe("Unique identifier of the index"),
147
+ filterableAttributes: z
148
+ .string()
149
+ .describe('JSON array of attributes that can be used as filters, e.g. ["genre", "director"]'),
144
150
  }, { category: "meilisearch" }, async ({ indexUid, filterableAttributes }) => {
145
151
  try {
146
152
  const response = await apiClient.put(`/indexes/${indexUid}/settings/filterable-attributes`, filterableAttributes);
@@ -189,6 +195,9 @@ export const registerSettingsTools = (server) => {
189
195
  // Update sortable attributes setting
190
196
  server.tool("update-sortable-attributes", "Update the sortable attributes setting for a Meilisearch index", {
191
197
  indexUid: z.string().describe("Unique identifier of the index"),
198
+ sortableAttributes: z
199
+ .string()
200
+ .describe('JSON array of attributes that can be used for sorting, e.g. ["price", "date"]'),
192
201
  }, { category: "meilisearch" }, async ({ indexUid, sortableAttributes }) => {
193
202
  try {
194
203
  const response = await apiClient.put(`/indexes/${indexUid}/settings/sortable-attributes`, sortableAttributes);
@@ -237,6 +246,9 @@ export const registerSettingsTools = (server) => {
237
246
  // Update searchable attributes setting
238
247
  server.tool("update-searchable-attributes", "Update the searchable attributes setting for a Meilisearch index", {
239
248
  indexUid: z.string().describe("Unique identifier of the index"),
249
+ searchableAttributes: z
250
+ .string()
251
+ .describe('JSON array of attributes that can be searched, e.g. ["title", "description"]'),
240
252
  }, { category: "meilisearch" }, async ({ indexUid, searchableAttributes }) => {
241
253
  try {
242
254
  const response = await apiClient.put(`/indexes/${indexUid}/settings/searchable-attributes`, searchableAttributes);
@@ -285,6 +297,9 @@ export const registerSettingsTools = (server) => {
285
297
  // Update ranking rules setting
286
298
  server.tool("update-ranking-rules", "Update the ranking rules setting for a Meilisearch index", {
287
299
  indexUid: z.string().describe("Unique identifier of the index"),
300
+ rankingRules: z
301
+ .string()
302
+ .describe('JSON array of ranking rules, e.g. ["typo", "words", "proximity", "attribute", "sort", "exactness"]'),
288
303
  }, { category: "meilisearch" }, async ({ indexUid, rankingRules }) => {
289
304
  try {
290
305
  const response = await apiClient.put(`/indexes/${indexUid}/settings/ranking-rules`, rankingRules);
@@ -333,6 +348,9 @@ export const registerSettingsTools = (server) => {
333
348
  // Update stop words setting
334
349
  server.tool("update-stop-words", "Update the stop words setting for a Meilisearch index", {
335
350
  indexUid: z.string().describe("Unique identifier of the index"),
351
+ stopWords: z
352
+ .string()
353
+ .describe('JSON array of words to ignore in search queries, e.g. ["the", "a", "an"]'),
336
354
  }, { category: "meilisearch" }, async ({ indexUid, stopWords }) => {
337
355
  try {
338
356
  const response = await apiClient.put(`/indexes/${indexUid}/settings/stop-words`, stopWords);
@@ -381,6 +399,9 @@ export const registerSettingsTools = (server) => {
381
399
  // Update synonyms setting
382
400
  server.tool("update-synonyms", "Update the synonyms setting for a Meilisearch index", {
383
401
  indexUid: z.string().describe("Unique identifier of the index"),
402
+ synonyms: z
403
+ .string()
404
+ .describe('JSON object mapping words to their synonyms, e.g. {"movie": ["film"]}'),
384
405
  }, { category: "meilisearch" }, async ({ indexUid, synonyms }) => {
385
406
  try {
386
407
  const response = await apiClient.put(`/indexes/${indexUid}/settings/synonyms`, synonyms);
@@ -429,6 +450,9 @@ export const registerSettingsTools = (server) => {
429
450
  // Update typo tolerance setting
430
451
  server.tool("update-typo-tolerance", "Update the typo tolerance setting for a Meilisearch index", {
431
452
  indexUid: z.string().describe("Unique identifier of the index"),
453
+ typoTolerance: z
454
+ .string()
455
+ .describe('JSON object with typo tolerance configuration, e.g. {"enabled": true, "minWordSizeForTypos": {"oneTypo": 5, "twoTypos": 9}}'),
432
456
  }, { category: "meilisearch" }, async ({ indexUid, typoTolerance }) => {
433
457
  try {
434
458
  const response = await apiClient.put(`/indexes/${indexUid}/settings/typo-tolerance`, typoTolerance);
@@ -477,6 +501,9 @@ export const registerSettingsTools = (server) => {
477
501
  // Update pagination setting
478
502
  server.tool("update-pagination", "Update the pagination setting for a Meilisearch index", {
479
503
  indexUid: z.string().describe("Unique identifier of the index"),
504
+ pagination: z
505
+ .string()
506
+ .describe('JSON object with pagination configuration, e.g. {"maxTotalHits": 1000}'),
480
507
  }, { category: "meilisearch" }, async ({ indexUid, pagination }) => {
481
508
  try {
482
509
  const response = await apiClient.put(`/indexes/${indexUid}/settings/pagination`, pagination);
@@ -525,6 +552,9 @@ export const registerSettingsTools = (server) => {
525
552
  // Update faceting setting
526
553
  server.tool("update-faceting", "Update the faceting setting for a Meilisearch index", {
527
554
  indexUid: z.string().describe("Unique identifier of the index"),
555
+ faceting: z
556
+ .string()
557
+ .describe('JSON object with faceting configuration, e.g. {"maxValuesPerFacet": 100}'),
528
558
  }, { category: "meilisearch" }, async ({ indexUid, faceting }) => {
529
559
  try {
530
560
  const response = await apiClient.put(`/indexes/${indexUid}/settings/faceting`, faceting);
@@ -573,6 +603,9 @@ export const registerSettingsTools = (server) => {
573
603
  // Update dictionary setting
574
604
  server.tool("update-dictionary", "Update the dictionary setting for a Meilisearch index", {
575
605
  indexUid: z.string().describe("Unique identifier of the index"),
606
+ dictionary: z
607
+ .string()
608
+ .describe('JSON array of words to consider as a single word, e.g. ["San Francisco", "New York"]'),
576
609
  }, { category: "meilisearch" }, async ({ indexUid, dictionary }) => {
577
610
  try {
578
611
  const response = await apiClient.put(`/indexes/${indexUid}/settings/dictionary`, dictionary);
@@ -621,6 +654,9 @@ export const registerSettingsTools = (server) => {
621
654
  // Update proximity precision setting
622
655
  server.tool("update-proximity-precision", "Update the proximity precision setting for a Meilisearch index", {
623
656
  indexUid: z.string().describe("Unique identifier of the index"),
657
+ proximityPrecision: z
658
+ .string()
659
+ .describe("String with proximity precision value, can be 'byWord' or 'byAttribute'"),
624
660
  }, { category: "meilisearch" }, async ({ indexUid, proximityPrecision }) => {
625
661
  try {
626
662
  const response = await apiClient.put(`/indexes/${indexUid}/settings/proximity-precision`, proximityPrecision);
@@ -669,6 +705,9 @@ export const registerSettingsTools = (server) => {
669
705
  // Update separator tokens setting
670
706
  server.tool("update-separator-tokens", "Update the separator tokens setting for a Meilisearch index", {
671
707
  indexUid: z.string().describe("Unique identifier of the index"),
708
+ separatorTokens: z
709
+ .string()
710
+ .describe('JSON array of tokens that should be considered as word separators, e.g. ["-", "_"]'),
672
711
  }, { category: "meilisearch" }, async ({ indexUid, separatorTokens }) => {
673
712
  try {
674
713
  const response = await apiClient.put(`/indexes/${indexUid}/settings/separator-tokens`, separatorTokens);
@@ -717,6 +756,9 @@ export const registerSettingsTools = (server) => {
717
756
  // Update non-separator tokens setting
718
757
  server.tool("update-non-separator-tokens", "Update the non-separator tokens setting for a Meilisearch index", {
719
758
  indexUid: z.string().describe("Unique identifier of the index"),
759
+ nonSeparatorTokens: z
760
+ .string()
761
+ .describe('JSON array of tokens that should not be considered as word separators, e.g. ["@", "."]'),
720
762
  }, { category: "meilisearch" }, async ({ indexUid, nonSeparatorTokens }) => {
721
763
  try {
722
764
  const response = await apiClient.put(`/indexes/${indexUid}/settings/non-separator-tokens`, nonSeparatorTokens);
@@ -765,6 +807,9 @@ export const registerSettingsTools = (server) => {
765
807
  // Update word dictionary setting
766
808
  server.tool("update-word-dictionary", "Update the word dictionary setting for a Meilisearch index", {
767
809
  indexUid: z.string().describe("Unique identifier of the index"),
810
+ wordDictionary: z
811
+ .string()
812
+ .describe('JSON array of custom words to add to the dictionary, e.g. ["cbuilder", "meilisearch"]'),
768
813
  }, { category: "meilisearch" }, async ({ indexUid, wordDictionary }) => {
769
814
  try {
770
815
  const response = await apiClient.put(`/indexes/${indexUid}/settings/word-dictionary`, wordDictionary);
@@ -5,9 +5,9 @@ interface AITool {
5
5
  parameters: Record<string, unknown>;
6
6
  }
7
7
  interface AIToolResponse {
8
+ error?: unknown;
8
9
  toolName?: string;
9
10
  reasoning?: string;
10
- error: string | null;
11
11
  parameters?: Record<string, unknown>;
12
12
  }
13
13
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"ai-handler.d.ts","sourceRoot":"","sources":["../../src/utils/ai-handler.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAG5D,UAAU,MAAM;IACd,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACrC;AAmBD,UAAU,cAAc;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAED;;;;;GAKG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,cAAc,CAAgB;IACtC,OAAO,CAAC,KAAK,CAA2B;IACxC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAA0B;IACjD,OAAO,CAAC,MAAM,CAAC,iBAAiB,CAAkB;IAClD,OAAO,CAAC,QAAQ,CAAmC;IACnD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAwB;IACrD,OAAO,CAAC,MAAM,CAAgD;IAE9D;;;OAGG;IACH,OAAO;IAEP;;;OAGG;WACW,WAAW,IAAI,SAAS;IAOtC;;;;;;OAMG;IACH,UAAU,CACR,MAAM,EAAE,MAAM,EACd,QAAQ,GAAE,qBAAgC,EAC1C,KAAK,CAAC,EAAE,MAAM,GACb,IAAI;IAyBP;;;OAGG;IACH,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI;IAIxC,iBAAiB,IAAI,OAAO;IAI5B;;;;OAIG;IACH,OAAO,CAAC,kBAAkB;IAgB1B;;;;OAIG;IACH,OAAO,CAAC,gBAAgB;IAaxB;;;;;OAKG;IACG,YAAY,CAChB,KAAK,EAAE,MAAM,EACb,aAAa,CAAC,EAAE,MAAM,EAAE,GACvB,OAAO,CAAC,cAAc,CAAC;YA4BZ,kBAAkB;YA+DlB,uBAAuB;CAyDtC"}
1
+ {"version":3,"file":"ai-handler.d.ts","sourceRoot":"","sources":["../../src/utils/ai-handler.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAG5D,UAAU,MAAM;IACd,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACrC;AAmBD,UAAU,cAAc;IACtB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAED;;;;;GAKG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,cAAc,CAAgB;IACtC,OAAO,CAAC,KAAK,CAA2B;IACxC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAA0B;IACjD,OAAO,CAAC,MAAM,CAAC,iBAAiB,CAAkB;IAClD,OAAO,CAAC,QAAQ,CAAmC;IACnD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAwB;IACrD,OAAO,CAAC,MAAM,CAAgD;IAE9D;;;OAGG;IACH,OAAO;IAEP;;;OAGG;WACW,WAAW,IAAI,SAAS;IAOtC;;;;;;OAMG;IACH,UAAU,CACR,MAAM,EAAE,MAAM,EACd,QAAQ,GAAE,qBAAgC,EAC1C,KAAK,CAAC,EAAE,MAAM,GACb,IAAI;IAyBP;;;OAGG;IACH,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI;IAIxC,iBAAiB,IAAI,OAAO;IAI5B;;;;OAIG;IACH,OAAO,CAAC,kBAAkB;IAgB1B;;;;OAIG;IACH,OAAO,CAAC,gBAAgB;IAaxB;;;;;OAKG;IACG,YAAY,CAChB,KAAK,EAAE,MAAM,EACb,aAAa,CAAC,EAAE,MAAM,EAAE,GACvB,OAAO,CAAC,cAAc,CAAC;YA4BZ,kBAAkB;YA6DlB,uBAAuB;CAuDtC"}
@@ -154,7 +154,6 @@ export class AIService {
154
154
  parameters: JSON.parse(toolCall.arguments),
155
155
  };
156
156
  return {
157
- error: null,
158
157
  toolName: inferenceToolResponse.name,
159
158
  parameters: inferenceToolResponse.parameters,
160
159
  reasoning: JSON.stringify(inferenceToolResponse, null, 2),
@@ -168,7 +167,6 @@ export class AIService {
168
167
  };
169
168
  }
170
169
  return {
171
- error: null,
172
170
  toolName: toolCall.name,
173
171
  parameters: toolCall.parameters,
174
172
  reasoning: JSON.stringify(toolCall, null, 2),
@@ -177,7 +175,7 @@ export class AIService {
177
175
  return { error: "No tool call or content in OpenAI response" };
178
176
  }
179
177
  catch (error) {
180
- return { error: `OpenAI API error: ${error}` };
178
+ return { error };
181
179
  }
182
180
  }
183
181
  async processHuggingFaceQuery(tools, messages) {
@@ -203,7 +201,6 @@ export class AIService {
203
201
  parameters: JSON.parse(toolCall.arguments),
204
202
  };
205
203
  return {
206
- error: null,
207
204
  toolName: inferenceToolResponse.name,
208
205
  parameters: inferenceToolResponse.parameters,
209
206
  reasoning: JSON.stringify(inferenceToolResponse, null, 2),
@@ -214,7 +211,6 @@ export class AIService {
214
211
  if (!toolCall)
215
212
  return { error: "Invalid tool call format in content" };
216
213
  return {
217
- error: null,
218
214
  toolName: toolCall.name,
219
215
  parameters: toolCall.parameters,
220
216
  reasoning: JSON.stringify(toolCall, null, 2),
@@ -223,7 +219,7 @@ export class AIService {
223
219
  return { error: "No tool call or content in Hugging Face response" };
224
220
  }
225
221
  catch (error) {
226
- return { error: `Hugging Face API error: ${error}` };
222
+ return { error };
227
223
  }
228
224
  }
229
225
  }
@@ -14,7 +14,7 @@ export declare const handleApiError: (error: any) => string;
14
14
  export declare const createErrorResponse: (error: any) => {
15
15
  isError: boolean;
16
16
  content: {
17
- type: string;
17
+ type: "text";
18
18
  text: string;
19
19
  }[];
20
20
  };
@@ -23,7 +23,7 @@ declare const _default: {
23
23
  createErrorResponse: (error: any) => {
24
24
  isError: boolean;
25
25
  content: {
26
- type: string;
26
+ type: "text";
27
27
  text: string;
28
28
  }[];
29
29
  };
@@ -12,7 +12,7 @@ export const handleApiError = (error) => {
12
12
  return `Meilisearch API error (${status}): ${JSON.stringify(data)}`;
13
13
  }
14
14
  // If it's a network error or other error
15
- return `MCP Server error: ${JSON.stringify(error)}`;
15
+ return JSON.stringify(error);
16
16
  };
17
17
  /**
18
18
  * Creates a standardized error response object for MCP tools
@@ -11,5 +11,5 @@ export declare function markdownToJson<T>(markdownJsonString: string): T | null;
11
11
  * Recursively removes null values from an object, replacing them with undefined
12
12
  * This ensures optional parameters are properly handled by JSON schema validation
13
13
  */
14
- export declare function cleanNullValues(obj?: Record<string, any>): Record<string, any>;
14
+ export declare function convertNullToUndefined(obj: unknown, seen?: WeakMap<object, unknown>): unknown;
15
15
  //# sourceMappingURL=response-handler.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"response-handler.d.ts","sourceRoot":"","sources":["../../src/utils/response-handler.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,kBAAkB,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI,CAoCtE;AAgCD;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GACxB,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAwBrB"}
1
+ {"version":3,"file":"response-handler.d.ts","sourceRoot":"","sources":["../../src/utils/response-handler.ts"],"names":[],"mappings":"AA0CA;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,kBAAkB,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI,CAuDtE;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,OAAO,EACZ,IAAI,GAAE,OAAO,CAAC,MAAM,EAAE,OAAO,CAAiB,GAC7C,OAAO,CA6BT"}
@@ -1,3 +1,41 @@
1
+ function tryParseJsonString(str) {
2
+ if (typeof str === "string" &&
3
+ str.length >= 2 &&
4
+ ((str.startsWith("{") && str.endsWith("}")) ||
5
+ (str.startsWith("[") && str.endsWith("]")))) {
6
+ try {
7
+ return JSON.parse(str);
8
+ }
9
+ catch {
10
+ return str;
11
+ }
12
+ }
13
+ return str;
14
+ }
15
+ function parseNestedJsonStrings(obj) {
16
+ if (Array.isArray(obj)) {
17
+ return obj.map(parseNestedJsonStrings);
18
+ }
19
+ if (obj !== null && typeof obj === "object") {
20
+ const result = {};
21
+ for (const key in obj) {
22
+ if (Object.prototype.hasOwnProperty.call(obj, key)) {
23
+ result[key] = parseNestedJsonStrings(obj[key]);
24
+ }
25
+ }
26
+ return result;
27
+ }
28
+ if (typeof obj === "string") {
29
+ return tryParseJsonString(obj);
30
+ }
31
+ return obj;
32
+ }
33
+ const TRAILING_COMMA_REGEX = /,\s*([}\]])/g;
34
+ const SINGLE_LINE_COMMENT_REGEX = /\/\/[^\r\n]*/g;
35
+ const MULTI_LINE_COMMENT_REGEX = /\/\*[\s\S]*?\*\//g;
36
+ const FENCE_REGEX = /^```(?:json)?\s*([\s\S]*?)\s*```$/;
37
+ const JSON_TAG_REGEX = /<json>\s*([\s\S]*?)\s*<\/json>/;
38
+ const UNQUOTED_KEYS_REGEX = /([{,]\s*)([a-zA-Z_][a-zA-Z0-9_]*)\s*:/g;
1
39
  /**
2
40
  * Transforms a string, potentially containing JSON embedded in Markdown
3
41
  * or with non-standard features like comments and trailing commas,
@@ -7,94 +45,87 @@
7
45
  * @returns A parsed JavaScript object/array, or null if parsing fails.
8
46
  */
9
47
  export function markdownToJson(markdownJsonString) {
10
- if (typeof markdownJsonString !== "string" || !markdownJsonString.trim()) {
48
+ if (typeof markdownJsonString !== "string")
11
49
  return null;
12
- }
13
- let S = markdownJsonString.trim();
14
- const fenceRegex = /^```(?:json)?\s*([\s\S]*?)\s*```$/;
15
- const fenceMatch = S.match(fenceRegex);
16
- if (fenceMatch && fenceMatch[1]) {
17
- S = fenceMatch[1].trim();
50
+ let jsonString = markdownJsonString.trim();
51
+ if (!jsonString)
52
+ return null;
53
+ const fenceMatch = jsonString.match(FENCE_REGEX);
54
+ if (fenceMatch && fenceMatch[1] !== undefined) {
55
+ jsonString = fenceMatch[1].trim();
18
56
  }
19
57
  else {
20
- const jsonTagRegex = /<json>\s*([\s\S]*?)\s*<\/json>/;
21
- const jsonTagMatch = S.match(jsonTagRegex);
22
- if (jsonTagMatch && jsonTagMatch[1]) {
23
- S = jsonTagMatch[1].trim();
58
+ const jsonTagMatch = jsonString.match(JSON_TAG_REGEX);
59
+ if (jsonTagMatch && jsonTagMatch[1] !== undefined) {
60
+ jsonString = jsonTagMatch[1].trim();
24
61
  }
25
62
  }
26
- if (S === "")
63
+ if (jsonString === "")
27
64
  return null;
28
- S = S.replace(/\/\/[^\r\n]*/g, "");
29
- S = S.replace(/\/\*[\s\S]*?\*\//g, "");
30
- S = S.replace(/,\s*([}\]])/g, "$1");
31
- S = S.replace(/([{,]\s*)([a-zA-Z_][a-zA-Z0-9_]*)\s*:/g, '$1"$2":');
65
+ let parsedJson;
66
+ try {
67
+ parsedJson = JSON.parse(jsonString);
68
+ }
69
+ catch {
70
+ let cleanedJson = jsonString;
71
+ cleanedJson = cleanedJson.replace(SINGLE_LINE_COMMENT_REGEX, "");
72
+ cleanedJson = cleanedJson.replace(MULTI_LINE_COMMENT_REGEX, "");
73
+ cleanedJson = cleanedJson.trim();
74
+ if (cleanedJson === "")
75
+ return null;
76
+ cleanedJson = cleanedJson.replace(TRAILING_COMMA_REGEX, "$1");
77
+ cleanedJson = cleanedJson.replace(UNQUOTED_KEYS_REGEX, '$1"$2":');
78
+ try {
79
+ parsedJson = JSON.parse(cleanedJson);
80
+ }
81
+ catch (error) {
82
+ console.error("Failed to parse JSON after transformations.");
83
+ console.error("Original string:", markdownJsonString);
84
+ console.error("String after extraction (before cleaning):", jsonString);
85
+ console.error("Processed string that failed parsing:", cleanedJson);
86
+ console.error("Error:", error);
87
+ return null;
88
+ }
89
+ }
32
90
  try {
33
- const parsedJson = JSON.parse(S);
34
91
  return parseNestedJsonStrings(parsedJson);
35
92
  }
36
93
  catch (error) {
37
- console.error("Failed to parse JSON after transformations.");
38
- console.error("Original string:", markdownJsonString);
39
- console.error("Processed string that failed:", S);
94
+ console.error("Error during nested JSON string parsing:");
95
+ console.error("Parsed object before nested parsing:", parsedJson);
40
96
  console.error("Error:", error);
41
97
  return null;
42
98
  }
43
99
  }
44
- function tryParseJsonString(str) {
45
- try {
46
- if (typeof str === "string" &&
47
- ((str.startsWith("[") && str.endsWith("]")) ||
48
- (str.startsWith("{") && str.endsWith("}")))) {
49
- return JSON.parse(str);
50
- }
51
- return str;
52
- }
53
- catch {
54
- return str;
55
- }
56
- }
57
- function parseNestedJsonStrings(obj) {
58
- if (Array.isArray(obj)) {
59
- return obj.map((item) => parseNestedJsonStrings(item));
60
- }
61
- else if (obj !== null && typeof obj === "object") {
62
- const result = {};
63
- for (const key of Object.keys(obj)) {
64
- result[key] = parseNestedJsonStrings(obj[key]);
65
- }
66
- return result;
67
- }
68
- else if (typeof obj === "string") {
69
- return tryParseJsonString(obj);
70
- }
71
- return obj;
72
- }
73
100
  /**
74
101
  * Recursively removes null values from an object, replacing them with undefined
75
102
  * This ensures optional parameters are properly handled by JSON schema validation
76
103
  */
77
- export function cleanNullValues(obj) {
78
- if (!obj || typeof obj !== "object")
79
- return obj ?? {};
80
- const result = {};
81
- for (const [key, value] of Object.entries(obj)) {
82
- if (value === null) {
83
- continue;
84
- }
85
- else if (typeof value === "object" && value !== null) {
86
- if (Array.isArray(value)) {
87
- result[key] = value.map((item) => typeof item === "object" && item !== null
88
- ? cleanNullValues(item)
89
- : item);
90
- }
91
- else {
92
- result[key] = cleanNullValues(value);
93
- }
94
- }
95
- else {
96
- result[key] = value;
104
+ export function convertNullToUndefined(obj, seen = new WeakMap()) {
105
+ if (obj === null)
106
+ return undefined;
107
+ if (obj === undefined || typeof obj !== "object")
108
+ return obj;
109
+ if (seen.has(obj))
110
+ return seen.get(obj);
111
+ if (obj instanceof Date)
112
+ return new Date(obj.getTime());
113
+ if (obj instanceof RegExp)
114
+ return new RegExp(obj.source, obj.flags);
115
+ if (Array.isArray(obj)) {
116
+ const result = [];
117
+ seen.set(obj, result);
118
+ for (const item of obj) {
119
+ result.push(convertNullToUndefined(item, seen));
97
120
  }
121
+ return result;
122
+ }
123
+ const result = {};
124
+ seen.set(obj, result);
125
+ const keys = Object.keys(obj);
126
+ for (const key of keys) {
127
+ const value = obj[key];
128
+ result[key] = convertNullToUndefined(value, seen);
98
129
  }
99
130
  return result;
100
131
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mcp-meilisearch",
3
- "version": "1.4.7",
3
+ "version": "1.4.9",
4
4
  "description": "Model Context Protocol (MCP) implementation for Meilisearch",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -33,7 +33,7 @@
33
33
  "@modelcontextprotocol/sdk": "^1.11.4",
34
34
  "axios": "^1.9.0",
35
35
  "openai": "^4.100.0",
36
- "zod": "^3.25.1"
36
+ "zod": "^3.25.7"
37
37
  },
38
38
  "devDependencies": {
39
39
  "@types/node": "^22.15.19",