@platf/bridge 0.0.2
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 +53 -0
- package/dist/gateways/statefulBridge.d.ts +22 -0
- package/dist/gateways/statefulBridge.js +211 -0
- package/dist/gateways/statefulBridge.js.map +1 -0
- package/dist/gateways/statelessBridge.d.ts +22 -0
- package/dist/gateways/statelessBridge.js +234 -0
- package/dist/gateways/statelessBridge.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +117 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/authMiddleware.d.ts +12 -0
- package/dist/lib/authMiddleware.js +41 -0
- package/dist/lib/authMiddleware.js.map +1 -0
- package/dist/lib/cors.d.ts +3 -0
- package/dist/lib/cors.js +29 -0
- package/dist/lib/cors.js.map +1 -0
- package/dist/lib/discoveryRoutes.d.ts +14 -0
- package/dist/lib/discoveryRoutes.js +86 -0
- package/dist/lib/discoveryRoutes.js.map +1 -0
- package/dist/lib/getLogger.d.ts +3 -0
- package/dist/lib/getLogger.js +34 -0
- package/dist/lib/getLogger.js.map +1 -0
- package/dist/lib/headers.d.ts +2 -0
- package/dist/lib/headers.js +19 -0
- package/dist/lib/headers.js.map +1 -0
- package/dist/lib/onSignals.d.ts +6 -0
- package/dist/lib/onSignals.js +16 -0
- package/dist/lib/onSignals.js.map +1 -0
- package/dist/lib/sessionAccessCounter.d.ts +11 -0
- package/dist/lib/sessionAccessCounter.js +72 -0
- package/dist/lib/sessionAccessCounter.js.map +1 -0
- package/dist/types.d.ts +11 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +41 -0
- package/src/gateways/statefulBridge.ts +271 -0
- package/src/gateways/statelessBridge.ts +310 -0
- package/src/index.ts +121 -0
- package/src/lib/authMiddleware.ts +58 -0
- package/src/lib/cors.ts +30 -0
- package/src/lib/discoveryRoutes.ts +95 -0
- package/src/lib/getLogger.ts +49 -0
- package/src/lib/headers.ts +26 -0
- package/src/lib/onSignals.ts +24 -0
- package/src/lib/sessionAccessCounter.ts +98 -0
- package/src/types.ts +12 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 platf.ai
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# platf-mcp-bridge
|
|
2
|
+
|
|
3
|
+
Stdio-to-Streamable HTTP bridge for MCP servers — part of the Platf AI Hub.
|
|
4
|
+
|
|
5
|
+
Wraps any MCP server that speaks JSON-RPC over **stdio** and exposes it as a **Streamable HTTP** (`/mcp`) endpoint. Built with [Bun](https://bun.sh).
|
|
6
|
+
|
|
7
|
+
## Modes
|
|
8
|
+
|
|
9
|
+
| Flag | Mode | Description |
|
|
10
|
+
|------|------|-------------|
|
|
11
|
+
| _(default)_ | **Stateless** | Spawns a fresh child process per request. Auto-initializes if the incoming message isn't an `initialize` request. |
|
|
12
|
+
| `--stateful` | **Stateful** | One child process per session (`Mcp-Session-Id` header). Optional inactivity timeout via `--sessionTimeout`. |
|
|
13
|
+
|
|
14
|
+
## Usage
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
# Stateless (default)
|
|
18
|
+
bun run src/index.ts --stdio "npx -y @modelcontextprotocol/server-everything" --port 8000 --cors '*' --healthEndpoint /healthz
|
|
19
|
+
|
|
20
|
+
# Stateful with 10 min session timeout
|
|
21
|
+
bun run src/index.ts --stdio "npx -y @modelcontextprotocol/server-everything" --stateful --sessionTimeout 600000 --cors '*'
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Docker
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
docker build -t platf-mcp-bridge .
|
|
28
|
+
|
|
29
|
+
docker run -p 8000:8000 platf-mcp-bridge \
|
|
30
|
+
--stdio "npx -y @modelcontextprotocol/server-everything" \
|
|
31
|
+
--cors '*' --healthEndpoint /healthz
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Options
|
|
35
|
+
|
|
36
|
+
| Option | Default | Description |
|
|
37
|
+
|--------|---------|-------------|
|
|
38
|
+
| `--stdio` | _(required)_ | Shell command for the stdio MCP server |
|
|
39
|
+
| `--port` | `8000` | HTTP listen port |
|
|
40
|
+
| `--path` | `/mcp` | HTTP endpoint path |
|
|
41
|
+
| `--stateful` | `false` | Enable stateful session mode |
|
|
42
|
+
| `--sessionTimeout` | — | Inactivity timeout (ms), stateful only |
|
|
43
|
+
| `--protocolVersion` | `2025-03-26` | MCP protocol version for auto-init |
|
|
44
|
+
| `--logLevel` | `info` | `none` / `info` / `debug` |
|
|
45
|
+
| `--cors` | — | CORS origins (omit=disabled, `*`=all) |
|
|
46
|
+
| `--healthEndpoint` | — | Health-check path(s) returning 200 |
|
|
47
|
+
| `--header` | — | Extra response headers (`Key: Value`) |
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
bun run index.ts
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
This project was created using `bun init` in bun v1.3.7. [Bun](https://bun.com) is a fast all-in-one JavaScript runtime.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type CorsOptions } from 'cors';
|
|
2
|
+
import type { AuthConfig, Logger } from '../types.js';
|
|
3
|
+
export interface StatefulBridgeArgs {
|
|
4
|
+
stdioCmd: string;
|
|
5
|
+
port: number;
|
|
6
|
+
path: string;
|
|
7
|
+
logger: Logger;
|
|
8
|
+
corsOrigin: CorsOptions['origin'];
|
|
9
|
+
healthEndpoints: string[];
|
|
10
|
+
headers: Record<string, string>;
|
|
11
|
+
sessionTimeout: number | null;
|
|
12
|
+
auth: AuthConfig | null;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Stateful stdio-to-Streamable HTTP bridge.
|
|
16
|
+
*
|
|
17
|
+
* Maintains session state via `Mcp-Session-Id` header. Each session
|
|
18
|
+
* spawns one child process; subsequent requests for the same session
|
|
19
|
+
* reuse the existing transport and process. Sessions are cleaned up
|
|
20
|
+
* after an optional inactivity timeout.
|
|
21
|
+
*/
|
|
22
|
+
export declare function startStatefulBridge(args: StatefulBridgeArgs): Promise<void>;
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import express from 'express';
|
|
2
|
+
import cors from 'cors';
|
|
3
|
+
import { spawn } from 'child_process';
|
|
4
|
+
import { randomUUID } from 'node:crypto';
|
|
5
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
6
|
+
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
|
7
|
+
import { isInitializeRequest } from '@modelcontextprotocol/sdk/types.js';
|
|
8
|
+
import { onSignals } from '../lib/onSignals.js';
|
|
9
|
+
import { serializeCorsOrigin } from '../lib/cors.js';
|
|
10
|
+
import { SessionAccessCounter } from '../lib/sessionAccessCounter.js';
|
|
11
|
+
import { createAuthMiddleware } from '../lib/authMiddleware.js';
|
|
12
|
+
import { createDiscoveryRouter } from '../lib/discoveryRoutes.js';
|
|
13
|
+
const VERSION = '1.0.0';
|
|
14
|
+
const setResponseHeaders = (res, headers) => Object.entries(headers).forEach(([key, value]) => res.setHeader(key, value));
|
|
15
|
+
/**
|
|
16
|
+
* Stateful stdio-to-Streamable HTTP bridge.
|
|
17
|
+
*
|
|
18
|
+
* Maintains session state via `Mcp-Session-Id` header. Each session
|
|
19
|
+
* spawns one child process; subsequent requests for the same session
|
|
20
|
+
* reuse the existing transport and process. Sessions are cleaned up
|
|
21
|
+
* after an optional inactivity timeout.
|
|
22
|
+
*/
|
|
23
|
+
export async function startStatefulBridge(args) {
|
|
24
|
+
const { stdioCmd, port, path, logger, corsOrigin, healthEndpoints, headers, sessionTimeout, auth, } = args;
|
|
25
|
+
logger.info(`[stateful] Starting platf-bridge`);
|
|
26
|
+
logger.info(` - Headers: ${Object.keys(headers).length ? JSON.stringify(headers) : '(none)'}`);
|
|
27
|
+
logger.info(` - port: ${port}`);
|
|
28
|
+
logger.info(` - stdio: ${stdioCmd}`);
|
|
29
|
+
logger.info(` - path: ${path}`);
|
|
30
|
+
logger.info(` - CORS: ${corsOrigin ? `enabled (${serializeCorsOrigin(corsOrigin)})` : 'disabled'}`);
|
|
31
|
+
logger.info(` - Health endpoints: ${healthEndpoints.length ? healthEndpoints.join(', ') : '(none)'}`);
|
|
32
|
+
logger.info(` - Session timeout: ${sessionTimeout ? `${sessionTimeout}ms` : 'disabled'}`);
|
|
33
|
+
onSignals({ logger });
|
|
34
|
+
const app = express();
|
|
35
|
+
app.use(express.json());
|
|
36
|
+
if (corsOrigin) {
|
|
37
|
+
app.use(cors({ origin: corsOrigin, exposedHeaders: ['Mcp-Session-Id'] }));
|
|
38
|
+
}
|
|
39
|
+
for (const ep of healthEndpoints) {
|
|
40
|
+
app.get(ep, (_req, res) => {
|
|
41
|
+
setResponseHeaders(res, headers);
|
|
42
|
+
res.send('ok');
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
// --- OAuth discovery & auth middleware (when auth is enabled) ---
|
|
46
|
+
if (auth) {
|
|
47
|
+
app.use(createDiscoveryRouter(auth, logger));
|
|
48
|
+
app.use(path, createAuthMiddleware(auth, logger));
|
|
49
|
+
logger.info(` - Auth: enabled (issuer=${auth.issuer})`);
|
|
50
|
+
}
|
|
51
|
+
// Session state
|
|
52
|
+
const transports = {};
|
|
53
|
+
const sessionCounter = sessionTimeout
|
|
54
|
+
? new SessionAccessCounter(sessionTimeout, (sessionId) => {
|
|
55
|
+
logger.info(`Session ${sessionId} timed out, cleaning up`);
|
|
56
|
+
const transport = transports[sessionId];
|
|
57
|
+
if (transport)
|
|
58
|
+
transport.close();
|
|
59
|
+
delete transports[sessionId];
|
|
60
|
+
}, logger)
|
|
61
|
+
: null;
|
|
62
|
+
// --- POST handler ---
|
|
63
|
+
app.post(path, async (req, res) => {
|
|
64
|
+
const sessionId = req.headers['mcp-session-id'];
|
|
65
|
+
let transport;
|
|
66
|
+
if (sessionId && transports[sessionId]) {
|
|
67
|
+
// Reuse existing session
|
|
68
|
+
transport = transports[sessionId];
|
|
69
|
+
sessionCounter?.inc(sessionId, 'POST request for existing session');
|
|
70
|
+
}
|
|
71
|
+
else if (!sessionId && isInitializeRequest(req.body)) {
|
|
72
|
+
// New session — spawn child process
|
|
73
|
+
const server = new Server({ name: 'platf-bridge', version: VERSION }, { capabilities: {} });
|
|
74
|
+
transport = new StreamableHTTPServerTransport({
|
|
75
|
+
sessionIdGenerator: () => randomUUID(),
|
|
76
|
+
onsessioninitialized: (newSessionId) => {
|
|
77
|
+
transports[newSessionId] = transport;
|
|
78
|
+
sessionCounter?.inc(newSessionId, 'session initialization');
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
await server.connect(transport);
|
|
82
|
+
const child = spawn(stdioCmd, { shell: true });
|
|
83
|
+
const pendingRequestIds = new Set();
|
|
84
|
+
let stderrOutput = '';
|
|
85
|
+
child.on('exit', (code, signal) => {
|
|
86
|
+
logger.error(`Child exited: code=${code}, signal=${signal}`);
|
|
87
|
+
// Send JSON-RPC error responses for all pending requests
|
|
88
|
+
for (const id of pendingRequestIds) {
|
|
89
|
+
const detail = stderrOutput.trim().slice(0, 1000);
|
|
90
|
+
const message = detail
|
|
91
|
+
? `Child process exited (code=${code}): ${detail}`
|
|
92
|
+
: `Child process exited unexpectedly (code=${code}, signal=${signal})`;
|
|
93
|
+
try {
|
|
94
|
+
transport.send({
|
|
95
|
+
jsonrpc: '2.0',
|
|
96
|
+
error: { code: -32603, message },
|
|
97
|
+
id,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
catch (e) {
|
|
101
|
+
logger.error(`Failed to send error response for request ${id}`, e);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
pendingRequestIds.clear();
|
|
105
|
+
transport.close();
|
|
106
|
+
});
|
|
107
|
+
let buffer = '';
|
|
108
|
+
child.stdout.on('data', (chunk) => {
|
|
109
|
+
buffer += chunk.toString('utf8');
|
|
110
|
+
const lines = buffer.split(/\r?\n/);
|
|
111
|
+
buffer = lines.pop() ?? '';
|
|
112
|
+
for (const line of lines) {
|
|
113
|
+
if (!line.trim())
|
|
114
|
+
continue;
|
|
115
|
+
try {
|
|
116
|
+
const jsonMsg = JSON.parse(line);
|
|
117
|
+
if ('id' in jsonMsg && jsonMsg.id !== undefined) {
|
|
118
|
+
pendingRequestIds.delete(jsonMsg.id);
|
|
119
|
+
}
|
|
120
|
+
logger.info('Child → HTTP:', line);
|
|
121
|
+
try {
|
|
122
|
+
transport.send(jsonMsg);
|
|
123
|
+
}
|
|
124
|
+
catch (e) {
|
|
125
|
+
logger.error('Failed to send to HTTP transport', e);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
logger.error(`Child non-JSON: ${line}`);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
child.stderr.on('data', (chunk) => {
|
|
134
|
+
const text = chunk.toString('utf8');
|
|
135
|
+
stderrOutput += text;
|
|
136
|
+
logger.error(`Child stderr: ${text}`);
|
|
137
|
+
});
|
|
138
|
+
transport.onmessage = (msg) => {
|
|
139
|
+
logger.info(`HTTP → Child: ${JSON.stringify(msg)}`);
|
|
140
|
+
if ('id' in msg && msg.id !== undefined) {
|
|
141
|
+
pendingRequestIds.add(msg.id);
|
|
142
|
+
}
|
|
143
|
+
child.stdin.write(JSON.stringify(msg) + '\n');
|
|
144
|
+
};
|
|
145
|
+
transport.onclose = () => {
|
|
146
|
+
logger.info(`HTTP connection closed (session ${sessionId})`);
|
|
147
|
+
if (transport.sessionId) {
|
|
148
|
+
sessionCounter?.clear(transport.sessionId, false, 'transport closed');
|
|
149
|
+
delete transports[transport.sessionId];
|
|
150
|
+
}
|
|
151
|
+
child.kill();
|
|
152
|
+
};
|
|
153
|
+
transport.onerror = (err) => {
|
|
154
|
+
logger.error(`HTTP transport error (session ${sessionId}):`, err);
|
|
155
|
+
if (transport.sessionId) {
|
|
156
|
+
sessionCounter?.clear(transport.sessionId, false, 'transport error');
|
|
157
|
+
delete transports[transport.sessionId];
|
|
158
|
+
}
|
|
159
|
+
child.kill();
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
res.status(400).json({
|
|
164
|
+
jsonrpc: '2.0',
|
|
165
|
+
error: { code: -32000, message: 'Bad Request: No valid session ID provided' },
|
|
166
|
+
id: null,
|
|
167
|
+
});
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
// Track response lifecycle for session cleanup
|
|
171
|
+
let responseEnded = false;
|
|
172
|
+
const handleResponseEnd = (event) => {
|
|
173
|
+
if (!responseEnded && transport.sessionId) {
|
|
174
|
+
responseEnded = true;
|
|
175
|
+
logger.info(`Response ${event}`, transport.sessionId);
|
|
176
|
+
sessionCounter?.dec(transport.sessionId, `POST response ${event}`);
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
res.on('finish', () => handleResponseEnd('finished'));
|
|
180
|
+
res.on('close', () => handleResponseEnd('closed'));
|
|
181
|
+
await transport.handleRequest(req, res, req.body);
|
|
182
|
+
});
|
|
183
|
+
// --- GET / DELETE handler (session-bound) ---
|
|
184
|
+
const handleSessionRequest = async (req, res) => {
|
|
185
|
+
const sessionId = req.headers['mcp-session-id'];
|
|
186
|
+
if (!sessionId || !transports[sessionId]) {
|
|
187
|
+
res.status(400).send('Invalid or missing session ID');
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
sessionCounter?.inc(sessionId, `${req.method} request for existing session`);
|
|
191
|
+
let responseEnded = false;
|
|
192
|
+
const handleResponseEnd = (event) => {
|
|
193
|
+
if (!responseEnded) {
|
|
194
|
+
responseEnded = true;
|
|
195
|
+
logger.info(`Response ${event}`, sessionId);
|
|
196
|
+
sessionCounter?.dec(sessionId, `${req.method} response ${event}`);
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
res.on('finish', () => handleResponseEnd('finished'));
|
|
200
|
+
res.on('close', () => handleResponseEnd('closed'));
|
|
201
|
+
const transport = transports[sessionId];
|
|
202
|
+
await transport.handleRequest(req, res);
|
|
203
|
+
};
|
|
204
|
+
app.get(path, handleSessionRequest);
|
|
205
|
+
app.delete(path, handleSessionRequest);
|
|
206
|
+
app.listen(port, () => {
|
|
207
|
+
logger.info(`Listening on port ${port}`);
|
|
208
|
+
logger.info(`Streamable HTTP endpoint: http://localhost:${port}${path}`);
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
//# sourceMappingURL=statefulBridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"statefulBridge.js","sourceRoot":"","sources":["../../src/gateways/statefulBridge.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type CorsOptions } from 'cors';
|
|
2
|
+
import type { AuthConfig, Logger } from '../types.js';
|
|
3
|
+
export interface StatelessBridgeArgs {
|
|
4
|
+
stdioCmd: string;
|
|
5
|
+
port: number;
|
|
6
|
+
path: string;
|
|
7
|
+
logger: Logger;
|
|
8
|
+
corsOrigin: CorsOptions['origin'];
|
|
9
|
+
healthEndpoints: string[];
|
|
10
|
+
headers: Record<string, string>;
|
|
11
|
+
protocolVersion: string;
|
|
12
|
+
auth: AuthConfig | null;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Stateless stdio-to-Streamable HTTP bridge.
|
|
16
|
+
*
|
|
17
|
+
* For every incoming POST request, spawns a fresh child process,
|
|
18
|
+
* auto-initializes it if the request is not an initialize request,
|
|
19
|
+
* and proxies JSON-RPC messages between the HTTP transport and the
|
|
20
|
+
* child's stdin/stdout.
|
|
21
|
+
*/
|
|
22
|
+
export declare function startStatelessBridge(args: StatelessBridgeArgs): Promise<void>;
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import express from 'express';
|
|
2
|
+
import cors from 'cors';
|
|
3
|
+
import { spawn } from 'child_process';
|
|
4
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
5
|
+
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
|
6
|
+
import { isInitializeRequest, } from '@modelcontextprotocol/sdk/types.js';
|
|
7
|
+
import { onSignals } from '../lib/onSignals.js';
|
|
8
|
+
import { serializeCorsOrigin } from '../lib/cors.js';
|
|
9
|
+
import { createAuthMiddleware } from '../lib/authMiddleware.js';
|
|
10
|
+
import { createDiscoveryRouter } from '../lib/discoveryRoutes.js';
|
|
11
|
+
const VERSION = '1.0.0';
|
|
12
|
+
const setResponseHeaders = (res, headers) => Object.entries(headers).forEach(([key, value]) => res.setHeader(key, value));
|
|
13
|
+
/** Create a synthetic MCP initialize request */
|
|
14
|
+
const createInitializeRequest = (id, protocolVersion) => ({
|
|
15
|
+
jsonrpc: '2.0',
|
|
16
|
+
id,
|
|
17
|
+
method: 'initialize',
|
|
18
|
+
params: {
|
|
19
|
+
protocolVersion,
|
|
20
|
+
capabilities: {
|
|
21
|
+
roots: { listChanged: true },
|
|
22
|
+
sampling: {},
|
|
23
|
+
},
|
|
24
|
+
clientInfo: {
|
|
25
|
+
name: 'platf-bridge',
|
|
26
|
+
version: VERSION,
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
const createInitializedNotification = () => ({
|
|
31
|
+
jsonrpc: '2.0',
|
|
32
|
+
method: 'notifications/initialized',
|
|
33
|
+
});
|
|
34
|
+
/**
|
|
35
|
+
* Stateless stdio-to-Streamable HTTP bridge.
|
|
36
|
+
*
|
|
37
|
+
* For every incoming POST request, spawns a fresh child process,
|
|
38
|
+
* auto-initializes it if the request is not an initialize request,
|
|
39
|
+
* and proxies JSON-RPC messages between the HTTP transport and the
|
|
40
|
+
* child's stdin/stdout.
|
|
41
|
+
*/
|
|
42
|
+
export async function startStatelessBridge(args) {
|
|
43
|
+
const { stdioCmd, port, path, logger, corsOrigin, healthEndpoints, headers, protocolVersion, auth, } = args;
|
|
44
|
+
logger.info(`[stateless] Starting platf-bridge`);
|
|
45
|
+
logger.info(` - Headers: ${Object.keys(headers).length ? JSON.stringify(headers) : '(none)'}`);
|
|
46
|
+
logger.info(` - port: ${port}`);
|
|
47
|
+
logger.info(` - stdio: ${stdioCmd}`);
|
|
48
|
+
logger.info(` - path: ${path}`);
|
|
49
|
+
logger.info(` - protocolVersion: ${protocolVersion}`);
|
|
50
|
+
logger.info(` - CORS: ${corsOrigin ? `enabled (${serializeCorsOrigin(corsOrigin)})` : 'disabled'}`);
|
|
51
|
+
logger.info(` - Health endpoints: ${healthEndpoints.length ? healthEndpoints.join(', ') : '(none)'}`);
|
|
52
|
+
onSignals({ logger });
|
|
53
|
+
const app = express();
|
|
54
|
+
app.use(express.json());
|
|
55
|
+
if (corsOrigin) {
|
|
56
|
+
app.use(cors({ origin: corsOrigin }));
|
|
57
|
+
}
|
|
58
|
+
for (const ep of healthEndpoints) {
|
|
59
|
+
app.get(ep, (_req, res) => {
|
|
60
|
+
setResponseHeaders(res, headers);
|
|
61
|
+
res.send('ok');
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
// --- OAuth discovery & auth middleware (when auth is enabled) ---
|
|
65
|
+
if (auth) {
|
|
66
|
+
app.use(createDiscoveryRouter(auth, logger));
|
|
67
|
+
app.use(path, createAuthMiddleware(auth, logger));
|
|
68
|
+
logger.info(` - Auth: enabled (issuer=${auth.issuer})`);
|
|
69
|
+
}
|
|
70
|
+
app.post(path, async (req, res) => {
|
|
71
|
+
try {
|
|
72
|
+
const server = new Server({ name: 'platf-bridge', version: VERSION }, { capabilities: {} });
|
|
73
|
+
const transport = new StreamableHTTPServerTransport({
|
|
74
|
+
sessionIdGenerator: undefined,
|
|
75
|
+
});
|
|
76
|
+
await server.connect(transport);
|
|
77
|
+
const child = spawn(stdioCmd, { shell: true });
|
|
78
|
+
const pendingRequestIds = new Set();
|
|
79
|
+
let stderrOutput = '';
|
|
80
|
+
child.on('exit', (code, signal) => {
|
|
81
|
+
logger.error(`Child exited: code=${code}, signal=${signal}`);
|
|
82
|
+
// Include queued original message's ID if it was never sent to the child
|
|
83
|
+
if (pendingOriginalMessage && 'id' in pendingOriginalMessage && pendingOriginalMessage.id !== undefined) {
|
|
84
|
+
pendingRequestIds.add(pendingOriginalMessage.id);
|
|
85
|
+
pendingOriginalMessage = null;
|
|
86
|
+
}
|
|
87
|
+
// Remove auto-init ID — the client doesn't expect a response for it
|
|
88
|
+
if (isAutoInitializing && initializeRequestId !== null) {
|
|
89
|
+
pendingRequestIds.delete(initializeRequestId);
|
|
90
|
+
}
|
|
91
|
+
// Send JSON-RPC error responses for all pending client requests
|
|
92
|
+
for (const id of pendingRequestIds) {
|
|
93
|
+
const detail = stderrOutput.trim().slice(0, 1000);
|
|
94
|
+
const message = detail
|
|
95
|
+
? `Child process exited (code=${code}): ${detail}`
|
|
96
|
+
: `Child process exited unexpectedly (code=${code}, signal=${signal})`;
|
|
97
|
+
try {
|
|
98
|
+
transport.send({
|
|
99
|
+
jsonrpc: '2.0',
|
|
100
|
+
error: { code: -32603, message },
|
|
101
|
+
id,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
catch (e) {
|
|
105
|
+
logger.error(`Failed to send error response for request ${id}`, e);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
pendingRequestIds.clear();
|
|
109
|
+
transport.close();
|
|
110
|
+
});
|
|
111
|
+
// --- Auto-initialization state ---
|
|
112
|
+
let isInitialized = false;
|
|
113
|
+
let initializeRequestId = null;
|
|
114
|
+
let isAutoInitializing = false;
|
|
115
|
+
let pendingOriginalMessage = null;
|
|
116
|
+
let buffer = '';
|
|
117
|
+
child.stdout.on('data', (chunk) => {
|
|
118
|
+
buffer += chunk.toString('utf8');
|
|
119
|
+
const lines = buffer.split(/\r?\n/);
|
|
120
|
+
buffer = lines.pop() ?? '';
|
|
121
|
+
for (const line of lines) {
|
|
122
|
+
if (!line.trim())
|
|
123
|
+
continue;
|
|
124
|
+
try {
|
|
125
|
+
const jsonMsg = JSON.parse(line);
|
|
126
|
+
if ('id' in jsonMsg && jsonMsg.id !== undefined) {
|
|
127
|
+
pendingRequestIds.delete(jsonMsg.id);
|
|
128
|
+
}
|
|
129
|
+
logger.info('Child → HTTP:', line);
|
|
130
|
+
// Handle initialize response (auto or client-initiated)
|
|
131
|
+
if (initializeRequestId && jsonMsg.id === initializeRequestId) {
|
|
132
|
+
logger.info('Initialize response received');
|
|
133
|
+
isInitialized = true;
|
|
134
|
+
if (isAutoInitializing) {
|
|
135
|
+
// Send initialized notification then the queued original message
|
|
136
|
+
const notification = createInitializedNotification();
|
|
137
|
+
logger.info(`HTTP → Child (initialized): ${JSON.stringify(notification)}`);
|
|
138
|
+
child.stdin.write(JSON.stringify(notification) + '\n');
|
|
139
|
+
if (pendingOriginalMessage) {
|
|
140
|
+
logger.info(`HTTP → Child (original): ${JSON.stringify(pendingOriginalMessage)}`);
|
|
141
|
+
child.stdin.write(JSON.stringify(pendingOriginalMessage) + '\n');
|
|
142
|
+
pendingOriginalMessage = null;
|
|
143
|
+
}
|
|
144
|
+
isAutoInitializing = false;
|
|
145
|
+
initializeRequestId = null;
|
|
146
|
+
return; // don't forward auto-init response to client
|
|
147
|
+
}
|
|
148
|
+
initializeRequestId = null;
|
|
149
|
+
}
|
|
150
|
+
try {
|
|
151
|
+
transport.send(jsonMsg);
|
|
152
|
+
}
|
|
153
|
+
catch (e) {
|
|
154
|
+
logger.error('Failed to send to HTTP transport', e);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
catch {
|
|
158
|
+
logger.error(`Child non-JSON: ${line}`);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
child.stderr.on('data', (chunk) => {
|
|
163
|
+
const text = chunk.toString('utf8');
|
|
164
|
+
stderrOutput += text;
|
|
165
|
+
logger.error(`Child stderr: ${text}`);
|
|
166
|
+
});
|
|
167
|
+
transport.onmessage = (msg) => {
|
|
168
|
+
logger.info(`HTTP → Child: ${JSON.stringify(msg)}`);
|
|
169
|
+
// Track client request IDs for error reporting on child exit
|
|
170
|
+
if ('id' in msg && msg.id !== undefined) {
|
|
171
|
+
pendingRequestIds.add(msg.id);
|
|
172
|
+
}
|
|
173
|
+
// Auto-initialize if the first message is not an initialize request
|
|
174
|
+
if (!isInitialized && !isInitializeRequest(msg)) {
|
|
175
|
+
pendingOriginalMessage = msg;
|
|
176
|
+
initializeRequestId = `init_${Date.now()}_${Math.random().toString(36).slice(2, 11)}`;
|
|
177
|
+
isAutoInitializing = true;
|
|
178
|
+
logger.info('Non-initialize message detected, sending auto-initialize first');
|
|
179
|
+
const initReq = createInitializeRequest(initializeRequestId, protocolVersion);
|
|
180
|
+
logger.info(`HTTP → Child (auto-init): ${JSON.stringify(initReq)}`);
|
|
181
|
+
child.stdin.write(JSON.stringify(initReq) + '\n');
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
// Track client-initiated initialize
|
|
185
|
+
if (isInitializeRequest(msg) && 'id' in msg && msg.id !== undefined) {
|
|
186
|
+
initializeRequestId = msg.id;
|
|
187
|
+
isAutoInitializing = false;
|
|
188
|
+
logger.info(`Tracking initialize request ID: ${msg.id}`);
|
|
189
|
+
}
|
|
190
|
+
child.stdin.write(JSON.stringify(msg) + '\n');
|
|
191
|
+
};
|
|
192
|
+
transport.onclose = () => {
|
|
193
|
+
logger.info('HTTP connection closed');
|
|
194
|
+
child.kill();
|
|
195
|
+
};
|
|
196
|
+
transport.onerror = (err) => {
|
|
197
|
+
logger.error('HTTP transport error:', err);
|
|
198
|
+
child.kill();
|
|
199
|
+
};
|
|
200
|
+
await transport.handleRequest(req, res, req.body);
|
|
201
|
+
}
|
|
202
|
+
catch (error) {
|
|
203
|
+
logger.error('Error handling MCP request:', error);
|
|
204
|
+
if (!res.headersSent) {
|
|
205
|
+
res.status(500).json({
|
|
206
|
+
jsonrpc: '2.0',
|
|
207
|
+
error: { code: -32603, message: 'Internal server error' },
|
|
208
|
+
id: null,
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
app.get(path, (_req, res) => {
|
|
214
|
+
logger.info('Received GET — method not allowed in stateless mode');
|
|
215
|
+
res.writeHead(405).end(JSON.stringify({
|
|
216
|
+
jsonrpc: '2.0',
|
|
217
|
+
error: { code: -32000, message: 'Method not allowed.' },
|
|
218
|
+
id: null,
|
|
219
|
+
}));
|
|
220
|
+
});
|
|
221
|
+
app.delete(path, (_req, res) => {
|
|
222
|
+
logger.info('Received DELETE — method not allowed in stateless mode');
|
|
223
|
+
res.writeHead(405).end(JSON.stringify({
|
|
224
|
+
jsonrpc: '2.0',
|
|
225
|
+
error: { code: -32000, message: 'Method not allowed.' },
|
|
226
|
+
id: null,
|
|
227
|
+
}));
|
|
228
|
+
});
|
|
229
|
+
app.listen(port, () => {
|
|
230
|
+
logger.info(`Listening on port ${port}`);
|
|
231
|
+
logger.info(`Streamable HTTP endpoint: http://localhost:${port}${path}`);
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
//# sourceMappingURL=statelessBridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"statelessBridge.js","sourceRoot":"","sources":["../../src/gateways/statelessBridge.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED