Skip to content

Repository files navigation

MCP Gateway

A centralized API gateway for Model Context Protocol (MCP) servers. MCP Gateway enables LLM clients to connect to multiple MCP servers through a single endpoint with unified authentication, session management, and rate limiting.

Features

  • Namespace-based routing: Route requests to different MCP servers based on namespace
  • API key authentication: Secure access with configurable API keys and namespace restrictions
  • Tool filtering: Allow or deny specific tools per namespace
  • Request logging: Track all MCP requests with DuckDB for analytics
  • Analytics API: Query usage statistics, tool popularity, and time series data
  • SSE streaming support: Full support for Server-Sent Events for streaming responses

Quick Start

Prerequisites

  • Go 1.21 or later
  • DuckDB (embedded, no separate installation required)

Installation

# Clone the repository
git clone https://github.com/sekoudoumbouya/mcp-gateway.git
cd mcp-gateway

# Install dependencies
go mod download

# Build the gateway
go build -o mcp-gateway ./cmd/gateway

Running the Gateway

# Start with default config
./mcp-gateway

# Start with custom config file
./mcp-gateway -config /path/to/config.yaml

The gateway will start on http://localhost:8080 by default.

Configuration

Create a config.yaml file:

server:
  host: "0.0.0.0"
  port: 8080

database:
  path: "gateway.duckdb"

# Namespace to MCP server mappings
namespaces:
  filesystem:
    url: "http://localhost:3001/mcp"
    description: "Filesystem operations"
    # Optional: restrict which tools are allowed
    allowed_tools:
      - "read_file"
      - "list_directory"

  search:
    url: "http://localhost:3002/mcp"
    description: "Web search and browsing"

  database:
    url: "http://localhost:3003/mcp"
    description: "Database operations"

# Authentication
auth:
  enabled: true
  api_keys:
    "dev-key-12345":
      user_id: "developer"
      description: "Development key"
      # Empty namespaces = access to all

    "prod-key-67890":
      user_id: "production"
      namespaces:
        - "filesystem"
        - "database"

    "search-only":
      user_id: "search-user"
      namespaces:
        - "search"

# Rate limiting
rate_limit:
  enabled: true
  requests_per_minute: 100
  burst_size: 10

Environment Variables

Override configuration with environment variables:

Variable Description
GATEWAY_HOST Server listen host
GATEWAY_PORT Server listen port
GATEWAY_DB_PATH DuckDB database path

Environment variable expansion is also supported in config values:

database:
  path: "${DATABASE_PATH}"

API Reference

Health Check

GET /health

Returns gateway health status.

Response:

{
  "status": "healthy",
  "time": "2024-01-15T10:30:00Z"
}

List Namespaces

GET /namespaces

Returns all configured namespaces.

Response:

{
  "namespaces": [
    {
      "name": "filesystem",
      "description": "Filesystem operations"
    },
    {
      "name": "search",
      "description": "Web search and browsing"
    }
  ]
}

MCP Endpoint

POST /mcp/:namespace
Authorization: Bearer <api-key>
Content-Type: application/json

Forward JSON-RPC 2.0 requests to the specified namespace's MCP server.

Request:

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/list"
}

Response:

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "tools": [...]
  }
}

For streaming responses, add Accept: text/event-stream header.

Analytics API

Get Usage Statistics

GET /analytics/usage?period=7d&group_by=user
Authorization: Bearer <api-key>

Parameters:

  • period: Time period (e.g., 7d, 24h, 1h, 30m)
  • group_by: Group by user (default) or tool

Response:

{
  "period": "168h0m0s",
  "results": [
    {
      "user_id": "developer",
      "namespace": "filesystem",
      "request_count": 150,
      "error_count": 2,
      "avg_latency_ms": 45.5,
      "total_request_bytes": 15000,
      "total_response_bytes": 75000
    }
  ]
}

Get User Statistics

