or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

client.mdcontent-types.mdindex.mdserver.mdtransport-http.mdtransport-stdio.mdtransport.md
tile.json

transport-http.mddocs/

HTTP Transports

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.

Package

import "github.com/metoro-io/mcp-golang/transport/http"

HTTPTransport (Server)

type HTTPTransport struct {
    // Contains unexported fields
}

Stateless HTTP transport for MCP servers using the standard library HTTP server.

Features:

  • Request-response communication only
  • No bidirectional features or notifications
  • Simple deployment and scaling
  • Standard HTTP/HTTPS support
  • Thread-safe

Limitations:

  • Cannot send server-initiated notifications
  • No persistent connection state
  • Not suitable for real-time updates

Creating an HTTPTransport

NewHTTPTransport

func NewHTTPTransport(endpoint string) *HTTPTransport

Creates 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")

Configuration Methods

WithAddr

func (h *HTTPTransport) WithAddr(addr string) *HTTPTransport

Sets 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")

Transport Interface Methods

Start

func (h *HTTPTransport) Start(ctx context.Context) error

Starts the HTTP server and begins accepting requests. Blocks until the context is cancelled or an error occurs.

Parameters:

  • ctx: Context for controlling the server lifecycle

Returns: 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)
    }
}()

Send

func (h *HTTPTransport) Send(ctx context.Context, message *transport.BaseJsonRpcMessage) error

Sends a JSON-RPC message as an HTTP response.

Parameters:

  • ctx: Context for the send operation
  • message: The JSON-RPC message to send

Returns: Error if sending fails

Close

func (h *HTTPTransport) Close() error

Closes the HTTP server and cleans up resources.

Returns: Error if cleanup fails

Example:

defer transport.Close()

SetCloseHandler

func (h *HTTPTransport) SetCloseHandler(handler func())

Sets a callback function invoked when the transport closes.

Parameters:

  • handler: Function to call when the transport closes

SetErrorHandler

func (h *HTTPTransport) SetErrorHandler(handler func(error))

Sets a callback function invoked when errors occur.

Parameters:

  • handler: Function to call with error details

SetMessageHandler

func (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 messages

HTTPTransport Example

package 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)
    }
}

GinTransport (Server)

type GinTransport struct {
    // Contains unexported fields
}

Stateless HTTP transport for MCP servers using the Gin web framework.

Features:

  • Integrates with existing Gin applications
  • Request-response communication only
  • No bidirectional features or notifications
  • Access to Gin middleware and routing
  • Thread-safe

Use Case: Adding MCP capabilities to existing Gin-based web services

Creating a GinTransport

NewGinTransport

func NewGinTransport() *GinTransport

Creates 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()

Special Methods

Handler

func (g *GinTransport) Handler() gin.HandlerFunc

Returns 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())

Transport Interface Methods

GinTransport implements the transport.Transport interface with these specifics:

Start

func (g *GinTransport) Start(ctx context.Context) error

No-op for Gin transport since the Gin framework handles server lifecycle.

Returns: Always returns nil

Send

func (g *GinTransport) Send(ctx context.Context, message *transport.BaseJsonRpcMessage) error

Sends a JSON-RPC message as the Gin response.

Parameters:

  • ctx: Context for the send operation
  • message: The JSON-RPC message to send

Returns: Error if sending fails

Close

func (g *GinTransport) Close() error

Closes the transport. The Gin server itself must be stopped separately.

Returns: Error if cleanup fails

SetCloseHandler

func (g *GinTransport) SetCloseHandler(handler func())

Sets a callback function invoked when the transport closes.

SetErrorHandler

func (g *GinTransport) SetErrorHandler(handler func(error))

Sets a callback function invoked when errors occur.

SetMessageHandler

func (g *GinTransport) SetMessageHandler(handler func(ctx context.Context, message *transport.BaseJsonRpcMessage))

Sets a callback function invoked when requests are received.

GinTransport Example

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)
    }
}

GinTransport with Middleware

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")
}

