@toolplex/client 0.1.1 → 0.1.3
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/dist/mcp-server/clientContext.d.ts +7 -4
- package/dist/mcp-server/clientContext.js +21 -10
- package/dist/mcp-server/index.js +9 -7
- package/dist/mcp-server/logging/telemetryLogger.d.ts +2 -2
- package/dist/mcp-server/logging/telemetryLogger.js +2 -2
- package/dist/mcp-server/policy/callToolObserver.js +4 -2
- package/dist/mcp-server/policy/feedbackPolicy.d.ts +4 -4
- package/dist/mcp-server/policy/feedbackPolicy.js +1 -1
- package/dist/mcp-server/policy/installObserver.js +4 -4
- package/dist/mcp-server/policy/playbookPolicy.d.ts +3 -3
- package/dist/mcp-server/policy/playbookPolicy.js +5 -5
- package/dist/mcp-server/policy/policyEnforcer.d.ts +4 -4
- package/dist/mcp-server/policy/policyEnforcer.js +13 -13
- package/dist/mcp-server/policy/serverPolicy.d.ts +1 -1
- package/dist/mcp-server/policy/serverPolicy.js +4 -2
- package/dist/mcp-server/promptsCache.js +2 -2
- package/dist/mcp-server/registry.d.ts +8 -8
- package/dist/mcp-server/registry.js +19 -17
- package/dist/mcp-server/serversCache.d.ts +1 -1
- package/dist/mcp-server/serversCache.js +6 -6
- package/dist/mcp-server/staticPrompts.js +2 -2
- package/dist/mcp-server/toolDefinitionsCache.d.ts +3 -3
- package/dist/mcp-server/toolDefinitionsCache.js +3 -3
- package/dist/mcp-server/toolHandlers/callToolHandler.d.ts +2 -2
- package/dist/mcp-server/toolHandlers/callToolHandler.js +32 -20
- package/dist/mcp-server/toolHandlers/getServerConfigHandler.d.ts +2 -2
- package/dist/mcp-server/toolHandlers/getServerConfigHandler.js +24 -18
- package/dist/mcp-server/toolHandlers/initHandler.d.ts +2 -2
- package/dist/mcp-server/toolHandlers/initHandler.js +41 -39
- package/dist/mcp-server/toolHandlers/installServerHandler.d.ts +2 -2
- package/dist/mcp-server/toolHandlers/installServerHandler.js +36 -32
- package/dist/mcp-server/toolHandlers/listServersHandler.d.ts +1 -1
- package/dist/mcp-server/toolHandlers/listServersHandler.js +21 -17
- package/dist/mcp-server/toolHandlers/listToolsHandler.d.ts +2 -2
- package/dist/mcp-server/toolHandlers/listToolsHandler.js +32 -26
- package/dist/mcp-server/toolHandlers/logPlaybookUsageHandler.d.ts +2 -2
- package/dist/mcp-server/toolHandlers/logPlaybookUsageHandler.js +14 -14
- package/dist/mcp-server/toolHandlers/lookupEntityHandler.d.ts +2 -2
- package/dist/mcp-server/toolHandlers/lookupEntityHandler.js +30 -28
- package/dist/mcp-server/toolHandlers/savePlaybookHandler.d.ts +2 -2
- package/dist/mcp-server/toolHandlers/savePlaybookHandler.js +17 -15
- package/dist/mcp-server/toolHandlers/searchHandler.d.ts +2 -2
- package/dist/mcp-server/toolHandlers/searchHandler.js +33 -28
- package/dist/mcp-server/toolHandlers/serverManagerUtils.d.ts +1 -1
- package/dist/mcp-server/toolHandlers/serverManagerUtils.js +2 -2
- package/dist/mcp-server/toolHandlers/submitFeedbackHandler.d.ts +2 -2
- package/dist/mcp-server/toolHandlers/submitFeedbackHandler.js +17 -15
- package/dist/mcp-server/toolHandlers/uninstallServerHandler.d.ts +2 -2
- package/dist/mcp-server/toolHandlers/uninstallServerHandler.js +21 -19
- package/dist/mcp-server/toolplexApi/service.d.ts +8 -8
- package/dist/mcp-server/toolplexApi/service.js +24 -28
- package/dist/mcp-server/toolplexApi/types.d.ts +3 -3
- package/dist/mcp-server/toolplexServer.d.ts +1 -1
- package/dist/mcp-server/toolplexServer.js +78 -77
- package/dist/mcp-server/tools.d.ts +1 -1
- package/dist/mcp-server/tools.js +3 -3
- package/dist/mcp-server/utils/initServerManagers.d.ts +4 -4
- package/dist/mcp-server/utils/initServerManagers.js +5 -5
- package/dist/mcp-server/utils/resultAnnotators.js +3 -7
- package/dist/mcp-server/utils/runtimeCheck.js +8 -8
- package/dist/server-manager/index.js +4 -4
- package/dist/server-manager/serverManager.d.ts +6 -6
- package/dist/server-manager/serverManager.js +34 -36
- package/dist/server-manager/stdioServer.js +37 -35
- package/dist/server-manager/stdioTransportProtocol.d.ts +2 -2
- package/dist/server-manager/stdioTransportProtocol.js +7 -7
- package/dist/shared/enhancedPath.js +13 -13
- package/dist/shared/fileLogger.js +19 -19
- package/dist/shared/mcpServerTypes.d.ts +4 -3
- package/dist/shared/mcpServerTypes.js +17 -10
- package/dist/shared/serverManagerTypes.d.ts +1 -1
- package/dist/shared/serverManagerTypes.js +1 -1
- package/dist/shared/stdioServerManagerClient.js +20 -18
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
|
@@ -1,29 +1,29 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import path from
|
|
3
|
-
import { fileURLToPath } from
|
|
4
|
-
import { Server } from
|
|
5
|
-
import { StdioServerTransport } from
|
|
6
|
-
import { CallToolRequestSchema, ListToolsRequestSchema, } from
|
|
7
|
-
import { ClientContext } from
|
|
8
|
-
import Registry from
|
|
9
|
-
import { PRE_INITIALIZATION_PROMPTS } from
|
|
10
|
-
import { createToolDefinitions } from
|
|
11
|
-
import { handleInitialize } from
|
|
12
|
-
import { handleSearchTool } from
|
|
13
|
-
import { handleInstallServer } from
|
|
14
|
-
import { handleListTools } from
|
|
15
|
-
import { handleListServers } from
|
|
16
|
-
import { handleCallTool } from
|
|
17
|
-
import { handleUninstallServer } from
|
|
18
|
-
import { handleSavePlaybook } from
|
|
19
|
-
import { handleLogPlaybookUsage } from
|
|
20
|
-
import { handleLookupEntityTool } from
|
|
21
|
-
import { handleSubmitFeedback } from
|
|
22
|
-
import { handleGetServerConfig } from
|
|
23
|
-
import { StdioServerManagerClient } from
|
|
24
|
-
import { FileLogger } from
|
|
25
|
-
import { CallToolParamsSchema, InitializeToolplexParamsSchema, InstallParamsSchema, ListToolsParamsSchema, SearchParamsSchema, UninstallParamsSchema, SavePlaybookParamsSchema, LogPlaybookUsageParamsSchema, LookupEntityParamsSchema, SubmitFeedbackParamsSchema, GetServerConfigParamsSchema, } from
|
|
26
|
-
import { version as clientVersion } from
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { fileURLToPath } from "url";
|
|
4
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
5
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
7
|
+
import { ClientContext } from "./clientContext.js";
|
|
8
|
+
import Registry from "./registry.js";
|
|
9
|
+
import { PRE_INITIALIZATION_PROMPTS } from "./staticPrompts.js";
|
|
10
|
+
import { createToolDefinitions } from "./tools.js";
|
|
11
|
+
import { handleInitialize } from "./toolHandlers/initHandler.js";
|
|
12
|
+
import { handleSearchTool } from "./toolHandlers/searchHandler.js";
|
|
13
|
+
import { handleInstallServer } from "./toolHandlers/installServerHandler.js";
|
|
14
|
+
import { handleListTools } from "./toolHandlers/listToolsHandler.js";
|
|
15
|
+
import { handleListServers } from "./toolHandlers/listServersHandler.js";
|
|
16
|
+
import { handleCallTool } from "./toolHandlers/callToolHandler.js";
|
|
17
|
+
import { handleUninstallServer } from "./toolHandlers/uninstallServerHandler.js";
|
|
18
|
+
import { handleSavePlaybook } from "./toolHandlers/savePlaybookHandler.js";
|
|
19
|
+
import { handleLogPlaybookUsage } from "./toolHandlers/logPlaybookUsageHandler.js";
|
|
20
|
+
import { handleLookupEntityTool } from "./toolHandlers/lookupEntityHandler.js";
|
|
21
|
+
import { handleSubmitFeedback } from "./toolHandlers/submitFeedbackHandler.js";
|
|
22
|
+
import { handleGetServerConfig } from "./toolHandlers/getServerConfigHandler.js";
|
|
23
|
+
import { StdioServerManagerClient } from "../shared/stdioServerManagerClient.js";
|
|
24
|
+
import { FileLogger } from "../shared/fileLogger.js";
|
|
25
|
+
import { CallToolParamsSchema, InitializeToolplexParamsSchema, InstallParamsSchema, ListToolsParamsSchema, SearchParamsSchema, UninstallParamsSchema, SavePlaybookParamsSchema, LogPlaybookUsageParamsSchema, LookupEntityParamsSchema, SubmitFeedbackParamsSchema, GetServerConfigParamsSchema, } from "../shared/mcpServerTypes.js";
|
|
26
|
+
import { version as clientVersion } from "../version.js";
|
|
27
27
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
28
28
|
const logger = FileLogger;
|
|
29
29
|
export async function serve(config) {
|
|
@@ -31,11 +31,12 @@ export async function serve(config) {
|
|
|
31
31
|
clientContext.dev = config.dev;
|
|
32
32
|
clientContext.apiKey = config.apiKey;
|
|
33
33
|
clientContext.clientMode = config.clientMode;
|
|
34
|
+
clientContext.clientName = config.clientName;
|
|
34
35
|
clientContext.clientVersion = clientVersion;
|
|
35
36
|
await Registry.init(clientContext);
|
|
36
|
-
await logger.info(`Starting Toolplex server in ${config.dev ?
|
|
37
|
+
await logger.info(`Starting Toolplex server in ${config.dev ? "development" : "production"} mode`);
|
|
37
38
|
const server = new Server({
|
|
38
|
-
name:
|
|
39
|
+
name: "toolplex-server",
|
|
39
40
|
version: clientContext.clientVersion,
|
|
40
41
|
}, {
|
|
41
42
|
capabilities: {
|
|
@@ -44,18 +45,18 @@ export async function serve(config) {
|
|
|
44
45
|
},
|
|
45
46
|
});
|
|
46
47
|
// Initialize server manager clients
|
|
47
|
-
await logger.info(
|
|
48
|
+
await logger.info("Initializing server manager clients");
|
|
48
49
|
const serverManagerClients = {
|
|
49
|
-
node: new StdioServerManagerClient(
|
|
50
|
+
node: new StdioServerManagerClient("node", [path.join(__dirname, "..", "server-manager", "index.js")], { LOG_LEVEL: config.logLevel }),
|
|
50
51
|
};
|
|
51
52
|
// Start all server manager clients
|
|
52
|
-
await logger.info(
|
|
53
|
+
await logger.info("Starting server manager clients");
|
|
53
54
|
await Promise.all(Object.values(serverManagerClients).map((client) => client.start()));
|
|
54
|
-
await logger.info(
|
|
55
|
+
await logger.info("All server manager clients started successfully");
|
|
55
56
|
Registry.setServerManagerClients(serverManagerClients);
|
|
56
57
|
// List tools handler
|
|
57
58
|
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
58
|
-
await logger.debug(
|
|
59
|
+
await logger.debug("Handling list tools request");
|
|
59
60
|
return {
|
|
60
61
|
tools: createToolDefinitions(),
|
|
61
62
|
};
|
|
@@ -67,23 +68,23 @@ export async function serve(config) {
|
|
|
67
68
|
let result;
|
|
68
69
|
if (!Registry.getToolDefinitionsCache().isInitialized()) {
|
|
69
70
|
result = {
|
|
70
|
-
role:
|
|
71
|
+
role: "system",
|
|
71
72
|
content: [
|
|
72
73
|
{
|
|
73
|
-
type:
|
|
74
|
+
type: "text",
|
|
74
75
|
text: PRE_INITIALIZATION_PROMPTS.tools_initialization_error,
|
|
75
76
|
},
|
|
76
77
|
],
|
|
77
78
|
};
|
|
78
79
|
return result;
|
|
79
80
|
}
|
|
80
|
-
if (!clientContext.isInitialized() && name !==
|
|
81
|
+
if (!clientContext.isInitialized() && name !== "initialize_toolplex") {
|
|
81
82
|
result = {
|
|
82
|
-
role:
|
|
83
|
+
role: "system",
|
|
83
84
|
content: [
|
|
84
85
|
{
|
|
85
|
-
type:
|
|
86
|
-
text: PRE_INITIALIZATION_PROMPTS.enforce_init_toolplex.replace(
|
|
86
|
+
type: "text",
|
|
87
|
+
text: PRE_INITIALIZATION_PROMPTS.enforce_init_toolplex.replace("{TOOL_NAME}", name),
|
|
87
88
|
},
|
|
88
89
|
],
|
|
89
90
|
};
|
|
@@ -91,8 +92,8 @@ export async function serve(config) {
|
|
|
91
92
|
}
|
|
92
93
|
try {
|
|
93
94
|
switch (name) {
|
|
94
|
-
case
|
|
95
|
-
await logger.debug(
|
|
95
|
+
case "initialize_toolplex": {
|
|
96
|
+
await logger.debug("Handling initialize_toolplex request");
|
|
96
97
|
const parsed = InitializeToolplexParamsSchema.safeParse(params);
|
|
97
98
|
if (!parsed.success)
|
|
98
99
|
throw new Error(`Invalid initialize_toolplex params: ${parsed.error}`);
|
|
@@ -100,16 +101,16 @@ export async function serve(config) {
|
|
|
100
101
|
result = await handleInitialize(parsed.data);
|
|
101
102
|
break;
|
|
102
103
|
}
|
|
103
|
-
case
|
|
104
|
-
await logger.debug(
|
|
104
|
+
case "search": {
|
|
105
|
+
await logger.debug("Handling search request");
|
|
105
106
|
const parsed = SearchParamsSchema.safeParse(params);
|
|
106
107
|
if (!parsed.success)
|
|
107
108
|
throw new Error(`Invalid search params: ${parsed.error}`);
|
|
108
109
|
result = await handleSearchTool(parsed.data);
|
|
109
110
|
break;
|
|
110
111
|
}
|
|
111
|
-
case
|
|
112
|
-
await logger.debug(
|
|
112
|
+
case "install": {
|
|
113
|
+
await logger.debug("Handling install request");
|
|
113
114
|
const parsed = InstallParamsSchema.safeParse(params);
|
|
114
115
|
if (!parsed.success)
|
|
115
116
|
throw new Error(`Invalid install params: ${parsed.error}`);
|
|
@@ -117,37 +118,37 @@ export async function serve(config) {
|
|
|
117
118
|
server.sendToolListChanged();
|
|
118
119
|
break;
|
|
119
120
|
}
|
|
120
|
-
case
|
|
121
|
-
await logger.debug(
|
|
121
|
+
case "list_tools": {
|
|
122
|
+
await logger.debug("Handling list_tools request");
|
|
122
123
|
const parsed = ListToolsParamsSchema.safeParse(params);
|
|
123
124
|
if (!parsed.success)
|
|
124
125
|
throw new Error(`Invalid list_toolplex_tools params: ${parsed.error}`);
|
|
125
126
|
result = await handleListTools(parsed.data);
|
|
126
127
|
break;
|
|
127
128
|
}
|
|
128
|
-
case
|
|
129
|
-
await logger.debug(
|
|
129
|
+
case "list_servers": {
|
|
130
|
+
await logger.debug("Handling list_toolplex_tools request");
|
|
130
131
|
result = await handleListServers();
|
|
131
132
|
break;
|
|
132
133
|
}
|
|
133
|
-
case
|
|
134
|
-
await logger.debug(
|
|
134
|
+
case "call_tool": {
|
|
135
|
+
await logger.debug("Handling call_tool request");
|
|
135
136
|
const parsed = CallToolParamsSchema.safeParse(params);
|
|
136
137
|
if (!parsed.success)
|
|
137
138
|
throw new Error(`Invalid call_tool params: ${parsed.error}`);
|
|
138
139
|
result = await handleCallTool(parsed.data);
|
|
139
140
|
break;
|
|
140
141
|
}
|
|
141
|
-
case
|
|
142
|
-
await logger.debug(
|
|
142
|
+
case "uninstall": {
|
|
143
|
+
await logger.debug("Handling uninstall request");
|
|
143
144
|
const parsed = UninstallParamsSchema.safeParse(params);
|
|
144
145
|
if (!parsed.success)
|
|
145
146
|
throw new Error(`Invalid uninstall params: ${parsed.error}`);
|
|
146
147
|
result = await handleUninstallServer(parsed.data);
|
|
147
148
|
break;
|
|
148
149
|
}
|
|
149
|
-
case
|
|
150
|
-
await logger.debug(
|
|
150
|
+
case "save_playbook": {
|
|
151
|
+
await logger.debug("Handling save_playbook request");
|
|
151
152
|
const parsed = SavePlaybookParamsSchema.safeParse(params);
|
|
152
153
|
if (!parsed.success)
|
|
153
154
|
throw new Error(`Invalid save_playbook params: ${parsed.error}`);
|
|
@@ -156,8 +157,8 @@ export async function serve(config) {
|
|
|
156
157
|
result = await handleSavePlaybook(parsed.data);
|
|
157
158
|
break;
|
|
158
159
|
}
|
|
159
|
-
case
|
|
160
|
-
await logger.debug(
|
|
160
|
+
case "log_playbook_usage": {
|
|
161
|
+
await logger.debug("Handling log_playbook_usage request");
|
|
161
162
|
const parsed = LogPlaybookUsageParamsSchema.safeParse(params);
|
|
162
163
|
if (!parsed.success)
|
|
163
164
|
throw new Error(`Invalid log_playbook_usage params: ${parsed.error}`);
|
|
@@ -166,16 +167,16 @@ export async function serve(config) {
|
|
|
166
167
|
result = await handleLogPlaybookUsage(parsed.data);
|
|
167
168
|
break;
|
|
168
169
|
}
|
|
169
|
-
case
|
|
170
|
-
await logger.debug(
|
|
170
|
+
case "lookup_entity": {
|
|
171
|
+
await logger.debug("Handling lookup_entity request");
|
|
171
172
|
const parsed = LookupEntityParamsSchema.safeParse(params);
|
|
172
173
|
if (!parsed.success)
|
|
173
174
|
throw new Error(`Invalid lookup_entity params: ${parsed.error}`);
|
|
174
175
|
result = await handleLookupEntityTool(parsed.data);
|
|
175
176
|
break;
|
|
176
177
|
}
|
|
177
|
-
case
|
|
178
|
-
await logger.debug(
|
|
178
|
+
case "submit_feedback": {
|
|
179
|
+
await logger.debug("Handling submit_feedback request");
|
|
179
180
|
const parsed = SubmitFeedbackParamsSchema.safeParse(params);
|
|
180
181
|
if (!parsed.success)
|
|
181
182
|
throw new Error(`Invalid submit_feedback params: ${parsed.error}`);
|
|
@@ -185,8 +186,8 @@ export async function serve(config) {
|
|
|
185
186
|
break;
|
|
186
187
|
}
|
|
187
188
|
// Add get_server_config tool handler
|
|
188
|
-
case
|
|
189
|
-
await logger.debug(
|
|
189
|
+
case "get_server_config": {
|
|
190
|
+
await logger.debug("Handling get_server_config request");
|
|
190
191
|
const parsed = GetServerConfigParamsSchema.safeParse(params);
|
|
191
192
|
if (!parsed.success)
|
|
192
193
|
throw new Error(`Invalid get_server_config params: ${parsed.error}`);
|
|
@@ -196,28 +197,28 @@ export async function serve(config) {
|
|
|
196
197
|
default:
|
|
197
198
|
await logger.warn(`Unknown tool requested: ${name}`);
|
|
198
199
|
result = {
|
|
199
|
-
role:
|
|
200
|
+
role: "system",
|
|
200
201
|
content: [
|
|
201
202
|
{
|
|
202
|
-
type:
|
|
203
|
-
text: PRE_INITIALIZATION_PROMPTS.unknown_tool.replace(
|
|
203
|
+
type: "text",
|
|
204
|
+
text: PRE_INITIALIZATION_PROMPTS.unknown_tool.replace("{TOOL_NAME}", name),
|
|
204
205
|
},
|
|
205
206
|
],
|
|
206
207
|
};
|
|
207
208
|
}
|
|
208
209
|
}
|
|
209
210
|
catch (error) {
|
|
210
|
-
let errorMessage =
|
|
211
|
+
let errorMessage = "Unknown error occurred";
|
|
211
212
|
if (error instanceof Error) {
|
|
212
213
|
errorMessage = error.message;
|
|
213
214
|
}
|
|
214
215
|
await logger.error(`Error calling ToolPlex: ${errorMessage}`);
|
|
215
216
|
result = {
|
|
216
|
-
role:
|
|
217
|
+
role: "system",
|
|
217
218
|
content: [
|
|
218
219
|
{
|
|
219
|
-
type:
|
|
220
|
-
text: PRE_INITIALIZATION_PROMPTS.unexpected_error.replace(
|
|
220
|
+
type: "text",
|
|
221
|
+
text: PRE_INITIALIZATION_PROMPTS.unexpected_error.replace("{ERROR}", errorMessage),
|
|
221
222
|
},
|
|
222
223
|
],
|
|
223
224
|
};
|
|
@@ -225,23 +226,23 @@ export async function serve(config) {
|
|
|
225
226
|
return result;
|
|
226
227
|
});
|
|
227
228
|
const transport = new StdioServerTransport();
|
|
228
|
-
await logger.info(
|
|
229
|
+
await logger.info("Connecting server transport");
|
|
229
230
|
await server.connect(transport);
|
|
230
|
-
await logger.info(
|
|
231
|
+
await logger.info("Server transport connected successfully");
|
|
231
232
|
// Clean up on process exit
|
|
232
|
-
process.on(
|
|
233
|
-
await logger.info(
|
|
233
|
+
process.on("exit", async () => {
|
|
234
|
+
await logger.info("Process exit - stopping server manager clients");
|
|
234
235
|
await logger.flush();
|
|
235
236
|
Object.values(serverManagerClients).forEach((client) => client.stop());
|
|
236
237
|
});
|
|
237
|
-
process.on(
|
|
238
|
-
await logger.warn(
|
|
238
|
+
process.on("SIGINT", async () => {
|
|
239
|
+
await logger.warn("SIGINT received - stopping server manager clients");
|
|
239
240
|
await logger.flush();
|
|
240
241
|
Object.values(serverManagerClients).forEach((client) => client.stop());
|
|
241
242
|
process.exit();
|
|
242
243
|
});
|
|
243
|
-
process.on(
|
|
244
|
-
await logger.warn(
|
|
244
|
+
process.on("SIGTERM", async () => {
|
|
245
|
+
await logger.warn("SIGTERM received - stopping server manager clients");
|
|
245
246
|
await logger.flush();
|
|
246
247
|
Object.values(serverManagerClients).forEach((client) => client.stop());
|
|
247
248
|
process.exit();
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { Tool } from
|
|
1
|
+
import { Tool } from "@modelcontextprotocol/sdk/types.js";
|
|
2
2
|
export declare function createToolDefinitions(): Tool[];
|
package/dist/mcp-server/tools.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import Registry from
|
|
1
|
+
import Registry from "./registry.js";
|
|
2
2
|
export function createToolDefinitions() {
|
|
3
3
|
const toolDefinitionsCache = Registry.getToolDefinitionsCache();
|
|
4
4
|
if (!toolDefinitionsCache.isInitialized()) {
|
|
5
5
|
return [
|
|
6
6
|
{
|
|
7
|
-
name:
|
|
8
|
-
inputSchema: { type:
|
|
7
|
+
name: "initialize_toolplex",
|
|
8
|
+
inputSchema: { type: "object", properties: {}, required: [] },
|
|
9
9
|
},
|
|
10
10
|
];
|
|
11
11
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { StdioServerManagerClient } from
|
|
2
|
-
import { InitializeResult } from
|
|
1
|
+
import { StdioServerManagerClient } from "../../shared/stdioServerManagerClient.js";
|
|
2
|
+
import { InitializeResult } from "../../shared/serverManagerTypes.js";
|
|
3
3
|
export declare function initServerManagersOnly(serverManagerClients: Record<string, StdioServerManagerClient>): Promise<{
|
|
4
|
-
succeeded: InitializeResult[
|
|
5
|
-
failures: InitializeResult[
|
|
4
|
+
succeeded: InitializeResult["succeeded"];
|
|
5
|
+
failures: InitializeResult["failures"];
|
|
6
6
|
}>;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { InitializeResultSchema } from
|
|
2
|
-
import { FileLogger } from
|
|
1
|
+
import { InitializeResultSchema, } from "../../shared/serverManagerTypes.js";
|
|
2
|
+
import { FileLogger } from "../../shared/fileLogger.js";
|
|
3
3
|
const logger = FileLogger;
|
|
4
4
|
export async function initServerManagersOnly(serverManagerClients) {
|
|
5
|
-
await logger.info(
|
|
5
|
+
await logger.info("Pre-warming server manager clients");
|
|
6
6
|
const initPromises = Object.entries(serverManagerClients).map(async ([runtime, client]) => {
|
|
7
7
|
try {
|
|
8
|
-
const response = await client.sendRequest(
|
|
9
|
-
if (
|
|
8
|
+
const response = await client.sendRequest("initialize", {});
|
|
9
|
+
if ("error" in response)
|
|
10
10
|
throw new Error(response.error.message);
|
|
11
11
|
const parsed = InitializeResultSchema.safeParse(response);
|
|
12
12
|
if (!parsed.success)
|
|
@@ -10,10 +10,8 @@
|
|
|
10
10
|
*/
|
|
11
11
|
export function annotateInstalledServer(
|
|
12
12
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
13
|
-
server, serversCache
|
|
14
|
-
|
|
15
|
-
) {
|
|
16
|
-
if (!server || typeof server !== 'object' || !server.server_id) {
|
|
13
|
+
server, serversCache) {
|
|
14
|
+
if (!server || typeof server !== "object" || !server.server_id) {
|
|
17
15
|
return server;
|
|
18
16
|
}
|
|
19
17
|
if (serversCache.isInstalled(server.server_id)) {
|
|
@@ -41,9 +39,7 @@ server, serversCache
|
|
|
41
39
|
*/
|
|
42
40
|
export function annotateInstalledServers(
|
|
43
41
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
44
|
-
servers, serversCache
|
|
45
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
46
|
-
) {
|
|
42
|
+
servers, serversCache) {
|
|
47
43
|
if (!Array.isArray(servers))
|
|
48
44
|
return [];
|
|
49
45
|
return servers.map((server) => annotateInstalledServer(server, serversCache));
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { getEnhancedPath } from
|
|
2
|
-
import which from
|
|
1
|
+
import { getEnhancedPath } from "../../shared/enhancedPath.js";
|
|
2
|
+
import which from "which";
|
|
3
3
|
const INSTALL_HINTS = {
|
|
4
|
-
uvx:
|
|
5
|
-
uv:
|
|
6
|
-
python:
|
|
7
|
-
python3:
|
|
8
|
-
node:
|
|
9
|
-
npx:
|
|
4
|
+
uvx: "Install uvx: https://docs.astral.sh/uv/getting-started/installation/",
|
|
5
|
+
uv: "Install uv: https://docs.astral.sh/uv/getting-started/installation/",
|
|
6
|
+
python: "Install Python: https://www.python.org/downloads/. Or check if you have `python3` installed.",
|
|
7
|
+
python3: "Install Python: https://www.python.org/downloads/. Or check if you have `python` installed.",
|
|
8
|
+
node: "Install Node.js: https://nodejs.org/en/download/",
|
|
9
|
+
npx: "Install npx (comes with Node.js): https://nodejs.org/en/download/",
|
|
10
10
|
};
|
|
11
11
|
export class RuntimeCheck {
|
|
12
12
|
static validateCommandOrThrow(rawCommand) {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { ServerManagerProtocol } from
|
|
2
|
-
import { FileLogger } from
|
|
3
|
-
FileLogger.initialize(
|
|
1
|
+
import { ServerManagerProtocol } from "./stdioServer.js";
|
|
2
|
+
import { FileLogger } from "../shared/fileLogger.js";
|
|
3
|
+
FileLogger.initialize("server-manager");
|
|
4
4
|
const protocol = new ServerManagerProtocol();
|
|
5
5
|
protocol.start().catch((error) => {
|
|
6
|
-
console.error(
|
|
6
|
+
console.error("Failed to start server:", error);
|
|
7
7
|
process.exit(1);
|
|
8
8
|
});
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { Client } from
|
|
2
|
-
import { StdioClientTransport } from
|
|
3
|
-
import { SSEClientTransport } from
|
|
4
|
-
import { Tool } from
|
|
5
|
-
import { ServerConfig } from
|
|
6
|
-
import { InitializeResult } from
|
|
1
|
+
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
2
|
+
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
3
|
+
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
|
|
4
|
+
import { Tool } from "@modelcontextprotocol/sdk/types.js";
|
|
5
|
+
import { ServerConfig } from "../shared/mcpServerTypes.js";
|
|
6
|
+
import { InitializeResult } from "../shared/serverManagerTypes.js";
|
|
7
7
|
export declare class ServerManager {
|
|
8
8
|
private sessions;
|
|
9
9
|
private tools;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { Client } from
|
|
2
|
-
import { StdioClientTransport, } from
|
|
3
|
-
import { SSEClientTransport } from
|
|
4
|
-
import * as fs from
|
|
5
|
-
import * as path from
|
|
6
|
-
import which from
|
|
7
|
-
import { FileLogger } from
|
|
8
|
-
import envPaths from
|
|
9
|
-
import { getEnhancedPath } from
|
|
1
|
+
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
2
|
+
import { StdioClientTransport, } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
3
|
+
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
|
|
4
|
+
import * as fs from "fs/promises";
|
|
5
|
+
import * as path from "path";
|
|
6
|
+
import which from "which";
|
|
7
|
+
import { FileLogger } from "../shared/fileLogger.js";
|
|
8
|
+
import envPaths from "env-paths";
|
|
9
|
+
import { getEnhancedPath } from "../shared/enhancedPath.js";
|
|
10
10
|
const logger = FileLogger;
|
|
11
11
|
export class ServerManager {
|
|
12
12
|
constructor() {
|
|
@@ -18,22 +18,22 @@ export class ServerManager {
|
|
|
18
18
|
this.sessions = new Map();
|
|
19
19
|
this.tools = new Map();
|
|
20
20
|
this.serverNames = new Map();
|
|
21
|
-
const paths = envPaths(
|
|
22
|
-
this.configPath = path.join(paths.data,
|
|
21
|
+
const paths = envPaths("ToolPlex", { suffix: "" });
|
|
22
|
+
this.configPath = path.join(paths.data, "server_config.json");
|
|
23
23
|
}
|
|
24
24
|
async loadConfig() {
|
|
25
25
|
try {
|
|
26
|
-
const data = await fs.readFile(this.configPath,
|
|
26
|
+
const data = await fs.readFile(this.configPath, "utf-8");
|
|
27
27
|
await logger.debug(`Loaded config from ${this.configPath}`);
|
|
28
28
|
const allConfig = JSON.parse(data);
|
|
29
29
|
// Validate the config structure
|
|
30
|
-
if (typeof allConfig !==
|
|
31
|
-
await logger.warn(
|
|
30
|
+
if (typeof allConfig !== "object" || allConfig === null) {
|
|
31
|
+
await logger.warn("Invalid config format, using empty config");
|
|
32
32
|
return {};
|
|
33
33
|
}
|
|
34
34
|
const config = {};
|
|
35
35
|
for (const [serverId, serverConfig] of Object.entries(allConfig)) {
|
|
36
|
-
if (typeof serverConfig ===
|
|
36
|
+
if (typeof serverConfig === "object" && serverConfig !== null) {
|
|
37
37
|
config[serverId] = serverConfig;
|
|
38
38
|
}
|
|
39
39
|
else {
|
|
@@ -43,14 +43,14 @@ export class ServerManager {
|
|
|
43
43
|
return config;
|
|
44
44
|
}
|
|
45
45
|
catch (error) {
|
|
46
|
-
let errorMessage =
|
|
46
|
+
let errorMessage = "Unknown error occurred";
|
|
47
47
|
if (error instanceof Error)
|
|
48
48
|
errorMessage = error.message;
|
|
49
49
|
await logger.debug(`No existing config found at ${this.configPath}: ${errorMessage}`);
|
|
50
50
|
// If the file exists but is malformed, back it up and start fresh
|
|
51
51
|
try {
|
|
52
52
|
await fs.access(this.configPath);
|
|
53
|
-
const backupPath = this.configPath +
|
|
53
|
+
const backupPath = this.configPath + ".backup." + Date.now();
|
|
54
54
|
await fs.copyFile(this.configPath, backupPath);
|
|
55
55
|
await logger.warn(`Malformed config backed up to ${backupPath}`);
|
|
56
56
|
}
|
|
@@ -65,11 +65,11 @@ export class ServerManager {
|
|
|
65
65
|
this.configLock = this.configLock.then(async () => {
|
|
66
66
|
let existingConfig = {};
|
|
67
67
|
try {
|
|
68
|
-
const data = await fs.readFile(this.configPath,
|
|
68
|
+
const data = await fs.readFile(this.configPath, "utf-8");
|
|
69
69
|
existingConfig = JSON.parse(data);
|
|
70
70
|
// Validate the existing config structure
|
|
71
|
-
if (typeof existingConfig !==
|
|
72
|
-
await logger.warn(
|
|
71
|
+
if (typeof existingConfig !== "object" || existingConfig === null) {
|
|
72
|
+
await logger.warn("Invalid existing config format, using empty config");
|
|
73
73
|
existingConfig = {};
|
|
74
74
|
}
|
|
75
75
|
}
|
|
@@ -92,7 +92,7 @@ export class ServerManager {
|
|
|
92
92
|
}
|
|
93
93
|
await fs.mkdir(path.dirname(this.configPath), { recursive: true });
|
|
94
94
|
// Write to a temporary file first, then rename (atomic operation)
|
|
95
|
-
const tempPath = this.configPath +
|
|
95
|
+
const tempPath = this.configPath + ".tmp";
|
|
96
96
|
try {
|
|
97
97
|
await fs.writeFile(tempPath, JSON.stringify(mergedConfig, null, 2));
|
|
98
98
|
await fs.rename(tempPath, this.configPath);
|
|
@@ -116,14 +116,14 @@ export class ServerManager {
|
|
|
116
116
|
const succeeded = [];
|
|
117
117
|
const failures = {};
|
|
118
118
|
try {
|
|
119
|
-
await logger.info(
|
|
119
|
+
await logger.info("Initializing ServerManager");
|
|
120
120
|
this.config = await this.loadConfig();
|
|
121
121
|
await logger.debug(`Loaded ${Object.keys(this.config).length} server configs`);
|
|
122
122
|
for (const [serverId, serverConfig] of Object.entries(this.config)) {
|
|
123
123
|
succeeded.push({
|
|
124
124
|
server_id: serverId,
|
|
125
125
|
server_name: serverConfig.server_name ?? serverId,
|
|
126
|
-
description: serverConfig.description ??
|
|
126
|
+
description: serverConfig.description ?? "",
|
|
127
127
|
});
|
|
128
128
|
}
|
|
129
129
|
}
|
|
@@ -196,14 +196,14 @@ export class ServerManager {
|
|
|
196
196
|
await this.removeServer(serverId);
|
|
197
197
|
}
|
|
198
198
|
let transport;
|
|
199
|
-
if (config.transport ===
|
|
199
|
+
if (config.transport === "sse") {
|
|
200
200
|
if (!config.url)
|
|
201
|
-
throw new Error(
|
|
201
|
+
throw new Error("URL is required for SSE transport");
|
|
202
202
|
transport = new SSEClientTransport(new URL(config.url));
|
|
203
203
|
}
|
|
204
|
-
else if (config.transport ===
|
|
204
|
+
else if (config.transport === "stdio") {
|
|
205
205
|
if (!config.command)
|
|
206
|
-
throw new Error(
|
|
206
|
+
throw new Error("Command is required for stdio transport");
|
|
207
207
|
const enhancedPath = getEnhancedPath();
|
|
208
208
|
let resolvedCommand = which.sync(config.command, {
|
|
209
209
|
path: enhancedPath,
|
|
@@ -221,14 +221,14 @@ export class ServerManager {
|
|
|
221
221
|
PATH: enhancedPath,
|
|
222
222
|
...(config.env || {}),
|
|
223
223
|
},
|
|
224
|
-
stderr:
|
|
224
|
+
stderr: "pipe",
|
|
225
225
|
};
|
|
226
226
|
transport = new StdioClientTransport(serverParams);
|
|
227
227
|
}
|
|
228
228
|
else {
|
|
229
229
|
throw new Error(`Invalid transport type: ${config.transport}`);
|
|
230
230
|
}
|
|
231
|
-
const client = new Client({ name: serverId, version:
|
|
231
|
+
const client = new Client({ name: serverId, version: "1.0.0" }, { capabilities: { prompts: {}, resources: {}, tools: {} } });
|
|
232
232
|
try {
|
|
233
233
|
const toolsResponse = await this.connectWithHandshakeTimeout(client, transport, 30000);
|
|
234
234
|
const tools = toolsResponse.tools || [];
|
|
@@ -267,9 +267,7 @@ export class ServerManager {
|
|
|
267
267
|
}
|
|
268
268
|
async callTool(serverId, toolName,
|
|
269
269
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
270
|
-
arguments_, timeout = 60000
|
|
271
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
272
|
-
) {
|
|
270
|
+
arguments_, timeout = 60000) {
|
|
273
271
|
// Check for ongoing installation before attempting to install
|
|
274
272
|
const existingInstall = this.installationPromises.get(serverId);
|
|
275
273
|
if (existingInstall) {
|
|
@@ -281,7 +279,7 @@ export class ServerManager {
|
|
|
281
279
|
if (!config)
|
|
282
280
|
throw new Error(`No config found for server ${serverId}`);
|
|
283
281
|
const name = config.server_name || serverId;
|
|
284
|
-
const description = config.description ||
|
|
282
|
+
const description = config.description || "";
|
|
285
283
|
await this.install(serverId, name, description, config);
|
|
286
284
|
}
|
|
287
285
|
const client = this.sessions.get(serverId);
|
|
@@ -339,7 +337,7 @@ export class ServerManager {
|
|
|
339
337
|
// Remove the server from the config file
|
|
340
338
|
let config = {};
|
|
341
339
|
try {
|
|
342
|
-
const data = await fs.readFile(this.configPath,
|
|
340
|
+
const data = await fs.readFile(this.configPath, "utf-8");
|
|
343
341
|
config = JSON.parse(data);
|
|
344
342
|
}
|
|
345
343
|
catch (error) {
|
|
@@ -375,7 +373,7 @@ export class ServerManager {
|
|
|
375
373
|
server_id: id,
|
|
376
374
|
server_name: cfg.server_name || id,
|
|
377
375
|
tool_count: this.tools.get(id)?.length || 0,
|
|
378
|
-
description: cfg.description ||
|
|
376
|
+
description: cfg.description || "",
|
|
379
377
|
}));
|
|
380
378
|
}
|
|
381
379
|
async listTools(serverId) {
|
|
@@ -389,7 +387,7 @@ export class ServerManager {
|
|
|
389
387
|
const config = this.config[serverId];
|
|
390
388
|
if (!config)
|
|
391
389
|
throw new Error(`No config for server ${serverId}`);
|
|
392
|
-
await this.install(serverId, config.server_name || serverId, config.description ||
|
|
390
|
+
await this.install(serverId, config.server_name || serverId, config.description || "", config);
|
|
393
391
|
}
|
|
394
392
|
return this.tools.get(serverId) || [];
|
|
395
393
|
}
|