-
Notifications
You must be signed in to change notification settings - Fork 18
Description
Summary
Add native HTTP transport support to smithy-java MCP server implementation, similar to the existing StdIO transport. This would enable MCP servers to be deployed as HTTP services without requiring custom transport layer implementations.
Motivation
Currently, smithy-java provides excellent support for StdIO-based MCP servers via McpServer.builder().stdio(), but lacks native HTTP transport support. The MCP specification defines HTTP as a standard transport mechanism, yet developers must implement their own HTTP layer.
This creates several issues:
- Duplication: Every project reimplements HTTP transport logic
- Inconsistency: Different implementations may handle protocol details differently
- Maintenance burden: Protocol updates require changes across multiple projects
- Error-prone: Easy to miss protocol requirements (e.g., returning 202 for notifications)
- Barrier to adoption: Increases complexity for new MCP server developers
Current Workaround
After PR: #893, Developers currently can implement custom HTTP servers that wrap McpService:
// Current approach - custom HTTP server required
public class HttpMCPServer {
private final McpService mcpService;
private HttpServer httpServer;
public HttpMCPServer(String host, int port, String serverName) {
var service = BillingAnalyticsService.builder()
.addOperation(new MyOperationImpl())
.build();
this.mcpService = McpService.builder()
.services(Map.of("billing", service))
.name(serverName)
.build();
}
public void start() throws IOException {
httpServer = HttpServer.create(new InetSocketAddress(host, port), 0);
httpServer.createContext("/mcp", new McpHandler());
httpServer.start();
}
private class McpHandler implements HttpHandler {
public void handle(HttpExchange exchange) throws IOException {
// Handle CORS, Origin validation, method routing
// Parse JSON-RPC request
// Delegate to mcpService.handleRequest()
// Return 202 for notifications, 200 for requests
// Handle errors appropriately
}
}
}This requires ~200+ lines of boilerplate code per project.
Proposed Solution
Add HTTP transport support to McpServer.Builder, making it as simple as StdIO:
// Proposed API - consistent with StdIO
var server = McpServer.builder()
.http("0.0.0.0", 8000) // Simple HTTP transport
.name("my-mcp-server")
.addService("billing", service)
.build();
server.start();Advanced Configuration
For production deployments, provide configuration options:
var server = McpServer.builder()
.http(HttpTransportConfig.builder()
.host("0.0.0.0")
.port(8000)
.path("/mcp")
.enableSSE(true) // Server-Sent Events for streaming
.cors(CorsConfig.builder()
.allowedOrigins("https://example.com")
.allowedMethods("POST", "GET", "DELETE")
.build())
.security(SecurityConfig.builder()
.validateOrigin(true)
.allowedOrigins("http://localhost:*", "https://*.example.com")
.build())
.build())
.name("my-mcp-server")
.addService("billing", service)
.build();Smithy Trait Representation
HTTP transport configuration could be represented as a Smithy trait:
namespace smithy.mcp
/// Configures HTTP transport for an MCP service
@trait(selector: "service")
structure httpTransport {
/// Host to bind to (default: "0.0.0.0")
host: String
/// Port to listen on (default: 8000)
port: Integer
/// HTTP path for MCP endpoint (default: "/mcp")
path: String
/// Enable Server-Sent Events for streaming (default: false)
enableSSE: Boolean
/// CORS configuration
cors: CorsConfiguration
/// Security configuration
security: SecurityConfiguration
}
structure CorsConfiguration {
/// Allowed origins (default: "*")
allowedOrigins: StringList
/// Allowed HTTP methods
allowedMethods: StringList
/// Allowed headers
allowedHeaders: StringList
}
structure SecurityConfiguration {
/// Validate Origin header to prevent DNS rebinding
validateOrigin: Boolean
/// Allowed origin patterns
allowedOrigins: StringList
}Usage in service definition:
@httpTransport(
host: "0.0.0.0"
port: 8000
path: "/mcp"
enableSSE: true
cors: {
allowedOrigins: ["https://example.com"]
allowedMethods: ["POST", "GET", "DELETE"]
}
)
service BillingAnalyticsService {
operations: [GetCostByService, GetCostByRegion]
}The code generator would then automatically configure HTTP transport based on these traits.