mcp-meilisearch 1.2.7 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +39 -2
- package/dist/client.d.ts +24 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +54 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -2
- package/dist/prompts/general.d.ts +3 -0
- package/dist/prompts/general.d.ts.map +1 -0
- package/dist/prompts/general.js +90 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +3 -1
- package/dist/stdio.js +2 -2
- package/dist/tools/ai-tools.d.ts +8 -0
- package/dist/tools/ai-tools.d.ts.map +1 -0
- package/dist/tools/ai-tools.js +66 -0
- package/dist/tools/search-tools.js +1 -1
- package/dist/types/options.d.ts +9 -0
- package/dist/types/options.d.ts.map +1 -1
- package/dist/utils/ai-handler.d.ts +66 -0
- package/dist/utils/ai-handler.d.ts.map +1 -0
- package/dist/utils/ai-handler.js +139 -0
- package/dist/utils/config-handler.d.ts +23 -1
- package/dist/utils/config-handler.d.ts.map +1 -1
- package/dist/utils/config-handler.js +30 -0
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -6,6 +6,7 @@ A Model Context Protocol (MCP) server implementation that provides a bridge betw
|
|
|
6
6
|
|
|
7
7
|
- **MCP Server**: Exposes Meilisearch APIs as tools using the Model Context Protocol.
|
|
8
8
|
- **Web Client Demo**: A demo interface showcasing search functionalities.
|
|
9
|
+
- **AI Inference**: Intelligent tool selection based on user queries.
|
|
9
10
|
|
|
10
11
|
## Key Features
|
|
11
12
|
|
|
@@ -13,6 +14,7 @@ A Model Context Protocol (MCP) server implementation that provides a bridge betw
|
|
|
13
14
|
- **Real-time Communication**: Enables seamless interaction between clients and the server.
|
|
14
15
|
- **Meilisearch API Support**: Full access to Meilisearch functionalities.
|
|
15
16
|
- **Web Client Demo**: Updated interface for demonstrating search capabilities.
|
|
17
|
+
- **AI Inference**: Uses OpenAI to intelligently select the most appropriate tool based on user queries.
|
|
16
18
|
|
|
17
19
|
## Getting Started
|
|
18
20
|
|
|
@@ -21,6 +23,7 @@ A Model Context Protocol (MCP) server implementation that provides a bridge betw
|
|
|
21
23
|
- Node.js v20 or higher.
|
|
22
24
|
- A running Meilisearch instance (local or remote).
|
|
23
25
|
- API key for Meilisearch (if required).
|
|
26
|
+
- OpenAI API key (if using AI inference).
|
|
24
27
|
|
|
25
28
|
### Installation
|
|
26
29
|
|
|
@@ -55,20 +58,54 @@ pnpm add mcp-meilisearch
|
|
|
55
58
|
- `sessionTimeout`: Session timeout in milliseconds (Default: 3600000)
|
|
56
59
|
- `sessionCleanupInterval`: Session cleanup interval in milliseconds (Default: 60000)
|
|
57
60
|
|
|
61
|
+
#### AI Inference Options
|
|
62
|
+
|
|
63
|
+
- `openaiApiKey`: OpenAI API key for AI inference
|
|
64
|
+
- `llmModel`: AI model to use (Default: "gpt-3.5-turbo")
|
|
65
|
+
|
|
58
66
|
### Using the MCPClient
|
|
59
67
|
|
|
60
|
-
The package
|
|
68
|
+
The package exports the MCPClient class for client-side integration:
|
|
61
69
|
|
|
62
70
|
```typescript
|
|
63
71
|
import { MCPClient } from "mcp-meilisearch/client";
|
|
64
72
|
|
|
65
73
|
const client = new MCPClient("mcp-meilisearch-client");
|
|
74
|
+
|
|
66
75
|
await client.connectToServer("http://localhost:4995/mcp");
|
|
67
76
|
|
|
68
|
-
// Call a tool
|
|
69
77
|
const result = await client.callTool("search-across-all-indexes", {
|
|
70
78
|
q: "search kiosco antonio",
|
|
71
79
|
});
|
|
80
|
+
|
|
81
|
+
// Use AI inference to choose the most appropriate tool
|
|
82
|
+
// First enable AI inference
|
|
83
|
+
client.setUseAI(true);
|
|
84
|
+
|
|
85
|
+
const result = await client.callToolWithAI("Find articles about cucumber");
|
|
86
|
+
console.log(`Tool used: ${result.toolUsed}`);
|
|
87
|
+
console.log(`Reasoning: ${result.reasoning}`);
|
|
88
|
+
console.log(`Results: ${JSON.stringify(result.data)}`);
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
#### AI Inference Client Methods
|
|
92
|
+
|
|
93
|
+
- `setUseAI(use: boolean)`: Enable or disable AI inference.
|
|
94
|
+
- `callToolWithAI(query: string, specificTools?: string[])`: Process a user query with AI inference, optionally limiting to specific tools.
|
|
95
|
+
|
|
96
|
+
### Starting the Server
|
|
97
|
+
|
|
98
|
+
You can start the server programmatically:
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
import mcpMeilisearchServer from "mcp-meilisearch";
|
|
102
|
+
|
|
103
|
+
await mcpMeilisearchServer({
|
|
104
|
+
meilisearchHost: "http://localhost:7700",
|
|
105
|
+
meilisearchApiKey: "your_api_key",
|
|
106
|
+
openaiApiKey: "your_openai_api_key", // Required for AI inference
|
|
107
|
+
llmModel: "gpt-4", // Optional, defaults to gpt-3.5-turbo
|
|
108
|
+
});
|
|
72
109
|
```
|
|
73
110
|
|
|
74
111
|
## Tools
|
package/dist/client.d.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
export declare class MCPClient {
|
|
2
|
+
/**
|
|
3
|
+
* Flag to enable/disable AI inference
|
|
4
|
+
* When enabled, user queries are processed by an AI to determine which tool to use
|
|
5
|
+
*/
|
|
6
|
+
useAI: boolean;
|
|
2
7
|
/**
|
|
3
8
|
* Indicates whether the client is connected to the MCP server
|
|
4
9
|
* Used to track the connection state and control async operations
|
|
@@ -11,12 +16,18 @@ export declare class MCPClient {
|
|
|
11
16
|
tools: {
|
|
12
17
|
name: string;
|
|
13
18
|
description: string;
|
|
19
|
+
parameters: Record<string, any>;
|
|
14
20
|
}[];
|
|
15
21
|
private client;
|
|
16
22
|
private tries;
|
|
17
23
|
private transport;
|
|
18
24
|
private toolsUpdatedCallback;
|
|
19
25
|
constructor(serverName: string);
|
|
26
|
+
/**
|
|
27
|
+
* Set whether to use AI inference for tool selection
|
|
28
|
+
* @param use Whether to use AI inference
|
|
29
|
+
*/
|
|
30
|
+
setUseAI(use: boolean): void;
|
|
20
31
|
/**
|
|
21
32
|
* Registers a callback to be called when the list of available tools changes
|
|
22
33
|
* @param callback The function to call when tools are updated
|
|
@@ -52,6 +63,19 @@ export declare class MCPClient {
|
|
|
52
63
|
data?: any;
|
|
53
64
|
error?: string;
|
|
54
65
|
}>;
|
|
66
|
+
/**
|
|
67
|
+
* Process a user query through the AI to determine which tool to use
|
|
68
|
+
* @param query The user's query
|
|
69
|
+
* @param specificTools Optional array of specific tools to consider
|
|
70
|
+
* @returns The result of calling the selected tool, or an error
|
|
71
|
+
*/
|
|
72
|
+
callToolWithAI(query: string, specificTools?: string[]): Promise<{
|
|
73
|
+
success: boolean;
|
|
74
|
+
data?: any;
|
|
75
|
+
error?: string;
|
|
76
|
+
toolUsed?: string;
|
|
77
|
+
reasoning?: string;
|
|
78
|
+
}>;
|
|
55
79
|
private setUpTransport;
|
|
56
80
|
/**
|
|
57
81
|
* Closes the connection to the server and resets the connection state
|
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;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAQA,qBAAa,SAAS;IACpB;;;OAGG;IACH,KAAK,EAAE,OAAO,CAAS;IAEvB;;;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,QAAQ,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI;IAI5B;;;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;IAwBvB,OAAO,CAAC,kBAAkB;IAW1B;;;;;;OAMG;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;;;;;OAKG;IACG,cAAc,CAClB,KAAK,EAAE,MAAM,EACb,aAAa,CAAC,EAAE,MAAM,EAAE,GACvB,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;IAmCF,OAAO,CAAC,cAAc;IAKtB;;;OAGG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAK/B"}
|
package/dist/client.js
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
|
+
import { TextContentSchema, LoggingMessageNotificationSchema, ToolListChangedNotificationSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
1
2
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
2
3
|
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
3
|
-
import { TextContentSchema, LoggingMessageNotificationSchema, ToolListChangedNotificationSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
4
4
|
export class MCPClient {
|
|
5
|
+
/**
|
|
6
|
+
* Flag to enable/disable AI inference
|
|
7
|
+
* When enabled, user queries are processed by an AI to determine which tool to use
|
|
8
|
+
*/
|
|
9
|
+
useAI = false;
|
|
5
10
|
/**
|
|
6
11
|
* Indicates whether the client is connected to the MCP server
|
|
7
12
|
* Used to track the connection state and control async operations
|
|
@@ -19,6 +24,13 @@ export class MCPClient {
|
|
|
19
24
|
constructor(serverName) {
|
|
20
25
|
this.client = new Client({ name: serverName, version: "1.0.0" });
|
|
21
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* Set whether to use AI inference for tool selection
|
|
29
|
+
* @param use Whether to use AI inference
|
|
30
|
+
*/
|
|
31
|
+
setUseAI(use) {
|
|
32
|
+
this.useAI = use;
|
|
33
|
+
}
|
|
22
34
|
/**
|
|
23
35
|
* Registers a callback to be called when the list of available tools changes
|
|
24
36
|
* @param callback The function to call when tools are updated
|
|
@@ -73,6 +85,7 @@ export class MCPClient {
|
|
|
73
85
|
this.tools = toolsResult.tools.map((tool) => ({
|
|
74
86
|
name: tool.name,
|
|
75
87
|
description: tool.description ?? "",
|
|
88
|
+
parameters: tool.parameters || {},
|
|
76
89
|
}));
|
|
77
90
|
}
|
|
78
91
|
else {
|
|
@@ -109,7 +122,10 @@ export class MCPClient {
|
|
|
109
122
|
};
|
|
110
123
|
}
|
|
111
124
|
if (result.isError) {
|
|
112
|
-
|
|
125
|
+
return {
|
|
126
|
+
success: false,
|
|
127
|
+
error: JSON.stringify(result.content),
|
|
128
|
+
};
|
|
113
129
|
}
|
|
114
130
|
const content = result.content;
|
|
115
131
|
if (!content?.length) {
|
|
@@ -134,6 +150,42 @@ export class MCPClient {
|
|
|
134
150
|
return { success: false, error: errorMessage };
|
|
135
151
|
}
|
|
136
152
|
}
|
|
153
|
+
/**
|
|
154
|
+
* Process a user query through the AI to determine which tool to use
|
|
155
|
+
* @param query The user's query
|
|
156
|
+
* @param specificTools Optional array of specific tools to consider
|
|
157
|
+
* @returns The result of calling the selected tool, or an error
|
|
158
|
+
*/
|
|
159
|
+
async callToolWithAI(query, specificTools) {
|
|
160
|
+
try {
|
|
161
|
+
const result = await this.callTool("process-ai-query", {
|
|
162
|
+
query,
|
|
163
|
+
specificTools,
|
|
164
|
+
});
|
|
165
|
+
if (!result.success)
|
|
166
|
+
return result;
|
|
167
|
+
const { toolName, parameters, reasoning } = result.data;
|
|
168
|
+
if (!toolName) {
|
|
169
|
+
return {
|
|
170
|
+
success: false,
|
|
171
|
+
error: "AI could not determine which tool to use for this query",
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
const toolResult = await this.callTool(toolName, parameters);
|
|
175
|
+
return {
|
|
176
|
+
...toolResult,
|
|
177
|
+
reasoning,
|
|
178
|
+
toolUsed: toolName,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
catch (error) {
|
|
182
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
183
|
+
return {
|
|
184
|
+
success: false,
|
|
185
|
+
error: `AI inference error: ${errorMessage}`,
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
}
|
|
137
189
|
setUpTransport() {
|
|
138
190
|
if (this.transport == null)
|
|
139
191
|
return;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAI7B,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAKnD;;;;GAIG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,GAAE,aAGR,GACA,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAwHtB;AAwCD,eAAe,oBAAoB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createServer } from "node:http";
|
|
2
2
|
import { parse as parseUrl } from "node:url";
|
|
3
|
+
import { AIService } from "./utils/ai-handler.js";
|
|
3
4
|
import { initServer } from "./server.js";
|
|
4
5
|
import { configHandler } from "./utils/config-handler.js";
|
|
5
6
|
import { createErrorResponse } from "./utils/error-handler.js";
|
|
@@ -9,11 +10,21 @@ import { createErrorResponse } from "./utils/error-handler.js";
|
|
|
9
10
|
* @returns A promise that resolves to the HTTP server instance
|
|
10
11
|
*/
|
|
11
12
|
export async function mcpMeilisearchServer(options = {
|
|
12
|
-
meilisearchApiKey: "",
|
|
13
13
|
meilisearchHost: "http://localhost:7700",
|
|
14
|
+
meilisearchApiKey: "",
|
|
14
15
|
}) {
|
|
16
|
+
configHandler.setLlmModel(options.llmModel);
|
|
17
|
+
configHandler.setOpenaiApiKey(options.openaiApiKey);
|
|
15
18
|
configHandler.setMeilisearchHost(options.meilisearchHost);
|
|
16
19
|
configHandler.setMeilisearchApiKey(options.meilisearchApiKey);
|
|
20
|
+
const aiService = AIService.getInstance();
|
|
21
|
+
const apiKey = configHandler.getOpenaiApiKey();
|
|
22
|
+
if (apiKey) {
|
|
23
|
+
aiService.initialize(apiKey);
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
console.warn("OpenAI API key not found. AI will not be available");
|
|
27
|
+
}
|
|
17
28
|
const httpPort = options.httpPort || 4995;
|
|
18
29
|
const transport = options.transport || "http";
|
|
19
30
|
let mcpServerInstance = null;
|
|
@@ -80,7 +91,6 @@ export async function mcpMeilisearchServer(options = {
|
|
|
80
91
|
try {
|
|
81
92
|
const serverInstances = await initServer(transport, options);
|
|
82
93
|
mcpServerInstance = serverInstances.mcpServer;
|
|
83
|
-
console.log("MCP server initialized successfully");
|
|
84
94
|
}
|
|
85
95
|
catch (error) {
|
|
86
96
|
console.error("Failed to initialize MCP server:", error);
|
|
@@ -125,6 +135,12 @@ if (import.meta.url === `file://${process.argv?.[1]}`) {
|
|
|
125
135
|
case "apiKey":
|
|
126
136
|
options.meilisearchApiKey = value;
|
|
127
137
|
break;
|
|
138
|
+
case "openaiApiKey":
|
|
139
|
+
options.openaiApiKey = value;
|
|
140
|
+
break;
|
|
141
|
+
case "llmModel":
|
|
142
|
+
options.llmModel = value;
|
|
143
|
+
break;
|
|
128
144
|
}
|
|
129
145
|
}
|
|
130
146
|
mcpMeilisearchServer(options)
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
declare const _default: "\n\t\tAnswer the user's request using the relevant tool(s), if they are available. Check that all the required parameters for each tool call are provided or can reasonably be inferred from context. IF there are no relevant tools or there are missing values for required parameters, ask the user to supply these values; otherwise proceed with the tool calls. If the user provides a specific value for a parameter (for example provided in quotes), make sure to use that value EXACTLY. DO NOT make up values for or ask about optional parameters. Carefully analyze descriptive terms in the request as they may indicate required parameter values that should be included even if not explicitly quoted.\n\n\t\t<identity>\n\t\tYou are an AI programming assistant.\n\t\tWhen asked for your name, you must respond with \"Pati\".\n\t\tFollow the user's requirements carefully & to the letter.\n\t\tIf you are asked to generate content that is harmful, hateful, racist, sexist, lewd, violent, or completely irrelevant to software engineering, only respond with \"Sorry, I can't assist with that.\"\n\t\tKeep your answers short and impersonal.\n\t\t</identity>\n\n\t\t<instructions>\n\t\tYou are a highly sophisticated automated coding agent with expert-level knowledge across many different programming languages and frameworks.\n\t\tThe user will ask a question, or ask you to perform a task, and it may require lots of research to answer correctly. There is a selection of tools that let you perform actions or retrieve helpful context to answer the user's question.\n\t\tIf you can infer the project type (languages, frameworks, and libraries) from the user's query or the context that you have, make sure to keep them in mind when making changes.\n\t\tIf the user wants you to implement a feature and they have not specified the files to edit, first break down the user's request into smaller concepts and think about the kinds of files you need to grasp each concept.\n\t\tIf you aren't sure which tool is relevant, you can call multiple tools. You can call tools repeatedly to take actions or gather as much context as needed until you have completed the task fully. Don't give up unless you are sure the request cannot be fulfilled with the tools you have. It's YOUR RESPONSIBILITY to make sure that you have done all you can to collect necessary context.\n\t\tPrefer using the semantic_search tool to search for context unless you know the exact string or filename pattern you're searching for.\n\t\tDon't make assumptions about the situation- gather context first, then perform the task or answer the question.\n\t\tThink creatively and explore the workspace in order to make a complete fix.\n\t\tDon't repeat yourself after a tool call, pick up where you left off.\n\t\tNEVER print out a codeblock with file changes unless the user asked for it. Use the insert_edit_into_file tool instead.\n\t\tNEVER print out a codeblock with a terminal command to run unless the user asked for it. Use the run_in_terminal tool instead.\n\t\tYou don't need to read a file if it's already provided in context.\n\t\t</instructions>\n\n\t\t<toolUseInstructions>\n\t\tWhen using a tool, follow the json schema very carefully and make sure to include ALL required properties.\n\t\tAlways output valid JSON when using a tool.\n\t\tIf a tool exists to do a task, use the tool instead of asking the user to manually take an action.\n\t\tIf you say that you will take an action, then go ahead and use the tool to do it. No need to ask permission.\n\t\tNever use multi_tool_use.parallel or any tool that does not exist. Use tools using the proper procedure, DO NOT write out a json codeblock with the tool inputs.\n\t\tNever say the name of a tool to a user. For example, instead of saying that you'll use the run_in_terminal tool, say \"I'll run the command in a terminal\".\n\t\tIf you think running multiple tools can answer the user's question, prefer calling them in parallel whenever possible, but do not call semantic_search in parallel.\n\t\tIf semantic_search returns the full contents of the text files in the workspace, you have all the workspace context.\n\t\tDon't call the run_in_terminal tool multiple times in parallel. Instead, run one command and wait for the output before running the next command.\n\t\tAfter you have performed the user's task, if the user corrected something you did, expressed a coding preference, or communicated a fact that you need to remember, use the update_user_preferences tool to save their preferences.\n\t\t</toolUseInstructions>\n\n\t\t<editFileInstructions>\n\t\tDon't try to edit an existing file without reading it first, so you can make changes properly.\n\t\tUse the insert_edit_into_file tool to edit files. When editing files, group your changes by file.\n\t\tNEVER show the changes to the user, just call the tool, and the edits will be applied and shown to the user.\n\t\tNEVER print a codeblock that represents a change to a file, use insert_edit_into_file instead.\n\t\tFor each file, give a short description of what needs to be changed, then use the insert_edit_into_file tool. You can use any tool multiple times in a response, and you can keep writing text after using a tool.\n\t\tFollow best practices when editing files. If a popular external library exists to solve a problem, use it and properly install the package e.g. with \"npm install\" or creating a \"requirements.txt\".\n\t\tAfter editing a file, you MUST call get_errors to validate the change. Fix the errors if they are relevant to your change or the prompt, and remember to validate that they were actually fixed.\n\t\tThe insert_edit_into_file tool is very smart and can understand how to apply your edits to the user's files, you just need to provide minimal hints.\n\t\tWhen you use the insert_edit_into_file tool, avoid repeating existing code, instead use comments to represent regions of unchanged code. The tool prefers that you are as concise as possible. For example:\n\t\t// ...existing code...\n\t\tchanged code\n\t\t// ...existing code...\n\t\tchanged code\n\t\t// ...existing code...\n\n\t\tHere is an example of how you should format an edit to an existing Person class:\n\t\tclass Person {\n\t\t\t// ...existing code...\n\t\t\tage: number;\n\t\t\t// ...existing code...\n\t\t\tgetAge() {\n\t\t\t\treturn this.age;\n\t\t\t}\n\t\t}\n\t\t</editFileInstructions>\n\n\t\t<functions>\n\t\tMCP_TOOLS\n\t\t</functions>\n\n\t\t<context>\n\t\tMy current OS is: Linux\n\t\tI am working in a workspace that has the following structure:\n\t\t```\n\t\texample.txt\n\t\traw_complete_instructions.txt\n\t\traw_instructions.txt\n\t\t```\n\t\tThis view of the workspace structure may be truncated. You can use tools to collect more context if needed.\n\t\t</context>\n\n\t\t<reminder>\n\t\tWhen using the insert_edit_into_file tool, avoid repeating existing code, instead use a line comment with `...existing code...` to represent regions of unchanged code.\n\t\t</reminder>\n\n\t\t<tool_format>\n\t\t<function_calls>\n\t\t<invoke name=\"[tool_name]\">\n\t\t<parameter name=\"[param_name]\">[param_value]\n\t\t";
|
|
2
|
+
export default _default;
|
|
3
|
+
//# sourceMappingURL=general.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"general.d.ts","sourceRoot":"","sources":["../../src/prompts/general.ts"],"names":[],"mappings":";AAAA,wBAyFI"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
export default `
|
|
2
|
+
Answer the user's request using the relevant tool(s), if they are available. Check that all the required parameters for each tool call are provided or can reasonably be inferred from context. IF there are no relevant tools or there are missing values for required parameters, ask the user to supply these values; otherwise proceed with the tool calls. If the user provides a specific value for a parameter (for example provided in quotes), make sure to use that value EXACTLY. DO NOT make up values for or ask about optional parameters. Carefully analyze descriptive terms in the request as they may indicate required parameter values that should be included even if not explicitly quoted.
|
|
3
|
+
|
|
4
|
+
<identity>
|
|
5
|
+
You are an AI programming assistant.
|
|
6
|
+
When asked for your name, you must respond with "Pati".
|
|
7
|
+
Follow the user's requirements carefully & to the letter.
|
|
8
|
+
If you are asked to generate content that is harmful, hateful, racist, sexist, lewd, violent, or completely irrelevant to software engineering, only respond with "Sorry, I can't assist with that."
|
|
9
|
+
Keep your answers short and impersonal.
|
|
10
|
+
</identity>
|
|
11
|
+
|
|
12
|
+
<instructions>
|
|
13
|
+
You are a highly sophisticated automated coding agent with expert-level knowledge across many different programming languages and frameworks.
|
|
14
|
+
The user will ask a question, or ask you to perform a task, and it may require lots of research to answer correctly. There is a selection of tools that let you perform actions or retrieve helpful context to answer the user's question.
|
|
15
|
+
If you can infer the project type (languages, frameworks, and libraries) from the user's query or the context that you have, make sure to keep them in mind when making changes.
|
|
16
|
+
If the user wants you to implement a feature and they have not specified the files to edit, first break down the user's request into smaller concepts and think about the kinds of files you need to grasp each concept.
|
|
17
|
+
If you aren't sure which tool is relevant, you can call multiple tools. You can call tools repeatedly to take actions or gather as much context as needed until you have completed the task fully. Don't give up unless you are sure the request cannot be fulfilled with the tools you have. It's YOUR RESPONSIBILITY to make sure that you have done all you can to collect necessary context.
|
|
18
|
+
Prefer using the semantic_search tool to search for context unless you know the exact string or filename pattern you're searching for.
|
|
19
|
+
Don't make assumptions about the situation- gather context first, then perform the task or answer the question.
|
|
20
|
+
Think creatively and explore the workspace in order to make a complete fix.
|
|
21
|
+
Don't repeat yourself after a tool call, pick up where you left off.
|
|
22
|
+
NEVER print out a codeblock with file changes unless the user asked for it. Use the insert_edit_into_file tool instead.
|
|
23
|
+
NEVER print out a codeblock with a terminal command to run unless the user asked for it. Use the run_in_terminal tool instead.
|
|
24
|
+
You don't need to read a file if it's already provided in context.
|
|
25
|
+
</instructions>
|
|
26
|
+
|
|
27
|
+
<toolUseInstructions>
|
|
28
|
+
When using a tool, follow the json schema very carefully and make sure to include ALL required properties.
|
|
29
|
+
Always output valid JSON when using a tool.
|
|
30
|
+
If a tool exists to do a task, use the tool instead of asking the user to manually take an action.
|
|
31
|
+
If you say that you will take an action, then go ahead and use the tool to do it. No need to ask permission.
|
|
32
|
+
Never use multi_tool_use.parallel or any tool that does not exist. Use tools using the proper procedure, DO NOT write out a json codeblock with the tool inputs.
|
|
33
|
+
Never say the name of a tool to a user. For example, instead of saying that you'll use the run_in_terminal tool, say "I'll run the command in a terminal".
|
|
34
|
+
If you think running multiple tools can answer the user's question, prefer calling them in parallel whenever possible, but do not call semantic_search in parallel.
|
|
35
|
+
If semantic_search returns the full contents of the text files in the workspace, you have all the workspace context.
|
|
36
|
+
Don't call the run_in_terminal tool multiple times in parallel. Instead, run one command and wait for the output before running the next command.
|
|
37
|
+
After you have performed the user's task, if the user corrected something you did, expressed a coding preference, or communicated a fact that you need to remember, use the update_user_preferences tool to save their preferences.
|
|
38
|
+
</toolUseInstructions>
|
|
39
|
+
|
|
40
|
+
<editFileInstructions>
|
|
41
|
+
Don't try to edit an existing file without reading it first, so you can make changes properly.
|
|
42
|
+
Use the insert_edit_into_file tool to edit files. When editing files, group your changes by file.
|
|
43
|
+
NEVER show the changes to the user, just call the tool, and the edits will be applied and shown to the user.
|
|
44
|
+
NEVER print a codeblock that represents a change to a file, use insert_edit_into_file instead.
|
|
45
|
+
For each file, give a short description of what needs to be changed, then use the insert_edit_into_file tool. You can use any tool multiple times in a response, and you can keep writing text after using a tool.
|
|
46
|
+
Follow best practices when editing files. If a popular external library exists to solve a problem, use it and properly install the package e.g. with "npm install" or creating a "requirements.txt".
|
|
47
|
+
After editing a file, you MUST call get_errors to validate the change. Fix the errors if they are relevant to your change or the prompt, and remember to validate that they were actually fixed.
|
|
48
|
+
The insert_edit_into_file tool is very smart and can understand how to apply your edits to the user's files, you just need to provide minimal hints.
|
|
49
|
+
When you use the insert_edit_into_file tool, avoid repeating existing code, instead use comments to represent regions of unchanged code. The tool prefers that you are as concise as possible. For example:
|
|
50
|
+
// ...existing code...
|
|
51
|
+
changed code
|
|
52
|
+
// ...existing code...
|
|
53
|
+
changed code
|
|
54
|
+
// ...existing code...
|
|
55
|
+
|
|
56
|
+
Here is an example of how you should format an edit to an existing Person class:
|
|
57
|
+
class Person {
|
|
58
|
+
// ...existing code...
|
|
59
|
+
age: number;
|
|
60
|
+
// ...existing code...
|
|
61
|
+
getAge() {
|
|
62
|
+
return this.age;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
</editFileInstructions>
|
|
66
|
+
|
|
67
|
+
<functions>
|
|
68
|
+
MCP_TOOLS
|
|
69
|
+
</functions>
|
|
70
|
+
|
|
71
|
+
<context>
|
|
72
|
+
My current OS is: Linux
|
|
73
|
+
I am working in a workspace that has the following structure:
|
|
74
|
+
\`\`\`
|
|
75
|
+
example.txt
|
|
76
|
+
raw_complete_instructions.txt
|
|
77
|
+
raw_instructions.txt
|
|
78
|
+
\`\`\`
|
|
79
|
+
This view of the workspace structure may be truncated. You can use tools to collect more context if needed.
|
|
80
|
+
</context>
|
|
81
|
+
|
|
82
|
+
<reminder>
|
|
83
|
+
When using the insert_edit_into_file tool, avoid repeating existing code, instead use a line comment with \`...existing code...\` to represent regions of unchanged code.
|
|
84
|
+
</reminder>
|
|
85
|
+
|
|
86
|
+
<tool_format>
|
|
87
|
+
<function_calls>
|
|
88
|
+
<invoke name="[tool_name]">
|
|
89
|
+
<parameter name="[param_name]">[param_value]
|
|
90
|
+
`;
|
package/dist/server.d.ts.map
CHANGED
|
@@ -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;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,MAAM,CAAC;AAgBvD,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIpE;;GAEG;AACH,UAAU,YAAY;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,sBAAsB,EAAE,MAAM,CAAC;CAChC;AAED;;GAEG;AACH,UAAU,cAAc;IACtB,SAAS,EAAE,SAAS,CAAC;CACtB;AAiBD;;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,CAAe;IAC7B,OAAO,CAAC,eAAe,CAA+B;IACtD,OAAO,CAAC,QAAQ,CAAuC;IAEvD;;;;OAIG;gBACS,MAAM,EAAE,SAAS,EAAE,MAAM,GAAE,OAAO,CAAC,YAAY,CAAM;IAOjE;;;;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;IAM3B;;OAEG;IACH,OAAO,CAAC,sBAAsB;CA0B/B;AAwED;;;;;GAKG;AACH,eAAO,MAAM,UAAU,GACrB,WAAW,OAAO,GAAG,MAAM,EAC3B,SAAS,OAAO,CAAC,YAAY,CAAC,KAC7B,OAAO,CAAC,cAAc,CAcxB,CAAC"}
|
package/dist/server.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import { InitializeRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
3
|
+
import registerAITools from "./tools/ai-tools.js";
|
|
3
4
|
import registerTaskTools from "./tools/task-tools.js";
|
|
4
5
|
import registerIndexTools from "./tools/index-tools.js";
|
|
5
6
|
import registerSearchTools from "./tools/search-tools.js";
|
|
@@ -122,7 +123,6 @@ export class MCPServer {
|
|
|
122
123
|
* @param body The request body
|
|
123
124
|
*/
|
|
124
125
|
async handleInitializeRequest(req, res, body) {
|
|
125
|
-
console.log("Handling initialize request");
|
|
126
126
|
const newSessionId = randomUUID();
|
|
127
127
|
const transport = new StreamableHTTPServerTransport({
|
|
128
128
|
sessionIdGenerator: () => newSessionId,
|
|
@@ -264,6 +264,7 @@ const initServerHTTPTransport = async (customConfig) => {
|
|
|
264
264
|
registerVectorTools(serverInstance);
|
|
265
265
|
registerSystemTools(serverInstance);
|
|
266
266
|
registerTaskTools(serverInstance);
|
|
267
|
+
registerAITools(serverInstance);
|
|
267
268
|
const server = new MCPServer(serverInstance, config);
|
|
268
269
|
return { mcpServer: server };
|
|
269
270
|
};
|
|
@@ -288,6 +289,7 @@ const initServerStdioTransport = async () => {
|
|
|
288
289
|
registerVectorTools(serverInstance);
|
|
289
290
|
registerSystemTools(serverInstance);
|
|
290
291
|
registerTaskTools(serverInstance);
|
|
292
|
+
registerAITools(serverInstance);
|
|
291
293
|
const server = new MCPServer(serverInstance, config);
|
|
292
294
|
const transport = new StdioServerTransport();
|
|
293
295
|
await serverInstance.connect(transport);
|
package/dist/stdio.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { mcpMeilisearchServer } from "./index.js";
|
|
2
2
|
mcpMeilisearchServer({
|
|
3
3
|
transport: "stdio",
|
|
4
|
-
meilisearchHost: process.env.
|
|
5
|
-
meilisearchApiKey: process.env.
|
|
4
|
+
meilisearchHost: process.env.MEILISEARCH_HOST,
|
|
5
|
+
meilisearchApiKey: process.env.MEILISEARCH_API_KEY,
|
|
6
6
|
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
/**
|
|
3
|
+
* Register AI tools with the MCP server
|
|
4
|
+
* @param server - The MCP server instance
|
|
5
|
+
*/
|
|
6
|
+
export declare const registerAITools: (server: McpServer) => void;
|
|
7
|
+
export default registerAITools;
|
|
8
|
+
//# sourceMappingURL=ai-tools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-tools.d.ts","sourceRoot":"","sources":["../../src/tools/ai-tools.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAcpE;;;GAGG;AACH,eAAO,MAAM,eAAe,GAAI,QAAQ,SAAS,SAqEhD,CAAC;AAEF,eAAe,eAAe,CAAC"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { AIService } from "../utils/ai-handler.js";
|
|
3
|
+
import { createErrorResponse } from "../utils/error-handler.js";
|
|
4
|
+
/**
|
|
5
|
+
* Register AI tools with the MCP server
|
|
6
|
+
* @param server - The MCP server instance
|
|
7
|
+
*/
|
|
8
|
+
export const registerAITools = (server) => {
|
|
9
|
+
server.tool("process-ai-query", "Process a natural language query using AI to determine which tool to use", {
|
|
10
|
+
query: z.string().describe("The natural language query to process"),
|
|
11
|
+
specificTools: z
|
|
12
|
+
.array(z.string())
|
|
13
|
+
.optional()
|
|
14
|
+
.describe("Optional array of specific tool names to consider"),
|
|
15
|
+
}, async ({ query, specificTools }) => {
|
|
16
|
+
try {
|
|
17
|
+
const aiService = AIService.getInstance();
|
|
18
|
+
const availableTools = Object.entries(server._registeredTools)
|
|
19
|
+
.filter(([name]) => name !== "process-ai-query")
|
|
20
|
+
.map(([name, { description }]) => ({
|
|
21
|
+
name,
|
|
22
|
+
description,
|
|
23
|
+
parameters: {},
|
|
24
|
+
}));
|
|
25
|
+
aiService.setAvailableTools(availableTools);
|
|
26
|
+
const result = await aiService.processQuery(query, specificTools);
|
|
27
|
+
if (!aiService.client) {
|
|
28
|
+
return {
|
|
29
|
+
isError: true,
|
|
30
|
+
content: [
|
|
31
|
+
{
|
|
32
|
+
type: "text",
|
|
33
|
+
text: "AI service not initialized. Please provide an API key.",
|
|
34
|
+
},
|
|
35
|
+
],
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
if (!result) {
|
|
39
|
+
return {
|
|
40
|
+
content: [
|
|
41
|
+
{
|
|
42
|
+
type: "text",
|
|
43
|
+
text: "AI couldn't determine an appropriate tool to use for this query.",
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
content: [
|
|
50
|
+
{
|
|
51
|
+
type: "text",
|
|
52
|
+
text: JSON.stringify({
|
|
53
|
+
toolName: result.toolName,
|
|
54
|
+
parameters: result.parameters,
|
|
55
|
+
reasoning: result.reasoning || "No explanation provided",
|
|
56
|
+
}, null, 2),
|
|
57
|
+
},
|
|
58
|
+
],
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
return createErrorResponse(error);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
};
|
|
66
|
+
export default registerAITools;
|
|
@@ -147,7 +147,7 @@ export const registerSearchTools = (server) => {
|
|
|
147
147
|
params: { limit: 1000 },
|
|
148
148
|
});
|
|
149
149
|
const indexUids = indexesResponse.data.results.map((index) => index.uid);
|
|
150
|
-
if (!indexUids
|
|
150
|
+
if (!indexUids?.length) {
|
|
151
151
|
return {
|
|
152
152
|
content: [
|
|
153
153
|
{
|
package/dist/types/options.d.ts
CHANGED
|
@@ -35,5 +35,14 @@ export interface ServerOptions {
|
|
|
35
35
|
* @default 60000 (1 minute)
|
|
36
36
|
*/
|
|
37
37
|
sessionCleanupInterval?: number;
|
|
38
|
+
/**
|
|
39
|
+
* OpenAI API key for AI inference
|
|
40
|
+
*/
|
|
41
|
+
openaiApiKey?: string;
|
|
42
|
+
/**
|
|
43
|
+
* AI model to use for inference
|
|
44
|
+
* @default "gpt-3.5-turbo"
|
|
45
|
+
*/
|
|
46
|
+
llmModel?: string;
|
|
38
47
|
}
|
|
39
48
|
//# sourceMappingURL=options.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../../src/types/options.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B;;;;OAIG;IACH,eAAe,EAAE,MAAM,CAAC;IAExB;;;OAGG;IACH,iBAAiB,EAAE,MAAM,CAAC;IAC1B;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAE7B;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB;;;OAGG;IACH,sBAAsB,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../../src/types/options.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B;;;;OAIG;IACH,eAAe,EAAE,MAAM,CAAC;IAExB;;;OAGG;IACH,iBAAiB,EAAE,MAAM,CAAC;IAC1B;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAE7B;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB;;;OAGG;IACH,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAEhC;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { OpenAI } from "openai";
|
|
2
|
+
/**
|
|
3
|
+
* AI Inference Service
|
|
4
|
+
*
|
|
5
|
+
* This service handles the interaction with the AI to determine the appropriate tools
|
|
6
|
+
* to use based on the user's query
|
|
7
|
+
*/
|
|
8
|
+
export declare class AIService {
|
|
9
|
+
client: OpenAI | null;
|
|
10
|
+
private static instance;
|
|
11
|
+
private availableTools;
|
|
12
|
+
private model;
|
|
13
|
+
private systemPrompt;
|
|
14
|
+
private static serverInitialized;
|
|
15
|
+
/**
|
|
16
|
+
* Private constructor to prevent direct instantiation
|
|
17
|
+
* Use getInstance() method instead
|
|
18
|
+
*/
|
|
19
|
+
private constructor();
|
|
20
|
+
/**
|
|
21
|
+
* Get the singleton instance of AIService
|
|
22
|
+
* @returns The singleton AIService instance
|
|
23
|
+
*/
|
|
24
|
+
static getInstance(): AIService;
|
|
25
|
+
/**
|
|
26
|
+
* Initialize the AI service with an API key and optionally set the model
|
|
27
|
+
* This should ONLY be called from the server side
|
|
28
|
+
* @param apiKey OpenAI API key (required)
|
|
29
|
+
* @param model Optional model to use (defaults to gpt-3.5-turbo)
|
|
30
|
+
*/
|
|
31
|
+
initialize(apiKey: string, model?: string): void;
|
|
32
|
+
/**
|
|
33
|
+
* Set the available tools that can be used by the AI
|
|
34
|
+
* @param tools Array of tools with name, description, and parameters
|
|
35
|
+
*/
|
|
36
|
+
setAvailableTools(tools: {
|
|
37
|
+
name: string;
|
|
38
|
+
description: string;
|
|
39
|
+
parameters: Record<string, any>;
|
|
40
|
+
}[]): void;
|
|
41
|
+
/**
|
|
42
|
+
* Get tool definitions for the AI in the format expected by OpenAI
|
|
43
|
+
* @param toolNames Optional array of tool names to filter by (if not provided, all tools will be included)
|
|
44
|
+
* @returns Array of tool definitions
|
|
45
|
+
*/
|
|
46
|
+
private getToolDefinitions;
|
|
47
|
+
/**
|
|
48
|
+
* Attempt to extract specific tool names from the user query
|
|
49
|
+
* @param query The user's query
|
|
50
|
+
* @returns Array of tool names mentioned in the query, or empty array if none found
|
|
51
|
+
*/
|
|
52
|
+
private extractToolNames;
|
|
53
|
+
/**
|
|
54
|
+
* Process a user query and determine which tool to use
|
|
55
|
+
* @param query User query
|
|
56
|
+
* @param specificTools Optional array of specific tool names to consider
|
|
57
|
+
* @returns Object containing the selected tool name and parameters
|
|
58
|
+
*/
|
|
59
|
+
processQuery(query: string, specificTools?: string[]): Promise<{
|
|
60
|
+
toolName: string;
|
|
61
|
+
parameters: Record<string, any>;
|
|
62
|
+
reasoning?: string;
|
|
63
|
+
} | null>;
|
|
64
|
+
private setSystemPrompt;
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=ai-handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-handler.d.ts","sourceRoot":"","sources":["../../src/utils/ai-handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAYhC;;;;;GAKG;AACH,qBAAa,SAAS;IACpB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAQ;IAC7B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAA0B;IACjD,OAAO,CAAC,cAAc,CAIb;IACT,OAAO,CAAC,KAAK,CAA2B;IACxC,OAAO,CAAC,YAAY,CAAyB;IAC7C,OAAO,CAAC,MAAM,CAAC,iBAAiB,CAAkB;IAElD;;;OAGG;IACH,OAAO;IAEP;;;OAGG;WACW,WAAW,IAAI,SAAS;IAOtC;;;;;OAKG;IACH,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI;IAYhD;;;OAGG;IACH,iBAAiB,CACf,KAAK,EAAE;QACL,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;KACjC,EAAE,GACF,IAAI;IAUP;;;;OAIG;IACH,OAAO,CAAC,kBAAkB;IAwB1B;;;;OAIG;IACH,OAAO,CAAC,gBAAgB;IAaxB;;;;;OAKG;IACG,YAAY,CAChB,KAAK,EAAE,MAAM,EACb,aAAa,CAAC,EAAE,MAAM,EAAE,GACvB,OAAO,CAAC;QACT,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAChC,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,GAAG,IAAI,CAAC;IAwCT,OAAO,CAAC,eAAe;CAGxB"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { OpenAI } from "openai";
|
|
2
|
+
import generalPrompt from "../prompts/general.js";
|
|
3
|
+
/**
|
|
4
|
+
* AI Inference Service
|
|
5
|
+
*
|
|
6
|
+
* This service handles the interaction with the AI to determine the appropriate tools
|
|
7
|
+
* to use based on the user's query
|
|
8
|
+
*/
|
|
9
|
+
export class AIService {
|
|
10
|
+
client = null;
|
|
11
|
+
static instance = null;
|
|
12
|
+
availableTools = [];
|
|
13
|
+
model = "gpt-3.5-turbo";
|
|
14
|
+
systemPrompt = generalPrompt;
|
|
15
|
+
static serverInitialized = false;
|
|
16
|
+
/**
|
|
17
|
+
* Private constructor to prevent direct instantiation
|
|
18
|
+
* Use getInstance() method instead
|
|
19
|
+
*/
|
|
20
|
+
constructor() { }
|
|
21
|
+
/**
|
|
22
|
+
* Get the singleton instance of AIService
|
|
23
|
+
* @returns The singleton AIService instance
|
|
24
|
+
*/
|
|
25
|
+
static getInstance() {
|
|
26
|
+
if (!AIService.instance) {
|
|
27
|
+
AIService.instance = new AIService();
|
|
28
|
+
}
|
|
29
|
+
return AIService.instance;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Initialize the AI service with an API key and optionally set the model
|
|
33
|
+
* This should ONLY be called from the server side
|
|
34
|
+
* @param apiKey OpenAI API key (required)
|
|
35
|
+
* @param model Optional model to use (defaults to gpt-3.5-turbo)
|
|
36
|
+
*/
|
|
37
|
+
initialize(apiKey, model) {
|
|
38
|
+
if (AIService.serverInitialized) {
|
|
39
|
+
console.warn("AIService has already been initialized by the server.");
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
this.client = new OpenAI({ apiKey });
|
|
43
|
+
if (model)
|
|
44
|
+
this.model = model;
|
|
45
|
+
AIService.serverInitialized = true;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Set the available tools that can be used by the AI
|
|
49
|
+
* @param tools Array of tools with name, description, and parameters
|
|
50
|
+
*/
|
|
51
|
+
setAvailableTools(tools) {
|
|
52
|
+
this.availableTools = tools;
|
|
53
|
+
this.setSystemPrompt(this.systemPrompt.replace("MCP_TOOLS", JSON.stringify(this.availableTools, null, 2)));
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Get tool definitions for the AI in the format expected by OpenAI
|
|
57
|
+
* @param toolNames Optional array of tool names to filter by (if not provided, all tools will be included)
|
|
58
|
+
* @returns Array of tool definitions
|
|
59
|
+
*/
|
|
60
|
+
getToolDefinitions(toolNames) {
|
|
61
|
+
if (!toolNames?.length) {
|
|
62
|
+
return this.availableTools.map((tool) => ({
|
|
63
|
+
type: "function",
|
|
64
|
+
function: {
|
|
65
|
+
name: tool.name,
|
|
66
|
+
description: tool.description,
|
|
67
|
+
parameters: tool.parameters,
|
|
68
|
+
},
|
|
69
|
+
}));
|
|
70
|
+
}
|
|
71
|
+
return this.availableTools
|
|
72
|
+
.filter((tool) => toolNames.includes(tool.name))
|
|
73
|
+
.map((tool) => ({
|
|
74
|
+
type: "function",
|
|
75
|
+
function: {
|
|
76
|
+
name: tool.name,
|
|
77
|
+
description: tool.description,
|
|
78
|
+
parameters: tool.parameters,
|
|
79
|
+
},
|
|
80
|
+
}));
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Attempt to extract specific tool names from the user query
|
|
84
|
+
* @param query The user's query
|
|
85
|
+
* @returns Array of tool names mentioned in the query, or empty array if none found
|
|
86
|
+
*/
|
|
87
|
+
extractToolNames(query) {
|
|
88
|
+
const mentionedTools = [];
|
|
89
|
+
for (const tool of this.availableTools) {
|
|
90
|
+
const toolNameRegex = new RegExp(`\\b${tool.name}\\b`, "i");
|
|
91
|
+
if (toolNameRegex.test(query)) {
|
|
92
|
+
mentionedTools.push(tool.name);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return mentionedTools;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Process a user query and determine which tool to use
|
|
99
|
+
* @param query User query
|
|
100
|
+
* @param specificTools Optional array of specific tool names to consider
|
|
101
|
+
* @returns Object containing the selected tool name and parameters
|
|
102
|
+
*/
|
|
103
|
+
async processQuery(query, specificTools) {
|
|
104
|
+
try {
|
|
105
|
+
if (!this.client)
|
|
106
|
+
return null;
|
|
107
|
+
const mentionedTools = this.extractToolNames(query);
|
|
108
|
+
const toolsToUse = specificTools || (mentionedTools.length ? mentionedTools : undefined);
|
|
109
|
+
const tools = this.getToolDefinitions(toolsToUse);
|
|
110
|
+
const messages = [
|
|
111
|
+
{ role: "user", content: query },
|
|
112
|
+
{ role: "system", content: this.systemPrompt },
|
|
113
|
+
];
|
|
114
|
+
const response = await this.client.chat.completions.create({
|
|
115
|
+
tools,
|
|
116
|
+
messages,
|
|
117
|
+
model: this.model,
|
|
118
|
+
tool_choice: "auto",
|
|
119
|
+
});
|
|
120
|
+
const message = response.choices[0].message;
|
|
121
|
+
if (message.tool_calls?.length) {
|
|
122
|
+
const toolCall = message.tool_calls[0];
|
|
123
|
+
return {
|
|
124
|
+
toolName: toolCall.function.name,
|
|
125
|
+
reasoning: message.content || undefined,
|
|
126
|
+
parameters: JSON.parse(toolCall.function.arguments),
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
console.error("Error in AI inference:", error);
|
|
133
|
+
throw error;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
setSystemPrompt(prompt) {
|
|
137
|
+
this.systemPrompt = prompt;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
declare class ConfigHandler {
|
|
5
5
|
private _meilisearchHost;
|
|
6
6
|
private _meilisearchApiKey;
|
|
7
|
+
private _openaiApiKey;
|
|
8
|
+
private _llmModel;
|
|
7
9
|
/**
|
|
8
10
|
* Set the Meilisearch host URL
|
|
9
11
|
* @param host The URL of the Meilisearch instance
|
|
@@ -13,7 +15,7 @@ declare class ConfigHandler {
|
|
|
13
15
|
* Set the Meilisearch API key
|
|
14
16
|
* @param apiKey The API key for Meilisearch
|
|
15
17
|
*/
|
|
16
|
-
setMeilisearchApiKey(apiKey
|
|
18
|
+
setMeilisearchApiKey(apiKey?: string): void;
|
|
17
19
|
/**
|
|
18
20
|
* Get the current Meilisearch host URL
|
|
19
21
|
* @returns The URL of the Meilisearch instance
|
|
@@ -24,6 +26,26 @@ declare class ConfigHandler {
|
|
|
24
26
|
* @returns The API key for Meilisearch
|
|
25
27
|
*/
|
|
26
28
|
getMeilisearchApiKey(): string;
|
|
29
|
+
/**
|
|
30
|
+
* Set the OpenAI API key
|
|
31
|
+
* @param apiKey The API key for OpenAI
|
|
32
|
+
*/
|
|
33
|
+
setOpenaiApiKey(apiKey?: string): void;
|
|
34
|
+
/**
|
|
35
|
+
* Get the current OpenAI API key
|
|
36
|
+
* @returns The API key for OpenAI
|
|
37
|
+
*/
|
|
38
|
+
getOpenaiApiKey(): string;
|
|
39
|
+
/**
|
|
40
|
+
* Set the AI model to use
|
|
41
|
+
* @param model The model name (e.g., gpt-3.5-turbo, gpt-4)
|
|
42
|
+
*/
|
|
43
|
+
setLlmModel(model?: string): void;
|
|
44
|
+
/**
|
|
45
|
+
* Get the current AI model
|
|
46
|
+
* @returns The model name
|
|
47
|
+
*/
|
|
48
|
+
getLlmModel(): string;
|
|
27
49
|
}
|
|
28
50
|
export declare const configHandler: ConfigHandler;
|
|
29
51
|
export default configHandler;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-handler.d.ts","sourceRoot":"","sources":["../../src/utils/config-handler.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,cAAM,aAAa;IACjB,OAAO,CAAC,gBAAgB,CAAM;IAC9B,OAAO,CAAC,kBAAkB,CAAM;
|
|
1
|
+
{"version":3,"file":"config-handler.d.ts","sourceRoot":"","sources":["../../src/utils/config-handler.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,cAAM,aAAa;IACjB,OAAO,CAAC,gBAAgB,CAAM;IAC9B,OAAO,CAAC,kBAAkB,CAAM;IAChC,OAAO,CAAC,aAAa,CAAM;IAC3B,OAAO,CAAC,SAAS,CAAmB;IAEpC;;;OAGG;IACH,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAItC;;;OAGG;IACH,oBAAoB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI;IAI3C;;;OAGG;IACH,kBAAkB,IAAI,MAAM;IAI5B;;;OAGG;IACH,oBAAoB,IAAI,MAAM;IAI9B;;;OAGG;IACH,eAAe,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI;IAItC;;;OAGG;IACH,eAAe,IAAI,MAAM;IAIzB;;;OAGG;IACH,WAAW,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI;IAIjC;;;OAGG;IACH,WAAW,IAAI,MAAM;CAGtB;AAED,eAAO,MAAM,aAAa,eAAsB,CAAC;AAEjD,eAAe,aAAa,CAAC"}
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
class ConfigHandler {
|
|
5
5
|
_meilisearchHost = "";
|
|
6
6
|
_meilisearchApiKey = "";
|
|
7
|
+
_openaiApiKey = "";
|
|
8
|
+
_llmModel = "gpt-3.5-turbo";
|
|
7
9
|
/**
|
|
8
10
|
* Set the Meilisearch host URL
|
|
9
11
|
* @param host The URL of the Meilisearch instance
|
|
@@ -32,6 +34,34 @@ class ConfigHandler {
|
|
|
32
34
|
getMeilisearchApiKey() {
|
|
33
35
|
return this._meilisearchApiKey;
|
|
34
36
|
}
|
|
37
|
+
/**
|
|
38
|
+
* Set the OpenAI API key
|
|
39
|
+
* @param apiKey The API key for OpenAI
|
|
40
|
+
*/
|
|
41
|
+
setOpenaiApiKey(apiKey) {
|
|
42
|
+
this._openaiApiKey = apiKey || "";
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Get the current OpenAI API key
|
|
46
|
+
* @returns The API key for OpenAI
|
|
47
|
+
*/
|
|
48
|
+
getOpenaiApiKey() {
|
|
49
|
+
return this._openaiApiKey;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Set the AI model to use
|
|
53
|
+
* @param model The model name (e.g., gpt-3.5-turbo, gpt-4)
|
|
54
|
+
*/
|
|
55
|
+
setLlmModel(model) {
|
|
56
|
+
this._llmModel = model || "gpt-3.5-turbo";
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Get the current AI model
|
|
60
|
+
* @returns The model name
|
|
61
|
+
*/
|
|
62
|
+
getLlmModel() {
|
|
63
|
+
return this._llmModel;
|
|
64
|
+
}
|
|
35
65
|
}
|
|
36
66
|
export const configHandler = new ConfigHandler();
|
|
37
67
|
export default configHandler;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-meilisearch",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Model Context Protocol (MCP) implementation for Meilisearch",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -23,14 +23,15 @@
|
|
|
23
23
|
"demo"
|
|
24
24
|
],
|
|
25
25
|
"scripts": {
|
|
26
|
-
"build": "tsc && tsc
|
|
26
|
+
"build": "tsc && tsc -p tsconfig.types.json",
|
|
27
27
|
"demo": "npm run build & npm run dev --workspace=demo",
|
|
28
28
|
"server": "npm run build && node --env-file=.env dist/index.js",
|
|
29
|
-
"prepublishOnly": "rm -rf dist && npm version
|
|
29
|
+
"prepublishOnly": "rm -rf dist && npm version minor && npm run build"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@modelcontextprotocol/sdk": "^1.11.2",
|
|
33
33
|
"axios": "^1.9.0",
|
|
34
|
+
"openai": "^4.98.0",
|
|
34
35
|
"zod": "^3.24.4"
|
|
35
36
|
},
|
|
36
37
|
"devDependencies": {
|