@fnet/cli 0.118.4 → 0.119.1
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
|
@@ -71,34 +71,90 @@
|
|
|
71
71
|
if (transportType === 'stdio') {
|
|
72
72
|
// Use stdio transport
|
|
73
73
|
transport = new StdioServerTransport();
|
|
74
|
-
} else if (transportType === '
|
|
75
|
-
// Use
|
|
74
|
+
} else if (transportType === 'http') {
|
|
75
|
+
// Use Streamable HTTP transport (official transport as of MCP 2025-03-26)
|
|
76
76
|
const app = express();
|
|
77
77
|
app.use(express.json());
|
|
78
78
|
|
|
79
79
|
const port = args['cli-port'] || args.cli_port || 3000;
|
|
80
|
-
const
|
|
81
|
-
|
|
80
|
+
const host = args['cli-host'] || args.cli_host || 'localhost';
|
|
81
|
+
const mcpEndpoint = '/mcp';
|
|
82
|
+
|
|
83
|
+
// Security: Validate Origin header to prevent DNS rebinding attacks
|
|
84
|
+
app.use((req, res, next) => {
|
|
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();
|
|
82
93
|
});
|
|
83
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
|
+
}
|
|
106
|
+
|
|
107
|
+
// For non-initialization requests, require session ID
|
|
108
|
+
const sessionId = req.get('Mcp-Session-Id');
|
|
109
|
+
if (!sessionId) {
|
|
110
|
+
return res.status(400).json({
|
|
111
|
+
jsonrpc: '2.0',
|
|
112
|
+
error: {
|
|
113
|
+
code: -32000,
|
|
114
|
+
message: 'Bad Request: Mcp-Session-Id header is required'
|
|
115
|
+
},
|
|
116
|
+
id: null
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
next();
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
app.use(mcpEndpoint, checkSessionId);
|
|
123
|
+
|
|
84
124
|
transport = new StreamableHTTPServerTransport({
|
|
85
|
-
sessionIdGenerator: () =>
|
|
125
|
+
sessionIdGenerator: () => {
|
|
126
|
+
// Generate cryptographically secure session ID
|
|
127
|
+
return require('crypto').randomBytes(16).toString('hex');
|
|
128
|
+
},
|
|
86
129
|
});
|
|
87
130
|
|
|
88
|
-
|
|
131
|
+
// Handle POST requests for client-to-server messages
|
|
132
|
+
app.post(mcpEndpoint, async (req, res) => {
|
|
89
133
|
await transport.handleRequest(req, res, req.body);
|
|
90
134
|
});
|
|
91
135
|
|
|
92
|
-
|
|
136
|
+
// Handle GET requests for server-to-client SSE stream
|
|
137
|
+
app.get(mcpEndpoint, async (req, res) => {
|
|
93
138
|
await transport.handleRequest(req, res);
|
|
94
139
|
});
|
|
95
140
|
|
|
96
|
-
|
|
141
|
+
// Handle DELETE requests for session termination
|
|
142
|
+
app.delete(mcpEndpoint, async (req, res) => {
|
|
97
143
|
await transport.handleRequest(req, res);
|
|
98
144
|
});
|
|
145
|
+
|
|
146
|
+
const httpServer = app.listen(port, host, () => {
|
|
147
|
+
console.log(`MCP server started with Streamable HTTP transport`);
|
|
148
|
+
console.log(`Endpoint: http://${host}:${port}${mcpEndpoint}`);
|
|
149
|
+
console.log(`Listening on ${host}:${port}`);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
// Connect transport to server
|
|
153
|
+
await server.connect(transport);
|
|
154
|
+
return;
|
|
99
155
|
} else {
|
|
100
156
|
console.error(`Unknown MCP transport type: ${transportType}`);
|
|
101
|
-
console.error(`Supported types: stdio,
|
|
157
|
+
console.error(`Supported types: stdio, http`);
|
|
102
158
|
process.exit(1);
|
|
103
159
|
}
|
|
104
160
|
|