mcp-meilisearch 1.4.12 → 1.4.14

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
@@ -13,7 +13,7 @@ A Model Context Protocol (MCP) server implementation that provides a bridge betw
13
13
  - **Multiple Transport Options**: Supports both STDIO and StreamableHTTP transports.
14
14
  - **Meilisearch API Support**: Full access to Meilisearch functionalities.
15
15
  - **Web Client Demo**: Updated interface showcasing search capabilities and features.
16
- - **AI Inference**: Leverages LLMs from providers such as OpenAIo HuggingFace to intelligently determine and utilize the most suitable tool for user queries.
16
+ - **AI Inference**: Leverages LLMs from providers such as OpenAI, HuggingFace, OpenRouter, and Ollama to intelligently determine and utilize the most suitable tool for user queries.
17
17
 
18
18
  ## Getting Started
19
19
 
@@ -100,10 +100,13 @@ const result = await client.callTool("global-search", {
100
100
 
101
101
  // Use AI inference to choose the most appropriate tool
102
102
 
103
- const result = await client.callToolWithAI("Find articles about cucumber");
103
+ const result = await client.callToolWithAI("Find articles about cucumber", {
104
+ provideSummary: true,
105
+ });
104
106
  console.log(`Tool used: ${result.toolUsed}`);
105
107
  console.log(`Reasoning: ${result.reasoning}`);
106
108
  console.log(`Results: ${JSON.stringify(result.data)}`);
109
+ console.log(`Summary: ${result.summary}`);
107
110
  ```
108
111
 
109
112
  #### AI Inference Client Methods
@@ -117,7 +120,9 @@ Processes a user query through AI to determine and execute the most appropriate
117
120
  - `query`: String - The user's query or request to be processed
118
121
  - `options`: Object (Optional) - Configuration options
119
122
  - `specificTools`: String[] (Optional) - Restricts tool selection to this list of tool names
120
- - `justReasoning`: Boolean (Optional) - When set to `true`, returns only the AI's reasoning without executing the selected tool
123
+ - `justReasoning`: Boolean (Optional) - When set to `true`, returns only the AI's reasoning without executing the
124
+ selected tool
125
+ - `provideSummary`: Boolean (Optional) - When set to `true`, generates a concise summary of the search results along with the regular response
121
126
 
122
127
  ### Starting the Server
123
128
 
package/dist/client.d.ts CHANGED
@@ -1,3 +1,16 @@
1
+ interface AIToolClientOptions {
2
+ specificTools?: string[];
3
+ justReasoning?: boolean;
4
+ provideSummary?: boolean;
5
+ }
6
+ interface AIToolClientResponse {
7
+ data?: any;
8
+ summary?: any;
9
+ error?: string;
10
+ success: boolean;
11
+ toolUsed?: string;
12
+ reasoning?: string;
13
+ }
1
14
  export declare class MCPClient {
2
15
  /**
3
16
  * Indicates whether the client is connected to the MCP server
@@ -60,19 +73,11 @@ export declare class MCPClient {
60
73
  * @param options Options for the AI processing
61
74
  * @param options.specificTools Optional array of specific tool names to consider
62
75
  * @param options.justReasoning If true, only returns the reasoning without calling the tool
76
+ * @param options.provideSummary If true, beyond the raw JSON, it will also provide a summary of the result
63
77
  * @throws Error if AI inference fails
64
78
  * @returns The result of calling the selected tool, or an error
65
79
  */
66
- callToolWithAI(query: string, options?: {
67
- specificTools?: string[];
68
- justReasoning?: boolean;
69
- }): Promise<{
70
- success: boolean;
71
- data?: any;
72
- error?: string;
73
- toolUsed?: string;
74
- reasoning?: string;
75
- }>;
80
+ callToolWithAI(query: string, options?: AIToolClientOptions): Promise<AIToolClientResponse>;
76
81
  private setUpTransport;
77
82
  /**
78
83
  * Closes the connection to the server and resets the connection state
@@ -80,4 +85,5 @@ export declare class MCPClient {
80
85
  */
81
86
  cleanup(): Promise<void>;
82
87
  }
88
+ export {};
83
89
  //# sourceMappingURL=client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAQA,qBAAa,SAAS;IACpB;;;OAGG;IACH,WAAW,EAAE,OAAO,CAAS;IAE7B;;;OAGG;IACH,KAAK,EAAE;QACL,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;KACjC,EAAE,CAAM;IAET,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,KAAK,CAAa;IAC1B,OAAO,CAAC,SAAS,CAA8C;IAC/D,OAAO,CAAC,oBAAoB,CAEZ;gBAEJ,UAAU,EAAE,MAAM;IAI9B;;;OAGG;IACH,sBAAsB,CACpB,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC,KAAK,IAAI;IAKzE;;;;;OAKG;IACG,WAAW,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAOhE;;;;OAIG;IACG,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAuBzC,SAAS;IA0BvB,OAAO,CAAC,kBAAkB;IAW1B;;;;;;;OAOG;IACG,QAAQ,CACZ,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GACzB,OAAO,CAAC;QACT,OAAO,EAAE,OAAO,CAAC;QACjB,IAAI,CAAC,EAAE,GAAG,CAAC;QACX,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;IA2CF;;;;;;;;OAQG;IACG,cAAc,CAClB,KAAK,EAAE,MAAM,EACb,OAAO,GAAE;QAAE,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,aAAa,CAAC,EAAE,OAAO,CAAA;KAAO,GAClE,OAAO,CAAC;QACT,OAAO,EAAE,OAAO,CAAC;QACjB,IAAI,CAAC,EAAE,GAAG,CAAC;QACX,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;IA6CF,OAAO,CAAC,cAAc;IAKtB;;;OAGG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAK/B"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAQA,UAAU,mBAAmB;IAC3B,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,UAAU,oBAAoB;IAC5B,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,OAAO,CAAC,EAAE,GAAG,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,qBAAa,SAAS;IACpB;;;OAGG;IACH,WAAW,EAAE,OAAO,CAAS;IAE7B;;;OAGG;IACH,KAAK,EAAE;QACL,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;KACjC,EAAE,CAAM;IAET,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,KAAK,CAAa;IAC1B,OAAO,CAAC,SAAS,CAA8C;IAC/D,OAAO,CAAC,oBAAoB,CAEZ;gBAEJ,UAAU,EAAE,MAAM;IAI9B;;;OAGG;IACH,sBAAsB,CACpB,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC,KAAK,IAAI;IAKzE;;;;;OAKG;IACG,WAAW,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAOhE;;;;OAIG;IACG,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAuBzC,SAAS;IA0BvB,OAAO,CAAC,kBAAkB;IAW1B;;;;;;;OAOG;IACG,QAAQ,CACZ,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GACzB,OAAO,CAAC;QACT,OAAO,EAAE,OAAO,CAAC;QACjB,IAAI,CAAC,EAAE,GAAG,CAAC;QACX,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;IA2CF;;;;;;;;;OASG;IACG,cAAc,CAClB,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,oBAAoB,CAAC;IA2DhC,OAAO,CAAC,cAAc;IAKtB;;;OAGG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAK/B"}
package/dist/client.js CHANGED
@@ -147,13 +147,14 @@ export class MCPClient {
147
147
  * @param options Options for the AI processing
148
148
  * @param options.specificTools Optional array of specific tool names to consider
149
149
  * @param options.justReasoning If true, only returns the reasoning without calling the tool
150
+ * @param options.provideSummary If true, beyond the raw JSON, it will also provide a summary of the result
150
151
  * @throws Error if AI inference fails
151
152
  * @returns The result of calling the selected tool, or an error
152
153
  */
153
154
  async callToolWithAI(query, options = {}) {
154
- const { specificTools, justReasoning } = options;
155
+ const { specificTools, justReasoning, provideSummary } = options;
155
156
  try {
156
- const result = await this.callTool("process-ai-query", {
157
+ const result = await this.callTool("process-ai-tool", {
157
158
  query,
158
159
  specificTools,
159
160
  });
@@ -174,11 +175,22 @@ export class MCPClient {
174
175
  };
175
176
  }
176
177
  const toolResult = await this.callTool(toolName, parameters);
177
- return {
178
+ if (!toolResult.success)
179
+ return toolResult;
180
+ const response = {
178
181
  ...toolResult,
179
182
  reasoning,
180
183
  toolUsed: toolName,
181
184
  };
185
+ if (provideSummary) {
186
+ const summary = await this.callTool("process-ai-text", {
187
+ query: JSON.stringify(toolResult.data),
188
+ });
189
+ if (!summary.success)
190
+ console.error(summary);
191
+ response["summary"] = summary.data;
192
+ }
193
+ return response;
182
194
  }
183
195
  catch (error) {
184
196
  const errorMessage = error instanceof Error ? error.message : String(error);
@@ -0,0 +1,6 @@
1
+ declare const _default: {
2
+ tool: string;
3
+ text: string;
4
+ };
5
+ export default _default;
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/prompts/developer/index.ts"],"names":[],"mappings":";;;;AAGA,wBAA8B"}
@@ -0,0 +1,3 @@
1
+ import tool from "./tool.js";
2
+ import text from "./text.js";
3
+ export default { tool, text };
@@ -0,0 +1,3 @@
1
+ declare const _default: "\n<identity>\n You are PATI, an AI agent.\n</identity>\n\n<instructions>\n Your primary function is to generate a summary. This summary MUST adhere to the following rules:\n\n 1. **Language Matching:** The language of your summary MUST strictly match the predominant language of the user's provided input.\n - If the user's input is in Spanish, your summary MUST be in Spanish.\n - If the user's input is in English, your summary MUST be in English.\n - And so on for any other language.\n\n 2. **Content to Summarize:** Your summary MUST be a description of the key information, findings, or results presented in the user's input.\n - Do NOT summarize the user's instructions to you or the act of providing input.\n - Focus ONLY on the core data or text provided by the user for summarization.\n\n 3. **Handling Structured Data (e.g., JSON):**\n - If the user provides structured data (like a JSON object), identify the key textual fields that contain the main information (e.g., 'title', 'abstract', 'summary', 'content_to_search', 'description', 'text', etc.).\n - Synthesize the information from these relevant fields into a coherent, natural language summary.\n - If the JSON contains multiple results (e.g., in a 'hits' or 'results' array), list each result separately and provide a summary for each.\n - Include a general summary of all results at the beginning or end when multiple results are present.\n - Do NOT describe the structure of the data (e.g., \"The JSON has a 'hits' array...\"). Summarize the *meaning* conveyed by the content within those fields.\n\n 4. **Output Format:**\n - Your response MUST be formatted as valid HTML.\n - Use appropriate HTML elements for structure (headings, paragraphs, lists, etc.).\n - No greetings, no apologies, no explanations, no meta-comments. Just the summary in HTML format.\n - Do not include HTML, HEAD, or BODY tags - focus only on the content elements.\n</instructions>\n";
2
+ export default _default;
3
+ //# sourceMappingURL=text.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../../src/prompts/developer/text.ts"],"names":[],"mappings":";AAAA,wBA8BE"}
@@ -0,0 +1,31 @@
1
+ export default `
2
+ <identity>
3
+ You are PATI, an AI agent.
4
+ </identity>
5
+
6
+ <instructions>
7
+ Your primary function is to generate a summary. This summary MUST adhere to the following rules:
8
+
9
+ 1. **Language Matching:** The language of your summary MUST strictly match the predominant language of the user's provided input.
10
+ - If the user's input is in Spanish, your summary MUST be in Spanish.
11
+ - If the user's input is in English, your summary MUST be in English.
12
+ - And so on for any other language.
13
+
14
+ 2. **Content to Summarize:** Your summary MUST be a description of the key information, findings, or results presented in the user's input.
15
+ - Do NOT summarize the user's instructions to you or the act of providing input.
16
+ - Focus ONLY on the core data or text provided by the user for summarization.
17
+
18
+ 3. **Handling Structured Data (e.g., JSON):**
19
+ - If the user provides structured data (like a JSON object), identify the key textual fields that contain the main information (e.g., 'title', 'abstract', 'summary', 'content_to_search', 'description', 'text', etc.).
20
+ - Synthesize the information from these relevant fields into a coherent, natural language summary.
21
+ - If the JSON contains multiple results (e.g., in a 'hits' or 'results' array), list each result separately and provide a summary for each.
22
+ - Include a general summary of all results at the beginning or end when multiple results are present.
23
+ - Do NOT describe the structure of the data (e.g., "The JSON has a 'hits' array..."). Summarize the *meaning* conveyed by the content within those fields.
24
+
25
+ 4. **Output Format:**
26
+ - Your response MUST be formatted as valid HTML.
27
+ - Use appropriate HTML elements for structure (headings, paragraphs, lists, etc.).
28
+ - No greetings, no apologies, no explanations, no meta-comments. Just the summary in HTML format.
29
+ - Do not include HTML, HEAD, or BODY tags - focus only on the content elements.
30
+ </instructions>
31
+ `;
@@ -1,3 +1,3 @@
1
1
  declare const _default: "\n <identity>\n You are PATI, an AI agent that translates user requests into JSON tool calls.\n Your output MUST be ONLY the JSON tool call or error object. NO TEXT BEFORE OR AFTER.\n </identity>\n\n <instructions>\n 1. Select the most appropriate tool from the <functions> section based on the user's request.\n \n 2. Extract parameters directly from the user's request:\n \u2022 Extract ONLY what is explicitly stated or clearly implied.\n \u2022 Preserve quoted values EXACTLY as provided by the user.\n \u2022 For indexUid parameters, ALWAYS translate to English equivalent (e.g., \"articulos\" \u2192 \"articles\").\n \n 3. Format:\n \u2022 RESPONSE MUST BE JUST A VALID JSON OBJECT with this structure:\n {\n \"name\": \"tool_name_from_schema\",\n \"parameters\": {\n \"parameter1\": \"value1\",\n \"parameter2\": \"value2\"\n }\n }\n \n \u2022 For errors, use:\n {\n \"name\": \"cannot_fulfill_request\",\n \"parameters\": {\n \"reason_code\": \"CODE\",\n \"message\": \"Brief explanation\",\n \"missing_parameters\": [\"param1\", \"param2\"] // Only for MISSING_REQUIRED_PARAMETERS\n }\n }\n </instructions>\n\n <functions>\n MCP_TOOLS\n </functions>\n";
2
2
  export default _default;
3
- //# sourceMappingURL=system.d.ts.map
3
+ //# sourceMappingURL=tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../../../src/prompts/developer/tool.ts"],"names":[],"mappings":";AAAA,wBAsCE"}
@@ -1 +1 @@
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,SAuDhD,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;AAoCpE;;;GAGG;AACH,eAAO,MAAM,eAAe,GAAI,QAAQ,SAAS,SAqEhD,CAAC;AAEF,eAAe,eAAe,CAAC"}
@@ -3,12 +3,26 @@ import { zodToJsonSchema } from "zod-to-json-schema";
3
3
  import { AIService } from "../../utils/ai-handler.js";
4
4
  import { createErrorResponse } from "../../utils/error-handler.js";
5
5
  import { convertNullToUndefined } from "../../utils/response-handler.js";
6
+ const setAvailableTools = (aiService, server) => {
7
+ const registeredTools = Object.entries(server._registeredTools);
8
+ const availableTools = registeredTools
9
+ .filter(([_, { annotations }]) => annotations?.category !== "core")
10
+ .map(([name, { description, inputSchema }]) => {
11
+ const { definitions } = zodToJsonSchema(inputSchema, "parameters");
12
+ return {
13
+ name,
14
+ description,
15
+ parameters: definitions?.parameters ?? {},
16
+ };
17
+ });
18
+ aiService.setAvailableTools(availableTools);
19
+ };
6
20
  /**
7
21
  * Register AI tools with the MCP server
8
22
  * @param server - The MCP server instance
9
23
  */
10
24
  export const registerAITools = (server) => {
11
- server.tool("process-ai-query", "Process a natural language query using AI to determine which tool to use", {
25
+ server.tool("process-ai-tool", "Process a natural language query using AI to determine which tool to use", {
12
26
  query: z.string().describe("The natural language query to process"),
13
27
  specificTools: z
14
28
  .array(z.string())
@@ -17,19 +31,11 @@ export const registerAITools = (server) => {
17
31
  }, { category: "core" }, async ({ query, specificTools }) => {
18
32
  try {
19
33
  const aiService = AIService.getInstance();
20
- const registeredTools = Object.entries(server._registeredTools);
21
- const availableTools = registeredTools
22
- .filter(([_, { annotations }]) => annotations?.category !== "core")
23
- .map(([name, { description, inputSchema }]) => {
24
- const { definitions } = zodToJsonSchema(inputSchema, "parameters");
25
- return {
26
- name,
27
- description,
28
- parameters: definitions?.parameters ?? {},
29
- };
34
+ setAvailableTools(aiService, server);
35
+ const response = await aiService.setupAIProcess(query, {
36
+ specificTools,
37
+ processType: "tool",
30
38
  });
31
- aiService.setAvailableTools(availableTools);
32
- const response = await aiService.processQuery(query, specificTools);
33
39
  if (response.error)
34
40
  return createErrorResponse(response.error);
35
41
  const { toolName, parameters: rawParameters } = response;
@@ -48,5 +54,23 @@ export const registerAITools = (server) => {
48
54
  return createErrorResponse(error);
49
55
  }
50
56
  });
57
+ server.tool("process-ai-text", "Process a summary text using AI to describe the data result from a tool", { query: z.string().describe("The natural language query to process") }, { category: "core" }, async ({ query }) => {
58
+ try {
59
+ const aiService = AIService.getInstance();
60
+ const response = await aiService.setupAIProcess(query, {
61
+ processType: "text",
62
+ });
63
+ if (response.error)
64
+ return createErrorResponse(response.error);
65
+ const { summary: result } = response;
66
+ return {
67
+ isError: false,
68
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
69
+ };
70
+ }
71
+ catch (error) {
72
+ return createErrorResponse(error);
73
+ }
74
+ });
51
75
  };
52
76
  export default registerAITools;
@@ -4,11 +4,20 @@ interface AITool {
4
4
  description: string;
5
5
  parameters: Record<string, unknown>;
6
6
  }
7
+ interface AIProcessSetupOptions {
8
+ specificTools?: string[];
9
+ processType: "tool" | "text";
10
+ }
7
11
  interface AIToolResponse {
8
- error?: unknown;
9
12
  toolName?: string;
10
13
  parameters?: Record<string, unknown>;
11
14
  }
15
+ interface AITextResponse {
16
+ summary?: string;
17
+ }
18
+ interface AIProcessResponse extends AIToolResponse, AITextResponse {
19
+ error?: unknown;
20
+ }
12
21
  /**
13
22
  * AI Inference Service
14
23
  *
@@ -21,7 +30,6 @@ export declare class AIService {
21
30
  private static instance;
22
31
  private static serverInitialized;
23
32
  private provider;
24
- private readonly systemPrompt;
25
33
  private client;
26
34
  /**
27
35
  * Private constructor to prevent direct instantiation
@@ -59,15 +67,12 @@ export declare class AIService {
59
67
  * @returns Array of tool names mentioned in the query, or empty array if none found
60
68
  */
61
69
  private extractToolNames;
62
- /**
63
- * Process a user query and determine which tool to use
64
- * @param query User query
65
- * @param specificTools Optional array of specific tool names to consider
66
- * @returns Object containing the selected tool name and parameters
67
- */
68
- processQuery(query: string, specificTools?: string[]): Promise<AIToolResponse>;
69
- private processOpenAIQuery;
70
- private processHuggingFaceQuery;
70
+ setupAIProcess(query: string, options: AIProcessSetupOptions): Promise<AIProcessResponse>;
71
+ private processOpenAITool;
72
+ private processOpenAIText;
73
+ private processHuggingFaceTool;
74
+ private processHuggingFaceText;
75
+ private splitTextIntoChunks;
71
76
  }
72
77
  export {};
73
78
  //# sourceMappingURL=ai-handler.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ai-handler.d.ts","sourceRoot":"","sources":["../../src/utils/ai-handler.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAI5D,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,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;IA4BP;;;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;CAwDtC"}
1
+ {"version":3,"file":"ai-handler.d.ts","sourceRoot":"","sources":["../../src/utils/ai-handler.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAI5D,UAAU,MAAM;IACd,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACrC;AAED,UAAU,qBAAqB;IAC7B,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,WAAW,EAAE,MAAM,GAAG,MAAM,CAAC;CAC9B;AAkBD,UAAU,cAAc;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAED,UAAU,cAAc;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,UAAU,iBAAkB,SAAQ,cAAc,EAAE,cAAc;IAChE,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;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,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;IA4BP;;;OAGG;IACH,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI;IAIxC,iBAAiB,IAAI,OAAO;IAI5B;;;;OAIG;IACH,OAAO,CAAC,kBAAkB;IAe1B;;;;OAIG;IACH,OAAO,CAAC,gBAAgB;IAalB,cAAc,CAClB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,iBAAiB,CAAC;YA6Df,iBAAiB;YA+DjB,iBAAiB;YA+BjB,sBAAsB;YA+DtB,sBAAsB;IAiCpC,OAAO,CAAC,mBAAmB;CAyD5B"}
@@ -1,5 +1,5 @@
1
1
  import { OpenAI } from "openai";
2
- import systemPrompt from "../prompts/system.js";
2
+ import developerPrompts from "../prompts/developer/index.js";
3
3
  import { markdownToJson } from "./response-handler.js";
4
4
  import { InferenceClient } from "@huggingface/inference";
5
5
  import { OLLAMA_API, OPEN_ROUTER_API } from "../types/enums.js";
@@ -15,7 +15,6 @@ export class AIService {
15
15
  static instance = null;
16
16
  static serverInitialized = false;
17
17
  provider = "openai";
18
- systemPrompt = systemPrompt;
19
18
  client = null;
20
19
  /**
21
20
  * Private constructor to prevent direct instantiation
@@ -87,7 +86,6 @@ export class AIService {
87
86
  return tools.map((tool) => ({
88
87
  type: "function",
89
88
  function: {
90
- strict: true,
91
89
  name: tool.name,
92
90
  parameters: tool.parameters,
93
91
  description: tool.description,
@@ -109,47 +107,69 @@ export class AIService {
109
107
  }
110
108
  return mentionedTools;
111
109
  }
112
- /**
113
- * Process a user query and determine which tool to use
114
- * @param query User query
115
- * @param specificTools Optional array of specific tool names to consider
116
- * @returns Object containing the selected tool name and parameters
117
- */
118
- async processQuery(query, specificTools) {
110
+ async setupAIProcess(query, options) {
119
111
  if (!this.ensureInitialized()) {
120
112
  return {
121
113
  error: "AI service not initialized. Please provide an API key.",
122
114
  };
123
115
  }
116
+ const toolsSubstringIdentifier = "MCP_TOOLS";
117
+ const { processType, specificTools } = options;
118
+ let developerPrompt = developerPrompts[processType];
124
119
  const mentionedTools = this.extractToolNames(query);
125
120
  const toolsToUse = specificTools || (mentionedTools.length ? mentionedTools : undefined);
126
121
  const tools = this.getToolDefinitions(toolsToUse);
127
- const systemPrompt = this.systemPrompt.replace("MCP_TOOLS", JSON.stringify(tools, null, 2));
122
+ if (developerPrompt.includes(toolsSubstringIdentifier)) {
123
+ developerPrompt = developerPrompt.replace(toolsSubstringIdentifier, JSON.stringify(tools, null, 2));
124
+ }
128
125
  const messages = [
129
- { role: "system", content: systemPrompt },
126
+ { role: "developer", content: developerPrompt },
130
127
  { role: "user", content: query },
131
128
  ];
132
- if (this.provider === "huggingface") {
133
- return await this.processHuggingFaceQuery(tools, messages);
129
+ if (processType === "text") {
130
+ const processTextMethod = this.provider === "huggingface"
131
+ ? this.processHuggingFaceText.bind(this)
132
+ : this.processOpenAIText.bind(this);
133
+ const chunks = this.splitTextIntoChunks(query, 50000);
134
+ if (chunks.length === 1) {
135
+ return processTextMethod(messages);
136
+ }
137
+ const chunkPromises = chunks.map((content) => processTextMethod([messages[0], { role: "user", content }]));
138
+ const results = await Promise.all(chunkPromises);
139
+ const error = results.find((result) => result.error);
140
+ if (error) {
141
+ return { error };
142
+ }
143
+ const summary = results.map((result) => result?.summary || "").join(" ");
144
+ return { summary };
145
+ }
146
+ else {
147
+ return this.provider === "huggingface"
148
+ ? await this.processHuggingFaceTool(tools, messages)
149
+ : await this.processOpenAITool(tools, messages);
134
150
  }
135
- return await this.processOpenAIQuery(tools, messages);
136
151
  }
137
- async processOpenAIQuery(tools, messages, withoutFC = false) {
152
+ async processOpenAITool(tools, messages) {
138
153
  try {
139
154
  const client = this.client;
140
155
  const response = await client.chat.completions.create({
156
+ tools,
141
157
  messages,
142
158
  model: this.model,
143
- ...(!withoutFC && { tools, tool_choice: "required" }),
159
+ tool_choice: "required",
144
160
  });
145
161
  if (!response.choices?.length) {
146
- return { error: "No choices returned from OpenAI" };
162
+ return {
163
+ error: "No choices returned from OpenAI; processType: 'tool'",
164
+ };
147
165
  }
148
166
  const message = response.choices[0].message;
149
167
  if (message.tool_calls?.length) {
150
168
  const toolCall = message.tool_calls[0]?.function;
151
169
  if (!toolCall) {
152
- return { error: "Invalid tool from OpenAI response" };
170
+ return {
171
+ error: "Invalid tool from OpenAI response; processType: 'tool'",
172
+ };
153
173
  }
154
174
  return {
155
175
  toolName: toolCall.name,
@@ -160,7 +180,7 @@ export class AIService {
160
180
  const toolCall = markdownToJson(message.content);
161
181
  if (!toolCall) {
162
182
  return {
163
- error: `Invalid tool call format in content: ${message.content}`,
183
+ error: "Invalid tool call format in content; processType: 'tool'",
164
184
  };
165
185
  }
166
186
  return {
@@ -168,33 +188,59 @@ export class AIService {
168
188
  parameters: toolCall.parameters,
169
189
  };
170
190
  }
171
- return { error: "No tool call or content in OpenAI response" };
191
+ return {
192
+ error: "No tool call or content in OpenAI response; processType: 'tool'.",
193
+ };
172
194
  }
173
195
  catch (error) {
174
196
  console.error(error);
175
- if (!withoutFC) {
176
- console.info("Retrying without function calling...");
177
- return this.processOpenAIQuery(tools, messages, true);
197
+ return { error };
198
+ }
199
+ }
200
+ async processOpenAIText(messages) {
201
+ try {
202
+ const client = this.client;
203
+ const response = await client.chat.completions.create({
204
+ messages,
205
+ model: this.model,
206
+ });
207
+ if (!response.choices?.length) {
208
+ return {
209
+ error: "No response returned from OpenAI; processType: 'text'.",
210
+ };
178
211
  }
212
+ const message = response.choices[0].message;
213
+ if (message.content) {
214
+ return { summary: message.content };
215
+ }
216
+ return { error: "No content in OpenAI response; processType: 'text'." };
217
+ }
218
+ catch (error) {
219
+ console.error(error);
179
220
  return { error };
180
221
  }
181
222
  }
182
- async processHuggingFaceQuery(tools, messages, withoutFC = false) {
223
+ async processHuggingFaceTool(tools, messages) {
183
224
  try {
184
225
  const client = this.client;
185
226
  const response = await client.chatCompletion({
227
+ tools,
186
228
  messages,
187
229
  model: this.model,
188
- ...(!withoutFC && { tools, tool_choice: "required" }),
230
+ tool_choice: "required",
189
231
  });
190
232
  if (!response.choices?.length) {
191
- return { error: "No choices in Hugging Face response" };
233
+ return {
234
+ error: "No choices in Hugging Face response; processType: 'tool'",
235
+ };
192
236
  }
193
237
  const message = response.choices[0].message;
194
238
  if (message.tool_calls?.length) {
195
239
  const toolCall = message.tool_calls[0]?.function;
196
240
  if (!toolCall) {
197
- return { error: "Invalid tool from Hugging Face response" };
241
+ return {
242
+ error: "Invalid tool from Hugging Face response; processType: 'tool'",
243
+ };
198
244
  }
199
245
  return {
200
246
  toolName: toolCall.name,
@@ -204,21 +250,90 @@ export class AIService {
204
250
  if (message.content) {
205
251
  const toolCall = markdownToJson(message.content);
206
252
  if (!toolCall)
207
- return { error: "Invalid tool call format in content" };
253
+ return {
254
+ error: "Invalid tool call format in content; processType: 'tool'",
255
+ };
208
256
  return {
209
257
  toolName: toolCall.name,
210
258
  parameters: toolCall.parameters,
211
259
  };
212
260
  }
213
- return { error: "No tool call or content in Hugging Face response" };
261
+ return {
262
+ error: "No tool call or content in Hugging Face response; processType: 'tool'",
263
+ };
214
264
  }
215
265
  catch (error) {
216
266
  console.error(error);
217
- if (!withoutFC) {
218
- console.info("Retrying without function calling...");
219
- return this.processHuggingFaceQuery(tools, messages, true);
267
+ return { error };
268
+ }
269
+ }
270
+ async processHuggingFaceText(messages) {
271
+ try {
272
+ const client = this.client;
273
+ const response = await client.chatCompletion({
274
+ messages,
275
+ model: this.model,
276
+ });
277
+ if (!response.choices?.length) {
278
+ return {
279
+ error: "No response returned from OpenAI; processType: 'text'.",
280
+ };
220
281
  }
282
+ const message = response.choices[0].message;
283
+ if (message.content) {
284
+ return { summary: message.content };
285
+ }
286
+ return {
287
+ error: "No content in Hugging Face response; processType: 'text'.",
288
+ };
289
+ }
290
+ catch (error) {
291
+ console.error(error);
221
292
  return { error };
222
293
  }
223
294
  }
295
+ splitTextIntoChunks(text, chunkSize) {
296
+ if (text.length <= chunkSize) {
297
+ return [text];
298
+ }
299
+ let currentIndex = 0;
300
+ const chunks = [];
301
+ const textLength = text.length;
302
+ const sentenceEndRegex = /[.!?]\s+/g;
303
+ while (currentIndex < textLength) {
304
+ let proposedEndIndex = Math.min(currentIndex + chunkSize, textLength);
305
+ let actualEndIndex = proposedEndIndex;
306
+ if (proposedEndIndex < textLength) {
307
+ let bestBreakPoint = -1;
308
+ const relevantTextSlice = text.substring(currentIndex, proposedEndIndex);
309
+ let match;
310
+ let lastMatch;
311
+ sentenceEndRegex.lastIndex = 0;
312
+ while ((match = sentenceEndRegex.exec(relevantTextSlice)) !== null) {
313
+ lastMatch = match;
314
+ }
315
+ if (lastMatch) {
316
+ bestBreakPoint = currentIndex + lastMatch.index + lastMatch[0].length;
317
+ }
318
+ if (bestBreakPoint > currentIndex) {
319
+ actualEndIndex = bestBreakPoint;
320
+ }
321
+ else {
322
+ const lastSpaceIndex = text.lastIndexOf(" ", proposedEndIndex - 1);
323
+ if (lastSpaceIndex > currentIndex) {
324
+ actualEndIndex = lastSpaceIndex + 1;
325
+ }
326
+ else {
327
+ actualEndIndex = proposedEndIndex;
328
+ }
329
+ }
330
+ }
331
+ else {
332
+ actualEndIndex = textLength;
333
+ }
334
+ chunks.push(text.substring(currentIndex, actualEndIndex));
335
+ currentIndex = actualEndIndex;
336
+ }
337
+ return chunks;
338
+ }
224
339
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mcp-meilisearch",
3
- "version": "1.4.12",
3
+ "version": "1.4.14",
4
4
  "description": "Model Context Protocol (MCP) implementation for Meilisearch",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -1 +0,0 @@
1
- {"version":3,"file":"system.d.ts","sourceRoot":"","sources":["../../src/prompts/system.ts"],"names":[],"mappings":";AAAA,wBAsCE"}
File without changes