mcp-orbit 0.1.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/LICENSE +21 -0
- package/README.md +247 -0
- package/dist/__tests__/helpers/test-server.d.ts +2 -0
- package/dist/__tests__/helpers/test-server.d.ts.map +1 -0
- package/dist/__tests__/helpers/test-server.js +27 -0
- package/dist/__tests__/helpers/test-server.js.map +1 -0
- package/dist/cli.d.ts +23 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +56 -0
- package/dist/cli.js.map +1 -0
- package/dist/clients/mcp-http.d.ts +36 -0
- package/dist/clients/mcp-http.d.ts.map +1 -0
- package/dist/clients/mcp-http.js +148 -0
- package/dist/clients/mcp-http.js.map +1 -0
- package/dist/clients/mcp-stdio.d.ts +38 -0
- package/dist/clients/mcp-stdio.d.ts.map +1 -0
- package/dist/clients/mcp-stdio.js +164 -0
- package/dist/clients/mcp-stdio.js.map +1 -0
- package/dist/clients/types.d.ts +104 -0
- package/dist/clients/types.d.ts.map +1 -0
- package/dist/clients/types.js +8 -0
- package/dist/clients/types.js.map +1 -0
- package/dist/core/prompt-registry.d.ts +56 -0
- package/dist/core/prompt-registry.d.ts.map +1 -0
- package/dist/core/prompt-registry.js +100 -0
- package/dist/core/prompt-registry.js.map +1 -0
- package/dist/core/resource-registry.d.ts +79 -0
- package/dist/core/resource-registry.d.ts.map +1 -0
- package/dist/core/resource-registry.js +135 -0
- package/dist/core/resource-registry.js.map +1 -0
- package/dist/core/resource-uri-templates.d.ts +64 -0
- package/dist/core/resource-uri-templates.d.ts.map +1 -0
- package/dist/core/resource-uri-templates.js +168 -0
- package/dist/core/resource-uri-templates.js.map +1 -0
- package/dist/core/server-http.d.ts +15 -0
- package/dist/core/server-http.d.ts.map +1 -0
- package/dist/core/server-http.js +302 -0
- package/dist/core/server-http.js.map +1 -0
- package/dist/core/server-stdio.d.ts +8 -0
- package/dist/core/server-stdio.d.ts.map +1 -0
- package/dist/core/server-stdio.js +15 -0
- package/dist/core/server-stdio.js.map +1 -0
- package/dist/core/server.d.ts +29 -0
- package/dist/core/server.d.ts.map +1 -0
- package/dist/core/server.js +265 -0
- package/dist/core/server.js.map +1 -0
- package/dist/core/types.d.ts +265 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +9 -0
- package/dist/core/types.js.map +1 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/utils/dynamic-resource-manager.d.ts +115 -0
- package/dist/utils/dynamic-resource-manager.d.ts.map +1 -0
- package/dist/utils/dynamic-resource-manager.js +460 -0
- package/dist/utils/dynamic-resource-manager.js.map +1 -0
- package/dist/utils/http-client.d.ts +29 -0
- package/dist/utils/http-client.d.ts.map +1 -0
- package/dist/utils/http-client.js +59 -0
- package/dist/utils/http-client.js.map +1 -0
- package/dist/utils/logger.d.ts +25 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +105 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/zod-to-mcp-schema.d.ts +42 -0
- package/dist/utils/zod-to-mcp-schema.d.ts.map +1 -0
- package/dist/utils/zod-to-mcp-schema.js +87 -0
- package/dist/utils/zod-to-mcp-schema.js.map +1 -0
- package/package.json +57 -0
- package/src/__tests__/helpers/test-server.ts +31 -0
- package/src/__tests__/plugin-system.basic.test.ts +137 -0
- package/src/__tests__/server.basic.test.ts +37 -0
- package/src/__tests__/stdio-roundtrip.basic.test.ts +67 -0
- package/src/__tests__/tool-registry.basic.test.ts +114 -0
- package/src/__tests__/zod-schema.basic.test.ts +105 -0
- package/src/cli.ts +58 -0
- package/src/clients/mcp-http.ts +192 -0
- package/src/clients/mcp-stdio.ts +209 -0
- package/src/clients/types.ts +136 -0
- package/src/core/prompt-registry.ts +114 -0
- package/src/core/resource-registry.ts +166 -0
- package/src/core/resource-uri-templates.ts +216 -0
- package/src/core/server-http.ts +407 -0
- package/src/core/server-stdio.ts +20 -0
- package/src/core/server.ts +320 -0
- package/src/core/types.ts +312 -0
- package/src/index.ts +92 -0
- package/src/utils/dynamic-resource-manager.ts +581 -0
- package/src/utils/http-client.ts +86 -0
- package/src/utils/logger.ts +138 -0
- package/src/utils/zod-to-mcp-schema.ts +127 -0
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP Server Transport (Protocol 2025-03-26)
|
|
3
|
+
*
|
|
4
|
+
* Modern MCP server implementation using StreamableHTTPServerTransport
|
|
5
|
+
* - Session management with transport reuse
|
|
6
|
+
* - Support for GET/POST/DELETE methods
|
|
7
|
+
* - Optional resumability with event store
|
|
8
|
+
* - Bearer token authentication
|
|
9
|
+
* - Health check endpoint
|
|
10
|
+
*
|
|
11
|
+
* Based on MCP SDK official examples
|
|
12
|
+
*/
|
|
13
|
+
import { createServer } from "node:http";
|
|
14
|
+
import { randomUUID } from "node:crypto";
|
|
15
|
+
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
16
|
+
import { isInitializeRequest } from "@modelcontextprotocol/sdk/types.js";
|
|
17
|
+
import logger from "../utils/logger.js";
|
|
18
|
+
const serverLogger = logger.child("server-http2");
|
|
19
|
+
// ============================================================================
|
|
20
|
+
// CONFIGURATION
|
|
21
|
+
// ============================================================================
|
|
22
|
+
const HEALTH_ENDPOINTS = ["/health"];
|
|
23
|
+
const MCP_ENDPOINT = "/mcp";
|
|
24
|
+
// ============================================================================
|
|
25
|
+
// REQUEST CONTEXT & LOGGING
|
|
26
|
+
// ============================================================================
|
|
27
|
+
function createRequestContext(req) {
|
|
28
|
+
return {
|
|
29
|
+
requestId: `${Date.now()}-${Math.random().toString(36).substring(7)}`,
|
|
30
|
+
startTime: Date.now(),
|
|
31
|
+
clientIp: req.socket.remoteAddress || "unknown",
|
|
32
|
+
userAgent: req.headers["user-agent"] || "unknown",
|
|
33
|
+
method: req.method || "UNKNOWN",
|
|
34
|
+
url: req.url || "/",
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function logRequest(context, sessionId) {
|
|
38
|
+
serverLogger.debug("HTTP request", {
|
|
39
|
+
requestId: context.requestId,
|
|
40
|
+
method: context.method,
|
|
41
|
+
url: context.url,
|
|
42
|
+
sessionId,
|
|
43
|
+
ip: context.clientIp,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
function logResponse(statusCode, context, message) {
|
|
47
|
+
const duration = Date.now() - context.startTime;
|
|
48
|
+
const logData = {
|
|
49
|
+
requestId: context.requestId,
|
|
50
|
+
statusCode,
|
|
51
|
+
duration: `${duration}ms`,
|
|
52
|
+
message,
|
|
53
|
+
};
|
|
54
|
+
if (statusCode >= 400) {
|
|
55
|
+
serverLogger.warn("HTTP response (error)", logData);
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
serverLogger.debug("HTTP response (success)", logData);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
// ============================================================================
|
|
62
|
+
// RESPONSE HELPERS
|
|
63
|
+
// ============================================================================
|
|
64
|
+
function sendJsonResponse(res, statusCode, data, context) {
|
|
65
|
+
res.statusCode = statusCode;
|
|
66
|
+
res.setHeader("Content-Type", "application/json");
|
|
67
|
+
res.end(JSON.stringify(data));
|
|
68
|
+
logResponse(statusCode, context, JSON.stringify(data).substring(0, 100));
|
|
69
|
+
}
|
|
70
|
+
function sendJsonRpcError(res, statusCode, code, message, context) {
|
|
71
|
+
sendJsonResponse(res, statusCode, {
|
|
72
|
+
jsonrpc: "2.0",
|
|
73
|
+
error: { code, message },
|
|
74
|
+
id: null,
|
|
75
|
+
}, context);
|
|
76
|
+
}
|
|
77
|
+
// ============================================================================
|
|
78
|
+
// AUTHENTICATION
|
|
79
|
+
// ============================================================================
|
|
80
|
+
function checkAuthentication(req) {
|
|
81
|
+
const apiKey = process.env.MCP_ORBIT_API_KEY;
|
|
82
|
+
// No API key configured = no auth required (development mode)
|
|
83
|
+
if (!apiKey) {
|
|
84
|
+
return { authenticated: true };
|
|
85
|
+
}
|
|
86
|
+
const authHeader = req.headers["authorization"];
|
|
87
|
+
const expectedAuth = `Bearer ${apiKey}`;
|
|
88
|
+
if (!authHeader) {
|
|
89
|
+
return {
|
|
90
|
+
authenticated: false,
|
|
91
|
+
reason: "No Authorization header provided",
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
if (authHeader !== expectedAuth) {
|
|
95
|
+
return {
|
|
96
|
+
authenticated: false,
|
|
97
|
+
reason: "Invalid API key",
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
return { authenticated: true };
|
|
101
|
+
}
|
|
102
|
+
// ============================================================================
|
|
103
|
+
// REQUEST HANDLERS
|
|
104
|
+
// ============================================================================
|
|
105
|
+
function isHealthCheckRequest(req) {
|
|
106
|
+
return req.method === "GET" && HEALTH_ENDPOINTS.includes(req.url);
|
|
107
|
+
}
|
|
108
|
+
function handleHealthCheck(res, context) {
|
|
109
|
+
sendJsonResponse(res, 200, {
|
|
110
|
+
status: "ok",
|
|
111
|
+
service: "mcp-orbit",
|
|
112
|
+
transport: "streamable-http",
|
|
113
|
+
protocol: "2025-03-26",
|
|
114
|
+
timestamp: Date.now(),
|
|
115
|
+
uptime: process.uptime(),
|
|
116
|
+
}, context);
|
|
117
|
+
}
|
|
118
|
+
async function handleMCPRequest(req, res, context, mcpServer, transports) {
|
|
119
|
+
// 1. Check authentication for MCP requests
|
|
120
|
+
const authResult = checkAuthentication(req);
|
|
121
|
+
if (!authResult.authenticated) {
|
|
122
|
+
serverLogger.warn("Unauthorized MCP request", {
|
|
123
|
+
requestId: context.requestId,
|
|
124
|
+
ip: context.clientIp,
|
|
125
|
+
reason: authResult.reason,
|
|
126
|
+
});
|
|
127
|
+
sendJsonRpcError(res, 401, -32000, `Unauthorized: ${authResult.reason}`, context);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
// 2. Read and parse request body
|
|
131
|
+
const bodyBuffer = await readRequestBody(req);
|
|
132
|
+
let parsedBody;
|
|
133
|
+
try {
|
|
134
|
+
parsedBody = bodyBuffer.length > 0 ? JSON.parse(bodyBuffer.toString("utf8")) : undefined;
|
|
135
|
+
}
|
|
136
|
+
catch (parseError) {
|
|
137
|
+
serverLogger.error("Failed to parse JSON", {
|
|
138
|
+
requestId: context.requestId,
|
|
139
|
+
error: parseError instanceof Error ? parseError.message : String(parseError),
|
|
140
|
+
});
|
|
141
|
+
sendJsonRpcError(res, 400, -32700, "Parse error: Invalid JSON", context);
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
// 3. Get or create transport (SDK pattern)
|
|
145
|
+
const sessionId = req.headers["mcp-session-id"];
|
|
146
|
+
let transport;
|
|
147
|
+
logRequest(context, sessionId);
|
|
148
|
+
if (sessionId && transports[sessionId]) {
|
|
149
|
+
// Reuse existing transport
|
|
150
|
+
transport = transports[sessionId];
|
|
151
|
+
serverLogger.debug("Reusing existing transport", {
|
|
152
|
+
requestId: context.requestId,
|
|
153
|
+
sessionId,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
else if (!sessionId && req.method === "POST" && isInitializeRequest(parsedBody)) {
|
|
157
|
+
// Create new transport for initialization request
|
|
158
|
+
serverLogger.info("Creating new transport (initialize request)", {
|
|
159
|
+
requestId: context.requestId,
|
|
160
|
+
});
|
|
161
|
+
transport = new StreamableHTTPServerTransport({
|
|
162
|
+
sessionIdGenerator: () => randomUUID(),
|
|
163
|
+
enableJsonResponse: true,
|
|
164
|
+
onsessioninitialized: (newSessionId) => {
|
|
165
|
+
serverLogger.info("Session initialized", {
|
|
166
|
+
requestId: context.requestId,
|
|
167
|
+
sessionId: newSessionId,
|
|
168
|
+
});
|
|
169
|
+
transports[newSessionId] = transport;
|
|
170
|
+
},
|
|
171
|
+
});
|
|
172
|
+
// Set up close handler for cleanup
|
|
173
|
+
transport.onclose = () => {
|
|
174
|
+
const sid = transport.sessionId;
|
|
175
|
+
if (sid && transports[sid]) {
|
|
176
|
+
serverLogger.info("Transport closed, cleaning up session", { sessionId: sid });
|
|
177
|
+
delete transports[sid];
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
// Connect transport to MCP server
|
|
181
|
+
await mcpServer.connect(transport);
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
// Invalid request - no session ID or not an initialization request
|
|
185
|
+
serverLogger.warn("Invalid request: no session ID and not an initialize request", {
|
|
186
|
+
requestId: context.requestId,
|
|
187
|
+
method: req.method,
|
|
188
|
+
hasSessionId: !!sessionId,
|
|
189
|
+
isInitialize: isInitializeRequest(parsedBody),
|
|
190
|
+
});
|
|
191
|
+
sendJsonRpcError(res, 400, -32000, "Bad Request: No valid session ID provided or not an initialize request", context);
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
// 4. Handle request with transport
|
|
195
|
+
try {
|
|
196
|
+
await transport.handleRequest(req, res, parsedBody);
|
|
197
|
+
// Log method if available
|
|
198
|
+
const mcpMethod = parsedBody?.method;
|
|
199
|
+
logResponse(res.statusCode || 200, context, `mcp:${mcpMethod || "unknown"}`);
|
|
200
|
+
}
|
|
201
|
+
catch (error) {
|
|
202
|
+
serverLogger.error("Transport handleRequest failed", {
|
|
203
|
+
requestId: context.requestId,
|
|
204
|
+
sessionId: transport.sessionId,
|
|
205
|
+
error: error instanceof Error ? error.message : String(error),
|
|
206
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
207
|
+
});
|
|
208
|
+
if (!res.headersSent) {
|
|
209
|
+
sendJsonRpcError(res, 500, -32603, "Internal server error", context);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
function readRequestBody(req) {
|
|
214
|
+
return new Promise((resolve, reject) => {
|
|
215
|
+
const chunks = [];
|
|
216
|
+
req.on("data", (chunk) => {
|
|
217
|
+
chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk);
|
|
218
|
+
});
|
|
219
|
+
req.on("error", reject);
|
|
220
|
+
req.on("end", () => {
|
|
221
|
+
resolve(Buffer.concat(chunks));
|
|
222
|
+
});
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
// ============================================================================
|
|
226
|
+
// SERVER STARTUP
|
|
227
|
+
// ============================================================================
|
|
228
|
+
export async function startHttpServer(port, host, mcpServer, logSecurityStatus, logServerStats) {
|
|
229
|
+
// Transport storage for session management (SDK pattern)
|
|
230
|
+
const transports = {};
|
|
231
|
+
// Security warning
|
|
232
|
+
if (host === "0.0.0.0") {
|
|
233
|
+
serverLogger.warn("Binding to 0.0.0.0 (all interfaces) - ensure API key is configured!");
|
|
234
|
+
}
|
|
235
|
+
// Create HTTP server
|
|
236
|
+
const httpServer = createServer(async (req, res) => {
|
|
237
|
+
const context = createRequestContext(req);
|
|
238
|
+
try {
|
|
239
|
+
// Route: Health check (no auth required)
|
|
240
|
+
if (isHealthCheckRequest(req)) {
|
|
241
|
+
handleHealthCheck(res, context);
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
// Route: MCP endpoint (auth required, all methods supported)
|
|
245
|
+
if (req.url === MCP_ENDPOINT) {
|
|
246
|
+
await handleMCPRequest(req, res, context, mcpServer, transports);
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
// Route: Unknown endpoint
|
|
250
|
+
serverLogger.warn("Unknown endpoint", {
|
|
251
|
+
requestId: context.requestId,
|
|
252
|
+
url: req.url,
|
|
253
|
+
});
|
|
254
|
+
sendJsonRpcError(res, 404, -32000, `Not Found: Unknown endpoint '${req.url}'`, context);
|
|
255
|
+
}
|
|
256
|
+
catch (error) {
|
|
257
|
+
serverLogger.error("Unhandled request error", {
|
|
258
|
+
requestId: context.requestId,
|
|
259
|
+
error: error instanceof Error ? error.message : String(error),
|
|
260
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
261
|
+
});
|
|
262
|
+
if (!res.headersSent) {
|
|
263
|
+
sendJsonRpcError(res, 500, -32603, "Internal server error", context);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
// Start server
|
|
268
|
+
await new Promise((resolve, reject) => {
|
|
269
|
+
httpServer.listen(port, host, () => resolve());
|
|
270
|
+
httpServer.on("error", reject);
|
|
271
|
+
});
|
|
272
|
+
// Graceful shutdown
|
|
273
|
+
const cleanup = async () => {
|
|
274
|
+
serverLogger.info("Shutting down server...");
|
|
275
|
+
// Close all active transports
|
|
276
|
+
const sessionIds = Object.keys(transports);
|
|
277
|
+
if (sessionIds.length > 0) {
|
|
278
|
+
serverLogger.info(`Closing ${sessionIds.length} active sessions`);
|
|
279
|
+
await Promise.all(sessionIds.map(async (sessionId) => {
|
|
280
|
+
try {
|
|
281
|
+
await transports[sessionId].close();
|
|
282
|
+
delete transports[sessionId];
|
|
283
|
+
}
|
|
284
|
+
catch (error) {
|
|
285
|
+
serverLogger.error(`Error closing transport for session ${sessionId}`, {
|
|
286
|
+
error: error instanceof Error ? error.message : String(error),
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
}));
|
|
290
|
+
}
|
|
291
|
+
httpServer.close(() => process.exit(0));
|
|
292
|
+
};
|
|
293
|
+
process.on("SIGINT", cleanup);
|
|
294
|
+
process.on("SIGTERM", cleanup);
|
|
295
|
+
// Log startup info
|
|
296
|
+
serverLogger.info("MCP Server ready (Streamable HTTP Transport - Protocol 2025-03-26)");
|
|
297
|
+
serverLogger.info(` URL: http://${host}:${port}${MCP_ENDPOINT}`);
|
|
298
|
+
serverLogger.info(` Health: http://${host}:${port}/health`);
|
|
299
|
+
logSecurityStatus();
|
|
300
|
+
logServerStats();
|
|
301
|
+
}
|
|
302
|
+
//# sourceMappingURL=server-http.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-http.js","sourceRoot":"","sources":["../../src/core/server-http.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stdio Server Transport
|
|
3
|
+
*
|
|
4
|
+
* Handles stdio transport for MCP server (Claude Desktop, CLI clients)
|
|
5
|
+
*/
|
|
6
|
+
import type { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
7
|
+
export declare function startStdioServer(mcpServer: Server, logServerStats: () => void): Promise<void>;
|
|
8
|
+
//# sourceMappingURL=server-stdio.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-stdio.d.ts","sourceRoot":"","sources":["../../src/core/server-stdio.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,2CAA2C,CAAC;AAKtE,wBAAsB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAOnG"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stdio Server Transport
|
|
3
|
+
*
|
|
4
|
+
* Handles stdio transport for MCP server (Claude Desktop, CLI clients)
|
|
5
|
+
*/
|
|
6
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
7
|
+
import logger from "../utils/logger.js";
|
|
8
|
+
const serverLogger = logger.child("server");
|
|
9
|
+
export async function startStdioServer(mcpServer, logServerStats) {
|
|
10
|
+
const transport = new StdioServerTransport();
|
|
11
|
+
await mcpServer.connect(transport);
|
|
12
|
+
serverLogger.info("MCP Server ready (stdio transport)");
|
|
13
|
+
logServerStats();
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=server-stdio.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-stdio.js","sourceRoot":"","sources":["../../src/core/server-stdio.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAC,oBAAoB,EAAC,MAAM,2CAA2C,CAAC;AAE/E,OAAO,MAAM,MAAM,oBAAoB,CAAC;AAExC,MAAM,YAAY,GAAG,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;AAE5C,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,SAAiB,EAAE,cAA0B;IAClF,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAE7C,MAAM,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAEnC,YAAY,CAAC,IAAI,CAAC,oCAAoC,CAAC,CAAC;IACxD,cAAc,EAAE,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
2
|
+
import type { Tool, MCPToolResult, MCPToolDefinition, MCPPlugin } from "./types.js";
|
|
3
|
+
export type TransportMode = "stdio" | "http";
|
|
4
|
+
export interface ServerConfig {
|
|
5
|
+
mode: TransportMode;
|
|
6
|
+
httpPort?: number;
|
|
7
|
+
httpHost?: string;
|
|
8
|
+
tools?: Tool[];
|
|
9
|
+
plugins?: MCPPlugin[];
|
|
10
|
+
serverName?: string;
|
|
11
|
+
serverVersion?: string;
|
|
12
|
+
}
|
|
13
|
+
export declare function registerTool(tool: Tool): void;
|
|
14
|
+
/**
|
|
15
|
+
* Register an entire plugin (tools + resources + prompts) in one call.
|
|
16
|
+
*
|
|
17
|
+
* ```typescript
|
|
18
|
+
* import { krakenPlugin } from "mcp-plugin-kraken";
|
|
19
|
+
* await registerPlugin(krakenPlugin);
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export declare function registerPlugin(plugin: MCPPlugin): Promise<void>;
|
|
23
|
+
export declare function getTool(name: string): Tool | undefined;
|
|
24
|
+
export declare function getToolDefinitions(): MCPToolDefinition[];
|
|
25
|
+
export declare function getToolCount(): number;
|
|
26
|
+
export declare function executeTool(name: string, args: unknown): Promise<MCPToolResult>;
|
|
27
|
+
export declare function createMCPServer(name?: string, version?: string): Server;
|
|
28
|
+
export declare function startServer(config: ServerConfig): Promise<void>;
|
|
29
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/core/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,MAAM,EAAC,MAAM,2CAA2C,CAAC;AAiBjE,OAAO,KAAK,EAAC,IAAI,EAAE,aAAa,EAAE,iBAAiB,EAAE,SAAS,EAAC,MAAM,YAAY,CAAC;AAUlF,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,MAAM,CAAC;AAC7C,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,aAAa,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,IAAI,EAAE,CAAC;IACf,OAAO,CAAC,EAAE,SAAS,EAAE,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAID,wBAAgB,YAAY,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAK7C;AAED;;;;;;;GAOG;AACH,wBAAsB,cAAc,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAmBrE;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAEtD;AAED,wBAAgB,kBAAkB,IAAI,iBAAiB,EAAE,CASxD;AAED,wBAAgB,YAAY,IAAI,MAAM,CAErC;AA+DD,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,aAAa,CAAC,CA8BrF;AAED,wBAAgB,eAAe,CAAC,IAAI,SAAc,EAAE,OAAO,SAAU,GAAG,MAAM,CA+E7E;AA4BD,wBAAsB,WAAW,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAwBrE"}
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
2
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
3
|
+
import { inspect } from "node:util";
|
|
4
|
+
import { resourceRegistry } from "./resource-registry.js";
|
|
5
|
+
import { promptRegistry } from "./prompt-registry.js";
|
|
6
|
+
import { startHttpServer } from "./server-http.js";
|
|
7
|
+
import { startStdioServer } from "./server-stdio.js";
|
|
8
|
+
import logger from "../utils/logger.js";
|
|
9
|
+
import { isZodArray } from "../utils/zod-to-mcp-schema.js";
|
|
10
|
+
import { createAndRegisterResource } from "./resource-registry.js";
|
|
11
|
+
import { createAndRegisterPrompt } from "./prompt-registry.js";
|
|
12
|
+
const serverLogger = logger.child("server");
|
|
13
|
+
const toolLogger = logger.child("tools");
|
|
14
|
+
const DEFAULT_HTTP_PORT = 3333;
|
|
15
|
+
const DEFAULT_HTTP_HOST = "0.0.0.0";
|
|
16
|
+
const MAX_PREVIEW = 160;
|
|
17
|
+
const toolRegistry = new Map();
|
|
18
|
+
export function registerTool(tool) {
|
|
19
|
+
if (toolRegistry.has(tool.definition.name)) {
|
|
20
|
+
toolLogger.warn(`Tool '${tool.definition.name}' already registered, overwriting.`);
|
|
21
|
+
}
|
|
22
|
+
toolRegistry.set(tool.definition.name, tool);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Register an entire plugin (tools + resources + prompts) in one call.
|
|
26
|
+
*
|
|
27
|
+
* ```typescript
|
|
28
|
+
* import { krakenPlugin } from "mcp-plugin-kraken";
|
|
29
|
+
* await registerPlugin(krakenPlugin);
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export async function registerPlugin(plugin) {
|
|
33
|
+
const pluginLogger = serverLogger.child(plugin.name);
|
|
34
|
+
if (plugin.init) {
|
|
35
|
+
pluginLogger.info("Initializing plugin...");
|
|
36
|
+
await plugin.init();
|
|
37
|
+
}
|
|
38
|
+
const toolCount = plugin.tools?.length ?? 0;
|
|
39
|
+
const resourceCount = plugin.resources?.length ?? 0;
|
|
40
|
+
const promptCount = plugin.prompts?.length ?? 0;
|
|
41
|
+
plugin.tools?.forEach((tool) => registerTool(tool));
|
|
42
|
+
plugin.resources?.forEach((resource) => createAndRegisterResource(resource));
|
|
43
|
+
plugin.prompts?.forEach((prompt) => createAndRegisterPrompt(prompt));
|
|
44
|
+
pluginLogger.info(`Plugin registered: ${toolCount} tools, ${resourceCount} resources, ${promptCount} prompts`);
|
|
45
|
+
}
|
|
46
|
+
export function getTool(name) {
|
|
47
|
+
return toolRegistry.get(name);
|
|
48
|
+
}
|
|
49
|
+
export function getToolDefinitions() {
|
|
50
|
+
return Array.from(toolRegistry.values()).map((tool) => {
|
|
51
|
+
const def = tool.definition;
|
|
52
|
+
// Inject tags into _meta so they survive MCP SDK's Zod stripping
|
|
53
|
+
if (def.tags && def.tags.length > 0) {
|
|
54
|
+
return { ...def, _meta: { ...def._meta, tags: def.tags } };
|
|
55
|
+
}
|
|
56
|
+
return def;
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
export function getToolCount() {
|
|
60
|
+
return toolRegistry.size;
|
|
61
|
+
}
|
|
62
|
+
// Helpers
|
|
63
|
+
const getErrorMsg = (err) => (err instanceof Error ? `${err.name}: ${err.message}` : String(err));
|
|
64
|
+
const truncate = (text, maxLen) => (text.length <= maxLen ? text : `${text.slice(0, maxLen - 3)}...`);
|
|
65
|
+
const formatArgsPreview = (args) => {
|
|
66
|
+
try {
|
|
67
|
+
const sanitized = JSON.parse(JSON.stringify(args));
|
|
68
|
+
const preview = inspect(sanitized, {
|
|
69
|
+
depth: 2,
|
|
70
|
+
breakLength: 80,
|
|
71
|
+
maxArrayLength: 10,
|
|
72
|
+
maxStringLength: 120,
|
|
73
|
+
colors: false,
|
|
74
|
+
});
|
|
75
|
+
return truncate(preview, MAX_PREVIEW).replace(/\s+/g, " ").trim();
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
return "[unprintable arguments]";
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
const formatResultSummary = (result) => {
|
|
82
|
+
const parts = [result.isError ? "error" : "ok"];
|
|
83
|
+
if (Array.isArray(result.content) && result.content.length > 0) {
|
|
84
|
+
const firstContent = result.content[0];
|
|
85
|
+
if (firstContent?.type === "text" && typeof firstContent.text === "string") {
|
|
86
|
+
parts.push(`text="${truncate(firstContent.text.trim(), MAX_PREVIEW)}"`);
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
const types = [...new Set(result.content.map((c) => c.type))];
|
|
90
|
+
parts.push(`contentTypes=[${types.join(",")}]`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
parts.push("content=none");
|
|
95
|
+
}
|
|
96
|
+
const structured = result.structuredContent;
|
|
97
|
+
if (structured !== undefined) {
|
|
98
|
+
if (Array.isArray(structured)) {
|
|
99
|
+
parts.push(`structured=array(len=${structured.length})`);
|
|
100
|
+
}
|
|
101
|
+
else if (structured && typeof structured === "object") {
|
|
102
|
+
const keys = Object.keys(structured).slice(0, 4);
|
|
103
|
+
const hasMore = Object.keys(structured).length > keys.length ? "..." : "";
|
|
104
|
+
parts.push(`structuredKeys=[${keys.join(",")}${hasMore}]`);
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
parts.push(`structured=${typeof structured}`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return parts.join(" | ");
|
|
111
|
+
};
|
|
112
|
+
const getRuntimeInputSchema = (tool) => {
|
|
113
|
+
if (!tool.runtimeInputSchema) {
|
|
114
|
+
throw new Error(`Tool '${tool.definition.name}' has no runtimeInputSchema configured`);
|
|
115
|
+
}
|
|
116
|
+
return tool.runtimeInputSchema;
|
|
117
|
+
};
|
|
118
|
+
const getRuntimeOutputSchema = (tool) => tool.runtimeOutputSchema;
|
|
119
|
+
export async function executeTool(name, args) {
|
|
120
|
+
const tool = getTool(name);
|
|
121
|
+
if (!tool)
|
|
122
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
123
|
+
const logPrefix = `[tool] ${name}`;
|
|
124
|
+
const start = Date.now();
|
|
125
|
+
toolLogger.info(`🔧 TOOL CALL: ${name} | args=${formatArgsPreview(args)}`);
|
|
126
|
+
let validatedArgs;
|
|
127
|
+
try {
|
|
128
|
+
validatedArgs = getRuntimeInputSchema(tool).parse(args);
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
const duration = Date.now() - start;
|
|
132
|
+
toolLogger.error(`${logPrefix} validation failed (${duration}ms): ${getErrorMsg(error)}`);
|
|
133
|
+
throw error;
|
|
134
|
+
}
|
|
135
|
+
let result;
|
|
136
|
+
try {
|
|
137
|
+
result = await tool.execute(validatedArgs);
|
|
138
|
+
}
|
|
139
|
+
catch (error) {
|
|
140
|
+
const duration = Date.now() - start;
|
|
141
|
+
toolLogger.error(`${logPrefix} execution failed (${duration}ms): ${getErrorMsg(error)}`);
|
|
142
|
+
throw error;
|
|
143
|
+
}
|
|
144
|
+
const duration = Date.now() - start;
|
|
145
|
+
toolLogger.info(`✅ TOOL COMPLETED: ${name} | ${duration}ms | status=${result.isError ? "ERROR" : "OK"}`);
|
|
146
|
+
return result;
|
|
147
|
+
}
|
|
148
|
+
export function createMCPServer(name = "mcp-orbit", version = "1.0.0") {
|
|
149
|
+
const server = new Server({
|
|
150
|
+
name,
|
|
151
|
+
version,
|
|
152
|
+
}, {
|
|
153
|
+
capabilities: {
|
|
154
|
+
tools: {},
|
|
155
|
+
resources: { listChanged: true },
|
|
156
|
+
prompts: {},
|
|
157
|
+
},
|
|
158
|
+
});
|
|
159
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
160
|
+
try {
|
|
161
|
+
const definitions = getToolDefinitions();
|
|
162
|
+
return {
|
|
163
|
+
tools: definitions,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
catch (error) {
|
|
167
|
+
serverLogger.error("Error getting tool definitions:", getErrorMsg(error));
|
|
168
|
+
throw error; // Re-throw to ensure the client receives an error response
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
172
|
+
const { name, arguments: args } = request.params;
|
|
173
|
+
try {
|
|
174
|
+
const result = await executeTool(name, args);
|
|
175
|
+
const tool = getTool(name);
|
|
176
|
+
const runtimeOutputSchema = tool ? getRuntimeOutputSchema(tool) : undefined;
|
|
177
|
+
// Automatically wrap array outputs to match the schema transformation
|
|
178
|
+
if (runtimeOutputSchema && isZodArray(runtimeOutputSchema) && result.structuredContent) {
|
|
179
|
+
result.structuredContent = { result: result.structuredContent };
|
|
180
|
+
}
|
|
181
|
+
return {
|
|
182
|
+
content: result.content,
|
|
183
|
+
structuredContent: result.structuredContent,
|
|
184
|
+
_meta: result._meta,
|
|
185
|
+
isError: result.isError,
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
catch (error) {
|
|
189
|
+
return {
|
|
190
|
+
isError: true,
|
|
191
|
+
content: [{ type: "text", text: `Tool execution failed: ${getErrorMsg(error)}` }],
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
server.setRequestHandler(ListResourcesRequestSchema, async () => ({
|
|
196
|
+
resources: resourceRegistry.listDefinitions(),
|
|
197
|
+
}));
|
|
198
|
+
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
199
|
+
try {
|
|
200
|
+
return await resourceRegistry.read(request.params.uri);
|
|
201
|
+
}
|
|
202
|
+
catch (error) {
|
|
203
|
+
throw new Error(`Failed to read resource: ${getErrorMsg(error)}`);
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
server.setRequestHandler(ListPromptsRequestSchema, async () => ({
|
|
207
|
+
prompts: promptRegistry.listDefinitions(),
|
|
208
|
+
}));
|
|
209
|
+
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
210
|
+
const { name, arguments: args } = request.params;
|
|
211
|
+
try {
|
|
212
|
+
return await promptRegistry.get(name, args);
|
|
213
|
+
}
|
|
214
|
+
catch (error) {
|
|
215
|
+
throw new Error(`Failed to get prompt: ${getErrorMsg(error)}`);
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
return server;
|
|
219
|
+
}
|
|
220
|
+
function logSecurityStatus() {
|
|
221
|
+
const status = process.env.MCP_ORBIT_API_KEY
|
|
222
|
+
? " Auth: ✓ API Key authentication enabled"
|
|
223
|
+
: " Auth: ✗ No MCP_ORBIT_API_KEY set — server accepts all requests (development mode).";
|
|
224
|
+
const logger = process.env.MCP_ORBIT_API_KEY ? serverLogger.info : serverLogger.warn;
|
|
225
|
+
logger(status);
|
|
226
|
+
}
|
|
227
|
+
function logServerStats() {
|
|
228
|
+
const toolNames = getToolDefinitions()
|
|
229
|
+
.map((t) => t.name)
|
|
230
|
+
.join(", ");
|
|
231
|
+
const resourceUris = resourceRegistry
|
|
232
|
+
.listDefinitions()
|
|
233
|
+
.map((r) => r.uri)
|
|
234
|
+
.join(", ");
|
|
235
|
+
const promptNames = promptRegistry
|
|
236
|
+
.listDefinitions()
|
|
237
|
+
.map((p) => p.name)
|
|
238
|
+
.join(", ");
|
|
239
|
+
serverLogger.info(` Tools: ${getToolCount()} (${toolNames})`);
|
|
240
|
+
serverLogger.info(` Resources: ${resourceRegistry.count} (${resourceUris})`);
|
|
241
|
+
serverLogger.info(` Prompts: ${promptRegistry.count} (${promptNames})`);
|
|
242
|
+
}
|
|
243
|
+
export async function startServer(config) {
|
|
244
|
+
// Auto-redirect logs to stderr in stdio mode (prevents JSON-RPC stream corruption)
|
|
245
|
+
if (config.mode === "stdio") {
|
|
246
|
+
const { _setForceStdErrMode } = await import("../utils/logger.js");
|
|
247
|
+
_setForceStdErrMode(true);
|
|
248
|
+
}
|
|
249
|
+
config.tools?.forEach((tool) => registerTool(tool));
|
|
250
|
+
// Register plugins (tools + resources + prompts in one call)
|
|
251
|
+
if (config.plugins) {
|
|
252
|
+
for (const plugin of config.plugins) {
|
|
253
|
+
await registerPlugin(plugin);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
const mcpServer = createMCPServer(config.serverName, config.serverVersion);
|
|
257
|
+
const { mode, httpPort = DEFAULT_HTTP_PORT, httpHost = DEFAULT_HTTP_HOST } = config;
|
|
258
|
+
if (mode === "http") {
|
|
259
|
+
await startHttpServer(httpPort, httpHost, mcpServer, logSecurityStatus, logServerStats);
|
|
260
|
+
}
|
|
261
|
+
else {
|
|
262
|
+
await startStdioServer(mcpServer, logServerStats);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
//# sourceMappingURL=server.js.map
|