@epicdm/flowstate-mcp-gateway 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -0
- package/dist/cli.d.mts +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +395 -0
- package/dist/cli.js.map +1 -0
- package/dist/cli.mjs +372 -0
- package/dist/cli.mjs.map +1 -0
- package/dist/index.d.mts +86 -0
- package/dist/index.d.ts +86 -0
- package/dist/index.js +335 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +298 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +58 -0
package/README.md
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# FlowState MCP Gateway
|
|
2
|
+
|
|
3
|
+
HTTP/REST gateway for FlowState MCP server, enabling web and Electron clients to access MCP tools.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- RESTful API for MCP tool execution
|
|
8
|
+
- CORS support for web clients
|
|
9
|
+
- Environment-based configuration
|
|
10
|
+
- Health check endpoint
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
yarn add @epic-flow/flowstate-mcp-gateway
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Usage
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
# Start server
|
|
22
|
+
yarn start
|
|
23
|
+
|
|
24
|
+
# Development mode
|
|
25
|
+
yarn dev
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## API Endpoints
|
|
29
|
+
|
|
30
|
+
- `GET /health` - Health check
|
|
31
|
+
- `GET /mcp/tools` - List available tools
|
|
32
|
+
- `POST /mcp/tools/call` - Execute a tool
|
package/dist/cli.d.mts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
18
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
19
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
20
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
21
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
22
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
23
|
+
mod
|
|
24
|
+
));
|
|
25
|
+
|
|
26
|
+
// src/server.ts
|
|
27
|
+
var import_express = __toESM(require("express"));
|
|
28
|
+
var import_cors = __toESM(require("cors"));
|
|
29
|
+
var import_flowstate_mcp = require("@epicdm/flowstate-mcp");
|
|
30
|
+
|
|
31
|
+
// src/InMemoryTransport.ts
|
|
32
|
+
var import_events = require("events");
|
|
33
|
+
var InMemoryTransport = class {
|
|
34
|
+
sessionId;
|
|
35
|
+
onclose;
|
|
36
|
+
onerror;
|
|
37
|
+
onmessage;
|
|
38
|
+
started = false;
|
|
39
|
+
emitter = new import_events.EventEmitter();
|
|
40
|
+
responseHandlers = /* @__PURE__ */ new Map();
|
|
41
|
+
async start() {
|
|
42
|
+
this.started = true;
|
|
43
|
+
this.sessionId = `inmemory-${Date.now()}-${Math.random().toString(36).substring(7)}`;
|
|
44
|
+
}
|
|
45
|
+
async send(message) {
|
|
46
|
+
if (!this.started) {
|
|
47
|
+
throw new Error("Transport not started");
|
|
48
|
+
}
|
|
49
|
+
if ("result" in message || "error" in message) {
|
|
50
|
+
const response = message;
|
|
51
|
+
const handler = this.responseHandlers.get(response.id);
|
|
52
|
+
if (handler) {
|
|
53
|
+
handler(message);
|
|
54
|
+
this.responseHandlers.delete(response.id);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
async close() {
|
|
59
|
+
this.started = false;
|
|
60
|
+
this.responseHandlers.clear();
|
|
61
|
+
this.onclose?.();
|
|
62
|
+
}
|
|
63
|
+
setProtocolVersion(version) {
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Send a request and wait for response
|
|
67
|
+
* Used by the gateway to make programmatic requests
|
|
68
|
+
*/
|
|
69
|
+
async sendRequest(request) {
|
|
70
|
+
if (!this.started) {
|
|
71
|
+
throw new Error("Transport not started");
|
|
72
|
+
}
|
|
73
|
+
return new Promise((resolve2, reject) => {
|
|
74
|
+
const req = request;
|
|
75
|
+
const timeout = setTimeout(() => {
|
|
76
|
+
this.responseHandlers.delete(req.id);
|
|
77
|
+
reject(new Error("Request timeout"));
|
|
78
|
+
}, 6e4);
|
|
79
|
+
this.responseHandlers.set(req.id, (response) => {
|
|
80
|
+
clearTimeout(timeout);
|
|
81
|
+
resolve2(response);
|
|
82
|
+
});
|
|
83
|
+
if (this.onmessage) {
|
|
84
|
+
this.onmessage(request);
|
|
85
|
+
} else {
|
|
86
|
+
reject(new Error("Transport not connected to server"));
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
// src/server.ts
|
|
93
|
+
var MCPGatewayServer = class {
|
|
94
|
+
app;
|
|
95
|
+
mcpServer;
|
|
96
|
+
config;
|
|
97
|
+
isInitialized = false;
|
|
98
|
+
httpServer;
|
|
99
|
+
transport;
|
|
100
|
+
constructor(config2) {
|
|
101
|
+
this.config = config2;
|
|
102
|
+
this.app = (0, import_express.default)();
|
|
103
|
+
this.mcpServer = new import_flowstate_mcp.FlowStateMCPServer({
|
|
104
|
+
rxdbServerUrl: config2.rxdbServerUrl,
|
|
105
|
+
domainId: config2.domainId,
|
|
106
|
+
projectPath: config2.projectPath || process.cwd(),
|
|
107
|
+
...config2.userId && { userId: config2.userId },
|
|
108
|
+
...config2.orgId && { orgId: config2.orgId }
|
|
109
|
+
});
|
|
110
|
+
this.setupMiddleware();
|
|
111
|
+
this.setupRoutes();
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Get list of tools from MCP server
|
|
115
|
+
*
|
|
116
|
+
* WARNING: This method accesses internal MCP server API via type casting.
|
|
117
|
+
* This is necessary because FlowStateMCPServer doesn't expose a public method
|
|
118
|
+
* for listing tools. The underlying server.request() method is used directly.
|
|
119
|
+
*
|
|
120
|
+
* RISKS:
|
|
121
|
+
* - Internal API may change without notice in future versions
|
|
122
|
+
* - Type casting bypasses TypeScript safety checks
|
|
123
|
+
* - May break if FlowStateMCPServer implementation changes
|
|
124
|
+
*
|
|
125
|
+
* TODO: Consider requesting a public API method in FlowStateMCPServer
|
|
126
|
+
* for listing and calling tools to avoid internal API access.
|
|
127
|
+
*/
|
|
128
|
+
async listTools() {
|
|
129
|
+
if (!this.transport) {
|
|
130
|
+
return [];
|
|
131
|
+
}
|
|
132
|
+
const request = {
|
|
133
|
+
jsonrpc: "2.0",
|
|
134
|
+
id: Date.now(),
|
|
135
|
+
method: "tools/list"
|
|
136
|
+
};
|
|
137
|
+
const response = await this.transport.sendRequest(request);
|
|
138
|
+
if ("error" in response) {
|
|
139
|
+
throw new Error(response.error.message || "Failed to list tools");
|
|
140
|
+
}
|
|
141
|
+
return response.result?.tools || [];
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Call a tool on the MCP server
|
|
145
|
+
*
|
|
146
|
+
* WARNING: This method accesses internal MCP server API via type casting.
|
|
147
|
+
* This is necessary because FlowStateMCPServer doesn't expose a public method
|
|
148
|
+
* for calling tools. The underlying server.request() method is used directly.
|
|
149
|
+
*
|
|
150
|
+
* RISKS:
|
|
151
|
+
* - Internal API may change without notice in future versions
|
|
152
|
+
* - Type casting bypasses TypeScript safety checks
|
|
153
|
+
* - May break if FlowStateMCPServer implementation changes
|
|
154
|
+
*
|
|
155
|
+
* TODO: Consider requesting a public API method in FlowStateMCPServer
|
|
156
|
+
* for listing and calling tools to avoid internal API access.
|
|
157
|
+
*
|
|
158
|
+
* NOTE: The MCP SDK's server.request() method appears to require the request
|
|
159
|
+
* object to be passed twice (once as the request, once as params). This seems
|
|
160
|
+
* to be how the underlying MCP SDK expects the call to be structured based on
|
|
161
|
+
* the protocol specification.
|
|
162
|
+
*/
|
|
163
|
+
async callTool(toolName, args) {
|
|
164
|
+
if (!this.transport) {
|
|
165
|
+
throw new Error("MCP server not available");
|
|
166
|
+
}
|
|
167
|
+
const request = {
|
|
168
|
+
jsonrpc: "2.0",
|
|
169
|
+
id: Date.now(),
|
|
170
|
+
method: "tools/call",
|
|
171
|
+
params: {
|
|
172
|
+
name: toolName,
|
|
173
|
+
arguments: args
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
const response = await this.transport.sendRequest(request);
|
|
177
|
+
if ("error" in response) {
|
|
178
|
+
throw new Error(response.error.message || "Failed to call tool");
|
|
179
|
+
}
|
|
180
|
+
return response.result?.content?.[0]?.text || response.result;
|
|
181
|
+
}
|
|
182
|
+
setupMiddleware() {
|
|
183
|
+
this.app.use(
|
|
184
|
+
(0, import_cors.default)({
|
|
185
|
+
origin: this.config.corsOrigins || "*",
|
|
186
|
+
methods: ["GET", "POST", "OPTIONS"],
|
|
187
|
+
allowedHeaders: ["Content-Type", "Authorization"]
|
|
188
|
+
})
|
|
189
|
+
);
|
|
190
|
+
this.app.use(import_express.default.json());
|
|
191
|
+
this.app.use(import_express.default.urlencoded({ extended: true }));
|
|
192
|
+
this.app.use((req, res, next) => {
|
|
193
|
+
console.log(`${(/* @__PURE__ */ new Date()).toISOString()} ${req.method} ${req.path}`);
|
|
194
|
+
next();
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Extract and forward auth token from request to MCP server
|
|
199
|
+
*
|
|
200
|
+
* This enables per-request auth so each API call can use its own token,
|
|
201
|
+
* rather than relying on the initial config token.
|
|
202
|
+
*/
|
|
203
|
+
updateAuthFromRequest(req) {
|
|
204
|
+
const authHeader = req.headers["authorization"];
|
|
205
|
+
if (!authHeader) {
|
|
206
|
+
console.log("[MCP Gateway] No Authorization header in request");
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
const token = authHeader.toString().replace("Bearer ", "");
|
|
210
|
+
if (!token) {
|
|
211
|
+
console.log("[MCP Gateway] Empty token after Bearer prefix removal");
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
if (!token.startsWith("eyJ") && !token.startsWith("epic_")) {
|
|
215
|
+
console.log(`[MCP Gateway] Invalid token format (starts with: ${token.substring(0, 10)}...)`);
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
try {
|
|
219
|
+
;
|
|
220
|
+
this.mcpServer.config.authToken = token;
|
|
221
|
+
console.log("[MCP Gateway] Auth token updated from request");
|
|
222
|
+
} catch (error) {
|
|
223
|
+
console.error("[MCP Gateway] Failed to update auth config:", error);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
setupRoutes() {
|
|
227
|
+
this.app.get("/health", (req, res) => {
|
|
228
|
+
res.json({
|
|
229
|
+
status: "ok",
|
|
230
|
+
initialized: this.isInitialized,
|
|
231
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
232
|
+
});
|
|
233
|
+
});
|
|
234
|
+
this.app.get("/mcp/tools", async (req, res) => {
|
|
235
|
+
try {
|
|
236
|
+
if (!this.isInitialized) {
|
|
237
|
+
return res.status(503).json({
|
|
238
|
+
error: "Server not initialized"
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
this.updateAuthFromRequest(req);
|
|
242
|
+
const tools = await this.listTools();
|
|
243
|
+
res.json({ tools });
|
|
244
|
+
} catch (error) {
|
|
245
|
+
console.error("Error listing tools:", error);
|
|
246
|
+
res.status(500).json({
|
|
247
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
this.app.post("/mcp/tools/call", async (req, res) => {
|
|
252
|
+
try {
|
|
253
|
+
if (!this.isInitialized) {
|
|
254
|
+
return res.status(503).json({
|
|
255
|
+
success: false,
|
|
256
|
+
error: "Server not initialized"
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
this.updateAuthFromRequest(req);
|
|
260
|
+
const { toolName, arguments: args } = req.body;
|
|
261
|
+
if (!toolName) {
|
|
262
|
+
return res.status(400).json({
|
|
263
|
+
success: false,
|
|
264
|
+
error: "toolName is required"
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
const result = await this.callTool(toolName, args || {});
|
|
268
|
+
const response = {
|
|
269
|
+
success: true,
|
|
270
|
+
result
|
|
271
|
+
};
|
|
272
|
+
res.json(response);
|
|
273
|
+
} catch (error) {
|
|
274
|
+
console.error("Error calling tool:", error);
|
|
275
|
+
const response = {
|
|
276
|
+
success: false,
|
|
277
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
278
|
+
};
|
|
279
|
+
res.status(500).json(response);
|
|
280
|
+
}
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
async initialize() {
|
|
284
|
+
await this.mcpServer.initialize();
|
|
285
|
+
this.transport = new InMemoryTransport();
|
|
286
|
+
const server = this.mcpServer.server;
|
|
287
|
+
if (server) {
|
|
288
|
+
await server.connect(this.transport);
|
|
289
|
+
}
|
|
290
|
+
this.isInitialized = true;
|
|
291
|
+
console.log("MCP Gateway initialized");
|
|
292
|
+
}
|
|
293
|
+
async start() {
|
|
294
|
+
await this.initialize();
|
|
295
|
+
return new Promise((resolve2) => {
|
|
296
|
+
this.httpServer = this.app.listen(this.config.port, this.config.host, () => {
|
|
297
|
+
console.log(`MCP Gateway listening on http://${this.config.host}:${this.config.port}`);
|
|
298
|
+
resolve2();
|
|
299
|
+
});
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
async close() {
|
|
303
|
+
if (this.httpServer) {
|
|
304
|
+
await new Promise((resolve2, reject) => {
|
|
305
|
+
this.httpServer.close((err) => {
|
|
306
|
+
if (err) {
|
|
307
|
+
console.error("Error closing HTTP server:", err);
|
|
308
|
+
reject(err);
|
|
309
|
+
} else {
|
|
310
|
+
console.log("HTTP server closed");
|
|
311
|
+
resolve2();
|
|
312
|
+
}
|
|
313
|
+
});
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
await this.mcpServer.close();
|
|
317
|
+
console.log("MCP Gateway closed");
|
|
318
|
+
}
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
// src/cli.ts
|
|
322
|
+
var import_dotenv = require("dotenv");
|
|
323
|
+
var import_path = require("path");
|
|
324
|
+
(0, import_dotenv.config)({ path: (0, import_path.resolve)(process.cwd(), ".env") });
|
|
325
|
+
var isShuttingDown = false;
|
|
326
|
+
process.on("unhandledRejection", (reason, promise) => {
|
|
327
|
+
console.error("Unhandled Rejection at:", promise, "reason:", reason);
|
|
328
|
+
process.exit(1);
|
|
329
|
+
});
|
|
330
|
+
process.on("uncaughtException", (error) => {
|
|
331
|
+
console.error("Uncaught Exception:", error);
|
|
332
|
+
process.exit(1);
|
|
333
|
+
});
|
|
334
|
+
async function main() {
|
|
335
|
+
const gatewayConfig = {
|
|
336
|
+
port: parseInt(process.env.MCP_GATEWAY_PORT || "7081", 10),
|
|
337
|
+
host: process.env.MCP_GATEWAY_HOST || "0.0.0.0",
|
|
338
|
+
rxdbServerUrl: process.env.RXDB_SERVER_URL || "",
|
|
339
|
+
authToken: process.env.RXDB_AUTH_TOKEN || "",
|
|
340
|
+
domainId: process.env.RXDB_DOMAIN_ID || "",
|
|
341
|
+
projectPath: process.env.PROJECT_PATH,
|
|
342
|
+
userId: process.env.USER_ID,
|
|
343
|
+
orgId: process.env.ORG_ID,
|
|
344
|
+
corsOrigins: process.env.CORS_ORIGINS?.split(",")
|
|
345
|
+
};
|
|
346
|
+
if (!gatewayConfig.rxdbServerUrl) {
|
|
347
|
+
console.error("ERROR: RXDB_SERVER_URL is required");
|
|
348
|
+
process.exit(1);
|
|
349
|
+
}
|
|
350
|
+
if (!gatewayConfig.authToken) {
|
|
351
|
+
console.error("ERROR: RXDB_AUTH_TOKEN is required");
|
|
352
|
+
process.exit(1);
|
|
353
|
+
}
|
|
354
|
+
if (!gatewayConfig.domainId) {
|
|
355
|
+
console.error("ERROR: RXDB_DOMAIN_ID is required");
|
|
356
|
+
process.exit(1);
|
|
357
|
+
}
|
|
358
|
+
console.log("MCP Gateway starting with configuration:");
|
|
359
|
+
console.log(` Port: ${gatewayConfig.port}`);
|
|
360
|
+
console.log(` Host: ${gatewayConfig.host}`);
|
|
361
|
+
console.log(` RxDB Server URL: ${gatewayConfig.rxdbServerUrl}`);
|
|
362
|
+
console.log(` Domain ID: ${gatewayConfig.domainId}`);
|
|
363
|
+
console.log(` Project Path: ${gatewayConfig.projectPath || "not set"}`);
|
|
364
|
+
console.log(` User ID: ${gatewayConfig.userId || "not set"}`);
|
|
365
|
+
console.log(` Org ID: ${gatewayConfig.orgId || "not set"}`);
|
|
366
|
+
console.log(` CORS Origins: ${gatewayConfig.corsOrigins?.join(", ") || "not set"}`);
|
|
367
|
+
const server = new MCPGatewayServer(gatewayConfig);
|
|
368
|
+
const gracefulShutdown = async (signal) => {
|
|
369
|
+
if (isShuttingDown) {
|
|
370
|
+
console.log("Shutdown already in progress, ignoring signal:", signal);
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
isShuttingDown = true;
|
|
374
|
+
console.log(`
|
|
375
|
+
Received ${signal}, shutting down gracefully...`);
|
|
376
|
+
try {
|
|
377
|
+
await server.close();
|
|
378
|
+
console.log("Server closed successfully");
|
|
379
|
+
process.exit(0);
|
|
380
|
+
} catch (error) {
|
|
381
|
+
console.error("Error during shutdown:", error);
|
|
382
|
+
process.exit(1);
|
|
383
|
+
}
|
|
384
|
+
};
|
|
385
|
+
process.on("SIGINT", () => gracefulShutdown("SIGINT"));
|
|
386
|
+
process.on("SIGTERM", () => gracefulShutdown("SIGTERM"));
|
|
387
|
+
try {
|
|
388
|
+
await server.start();
|
|
389
|
+
} catch (error) {
|
|
390
|
+
console.error("Failed to start MCP Gateway:", error);
|
|
391
|
+
process.exit(1);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
main();
|
|
395
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/server.ts","../src/InMemoryTransport.ts","../src/cli.ts"],"sourcesContent":["// Copyright 2026 Epic Digital Interactive Media LLC\n// SPDX-License-Identifier: Apache-2.0\n\nimport express, { Express, Request, Response } from 'express'\nimport cors from 'cors'\nimport { FlowStateMCPServer } from '@epicdm/flowstate-mcp'\nimport { InMemoryTransport } from './InMemoryTransport'\nimport type { MCPGatewayConfig, ToolCallRequest, ToolCallResponse } from './types'\n\nexport class MCPGatewayServer {\n private app: Express\n private mcpServer: FlowStateMCPServer\n private config: MCPGatewayConfig\n private isInitialized = false\n private httpServer?: ReturnType<Express['listen']>\n private transport?: InMemoryTransport\n\n constructor(config: MCPGatewayConfig) {\n this.config = config\n this.app = express()\n\n // Initialize MCP Server\n this.mcpServer = new FlowStateMCPServer({\n rxdbServerUrl: config.rxdbServerUrl,\n domainId: config.domainId,\n projectPath: config.projectPath || process.cwd(),\n ...(config.userId && { userId: config.userId }),\n ...(config.orgId && { orgId: config.orgId }),\n } as any)\n\n this.setupMiddleware()\n this.setupRoutes()\n }\n\n /**\n * Get list of tools from MCP server\n *\n * WARNING: This method accesses internal MCP server API via type casting.\n * This is necessary because FlowStateMCPServer doesn't expose a public method\n * for listing tools. The underlying server.request() method is used directly.\n *\n * RISKS:\n * - Internal API may change without notice in future versions\n * - Type casting bypasses TypeScript safety checks\n * - May break if FlowStateMCPServer implementation changes\n *\n * TODO: Consider requesting a public API method in FlowStateMCPServer\n * for listing and calling tools to avoid internal API access.\n */\n private async listTools(): Promise<any[]> {\n if (!this.transport) {\n return []\n }\n\n // Send request through transport\n const request = {\n jsonrpc: '2.0' as const,\n id: Date.now(),\n method: 'tools/list' as const,\n }\n\n const response: any = await this.transport.sendRequest(request)\n\n if ('error' in response) {\n throw new Error(response.error.message || 'Failed to list tools')\n }\n\n return response.result?.tools || []\n }\n\n /**\n * Call a tool on the MCP server\n *\n * WARNING: This method accesses internal MCP server API via type casting.\n * This is necessary because FlowStateMCPServer doesn't expose a public method\n * for calling tools. The underlying server.request() method is used directly.\n *\n * RISKS:\n * - Internal API may change without notice in future versions\n * - Type casting bypasses TypeScript safety checks\n * - May break if FlowStateMCPServer implementation changes\n *\n * TODO: Consider requesting a public API method in FlowStateMCPServer\n * for listing and calling tools to avoid internal API access.\n *\n * NOTE: The MCP SDK's server.request() method appears to require the request\n * object to be passed twice (once as the request, once as params). This seems\n * to be how the underlying MCP SDK expects the call to be structured based on\n * the protocol specification.\n */\n private async callTool(toolName: string, args: Record<string, any>): Promise<any> {\n if (!this.transport) {\n throw new Error('MCP server not available')\n }\n\n // Send request through transport\n const request = {\n jsonrpc: '2.0' as const,\n id: Date.now(),\n method: 'tools/call' as const,\n params: {\n name: toolName,\n arguments: args,\n },\n }\n\n const response: any = await this.transport.sendRequest(request)\n\n if ('error' in response) {\n throw new Error(response.error.message || 'Failed to call tool')\n }\n\n return response.result?.content?.[0]?.text || response.result\n }\n\n private setupMiddleware(): void {\n // CORS\n this.app.use(\n cors({\n origin: this.config.corsOrigins || '*',\n methods: ['GET', 'POST', 'OPTIONS'],\n allowedHeaders: ['Content-Type', 'Authorization'],\n })\n )\n\n // Body parsing\n this.app.use(express.json())\n this.app.use(express.urlencoded({ extended: true }))\n\n // Request logging\n this.app.use((req, res, next) => {\n console.log(`${new Date().toISOString()} ${req.method} ${req.path}`)\n next()\n })\n }\n\n /**\n * Extract and forward auth token from request to MCP server\n *\n * This enables per-request auth so each API call can use its own token,\n * rather than relying on the initial config token.\n */\n private updateAuthFromRequest(req: Request): void {\n const authHeader = req.headers['authorization']\n if (!authHeader) {\n console.log('[MCP Gateway] No Authorization header in request')\n return\n }\n\n const token = authHeader.toString().replace('Bearer ', '')\n if (!token) {\n console.log('[MCP Gateway] Empty token after Bearer prefix removal')\n return\n }\n\n // Only accept valid-looking tokens (JWT or API tokens)\n if (!token.startsWith('eyJ') && !token.startsWith('epic_')) {\n console.log(`[MCP Gateway] Invalid token format (starts with: ${token.substring(0, 10)}...)`)\n return\n }\n\n try {\n ;(this.mcpServer as any).config.authToken = token\n console.log('[MCP Gateway] Auth token updated from request')\n } catch (error) {\n console.error('[MCP Gateway] Failed to update auth config:', error)\n }\n }\n\n private setupRoutes(): void {\n // Health check\n this.app.get('/health', (req: Request, res: Response) => {\n res.json({\n status: 'ok',\n initialized: this.isInitialized,\n timestamp: new Date().toISOString(),\n })\n })\n\n // List available tools\n this.app.get('/mcp/tools', async (req: Request, res: Response) => {\n try {\n if (!this.isInitialized) {\n return res.status(503).json({\n error: 'Server not initialized',\n })\n }\n\n // Forward per-request auth to MCP server\n this.updateAuthFromRequest(req)\n\n const tools = await this.listTools()\n res.json({ tools })\n } catch (error) {\n console.error('Error listing tools:', error)\n res.status(500).json({\n error: error instanceof Error ? error.message : 'Unknown error',\n })\n }\n })\n\n // Execute a tool\n this.app.post('/mcp/tools/call', async (req: Request, res: Response) => {\n try {\n if (!this.isInitialized) {\n return res.status(503).json({\n success: false,\n error: 'Server not initialized',\n })\n }\n\n // Forward per-request auth to MCP server\n this.updateAuthFromRequest(req)\n\n const { toolName, arguments: args } = req.body as ToolCallRequest\n\n if (!toolName) {\n return res.status(400).json({\n success: false,\n error: 'toolName is required',\n })\n }\n\n const result = await this.callTool(toolName, args || {})\n\n const response: ToolCallResponse = {\n success: true,\n result,\n }\n\n res.json(response)\n } catch (error) {\n console.error('Error calling tool:', error)\n const response: ToolCallResponse = {\n success: false,\n error: error instanceof Error ? error.message : 'Unknown error',\n }\n res.status(500).json(response)\n }\n })\n }\n\n async initialize(): Promise<void> {\n await this.mcpServer.initialize()\n\n // Connect the MCP server to an in-memory transport\n // This is required for the MCP SDK to handle requests\n this.transport = new InMemoryTransport()\n const server = (this.mcpServer as any).server\n if (server) {\n await server.connect(this.transport)\n }\n\n this.isInitialized = true\n console.log('MCP Gateway initialized')\n }\n\n async start(): Promise<void> {\n await this.initialize()\n\n return new Promise(resolve => {\n this.httpServer = this.app.listen(this.config.port, this.config.host, () => {\n console.log(`MCP Gateway listening on http://${this.config.host}:${this.config.port}`)\n resolve()\n })\n })\n }\n\n async close(): Promise<void> {\n // Close HTTP server first\n if (this.httpServer) {\n await new Promise<void>((resolve, reject) => {\n this.httpServer!.close(err => {\n if (err) {\n console.error('Error closing HTTP server:', err)\n reject(err)\n } else {\n console.log('HTTP server closed')\n resolve()\n }\n })\n })\n }\n\n // Then close MCP server\n await this.mcpServer.close()\n console.log('MCP Gateway closed')\n }\n}\n","// Copyright 2026 Epic Digital Interactive Media LLC\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';\nimport type { JSONRPCMessage, JSONRPCRequest, JSONRPCResponse, JSONRPCErrorResponse } from '@modelcontextprotocol/sdk/types.js';\nimport { EventEmitter } from 'events';\n\n/**\n * In-Memory Transport for programmatic MCP server usage\n *\n * This transport creates a bidirectional message channel that allows\n * the MCP server to be used programmatically without stdio/SSE.\n */\nexport class InMemoryTransport implements Transport {\n sessionId?: string;\n onclose?: () => void;\n onerror?: (error: Error) => void;\n onmessage?: (message: JSONRPCMessage) => void;\n\n private started = false;\n private emitter = new EventEmitter();\n private responseHandlers = new Map<string | number, (response: JSONRPCMessage) => void>();\n\n async start(): Promise<void> {\n this.started = true;\n this.sessionId = `inmemory-${Date.now()}-${Math.random().toString(36).substring(7)}`;\n }\n\n async send(message: JSONRPCMessage): Promise<void> {\n if (!this.started) {\n throw new Error('Transport not started');\n }\n\n // If this is a response (has 'result' or 'error' and 'id')\n if ('result' in message || 'error' in message) {\n const response = message as JSONRPCResponse | JSONRPCErrorResponse;\n const handler = this.responseHandlers.get(response.id!);\n if (handler) {\n handler(message);\n this.responseHandlers.delete(response.id!);\n }\n }\n }\n\n async close(): Promise<void> {\n this.started = false;\n this.responseHandlers.clear();\n this.onclose?.();\n }\n\n setProtocolVersion?(version: string): void {\n // No-op for in-memory transport\n }\n\n /**\n * Send a request and wait for response\n * Used by the gateway to make programmatic requests\n */\n async sendRequest(request: JSONRPCMessage): Promise<JSONRPCMessage> {\n if (!this.started) {\n throw new Error('Transport not started');\n }\n\n return new Promise((resolve, reject) => {\n const req = request as JSONRPCRequest;\n const timeout = setTimeout(() => {\n this.responseHandlers.delete(req.id);\n reject(new Error('Request timeout'));\n }, 60000);\n\n this.responseHandlers.set(req.id, (response) => {\n clearTimeout(timeout);\n resolve(response);\n });\n\n // Route request to server's message handler\n if (this.onmessage) {\n this.onmessage(request);\n } else {\n reject(new Error('Transport not connected to server'));\n }\n });\n }\n}\n","#!/usr/bin/env node\n// Copyright 2026 Epic Digital Interactive Media LLC\n// SPDX-License-Identifier: Apache-2.0\n\nimport { MCPGatewayServer } from './server';\nimport { config } from 'dotenv';\nimport { resolve } from 'path';\n\n// Load environment variables\nconfig({ path: resolve(process.cwd(), '.env') });\n\n// Shutdown guard to prevent race conditions\nlet isShuttingDown = false;\n\n// Global error handlers\nprocess.on('unhandledRejection', (reason, promise) => {\n console.error('Unhandled Rejection at:', promise, 'reason:', reason);\n process.exit(1);\n});\n\nprocess.on('uncaughtException', (error) => {\n console.error('Uncaught Exception:', error);\n process.exit(1);\n});\n\nasync function main() {\n const gatewayConfig = {\n port: parseInt(process.env.MCP_GATEWAY_PORT || '7081', 10),\n host: process.env.MCP_GATEWAY_HOST || '0.0.0.0',\n rxdbServerUrl: process.env.RXDB_SERVER_URL || '',\n authToken: process.env.RXDB_AUTH_TOKEN || '',\n domainId: process.env.RXDB_DOMAIN_ID || '',\n projectPath: process.env.PROJECT_PATH,\n userId: process.env.USER_ID,\n orgId: process.env.ORG_ID,\n corsOrigins: process.env.CORS_ORIGINS?.split(','),\n };\n\n // Validate required config\n if (!gatewayConfig.rxdbServerUrl) {\n console.error('ERROR: RXDB_SERVER_URL is required');\n process.exit(1);\n }\n if (!gatewayConfig.authToken) {\n console.error('ERROR: RXDB_AUTH_TOKEN is required');\n process.exit(1);\n }\n if (!gatewayConfig.domainId) {\n console.error('ERROR: RXDB_DOMAIN_ID is required');\n process.exit(1);\n }\n\n // Log non-sensitive configuration on startup\n console.log('MCP Gateway starting with configuration:');\n console.log(` Port: ${gatewayConfig.port}`);\n console.log(` Host: ${gatewayConfig.host}`);\n console.log(` RxDB Server URL: ${gatewayConfig.rxdbServerUrl}`);\n console.log(` Domain ID: ${gatewayConfig.domainId}`);\n console.log(` Project Path: ${gatewayConfig.projectPath || 'not set'}`);\n console.log(` User ID: ${gatewayConfig.userId || 'not set'}`);\n console.log(` Org ID: ${gatewayConfig.orgId || 'not set'}`);\n console.log(` CORS Origins: ${gatewayConfig.corsOrigins?.join(', ') || 'not set'}`);\n\n const server = new MCPGatewayServer(gatewayConfig);\n\n // Graceful shutdown handler\n const gracefulShutdown = async (signal: string) => {\n if (isShuttingDown) {\n console.log('Shutdown already in progress, ignoring signal:', signal);\n return;\n }\n\n isShuttingDown = true;\n console.log(`\\nReceived ${signal}, shutting down gracefully...`);\n\n try {\n await server.close();\n console.log('Server closed successfully');\n process.exit(0);\n } catch (error) {\n console.error('Error during shutdown:', error);\n process.exit(1);\n }\n };\n\n // Register signal handlers\n process.on('SIGINT', () => gracefulShutdown('SIGINT'));\n process.on('SIGTERM', () => gracefulShutdown('SIGTERM'));\n\n try {\n await server.start();\n } catch (error) {\n console.error('Failed to start MCP Gateway:', error);\n process.exit(1);\n }\n}\n\nmain();\n"],"mappings":"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","names":["resolve","config","express","cors","resolve"]}
|