@toolplex/client 0.1.1
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/LICENSE +98 -0
- package/README.md +112 -0
- package/dist/mcp-server/clientContext.d.ts +35 -0
- package/dist/mcp-server/clientContext.js +107 -0
- package/dist/mcp-server/index.d.ts +1 -0
- package/dist/mcp-server/index.js +22 -0
- package/dist/mcp-server/logging/telemetryLogger.d.ts +18 -0
- package/dist/mcp-server/logging/telemetryLogger.js +54 -0
- package/dist/mcp-server/policy/callToolObserver.d.ts +9 -0
- package/dist/mcp-server/policy/callToolObserver.js +25 -0
- package/dist/mcp-server/policy/feedbackPolicy.d.ts +27 -0
- package/dist/mcp-server/policy/feedbackPolicy.js +39 -0
- package/dist/mcp-server/policy/installObserver.d.ts +11 -0
- package/dist/mcp-server/policy/installObserver.js +35 -0
- package/dist/mcp-server/policy/playbookPolicy.d.ts +29 -0
- package/dist/mcp-server/policy/playbookPolicy.js +81 -0
- package/dist/mcp-server/policy/policyEnforcer.d.ts +57 -0
- package/dist/mcp-server/policy/policyEnforcer.js +105 -0
- package/dist/mcp-server/policy/serverPolicy.d.ts +39 -0
- package/dist/mcp-server/policy/serverPolicy.js +61 -0
- package/dist/mcp-server/promptsCache.d.ts +25 -0
- package/dist/mcp-server/promptsCache.js +51 -0
- package/dist/mcp-server/registry.d.ts +34 -0
- package/dist/mcp-server/registry.js +109 -0
- package/dist/mcp-server/serversCache.d.ts +53 -0
- package/dist/mcp-server/serversCache.js +100 -0
- package/dist/mcp-server/staticPrompts.d.ts +6 -0
- package/dist/mcp-server/staticPrompts.js +6 -0
- package/dist/mcp-server/toolDefinitionsCache.d.ts +33 -0
- package/dist/mcp-server/toolDefinitionsCache.js +67 -0
- package/dist/mcp-server/toolHandlers/callToolHandler.d.ts +3 -0
- package/dist/mcp-server/toolHandlers/callToolHandler.js +79 -0
- package/dist/mcp-server/toolHandlers/getServerConfigHandler.d.ts +3 -0
- package/dist/mcp-server/toolHandlers/getServerConfigHandler.js +69 -0
- package/dist/mcp-server/toolHandlers/initHandler.d.ts +3 -0
- package/dist/mcp-server/toolHandlers/initHandler.js +117 -0
- package/dist/mcp-server/toolHandlers/installServerHandler.d.ts +3 -0
- package/dist/mcp-server/toolHandlers/installServerHandler.js +151 -0
- package/dist/mcp-server/toolHandlers/listServersHandler.d.ts +2 -0
- package/dist/mcp-server/toolHandlers/listServersHandler.js +81 -0
- package/dist/mcp-server/toolHandlers/listToolsHandler.d.ts +3 -0
- package/dist/mcp-server/toolHandlers/listToolsHandler.js +112 -0
- package/dist/mcp-server/toolHandlers/logPlaybookUsageHandler.d.ts +3 -0
- package/dist/mcp-server/toolHandlers/logPlaybookUsageHandler.js +65 -0
- package/dist/mcp-server/toolHandlers/lookupEntityHandler.d.ts +3 -0
- package/dist/mcp-server/toolHandlers/lookupEntityHandler.js +112 -0
- package/dist/mcp-server/toolHandlers/savePlaybookHandler.d.ts +3 -0
- package/dist/mcp-server/toolHandlers/savePlaybookHandler.js +65 -0
- package/dist/mcp-server/toolHandlers/searchHandler.d.ts +3 -0
- package/dist/mcp-server/toolHandlers/searchHandler.js +114 -0
- package/dist/mcp-server/toolHandlers/serverManagerUtils.d.ts +2 -0
- package/dist/mcp-server/toolHandlers/serverManagerUtils.js +20 -0
- package/dist/mcp-server/toolHandlers/submitFeedbackHandler.d.ts +3 -0
- package/dist/mcp-server/toolHandlers/submitFeedbackHandler.js +70 -0
- package/dist/mcp-server/toolHandlers/uninstallServerHandler.d.ts +3 -0
- package/dist/mcp-server/toolHandlers/uninstallServerHandler.js +83 -0
- package/dist/mcp-server/toolplexApi/service.d.ts +32 -0
- package/dist/mcp-server/toolplexApi/service.js +222 -0
- package/dist/mcp-server/toolplexApi/types.d.ts +124 -0
- package/dist/mcp-server/toolplexApi/types.js +1 -0
- package/dist/mcp-server/toolplexServer.d.ts +3 -0
- package/dist/mcp-server/toolplexServer.js +249 -0
- package/dist/mcp-server/tools.d.ts +2 -0
- package/dist/mcp-server/tools.js +13 -0
- package/dist/mcp-server/utils/initServerManagers.d.ts +6 -0
- package/dist/mcp-server/utils/initServerManagers.js +31 -0
- package/dist/mcp-server/utils/resultAnnotators.d.ts +23 -0
- package/dist/mcp-server/utils/resultAnnotators.js +50 -0
- package/dist/mcp-server/utils/runtimeCheck.d.ts +4 -0
- package/dist/mcp-server/utils/runtimeCheck.js +30 -0
- package/dist/server-manager/index.d.ts +1 -0
- package/dist/server-manager/index.js +8 -0
- package/dist/server-manager/serverManager.d.ts +37 -0
- package/dist/server-manager/serverManager.js +419 -0
- package/dist/server-manager/stdioServer.d.ts +9 -0
- package/dist/server-manager/stdioServer.js +136 -0
- package/dist/server-manager/stdioTransportProtocol.d.ts +31 -0
- package/dist/server-manager/stdioTransportProtocol.js +67 -0
- package/dist/shared/enhancedPath.d.ts +7 -0
- package/dist/shared/enhancedPath.js +52 -0
- package/dist/shared/fileLogger.d.ts +13 -0
- package/dist/shared/fileLogger.js +66 -0
- package/dist/shared/mcpServerTypes.d.ts +398 -0
- package/dist/shared/mcpServerTypes.js +148 -0
- package/dist/shared/serverManagerTypes.d.ts +179 -0
- package/dist/shared/serverManagerTypes.js +73 -0
- package/dist/shared/stdioServerManagerClient.d.ts +12 -0
- package/dist/shared/stdioServerManagerClient.js +96 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +1 -0
- package/package.json +70 -0
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
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
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
28
|
+
const logger = FileLogger;
|
|
29
|
+
export async function serve(config) {
|
|
30
|
+
const clientContext = new ClientContext();
|
|
31
|
+
clientContext.dev = config.dev;
|
|
32
|
+
clientContext.apiKey = config.apiKey;
|
|
33
|
+
clientContext.clientMode = config.clientMode;
|
|
34
|
+
clientContext.clientVersion = clientVersion;
|
|
35
|
+
await Registry.init(clientContext);
|
|
36
|
+
await logger.info(`Starting Toolplex server in ${config.dev ? 'development' : 'production'} mode`);
|
|
37
|
+
const server = new Server({
|
|
38
|
+
name: 'toolplex-server',
|
|
39
|
+
version: clientContext.clientVersion,
|
|
40
|
+
}, {
|
|
41
|
+
capabilities: {
|
|
42
|
+
resources: {},
|
|
43
|
+
tools: {},
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
// Initialize server manager clients
|
|
47
|
+
await logger.info('Initializing server manager clients');
|
|
48
|
+
const serverManagerClients = {
|
|
49
|
+
node: new StdioServerManagerClient('node', [path.join(__dirname, '..', 'server-manager', 'index.js')], { LOG_LEVEL: config.logLevel }),
|
|
50
|
+
};
|
|
51
|
+
// Start all server manager clients
|
|
52
|
+
await logger.info('Starting server manager clients');
|
|
53
|
+
await Promise.all(Object.values(serverManagerClients).map((client) => client.start()));
|
|
54
|
+
await logger.info('All server manager clients started successfully');
|
|
55
|
+
Registry.setServerManagerClients(serverManagerClients);
|
|
56
|
+
// List tools handler
|
|
57
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
58
|
+
await logger.debug('Handling list tools request');
|
|
59
|
+
return {
|
|
60
|
+
tools: createToolDefinitions(),
|
|
61
|
+
};
|
|
62
|
+
});
|
|
63
|
+
// Call tool handler
|
|
64
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
65
|
+
const { name, arguments: params } = request.params;
|
|
66
|
+
await logger.info(`Handling tool call request for tool: ${name}`);
|
|
67
|
+
let result;
|
|
68
|
+
if (!Registry.getToolDefinitionsCache().isInitialized()) {
|
|
69
|
+
result = {
|
|
70
|
+
role: 'system',
|
|
71
|
+
content: [
|
|
72
|
+
{
|
|
73
|
+
type: 'text',
|
|
74
|
+
text: PRE_INITIALIZATION_PROMPTS.tools_initialization_error,
|
|
75
|
+
},
|
|
76
|
+
],
|
|
77
|
+
};
|
|
78
|
+
return result;
|
|
79
|
+
}
|
|
80
|
+
if (!clientContext.isInitialized() && name !== 'initialize_toolplex') {
|
|
81
|
+
result = {
|
|
82
|
+
role: 'system',
|
|
83
|
+
content: [
|
|
84
|
+
{
|
|
85
|
+
type: 'text',
|
|
86
|
+
text: PRE_INITIALIZATION_PROMPTS.enforce_init_toolplex.replace('{TOOL_NAME}', name),
|
|
87
|
+
},
|
|
88
|
+
],
|
|
89
|
+
};
|
|
90
|
+
return result;
|
|
91
|
+
}
|
|
92
|
+
try {
|
|
93
|
+
switch (name) {
|
|
94
|
+
case 'initialize_toolplex': {
|
|
95
|
+
await logger.debug('Handling initialize_toolplex request');
|
|
96
|
+
const parsed = InitializeToolplexParamsSchema.safeParse(params);
|
|
97
|
+
if (!parsed.success)
|
|
98
|
+
throw new Error(`Invalid initialize_toolplex params: ${parsed.error}`);
|
|
99
|
+
clientContext.llmContext = parsed.data.llm_context;
|
|
100
|
+
result = await handleInitialize(parsed.data);
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
case 'search': {
|
|
104
|
+
await logger.debug('Handling search request');
|
|
105
|
+
const parsed = SearchParamsSchema.safeParse(params);
|
|
106
|
+
if (!parsed.success)
|
|
107
|
+
throw new Error(`Invalid search params: ${parsed.error}`);
|
|
108
|
+
result = await handleSearchTool(parsed.data);
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
case 'install': {
|
|
112
|
+
await logger.debug('Handling install request');
|
|
113
|
+
const parsed = InstallParamsSchema.safeParse(params);
|
|
114
|
+
if (!parsed.success)
|
|
115
|
+
throw new Error(`Invalid install params: ${parsed.error}`);
|
|
116
|
+
result = await handleInstallServer(parsed.data);
|
|
117
|
+
server.sendToolListChanged();
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
case 'list_tools': {
|
|
121
|
+
await logger.debug('Handling list_tools request');
|
|
122
|
+
const parsed = ListToolsParamsSchema.safeParse(params);
|
|
123
|
+
if (!parsed.success)
|
|
124
|
+
throw new Error(`Invalid list_toolplex_tools params: ${parsed.error}`);
|
|
125
|
+
result = await handleListTools(parsed.data);
|
|
126
|
+
break;
|
|
127
|
+
}
|
|
128
|
+
case 'list_servers': {
|
|
129
|
+
await logger.debug('Handling list_toolplex_tools request');
|
|
130
|
+
result = await handleListServers();
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
133
|
+
case 'call_tool': {
|
|
134
|
+
await logger.debug('Handling call_tool request');
|
|
135
|
+
const parsed = CallToolParamsSchema.safeParse(params);
|
|
136
|
+
if (!parsed.success)
|
|
137
|
+
throw new Error(`Invalid call_tool params: ${parsed.error}`);
|
|
138
|
+
result = await handleCallTool(parsed.data);
|
|
139
|
+
break;
|
|
140
|
+
}
|
|
141
|
+
case 'uninstall': {
|
|
142
|
+
await logger.debug('Handling uninstall request');
|
|
143
|
+
const parsed = UninstallParamsSchema.safeParse(params);
|
|
144
|
+
if (!parsed.success)
|
|
145
|
+
throw new Error(`Invalid uninstall params: ${parsed.error}`);
|
|
146
|
+
result = await handleUninstallServer(parsed.data);
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
case 'save_playbook': {
|
|
150
|
+
await logger.debug('Handling save_playbook request');
|
|
151
|
+
const parsed = SavePlaybookParamsSchema.safeParse(params);
|
|
152
|
+
if (!parsed.success)
|
|
153
|
+
throw new Error(`Invalid save_playbook params: ${parsed.error}`);
|
|
154
|
+
if (!clientContext.isInitialized())
|
|
155
|
+
throw new Error(`ToolPlex is not initialized`);
|
|
156
|
+
result = await handleSavePlaybook(parsed.data);
|
|
157
|
+
break;
|
|
158
|
+
}
|
|
159
|
+
case 'log_playbook_usage': {
|
|
160
|
+
await logger.debug('Handling log_playbook_usage request');
|
|
161
|
+
const parsed = LogPlaybookUsageParamsSchema.safeParse(params);
|
|
162
|
+
if (!parsed.success)
|
|
163
|
+
throw new Error(`Invalid log_playbook_usage params: ${parsed.error}`);
|
|
164
|
+
if (!clientContext.isInitialized())
|
|
165
|
+
throw new Error(`ToolPlex is not initialized`);
|
|
166
|
+
result = await handleLogPlaybookUsage(parsed.data);
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
169
|
+
case 'lookup_entity': {
|
|
170
|
+
await logger.debug('Handling lookup_entity request');
|
|
171
|
+
const parsed = LookupEntityParamsSchema.safeParse(params);
|
|
172
|
+
if (!parsed.success)
|
|
173
|
+
throw new Error(`Invalid lookup_entity params: ${parsed.error}`);
|
|
174
|
+
result = await handleLookupEntityTool(parsed.data);
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
case 'submit_feedback': {
|
|
178
|
+
await logger.debug('Handling submit_feedback request');
|
|
179
|
+
const parsed = SubmitFeedbackParamsSchema.safeParse(params);
|
|
180
|
+
if (!parsed.success)
|
|
181
|
+
throw new Error(`Invalid submit_feedback params: ${parsed.error}`);
|
|
182
|
+
if (!clientContext.isInitialized())
|
|
183
|
+
throw new Error(`ToolPlex is not initialized`);
|
|
184
|
+
result = await handleSubmitFeedback(parsed.data);
|
|
185
|
+
break;
|
|
186
|
+
}
|
|
187
|
+
// Add get_server_config tool handler
|
|
188
|
+
case 'get_server_config': {
|
|
189
|
+
await logger.debug('Handling get_server_config request');
|
|
190
|
+
const parsed = GetServerConfigParamsSchema.safeParse(params);
|
|
191
|
+
if (!parsed.success)
|
|
192
|
+
throw new Error(`Invalid get_server_config params: ${parsed.error}`);
|
|
193
|
+
result = await handleGetServerConfig(parsed.data);
|
|
194
|
+
break;
|
|
195
|
+
}
|
|
196
|
+
default:
|
|
197
|
+
await logger.warn(`Unknown tool requested: ${name}`);
|
|
198
|
+
result = {
|
|
199
|
+
role: 'system',
|
|
200
|
+
content: [
|
|
201
|
+
{
|
|
202
|
+
type: 'text',
|
|
203
|
+
text: PRE_INITIALIZATION_PROMPTS.unknown_tool.replace('{TOOL_NAME}', name),
|
|
204
|
+
},
|
|
205
|
+
],
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
catch (error) {
|
|
210
|
+
let errorMessage = 'Unknown error occurred';
|
|
211
|
+
if (error instanceof Error) {
|
|
212
|
+
errorMessage = error.message;
|
|
213
|
+
}
|
|
214
|
+
await logger.error(`Error calling ToolPlex: ${errorMessage}`);
|
|
215
|
+
result = {
|
|
216
|
+
role: 'system',
|
|
217
|
+
content: [
|
|
218
|
+
{
|
|
219
|
+
type: 'text',
|
|
220
|
+
text: PRE_INITIALIZATION_PROMPTS.unexpected_error.replace('{ERROR}', errorMessage),
|
|
221
|
+
},
|
|
222
|
+
],
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
return result;
|
|
226
|
+
});
|
|
227
|
+
const transport = new StdioServerTransport();
|
|
228
|
+
await logger.info('Connecting server transport');
|
|
229
|
+
await server.connect(transport);
|
|
230
|
+
await logger.info('Server transport connected successfully');
|
|
231
|
+
// Clean up on process exit
|
|
232
|
+
process.on('exit', async () => {
|
|
233
|
+
await logger.info('Process exit - stopping server manager clients');
|
|
234
|
+
await logger.flush();
|
|
235
|
+
Object.values(serverManagerClients).forEach((client) => client.stop());
|
|
236
|
+
});
|
|
237
|
+
process.on('SIGINT', async () => {
|
|
238
|
+
await logger.warn('SIGINT received - stopping server manager clients');
|
|
239
|
+
await logger.flush();
|
|
240
|
+
Object.values(serverManagerClients).forEach((client) => client.stop());
|
|
241
|
+
process.exit();
|
|
242
|
+
});
|
|
243
|
+
process.on('SIGTERM', async () => {
|
|
244
|
+
await logger.warn('SIGTERM received - stopping server manager clients');
|
|
245
|
+
await logger.flush();
|
|
246
|
+
Object.values(serverManagerClients).forEach((client) => client.stop());
|
|
247
|
+
process.exit();
|
|
248
|
+
});
|
|
249
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import Registry from './registry.js';
|
|
2
|
+
export function createToolDefinitions() {
|
|
3
|
+
const toolDefinitionsCache = Registry.getToolDefinitionsCache();
|
|
4
|
+
if (!toolDefinitionsCache.isInitialized()) {
|
|
5
|
+
return [
|
|
6
|
+
{
|
|
7
|
+
name: 'initialize_toolplex',
|
|
8
|
+
inputSchema: { type: 'object', properties: {}, required: [] },
|
|
9
|
+
},
|
|
10
|
+
];
|
|
11
|
+
}
|
|
12
|
+
return toolDefinitionsCache.getTools();
|
|
13
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { StdioServerManagerClient } from '../../shared/stdioServerManagerClient.js';
|
|
2
|
+
import { InitializeResult } from '../../shared/serverManagerTypes.js';
|
|
3
|
+
export declare function initServerManagersOnly(serverManagerClients: Record<string, StdioServerManagerClient>): Promise<{
|
|
4
|
+
succeeded: InitializeResult['succeeded'];
|
|
5
|
+
failures: InitializeResult['failures'];
|
|
6
|
+
}>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { InitializeResultSchema } from '../../shared/serverManagerTypes.js';
|
|
2
|
+
import { FileLogger } from '../../shared/fileLogger.js';
|
|
3
|
+
const logger = FileLogger;
|
|
4
|
+
export async function initServerManagersOnly(serverManagerClients) {
|
|
5
|
+
await logger.info('Pre-warming server manager clients');
|
|
6
|
+
const initPromises = Object.entries(serverManagerClients).map(async ([runtime, client]) => {
|
|
7
|
+
try {
|
|
8
|
+
const response = await client.sendRequest('initialize', {});
|
|
9
|
+
if ('error' in response)
|
|
10
|
+
throw new Error(response.error.message);
|
|
11
|
+
const parsed = InitializeResultSchema.safeParse(response);
|
|
12
|
+
if (!parsed.success)
|
|
13
|
+
throw new Error(parsed.error.message);
|
|
14
|
+
return { runtime, result: parsed.data };
|
|
15
|
+
}
|
|
16
|
+
catch (err) {
|
|
17
|
+
await logger.error(`Warmup error for ${runtime}: ${err}`);
|
|
18
|
+
return { runtime, result: { succeeded: [], failures: {} } };
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
const results = await Promise.all(initPromises);
|
|
22
|
+
const allSucceeded = [];
|
|
23
|
+
const allFailures = {};
|
|
24
|
+
for (const { runtime, result } of results) {
|
|
25
|
+
allSucceeded.push(...(result.succeeded || []));
|
|
26
|
+
Object.assign(allFailures, result.failures || {});
|
|
27
|
+
await logger.debug(`Warmup result for ${runtime}: ${JSON.stringify(result)}`);
|
|
28
|
+
}
|
|
29
|
+
await logger.debug(`Warmup completed: ${allSucceeded.length} successes, ${Object.keys(allFailures).length} failures`);
|
|
30
|
+
return { succeeded: allSucceeded, failures: allFailures };
|
|
31
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Annotate a server object with "(installed)" in the server_name or set installed: true,
|
|
3
|
+
* if the server is installed according to the provided serversCache.
|
|
4
|
+
*
|
|
5
|
+
* This is used in both searchHandler and lookupEntityHandler.
|
|
6
|
+
*
|
|
7
|
+
* @param server - The server object to annotate (should have server_id and optionally server_name)
|
|
8
|
+
* @param serversCache - The ServersCache instance with isInstalled(server_id) method
|
|
9
|
+
* @returns The annotated server object (may be the same object if not installed)
|
|
10
|
+
*/
|
|
11
|
+
export declare function annotateInstalledServer(server: any, serversCache: {
|
|
12
|
+
isInstalled: (id: string) => boolean;
|
|
13
|
+
}): any;
|
|
14
|
+
/**
|
|
15
|
+
* Annotate an array of server objects with installed status.
|
|
16
|
+
*
|
|
17
|
+
* @param servers - Array of server objects
|
|
18
|
+
* @param serversCache - The ServersCache instance
|
|
19
|
+
* @returns Annotated array of server objects
|
|
20
|
+
*/
|
|
21
|
+
export declare function annotateInstalledServers(servers: any[], serversCache: {
|
|
22
|
+
isInstalled: (id: string) => boolean;
|
|
23
|
+
}): any[];
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Annotate a server object with "(installed)" in the server_name or set installed: true,
|
|
3
|
+
* if the server is installed according to the provided serversCache.
|
|
4
|
+
*
|
|
5
|
+
* This is used in both searchHandler and lookupEntityHandler.
|
|
6
|
+
*
|
|
7
|
+
* @param server - The server object to annotate (should have server_id and optionally server_name)
|
|
8
|
+
* @param serversCache - The ServersCache instance with isInstalled(server_id) method
|
|
9
|
+
* @returns The annotated server object (may be the same object if not installed)
|
|
10
|
+
*/
|
|
11
|
+
export function annotateInstalledServer(
|
|
12
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
13
|
+
server, serversCache
|
|
14
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
15
|
+
) {
|
|
16
|
+
if (!server || typeof server !== 'object' || !server.server_id) {
|
|
17
|
+
return server;
|
|
18
|
+
}
|
|
19
|
+
if (serversCache.isInstalled(server.server_id)) {
|
|
20
|
+
if (server.server_name) {
|
|
21
|
+
return {
|
|
22
|
+
...server,
|
|
23
|
+
server_name: `${server.server_name} (installed)`,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
return {
|
|
28
|
+
...server,
|
|
29
|
+
installed: true,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return server;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Annotate an array of server objects with installed status.
|
|
37
|
+
*
|
|
38
|
+
* @param servers - Array of server objects
|
|
39
|
+
* @param serversCache - The ServersCache instance
|
|
40
|
+
* @returns Annotated array of server objects
|
|
41
|
+
*/
|
|
42
|
+
export function annotateInstalledServers(
|
|
43
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
44
|
+
servers, serversCache
|
|
45
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
46
|
+
) {
|
|
47
|
+
if (!Array.isArray(servers))
|
|
48
|
+
return [];
|
|
49
|
+
return servers.map((server) => annotateInstalledServer(server, serversCache));
|
|
50
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { getEnhancedPath } from '../../shared/enhancedPath.js';
|
|
2
|
+
import which from 'which';
|
|
3
|
+
const INSTALL_HINTS = {
|
|
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
|
+
};
|
|
11
|
+
export class RuntimeCheck {
|
|
12
|
+
static validateCommandOrThrow(rawCommand) {
|
|
13
|
+
const command = this.extractCommandName(rawCommand);
|
|
14
|
+
const enhancedPath = getEnhancedPath();
|
|
15
|
+
const resolved = which.sync(command, {
|
|
16
|
+
path: enhancedPath,
|
|
17
|
+
nothrow: true,
|
|
18
|
+
});
|
|
19
|
+
if (!resolved) {
|
|
20
|
+
const hint = INSTALL_HINTS[command];
|
|
21
|
+
if (hint) {
|
|
22
|
+
throw new Error(`Missing required command: '${command}'.\n👉 ${hint}`);
|
|
23
|
+
}
|
|
24
|
+
throw new Error(`Command '${command}' not found in enhanced PATH. Please install it manually or check your config.`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
static extractCommandName(command) {
|
|
28
|
+
return command.trim().split(/\s+/)[0];
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { ServerManagerProtocol } from './stdioServer.js';
|
|
2
|
+
import { FileLogger } from '../shared/fileLogger.js';
|
|
3
|
+
FileLogger.initialize('server-manager');
|
|
4
|
+
const protocol = new ServerManagerProtocol();
|
|
5
|
+
protocol.start().catch((error) => {
|
|
6
|
+
console.error('Failed to start server:', error);
|
|
7
|
+
process.exit(1);
|
|
8
|
+
});
|
|
@@ -0,0 +1,37 @@
|
|
|
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
|
+
export declare class ServerManager {
|
|
8
|
+
private sessions;
|
|
9
|
+
private tools;
|
|
10
|
+
private serverNames;
|
|
11
|
+
private configPath;
|
|
12
|
+
private config;
|
|
13
|
+
private installationPromises;
|
|
14
|
+
private configLock;
|
|
15
|
+
constructor();
|
|
16
|
+
private loadConfig;
|
|
17
|
+
private saveConfig;
|
|
18
|
+
initialize(): Promise<InitializeResult>;
|
|
19
|
+
getServerName(serverId: string): Promise<string>;
|
|
20
|
+
connectWithHandshakeTimeout(client: Client, transport: SSEClientTransport | StdioClientTransport, ms?: number): Promise<{
|
|
21
|
+
tools?: Tool[];
|
|
22
|
+
}>;
|
|
23
|
+
install(serverId: string, serverName: string, description: string, config: ServerConfig): Promise<void>;
|
|
24
|
+
private performInstall;
|
|
25
|
+
callTool(serverId: string, toolName: string, arguments_: Record<string, any>, timeout?: number): Promise<any>;
|
|
26
|
+
uninstall(serverId: string): Promise<void>;
|
|
27
|
+
removeServer(serverId: string): Promise<void>;
|
|
28
|
+
listServers(): Promise<Array<{
|
|
29
|
+
server_id: string;
|
|
30
|
+
server_name: string;
|
|
31
|
+
tool_count: number;
|
|
32
|
+
description: string;
|
|
33
|
+
}>>;
|
|
34
|
+
listTools(serverId: string): Promise<Tool[]>;
|
|
35
|
+
getServerConfig(serverId: string): Promise<ServerConfig>;
|
|
36
|
+
cleanup(): Promise<void>;
|
|
37
|
+
}
|