GET /analytics/usage/:user_id?period=24h
Authorization: Bearer <api-key>

Returns detailed statistics for a specific user.

Get Tool Popularity

GET /analytics/tools?period=7d&limit=20
Authorization: Bearer <api-key>

Response:

{
  "period": "168h0m0s",
  "tools": [
    {
      "tool_name": "read_file",
      "namespace": "filesystem",
      "invocations": 500,
      "unique_users": 10,
      "avg_latency_ms": 25.3,
      "error_rate": 0.02
    }
  ]
}

Get Time Series Data

GET /analytics/timeseries?period=24h&bucket=1h
Authorization: Bearer <api-key>

Response:

{
  "period": "24h0m0s",
  "bucket": "1h0m0s",
  "data": [
    {
      "timestamp": "2024-01-15T09:00:00Z",
      "value": 45
    },
    {
      "timestamp": "2024-01-15T10:00:00Z",
      "value": 62
    }
  ]
}

Architecture

┌─────────────────────────────────────────────────────────────┐
│                        LLM Clients                          │
│              (Claude, GPT, etc. with MCP config)            │
└─────────────────────────┬───────────────────────────────────┘
                          │
                          ▼
┌─────────────────────────────────────────────────────────────┐
│                      MCP Gateway                            │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────────────┐  │
│  │    Auth     │  │   Router    │  │    Event Logger     │  │
│  │ Middleware  │  │ (Namespace) │  │     (DuckDB)        │  │
│  └─────────────┘  └─────────────┘  └─────────────────────┘  │
│  ┌─────────────────────────────────────────────────────────┐│
│  │                    MCP Handler                          ││
│  │  - HTTP/JSON-RPC proxy                                  ││
│  │  - SSE streaming support                                ││
│  │  - Tool filtering                                       ││
│  └─────────────────────────────────────────────────────────┘│
└─────────────────────────┬───────────────────────────────────┘
                          │
          ┌───────────────┼───────────────┐
          ▼               ▼               ▼
    ┌──────────┐    ┌──────────┐    ┌──────────┐
    │ MCP      │    │ MCP      │    │ MCP      │
    │ Server 1 │    │ Server 2 │    │ Server N │
    └──────────┘    └──────────┘    └──────────┘

Development

Running Tests

# Run all unit tests
go test ./...

# Run with verbose output
go test -v ./...

# Run integration tests
go test -tags=integration ./...

# Run with coverage
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.out

Project Structure

mcp-gateway/
├── cmd/
│   └── gateway/
│       └── main.go           # Application entry point
├── internal/
│   ├── config/
│   │   ├── config.go         # Configuration loading and validation
│   │   └── config_test.go
│   ├── auth/
│   │   ├── apikey.go         # API key authentication middleware
│   │   └── apikey_test.go
│   ├── gateway/
│   │   ├── router.go         # Namespace routing
│   │   ├── router_test.go
│   │   ├── handler.go        # MCP request handler
│   │   └── handler_test.go
│   ├── db/
│   │   ├── duckdb.go         # Database layer
│   │   ├── events.go         # Event logging
│   │   └── db_test.go
│   ├── analytics/
│   │   ├── queries.go        # Analytics query service
│   │   └── queries_test.go
│   └── api/
│       ├── analytics.go      # Analytics REST API
│       └── analytics_test.go
├── testdata/                  # Test fixtures
│   ├── config_valid.yaml
│   ├── config_minimal.yaml
│   └── config_invalid_*.yaml
├── integration_test.go        # Integration tests
├── config.yaml                # Default configuration
├── go.mod
└── README.md

Error Codes

The gateway uses JSON-RPC 2.0 error codes:

Code Message
-32700 Parse error - Invalid JSON
-32600 Invalid Request - Missing authorization, access denied
-32601 Method not found
-32603 Internal error - Failed to connect to MCP server

License

MIT License

About

Centralized API gateway for Model Context Protocol (MCP) servers with auth, routing, and analytics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages