The HTTP transport package provides stateless HTTP-based communication for MCP. It includes server-side transports (standard HTTP and Gin framework) and a client-side transport for connecting to HTTP-based MCP servers.
import "github.com/metoro-io/mcp-golang/transport/http"type HTTPTransport struct {
// Contains unexported fields
}Stateless HTTP transport for MCP servers using the standard library HTTP server.
Features:
Limitations:
func NewHTTPTransport(endpoint string) *HTTPTransportCreates an HTTP transport that listens on the specified endpoint path.
Parameters:
endpoint: HTTP endpoint path (e.g., "/mcp", "/api/mcp")Returns: HTTPTransport ready for configuration
Example:
import "github.com/metoro-io/mcp-golang/transport/http"
transport := http.NewHTTPTransport("/mcp")func (h *HTTPTransport) WithAddr(addr string) *HTTPTransportSets the address and port to listen on.
Parameters:
addr: Listen address (e.g., ":8080", "localhost:3000", "0.0.0.0:8080")Returns: The same HTTPTransport instance for method chaining
Example:
transport := http.NewHTTPTransport("/mcp").
WithAddr(":8080")func (h *HTTPTransport) Start(ctx context.Context) errorStarts the HTTP server and begins accepting requests. Blocks until the context is cancelled or an error occurs.
Parameters:
ctx: Context for controlling the server lifecycleReturns: Error if the server fails to start
Example:
ctx := context.Background()
go func() {
if err := transport.Start(ctx); err != nil {
log.Fatalf("Server error: %v", err)
}
}()func (h *HTTPTransport) Send(ctx context.Context, message *transport.BaseJsonRpcMessage) errorSends a JSON-RPC message as an HTTP response.
Parameters:
ctx: Context for the send operationmessage: The JSON-RPC message to sendReturns: Error if sending fails
func (h *HTTPTransport) Close() errorCloses the HTTP server and cleans up resources.
Returns: Error if cleanup fails
Example:
defer transport.Close()func (h *HTTPTransport) SetCloseHandler(handler func())Sets a callback function invoked when the transport closes.
Parameters:
handler: Function to call when the transport closesfunc (h *HTTPTransport) SetErrorHandler(handler func(error))Sets a callback function invoked when errors occur.
Parameters:
handler: Function to call with error detailsfunc (h *HTTPTransport) SetMessageHandler(handler func(ctx context.Context, message *transport.BaseJsonRpcMessage))Sets a callback function invoked when requests are received.
Parameters:
handler: Function to call with received messagespackage main
import (
"fmt"
"log"
mcp "github.com/metoro-io/mcp-golang"
"github.com/metoro-io/mcp-golang/transport/http"
)
type CalculateArgs struct {
A int `json:"a" jsonschema:"required"`
B int `json:"b" jsonschema:"required"`
}
func main() {
// Create HTTP transport
transport := http.NewHTTPTransport("/mcp").
WithAddr(":8080")
// Create server
server := mcp.NewServer(
transport,
mcp.WithName("http-calculator"),
mcp.WithVersion("1.0.0"),
)
// Register tool
server.RegisterTool("add", "Adds two numbers",
func(args CalculateArgs) (*mcp.ToolResponse, error) {
result := args.A + args.B
return mcp.NewToolResponse(
mcp.NewTextContent(fmt.Sprintf("Result: %d", result)),
), nil
})
// Start server
log.Println("HTTP MCP server listening on :8080/mcp")
if err := server.Serve(); err != nil {
log.Fatalf("Server error: %v", err)
}
}type GinTransport struct {
// Contains unexported fields
}Stateless HTTP transport for MCP servers using the Gin web framework.
Features:
Use Case: Adding MCP capabilities to existing Gin-based web services
func NewGinTransport() *GinTransportCreates a new Gin transport.
Returns: GinTransport ready for use with Gin
Example:
import (
"github.com/gin-gonic/gin"
"github.com/metoro-io/mcp-golang/transport/http"
)
transport := http.NewGinTransport()func (g *GinTransport) Handler() gin.HandlerFuncReturns a Gin handler function for use with Gin routers.
Returns: gin.HandlerFunc that processes MCP requests
Example:
router := gin.Default()
transport := http.NewGinTransport()
// Register MCP endpoint
router.POST("/mcp", transport.Handler())
// Can also use route groups
apiGroup := router.Group("/api")
apiGroup.POST("/mcp", transport.Handler())GinTransport implements the transport.Transport interface with these specifics:
func (g *GinTransport) Start(ctx context.Context) errorNo-op for Gin transport since the Gin framework handles server lifecycle.
Returns: Always returns nil
func (g *GinTransport) Send(ctx context.Context, message *transport.BaseJsonRpcMessage) errorSends a JSON-RPC message as the Gin response.
Parameters:
ctx: Context for the send operationmessage: The JSON-RPC message to sendReturns: Error if sending fails
func (g *GinTransport) Close() errorCloses the transport. The Gin server itself must be stopped separately.
Returns: Error if cleanup fails
func (g *GinTransport) SetCloseHandler(handler func())Sets a callback function invoked when the transport closes.
func (g *GinTransport) SetErrorHandler(handler func(error))Sets a callback function invoked when errors occur.
func (g *GinTransport) SetMessageHandler(handler func(ctx context.Context, message *transport.BaseJsonRpcMessage))Sets a callback function invoked when requests are received.
package main
import (
"fmt"
"log"
"github.com/gin-gonic/gin"
mcp "github.com/metoro-io/mcp-golang"
"github.com/metoro-io/mcp-golang/transport/http"
)
type SearchArgs struct {
Query string `json:"query" jsonschema:"required"`
}
func main() {
// Create Gin router
router := gin.Default()
// Add middleware
router.Use(gin.Logger())
router.Use(gin.Recovery())
// Regular HTTP endpoints
router.GET("/health", func(c *gin.Context) {
c.JSON(200, gin.H{"status": "ok"})
})
// Create MCP transport and server
transport := http.NewGinTransport()
server := mcp.NewServer(
transport,
mcp.WithName("gin-search-server"),
mcp.WithVersion("1.0.0"),
)
// Register MCP tools
server.RegisterTool("search", "Searches for items",
func(args SearchArgs) (*mcp.ToolResponse, error) {
result := fmt.Sprintf("Results for: %s", args.Query)
return mcp.NewToolResponse(
mcp.NewTextContent(result),
), nil
})
// Register MCP handler with Gin
router.POST("/mcp", transport.Handler())
// Start MCP server in background
go func() {
if err := server.Serve(); err != nil {
log.Fatalf("MCP server error: %v", err)
}
}()
// Start Gin server
log.Println("Server listening on :8080")
log.Println("MCP endpoint: POST http://localhost:8080/mcp")
if err := router.Run(":8080"); err != nil {
log.Fatalf("Failed to start server: %v", err)
}
}package main
import (
"log"
"time"
"github.com/gin-gonic/gin"
mcp "github.com/metoro-io/mcp-golang"
"github.com/metoro-io/mcp-golang/transport/http"
)
// Custom authentication middleware
func authMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
token := c.GetHeader("Authorization")
if token != "Bearer secret-token" {
c.JSON(401, gin.H{"error": "unauthorized"})
c.Abort()
return
}
c.Next()
}
}
// Rate limiting middleware
func rateLimiter() gin.HandlerFunc {
return func(c *gin.Context) {
// Implement rate limiting logic
c.Next()
}
}
func main() {
router := gin.Default()
// Create MCP server
transport := http.NewGinTransport()
server := mcp.NewServer(transport)
server.RegisterTool("status", "Server status",
func() (*mcp.ToolResponse, error) {
return mcp.NewToolResponse(
mcp.NewTextContent("Server operational"),
), nil
})
// MCP endpoint with middleware
mcpGroup := router.Group("/api")
mcpGroup.Use(authMiddleware())
mcpGroup.Use(rateLimiter())
mcpGroup.POST("/mcp", transport.Handler())
go server.Serve()
router.Run(":8080")
}type HTTPClientTransport struct {
// Contains unexported fields
}Client-side HTTP transport for connecting to HTTP-based MCP servers.
Features:
func NewHTTPClientTransport(endpoint string) *HTTPClientTransportCreates an HTTP client transport connecting to the specified endpoint URL.
Parameters:
endpoint: Full URL to the MCP server endpoint (e.g., "http://localhost:8080/mcp")Returns: HTTPClientTransport ready for configuration
Example:
import "github.com/metoro-io/mcp-golang/transport/http"
transport := http.NewHTTPClientTransport("http://localhost:8080/mcp")func (h *HTTPClientTransport) WithClient(c HTTPClient) *HTTPClientTransportSets a custom HTTP client for requests.
Parameters:
c: HTTP client implementing the HTTPClient interfaceReturns: The same HTTPClientTransport instance for method chaining
Example:
import (
"net/http"
"time"
)
customClient := &http.Client{
Timeout: 30 * time.Second,
Transport: &http.Transport{
MaxIdleConns: 10,
IdleConnTimeout: 90 * time.Second,
},
}
transport := http.NewHTTPClientTransport("http://localhost:8080/mcp").
WithClient(customClient)func (h *HTTPClientTransport) WithBaseURL(baseURL string) *HTTPClientTransportSets or updates the base URL for the MCP server.
Parameters:
baseURL: Base URL for the serverReturns: The same HTTPClientTransport instance for method chaining
Example:
transport := http.NewHTTPClientTransport("http://localhost:8080/mcp").
WithBaseURL("https://api.example.com/mcp")func (h *HTTPClientTransport) WithHeader(key, value string) *HTTPClientTransportAdds an HTTP header to all requests.
Parameters:
key: Header namevalue: Header valueReturns: The same HTTPClientTransport instance for method chaining
Example:
transport := http.NewHTTPClientTransport("http://localhost:8080/mcp").
WithHeader("Authorization", "Bearer secret-token").
WithHeader("X-Client-Version", "1.0.0")func (h *HTTPClientTransport) Start(ctx context.Context) errorInitializes the transport. For HTTP client, this is typically a no-op.
Parameters:
ctx: Context for initializationReturns: Error if initialization fails
func (h *HTTPClientTransport) Send(ctx context.Context, message *transport.BaseJsonRpcMessage) errorSends a JSON-RPC message to the server via HTTP POST.
Parameters:
ctx: Context for the send operationmessage: The JSON-RPC message to sendReturns: Error if sending fails
func (h *HTTPClientTransport) Close() errorCloses the transport and cleans up resources.
Returns: Error if cleanup fails
func (h *HTTPClientTransport) SetCloseHandler(handler func())Sets a callback function invoked when the transport closes.
func (h *HTTPClientTransport) SetErrorHandler(handler func(error))Sets a callback function invoked when errors occur.
func (h *HTTPClientTransport) SetMessageHandler(handler func(ctx context.Context, message *transport.BaseJsonRpcMessage))Sets a callback function invoked when responses are received.
type HTTPClient interface {
Do(r *http.Request) (*http.Response, error)
}Interface for HTTP client operations. Implemented by *http.Client from the standard library.
Methods:
Do: Executes an HTTP request and returns the responsepackage main
import (
"context"
"log"
mcp "github.com/metoro-io/mcp-golang"
"github.com/metoro-io/mcp-golang/transport/http"
)
type EchoArgs struct {
Message string `json:"message"`
}
func main() {
// Create HTTP client transport
transport := http.NewHTTPClientTransport("http://localhost:8080/mcp")
// Create MCP client
client := mcp.NewClient(transport)
// Initialize
ctx := context.Background()
_, err := client.Initialize(ctx)
if err != nil {
log.Fatalf("Failed to initialize: %v", err)
}
// Call tool
response, err := client.CallTool(ctx, "echo", EchoArgs{
Message: "Hello, HTTP MCP!",
})
if err != nil {
log.Fatalf("Failed to call tool: %v", err)
}
log.Printf("Response: %s", response.Content[0].TextContent.Text)
}package main
import (
"context"
"log"
"net/http"
"time"
mcp "github.com/metoro-io/mcp-golang"
httpTransport "github.com/metoro-io/mcp-golang/transport/http"
)
func main() {
// Create custom HTTP client with timeout
httpClient := &http.Client{
Timeout: 30 * time.Second,
}
// Create transport with authentication
transport := httpTransport.NewHTTPClientTransport("https://api.example.com/mcp").
WithClient(httpClient).
WithHeader("Authorization", "Bearer my-api-token").
WithHeader("X-API-Version", "1.0")
// Create MCP client
client := mcp.NewClientWithInfo(transport, mcp.ClientInfo{
Name: "my-http-client",
Version: "1.0.0",
})
ctx := context.Background()
_, err := client.Initialize(ctx)
if err != nil {
log.Fatalf("Failed to initialize: %v", err)
}
// List available tools
tools, err := client.ListTools(ctx, nil)
if err != nil {
log.Fatalf("Failed to list tools: %v", err)
}
for _, tool := range tools.Tools {
log.Printf("Tool: %s - %s", tool.Name, *tool.Description)
}
}package main
import (
"context"
"log"
"net/http"
"time"
mcp "github.com/metoro-io/mcp-golang"
httpTransport "github.com/metoro-io/mcp-golang/transport/http"
)
// Custom HTTP client with retry
type RetryClient struct {
client *http.Client
maxRetries int
retryDelay time.Duration
}
func (r *RetryClient) Do(req *http.Request) (*http.Response, error) {
var resp *http.Response
var err error
for i := 0; i <= r.maxRetries; i++ {
resp, err = r.client.Do(req)
if err == nil && resp.StatusCode < 500 {
return resp, nil
}
if i < r.maxRetries {
time.Sleep(r.retryDelay)
}
}
return resp, err
}
func main() {
// Create retry client
retryClient := &RetryClient{
client: &http.Client{Timeout: 10 * time.Second},
maxRetries: 3,
retryDelay: 1 * time.Second,
}
// Create transport with retry client
transport := httpTransport.NewHTTPClientTransport("http://localhost:8080/mcp").
WithClient(retryClient)
client := mcp.NewClient(transport)
ctx := context.Background()
_, err := client.Initialize(ctx)
if err != nil {
log.Fatalf("Failed to initialize after retries: %v", err)
}
log.Println("Connected successfully")
}// Development
transport := http.NewHTTPTransport("/mcp").WithAddr(":8080")
// Production
transport := http.NewHTTPTransport("/mcp").WithAddr(":443")
// Configure TLS certificates for the HTTP server// Server-side: Use middleware or custom handlers
router.Use(authMiddleware())
router.POST("/mcp", transport.Handler())
// Client-side: Add auth headers
transport.WithHeader("Authorization", "Bearer token")httpClient := &http.Client{
Timeout: 30 * time.Second,
}
transport.WithClient(httpClient)transport.SetErrorHandler(func(err error) {
log.Printf("Transport error: %v", err)
// Implement retry or fallback logic
})| Feature | HTTP | Stdio |
|---|---|---|
| Bidirectional | No | Yes |
| Notifications | No | Yes |
| Deployment | Web-friendly | Process-based |
| Scaling | Horizontal | Vertical |
| Connection | Stateless | Stateful |
| Use Case | Web services | Subprocesses, CLI |
Use HTTP when:
Use Stdio when: