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.
Files changed (93) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +247 -0
  3. package/dist/__tests__/helpers/test-server.d.ts +2 -0
  4. package/dist/__tests__/helpers/test-server.d.ts.map +1 -0
  5. package/dist/__tests__/helpers/test-server.js +27 -0
  6. package/dist/__tests__/helpers/test-server.js.map +1 -0
  7. package/dist/cli.d.ts +23 -0
  8. package/dist/cli.d.ts.map +1 -0
  9. package/dist/cli.js +56 -0
  10. package/dist/cli.js.map +1 -0
  11. package/dist/clients/mcp-http.d.ts +36 -0
  12. package/dist/clients/mcp-http.d.ts.map +1 -0
  13. package/dist/clients/mcp-http.js +148 -0
  14. package/dist/clients/mcp-http.js.map +1 -0
  15. package/dist/clients/mcp-stdio.d.ts +38 -0
  16. package/dist/clients/mcp-stdio.d.ts.map +1 -0
  17. package/dist/clients/mcp-stdio.js +164 -0
  18. package/dist/clients/mcp-stdio.js.map +1 -0
  19. package/dist/clients/types.d.ts +104 -0
  20. package/dist/clients/types.d.ts.map +1 -0
  21. package/dist/clients/types.js +8 -0
  22. package/dist/clients/types.js.map +1 -0
  23. package/dist/core/prompt-registry.d.ts +56 -0
  24. package/dist/core/prompt-registry.d.ts.map +1 -0
  25. package/dist/core/prompt-registry.js +100 -0
  26. package/dist/core/prompt-registry.js.map +1 -0
  27. package/dist/core/resource-registry.d.ts +79 -0
  28. package/dist/core/resource-registry.d.ts.map +1 -0
  29. package/dist/core/resource-registry.js +135 -0
  30. package/dist/core/resource-registry.js.map +1 -0
  31. package/dist/core/resource-uri-templates.d.ts +64 -0
  32. package/dist/core/resource-uri-templates.d.ts.map +1 -0
  33. package/dist/core/resource-uri-templates.js +168 -0
  34. package/dist/core/resource-uri-templates.js.map +1 -0
  35. package/dist/core/server-http.d.ts +15 -0
  36. package/dist/core/server-http.d.ts.map +1 -0
  37. package/dist/core/server-http.js +302 -0
  38. package/dist/core/server-http.js.map +1 -0
  39. package/dist/core/server-stdio.d.ts +8 -0
  40. package/dist/core/server-stdio.d.ts.map +1 -0
  41. package/dist/core/server-stdio.js +15 -0
  42. package/dist/core/server-stdio.js.map +1 -0
  43. package/dist/core/server.d.ts +29 -0
  44. package/dist/core/server.d.ts.map +1 -0
  45. package/dist/core/server.js +265 -0
  46. package/dist/core/server.js.map +1 -0
  47. package/dist/core/types.d.ts +265 -0
  48. package/dist/core/types.d.ts.map +1 -0
  49. package/dist/core/types.js +9 -0
  50. package/dist/core/types.js.map +1 -0
  51. package/dist/index.d.ts +28 -0
  52. package/dist/index.d.ts.map +1 -0
  53. package/dist/index.js +26 -0
  54. package/dist/index.js.map +1 -0
  55. package/dist/utils/dynamic-resource-manager.d.ts +115 -0
  56. package/dist/utils/dynamic-resource-manager.d.ts.map +1 -0
  57. package/dist/utils/dynamic-resource-manager.js +460 -0
  58. package/dist/utils/dynamic-resource-manager.js.map +1 -0
  59. package/dist/utils/http-client.d.ts +29 -0
  60. package/dist/utils/http-client.d.ts.map +1 -0
  61. package/dist/utils/http-client.js +59 -0
  62. package/dist/utils/http-client.js.map +1 -0
  63. package/dist/utils/logger.d.ts +25 -0
  64. package/dist/utils/logger.d.ts.map +1 -0
  65. package/dist/utils/logger.js +105 -0
  66. package/dist/utils/logger.js.map +1 -0
  67. package/dist/utils/zod-to-mcp-schema.d.ts +42 -0
  68. package/dist/utils/zod-to-mcp-schema.d.ts.map +1 -0
  69. package/dist/utils/zod-to-mcp-schema.js +87 -0
  70. package/dist/utils/zod-to-mcp-schema.js.map +1 -0
  71. package/package.json +57 -0
  72. package/src/__tests__/helpers/test-server.ts +31 -0
  73. package/src/__tests__/plugin-system.basic.test.ts +137 -0
  74. package/src/__tests__/server.basic.test.ts +37 -0
  75. package/src/__tests__/stdio-roundtrip.basic.test.ts +67 -0
  76. package/src/__tests__/tool-registry.basic.test.ts +114 -0
  77. package/src/__tests__/zod-schema.basic.test.ts +105 -0
  78. package/src/cli.ts +58 -0
  79. package/src/clients/mcp-http.ts +192 -0
  80. package/src/clients/mcp-stdio.ts +209 -0
  81. package/src/clients/types.ts +136 -0
  82. package/src/core/prompt-registry.ts +114 -0
  83. package/src/core/resource-registry.ts +166 -0
  84. package/src/core/resource-uri-templates.ts +216 -0
  85. package/src/core/server-http.ts +407 -0
  86. package/src/core/server-stdio.ts +20 -0
  87. package/src/core/server.ts +320 -0
  88. package/src/core/types.ts +312 -0
  89. package/src/index.ts +92 -0
  90. package/src/utils/dynamic-resource-manager.ts +581 -0
  91. package/src/utils/http-client.ts +86 -0
  92. package/src/utils/logger.ts +138 -0
  93. 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