Add Streamable HTTP transport for Azure Container Apps deployment#2
Add Streamable HTTP transport for Azure Container Apps deployment#2
Conversation
Implements modern Streamable HTTP transport (MCP v1.20.2) to enable: - Azure Container Apps deployment - Azure AI Foundry integration - Smithery hosted deployment Key changes: - Upgrade @modelcontextprotocol/sdk from 0.6.0 to 1.20.2 - Add StreamableHTTPServerTransport in src/http-server.ts - Extract shared server logic to src/server.ts - Switch to DefaultAzureCredential for flexible auth (Managed Identity + Azure CLI) - Update Dockerfile for HTTP server deployment - Update smithery.yaml to HTTP transport - Add Azure Container Apps deployment docs to README Maintains backward compatibility: - STDIO mode (npx) continues to work as before - Both transports share the same server implementation Closes #1 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
Pull Request Overview
This PR implements Streamable HTTP transport to enable Azure Container Apps and Smithery deployments, replacing the deprecated SSE approach while maintaining full backward compatibility with existing STDIO mode.
Key Changes:
- Upgraded
@modelcontextprotocol/sdkfrom 0.6.0 to 1.20.2 for modern HTTP transport support - Added Express-based HTTP server with session management alongside existing STDIO mode
- Switched from
AzureCliCredentialtoDefaultAzureCredentialfor flexible authentication across local and cloud environments
Reviewed Changes
Copilot reviewed 8 out of 9 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| src/server.ts | New shared server factory function containing all MCP tool registrations, used by both STDIO and HTTP transports |
| src/index.ts | Refactored STDIO entry point to use shared server logic, reduced from 300+ to 28 lines |
| src/http-server.ts | New HTTP server with Express, session management, and StreamableHTTPServerTransport |
| src/business-central-client.ts | Changed from AzureCliCredential to DefaultAzureCredential for multi-environment auth support |
| smithery.yaml | Updated from stdio to http transport configuration with /mcp endpoint |
| package.json | Version bump to 0.2.0, SDK upgrade, added express dependencies and start:http script |
| README.md | Added Azure Container Apps deployment section, authentication methods documentation |
| Dockerfile | Multi-stage build optimized for HTTP server deployment instead of STDIO |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
This Streamable HTTP transport implementation is now being used as a reference for adding the same capability to the mcp-neo4j-agent-memory repository. See knowall-ai/mcp-neo4j-agent-memory#4 for details. |
…mapping - Add runtime: container and build configuration - Add env section to map config values to environment variables - Add exampleConfig for better user experience - Fixes deployment error where BC_URL_SERVER and BC_COMPANY were missing
- Remove manual session tracking (transports Map) - Let StreamableHTTPServerTransport handle sessions via callbacks - Use single transport instance with sessionIdGenerator - Wrap initialization in async main() function - Change to app.all() to handle all HTTP methods (POST, GET, DELETE) This fixes the 'stream is not readable' error by eliminating double session management between our code and the SDK.
- Define test config with dummy Business Central credentials - Add health check endpoint test (GET /health) - Add MCP initialize test (POST /mcp) - Verify HTTP 200 responses and session ID generation - Tests validate the HTTP transport layer works correctly
- Added test request for MCP tools/list endpoint - Verifies tool discovery works without authentication - Helps Smithery scanner properly discover available tools
…ients - Install cors and @types/cors packages - Configure CORS middleware with Access-Control-Allow-Origin: * - Expose mcp-session-id header for browser access - Allow Content-Type, mcp-session-id, and Accept headers in requests - Required for Smithery scanner to access session management 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
Pull Request Overview
Copilot reviewed 8 out of 9 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Create single transport instance with session management | ||
| const transport = new StreamableHTTPServerTransport({ | ||
| sessionIdGenerator: () => { | ||
| const sessionId = `bc-${Date.now()}-${Math.random().toString(36).substring(7)}`; |
There was a problem hiding this comment.
Session ID generation uses Math.random() which is not cryptographically secure. For session identifiers, use a cryptographically secure random number generator like crypto.randomUUID() or crypto.randomBytes() to prevent session prediction attacks.
|
|
||
| // Configure CORS to expose the mcp-session-id header (required for browser-based clients) | ||
| app.use(cors({ | ||
| origin: '*', // Allow all origins (Smithery needs this) |
There was a problem hiding this comment.
CORS is configured to allow all origins ('*'). While the comment indicates this is for Smithery, allowing all origins can expose the API to unauthorized cross-origin requests. Consider restricting to specific trusted origins or implementing additional authentication layers.
| expectedResponse: | ||
| statusCode: 200 | ||
| headers: | ||
| mcp-session-id: ".*" # Should return a session ID |
There was a problem hiding this comment.
The regex pattern .* in the test assertion is too permissive and would match empty strings or malformed session IDs. Consider using a more specific pattern that validates the expected session ID format (e.g., bc-\\d+-[a-z0-9]+ to match the format generated in http-server.ts).
| mcp-session-id: ".*" # Should return a session ID | |
| mcp-session-id: "bc-\\d+-[a-z0-9]+" # Should return a session ID in expected format |
Overview
This PR implements Streamable HTTP transport to enable Azure Container Apps deployment and Smithery hosting, replacing the deprecated SSE transport approach.
Closes #1
Changes
🆙 Upgraded Dependencies
0.6.0→1.20.2StreamableHTTPServerTransport✨ New Features
src/http-server.ts- HTTP Server Entry Point/mcpendpoint supporting:/healthsrc/server.ts- Shared Server Logic🔄 Updated Components
src/business-central-client.tsAzureCliCredentialonlyDefaultAzureCredentialsrc/index.ts(STDIO Entry Point)createMCPServer()Dockerfilesmithery.yamltype: stdio(deprecated by Smithery)type: httpwith/mcpendpointREADME.mdDefaultAzureCredentialBackward Compatibility ✅
No breaking changes - existing users are unaffected:
{ "mcpServers": { "business-central": { "type": "stdio", "command": "cmd", "args": ["/c", "npx", "-y", "@knowall-ai/mcp-business-central"], "env": { "BC_URL_SERVER": "...", "BC_COMPANY": "..." } } } }The npx entry point (
build/index.js) remains unchanged and uses STDIO transport.New Capabilities 🚀
1. Azure Container Apps Deployment
2. Local HTTP Testing
npm run build npm run start:http # Server at http://localhost:3000/mcp3. Smithery Deployment
HTTP transport configuration now allows Smithery to host the server.
Testing
Technical Details
Transport Architecture
STDIO Transport (
src/index.js):HTTP Transport (
src/http-server.js):Both use the same server logic, ensuring consistent behavior.
Authentication Flow
Local Development:
Azure Container Apps:
References
Checklist
🤖 Generated with Claude Code
Co-Authored-By: Claude noreply@anthropic.com