feat: add Streamable HTTP transport support
Add support for running the MCP server over HTTP with Server-Sent Events (SSE) using the MCP Streamable HTTP specification, alongside the existing STDIO transport. New features: - Transport abstraction with Transport interface - HTTP transport with session management - SSE support for server-initiated notifications - CORS security with configurable allowed origins - Optional TLS support - CLI flags for HTTP configuration (--transport, --http-address, etc.) - NixOS module options for HTTP transport The HTTP transport implements: - POST /mcp: JSON-RPC requests with session management - GET /mcp: SSE stream for server notifications - DELETE /mcp: Session termination - Origin validation (localhost-only by default) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
63
internal/mcp/transport_stdio.go
Normal file
63
internal/mcp/transport_stdio.go
Normal file
@@ -0,0 +1,63 @@
|
||||
package mcp
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
// StdioTransport implements the MCP protocol over STDIO using line-delimited JSON-RPC.
|
||||
type StdioTransport struct {
|
||||
server *Server
|
||||
reader io.Reader
|
||||
writer io.Writer
|
||||
}
|
||||
|
||||
// NewStdioTransport creates a new STDIO transport.
|
||||
func NewStdioTransport(server *Server, r io.Reader, w io.Writer) *StdioTransport {
|
||||
return &StdioTransport{
|
||||
server: server,
|
||||
reader: r,
|
||||
writer: w,
|
||||
}
|
||||
}
|
||||
|
||||
// Run starts the STDIO transport, reading line-delimited JSON-RPC from the reader
|
||||
// and writing responses to the writer.
|
||||
func (t *StdioTransport) Run(ctx context.Context) error {
|
||||
scanner := bufio.NewScanner(t.reader)
|
||||
encoder := json.NewEncoder(t.writer)
|
||||
|
||||
for scanner.Scan() {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
default:
|
||||
}
|
||||
|
||||
line := scanner.Bytes()
|
||||
if len(line) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
resp, err := t.server.HandleMessage(ctx, line)
|
||||
if err != nil {
|
||||
t.server.logger.Printf("Error handling message: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
if resp != nil {
|
||||
if err := encoder.Encode(resp); err != nil {
|
||||
return fmt.Errorf("failed to write response: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := scanner.Err(); err != nil {
|
||||
return fmt.Errorf("scanner error: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user