hanahmily commented on code in PR #1010:
URL: 
https://github.com/apache/skywalking-banyandb/pull/1010#discussion_r2974401794


##########
docs/operation/mcp/setup.md:
##########
@@ -131,6 +127,89 @@ curl http://localhost:17913/api/healthz
 grpcurl -plaintext localhost:17912 list
 ```
 
+## HTTP Transport Mode
+
+By default the MCP server communicates over standard I/O (`TRANSPORT=stdio`), 
which is suitable for desktop clients such as Claude Desktop. Set 
`TRANSPORT=http` to expose the server as an HTTP endpoint instead. This mode 
uses the MCP [Streamable 
HTTP](https://modelcontextprotocol.io/specification/2025-11-25/basic/transports)
 transport, which supports both streaming (SSE) and direct JSON responses.
+
+### Start in HTTP Mode
+
+```bash
+# Default port 3000
+TRANSPORT=http BANYANDB_ADDRESS=localhost:17900 node dist/index.js
+
+# Custom port
+TRANSPORT=http MCP_PORT=8080 BANYANDB_ADDRESS=localhost:17900 node 
dist/index.js
+```
+
+The server prints the listening address on startup:
+
+```
+BanyanDB MCP HTTP server listening on :3000/mcp
+```
+
+The single endpoint is `POST /mcp` (also handles `GET /mcp` for 
server-to-client notifications). All other paths return 404.

Review Comment:
   The HTTP handler only processes requests after fully reading the body via 
`req.on('end', ...)`. There's no explicit GET handling. If the transport 
doesn't support GET, this documentation claim is incorrect.



##########
mcp/src/index.ts:
##########
@@ -33,11 +38,86 @@ dotenv.config();
 setupGlobalErrorHandlers();
 
 const BANYANDB_ADDRESS = process.env.BANYANDB_ADDRESS || 'localhost:17900';
-const LLM_API_KEY = process.env.LLM_API_KEY;
-const LLM_BASE_URL = process.env.LLM_BASE_URL;
+const TRANSPORT = process.env.TRANSPORT || 'stdio';
+const mcpPortRaw = parseInt(process.env.MCP_PORT || '3000', 10);
+if (!Number.isFinite(mcpPortRaw) || mcpPortRaw <= 0 || mcpPortRaw > 65535) {
+  log.error(`Invalid MCP_PORT value "${process.env.MCP_PORT}": must be an 
integer between 1 and 65535. Defaulting to 3000.`);

Review Comment:
   Port validation logs error but doesn't exit. This could mask configuration 
errors



##########
mcp/src/index.ts:
##########
@@ -33,11 +38,86 @@ dotenv.config();
 setupGlobalErrorHandlers();
 
 const BANYANDB_ADDRESS = process.env.BANYANDB_ADDRESS || 'localhost:17900';
-const LLM_API_KEY = process.env.LLM_API_KEY;
-const LLM_BASE_URL = process.env.LLM_BASE_URL;
+const TRANSPORT = process.env.TRANSPORT || 'stdio';
+const mcpPortRaw = parseInt(process.env.MCP_PORT || '3000', 10);
+if (!Number.isFinite(mcpPortRaw) || mcpPortRaw <= 0 || mcpPortRaw > 65535) {
+  log.error(`Invalid MCP_PORT value "${process.env.MCP_PORT}": must be an 
integer between 1 and 65535. Defaulting to 3000.`);
+}
+const MCP_PORT = Number.isFinite(mcpPortRaw) && mcpPortRaw > 0 && mcpPortRaw 
<= 65535 ? mcpPortRaw : 3000;
+
+// Prompt schema for generate_BydbQL — used with registerPrompt which requires 
a type cast
+// due to MCP SDK 1.x Zod v3/v4 compatibility layer causing TS2589 deep type 
instantiation.
+const generateBydbQLPromptSchema = {
+  description: z.string().describe(
+    "Natural language description of the query (e.g., 'list the last 30 
minutes service_cpm_minute', 'show the last 30 zipkin spans order by time')",
+  ),
+  resource_type: z.enum(['stream', 'measure', 'trace', 
'property']).optional().describe('Optional resource type hint: stream, measure, 
trace, or property'),
+  resource_name: z.string().optional().describe('Optional resource name hint 
(stream/measure/trace/property name)'),
+  group: z.string().optional().describe('Optional group hint, for example the 
properties group'),
+} as const;
+
+type QueryHints = {
+  description?: string;
+  BydbQL?: string;
+  resource_type?: string;
+  resource_name?: string;
+  group?: string;
+};
+
+function normalizeQueryHints(args: unknown): QueryHints {
+  if (!args || typeof args !== 'object') {
+    return {};
+  }
 
-async function main() {
-  // Create MCP server
+  const rawArgs = args as Record<string, unknown>;
+  return {
+    description: typeof rawArgs.description === 'string' ? 
rawArgs.description.trim() : undefined,
+    BydbQL: typeof rawArgs.BydbQL === 'string' ? rawArgs.BydbQL.trim() : 
typeof rawArgs.bydbql === 'string' ? rawArgs.bydbql.trim() : undefined,

Review Comment:
   Why do you use two different casings? Could you choose one? It looks like 
lowercase matches the parameter's convention.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to