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 +8 -3
- package/dist/client.d.ts +16 -10
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +15 -3
- package/dist/prompts/developer/index.d.ts +6 -0
- package/dist/prompts/developer/index.d.ts.map +1 -0
- package/dist/prompts/developer/index.js +3 -0
- package/dist/prompts/developer/text.d.ts +3 -0
- package/dist/prompts/developer/text.d.ts.map +1 -0
- package/dist/prompts/developer/text.js +31 -0
- package/dist/prompts/{system.d.ts → developer/tool.d.ts} +1 -1
- package/dist/prompts/developer/tool.d.ts.map +1 -0
- package/dist/tools/core/ai-tools.d.ts.map +1 -1
- package/dist/tools/core/ai-tools.js +37 -13
- package/dist/utils/ai-handler.d.ts +16 -11
- package/dist/utils/ai-handler.d.ts.map +1 -1
- package/dist/utils/ai-handler.js +148 -33
- package/package.json +1 -1
- package/dist/prompts/system.d.ts.map +0 -1
- /package/dist/prompts/{system.js → developer/tool.js} +0 -0
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
|
|
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
|
|
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
|
package/dist/client.d.ts.map
CHANGED
|
@@ -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
|
|
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-
|
|
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
|
-
|
|
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 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/prompts/developer/index.ts"],"names":[],"mappings":";;;;AAGA,wBAA8B"}
|
|
@@ -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=
|
|
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;
|
|
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-
|
|
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
|
-
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
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
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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;
|
|
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"}
|
package/dist/utils/ai-handler.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { OpenAI } from "openai";
|
|
2
|
-
import
|
|
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
|
-
|
|
122
|
+
if (developerPrompt.includes(toolsSubstringIdentifier)) {
|
|
123
|
+
developerPrompt = developerPrompt.replace(toolsSubstringIdentifier, JSON.stringify(tools, null, 2));
|
|
124
|
+
}
|
|
128
125
|
const messages = [
|
|
129
|
-
{ role: "
|
|
126
|
+
{ role: "developer", content: developerPrompt },
|
|
130
127
|
{ role: "user", content: query },
|
|
131
128
|
];
|
|
132
|
-
if (
|
|
133
|
-
|
|
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
|
|
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
|
-
|
|
159
|
+
tool_choice: "required",
|
|
144
160
|
});
|
|
145
161
|
if (!response.choices?.length) {
|
|
146
|
-
return {
|
|
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 {
|
|
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:
|
|
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 {
|
|
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
|
-
|
|
176
|
-
|
|
177
|
-
|
|
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
|
|
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
|
-
|
|
230
|
+
tool_choice: "required",
|
|
189
231
|
});
|
|
190
232
|
if (!response.choices?.length) {
|
|
191
|
-
return {
|
|
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 {
|
|
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 {
|
|
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 {
|
|
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
|
-
|
|
218
|
-
|
|
219
|
-
|
|
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 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"system.d.ts","sourceRoot":"","sources":["../../src/prompts/system.ts"],"names":[],"mappings":";AAAA,wBAsCE"}
|
|
File without changes
|