HTTPClientTransport (Client)

type HTTPClientTransport struct {
    // Contains unexported fields
}

Client-side HTTP transport for connecting to HTTP-based MCP servers.

Features:

  • Stateless HTTP communication
  • Custom HTTP client support
  • Header configuration
  • No notification support (client cannot receive server-initiated messages)

Creating an HTTPClientTransport

NewHTTPClientTransport

func NewHTTPClientTransport(endpoint string) *HTTPClientTransport

Creates 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")

Configuration Methods

WithClient

func (h *HTTPClientTransport) WithClient(c HTTPClient) *HTTPClientTransport

Sets a custom HTTP client for requests.

Parameters:

  • c: HTTP client implementing the HTTPClient interface

Returns: 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)

WithBaseURL

func (h *HTTPClientTransport) WithBaseURL(baseURL string) *HTTPClientTransport

Sets or updates the base URL for the MCP server.

Parameters:

  • baseURL: Base URL for the server

Returns: The same HTTPClientTransport instance for method chaining

Example:

transport := http.NewHTTPClientTransport("http://localhost:8080/mcp").
    WithBaseURL("https://api.example.com/mcp")

WithHeader

func (h *HTTPClientTransport) WithHeader(key, value string) *HTTPClientTransport

Adds an HTTP header to all requests.

Parameters:

  • key: Header name
  • value: Header value

Returns: 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")

Transport Interface Methods

Start

func (h *HTTPClientTransport) Start(ctx context.Context) error

Initializes the transport. For HTTP client, this is typically a no-op.

Parameters:

  • ctx: Context for initialization

Returns: Error if initialization fails

Send

func (h *HTTPClientTransport) Send(ctx context.Context, message *transport.BaseJsonRpcMessage) error

Sends a JSON-RPC message to the server via HTTP POST.

Parameters:

  • ctx: Context for the send operation
  • message: The JSON-RPC message to send

Returns: Error if sending fails

Close

func (h *HTTPClientTransport) Close() error

Closes the transport and cleans up resources.

Returns: Error if cleanup fails

SetCloseHandler

func (h *HTTPClientTransport) SetCloseHandler(handler func())

Sets a callback function invoked when the transport closes.

SetErrorHandler

func (h *HTTPClientTransport) SetErrorHandler(handler func(error))

Sets a callback function invoked when errors occur.

SetMessageHandler

func (h *HTTPClientTransport) SetMessageHandler(handler func(ctx context.Context, message *transport.BaseJsonRpcMessage))

Sets a callback function invoked when responses are received.

HTTPClient Interface

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 response

HTTPClientTransport Examples

Basic Client

package 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)
}

Client with Authentication and Custom Timeout

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)
    }
}

Client with Retry Logic

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")
}

Best Practices

1. Use HTTPS in Production

// Development
transport := http.NewHTTPTransport("/mcp").WithAddr(":8080")

// Production
transport := http.NewHTTPTransport("/mcp").WithAddr(":443")
// Configure TLS certificates for the HTTP server

2. Add Authentication for HTTP Endpoints

// 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")

3. Set Appropriate Timeouts

httpClient := &http.Client{
    Timeout: 30 * time.Second,
}
transport.WithClient(httpClient)

4. Handle Connection Errors

transport.SetErrorHandler(func(err error) {
    log.Printf("Transport error: %v", err)
    // Implement retry or fallback logic
})

Comparison: HTTP vs Stdio Transport

FeatureHTTPStdio
BidirectionalNoYes
NotificationsNoYes
DeploymentWeb-friendlyProcess-based
ScalingHorizontalVertical
ConnectionStatelessStateful
Use CaseWeb servicesSubprocesses, CLI

Use HTTP when:

  • Building web-based MCP services
  • Need to scale horizontally
  • Integrating with existing web infrastructure
  • Don't need server-initiated notifications

Use Stdio when:

  • Building Claude Desktop integrations
  • Need bidirectional communication
  • Running as subprocess
  • Require notification support