@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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fnet/cli",
3
- "version": "0.118.4",
3
+ "version": "0.119.1",
4
4
  "files": [
5
5
  "dist",
6
6
  "template"
@@ -71,34 +71,90 @@
71
71
  if (transportType === 'stdio') {
72
72
  // Use stdio transport
73
73
  transport = new StdioServerTransport();
74
- } else if (transportType === 'sse') {
75
- // Use SSE transport
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 server = app.listen(port, () => {
81
- console.log(`MCP server started with SSE transport on port ${port}`);
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: () => Math.random().toString(36).substring(2, 15),
125
+ sessionIdGenerator: () => {
126
+ // Generate cryptographically secure session ID
127
+ return require('crypto').randomBytes(16).toString('hex');
128
+ },
86
129
  });
87
130
 
88
- app.post('/sse', async (req, res) => {
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
- app.get('/sse', async (req, res) => {
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
- app.delete('/sse', async (req, res) => {
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, sse`);
157
+ console.error(`Supported types: stdio, http`);
102
158
  process.exit(1);
103
159
  }
104
160