@fnet/cli 0.119.1 → 0.119.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/package.json
CHANGED
|
@@ -80,77 +80,80 @@
|
|
|
80
80
|
const host = args['cli-host'] || args.cli_host || 'localhost';
|
|
81
81
|
const mcpEndpoint = '/mcp';
|
|
82
82
|
|
|
83
|
-
//
|
|
84
|
-
|
|
85
|
-
const origin = req.get('origin');
|
|
86
|
-
if (origin && host === 'localhost') {
|
|
87
|
-
const originUrl = new URL(origin);
|
|
88
|
-
if (originUrl.hostname !== 'localhost' && originUrl.hostname !== '127.0.0.1') {
|
|
89
|
-
return res.status(403).json({ error: 'Forbidden: Invalid origin' });
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
next();
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
// Middleware to check session ID (except for initialization)
|
|
96
|
-
const checkSessionId = (req, res, next) => {
|
|
97
|
-
// Skip session check for initialization requests
|
|
98
|
-
if (req.method === 'POST' && req.body) {
|
|
99
|
-
const body = req.body;
|
|
100
|
-
// Check if this is an initialization request
|
|
101
|
-
if (body.method === 'initialize' ||
|
|
102
|
-
(Array.isArray(body) && body.some(item => item.method === 'initialize'))) {
|
|
103
|
-
return next();
|
|
104
|
-
}
|
|
105
|
-
}
|
|
83
|
+
// Map to store transports by session ID
|
|
84
|
+
const transports = {};
|
|
106
85
|
|
|
107
|
-
|
|
86
|
+
// Handle POST requests for client-to-server communication
|
|
87
|
+
app.post(mcpEndpoint, async (req, res) => {
|
|
88
|
+
// Check for existing session ID
|
|
108
89
|
const sessionId = req.get('Mcp-Session-Id');
|
|
109
|
-
|
|
90
|
+
let transport;
|
|
91
|
+
|
|
92
|
+
if (sessionId && transports[sessionId]) {
|
|
93
|
+
// Reuse existing transport
|
|
94
|
+
transport = transports[sessionId];
|
|
95
|
+
} else if (!sessionId && req.body && (req.body.method === 'initialize' ||
|
|
96
|
+
(Array.isArray(req.body) && req.body.some(item => item.method === 'initialize')))) {
|
|
97
|
+
// New initialization request
|
|
98
|
+
transport = new StreamableHTTPServerTransport({
|
|
99
|
+
sessionIdGenerator: () => {
|
|
100
|
+
// Generate cryptographically secure session ID
|
|
101
|
+
return require('crypto').randomBytes(16).toString('hex');
|
|
102
|
+
},
|
|
103
|
+
onsessioninitialized: (sessionId) => {
|
|
104
|
+
// Store the transport by session ID
|
|
105
|
+
transports[sessionId] = transport;
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
// Clean up transport when closed
|
|
110
|
+
transport.onclose = () => {
|
|
111
|
+
if (transport.sessionId) {
|
|
112
|
+
delete transports[transport.sessionId];
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
// Connect to the MCP server
|
|
117
|
+
await server.connect(transport);
|
|
118
|
+
} else {
|
|
119
|
+
// Invalid request
|
|
110
120
|
return res.status(400).json({
|
|
111
121
|
jsonrpc: '2.0',
|
|
112
122
|
error: {
|
|
113
123
|
code: -32000,
|
|
114
|
-
message: 'Bad Request:
|
|
124
|
+
message: 'Bad Request: No valid session ID provided'
|
|
115
125
|
},
|
|
116
126
|
id: null
|
|
117
127
|
});
|
|
118
128
|
}
|
|
119
|
-
next();
|
|
120
|
-
};
|
|
121
|
-
|
|
122
|
-
app.use(mcpEndpoint, checkSessionId);
|
|
123
129
|
|
|
124
|
-
|
|
125
|
-
sessionIdGenerator: () => {
|
|
126
|
-
// Generate cryptographically secure session ID
|
|
127
|
-
return require('crypto').randomBytes(16).toString('hex');
|
|
128
|
-
},
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
// Handle POST requests for client-to-server messages
|
|
132
|
-
app.post(mcpEndpoint, async (req, res) => {
|
|
130
|
+
// Handle the request
|
|
133
131
|
await transport.handleRequest(req, res, req.body);
|
|
134
132
|
});
|
|
135
133
|
|
|
136
|
-
//
|
|
137
|
-
|
|
134
|
+
// Reusable handler for GET and DELETE requests
|
|
135
|
+
const handleSessionRequest = async (req, res) => {
|
|
136
|
+
const sessionId = req.get('Mcp-Session-Id');
|
|
137
|
+
if (!sessionId || !transports[sessionId]) {
|
|
138
|
+
return res.status(400).send('Invalid or missing session ID');
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const transport = transports[sessionId];
|
|
138
142
|
await transport.handleRequest(req, res);
|
|
139
|
-
}
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
// Handle GET requests for server-to-client notifications via SSE
|
|
146
|
+
app.get(mcpEndpoint, handleSessionRequest);
|
|
140
147
|
|
|
141
148
|
// Handle DELETE requests for session termination
|
|
142
|
-
app.delete(mcpEndpoint,
|
|
143
|
-
await transport.handleRequest(req, res);
|
|
144
|
-
});
|
|
149
|
+
app.delete(mcpEndpoint, handleSessionRequest);
|
|
145
150
|
|
|
146
|
-
|
|
151
|
+
app.listen(port, host, () => {
|
|
147
152
|
console.log(`MCP server started with Streamable HTTP transport`);
|
|
148
153
|
console.log(`Endpoint: http://${host}:${port}${mcpEndpoint}`);
|
|
149
154
|
console.log(`Listening on ${host}:${port}`);
|
|
150
155
|
});
|
|
151
156
|
|
|
152
|
-
// Connect transport to server
|
|
153
|
-
await server.connect(transport);
|
|
154
157
|
return;
|
|
155
158
|
} else {
|
|
156
159
|
console.error(`Unknown MCP transport type: ${transportType}`);
|