MCP工具代理服务

mcp-anything 是一个无状态代理服务,可将 REST API、Shell 命令和 JavaScript 脚本转换为 MCP 工具,并支持通过 YAML 配置快速接入 MCP 客户端。

  • by gaarutyunov
  • Go
  • 本地部署
  • 3 星标
  • 更新于
在 GitHub 查看 gaarutyunov/mcp-anything

使用说明

mcp-anything

A stateless Go proxy that turns anything — REST APIs, shell commands, JavaScript scripts — into MCP tools. No code, no plugins — just config.

Features

  • OpenAPI → MCP tools — auto-generates tools from OpenAPI 3.0 specs with input schemas, jq transforms, and dry-run validation
  • Shell commands — expose kubectl, aws, or any CLI as MCP tools with template argument interpolation
  • JavaScript scripts — custom tool logic in a sandboxed Sobek runtime
  • Multi-upstream routing — proxy multiple backends from a single instance with prefix-based namespacing
  • Pluggable auth — JWT, OAuth2 Client Credentials, API key, token introspection, Lua, JavaScript (inbound + outbound)
  • OpenAPI Overlays — RFC 9535 JSONPath to customize tools without touching the original spec
  • Tool groups — multiple MCP endpoints with JSONPath filters (read-only, premium, admin, etc.)
  • Config hot-reload — fsnotify-based, Kubernetes ConfigMap-aware, zero downtime
  • Background spec refresh — periodic re-fetch with ETag/conditional GET and atomic swaps
  • OpenTelemetry — OTLP traces, Prometheus metrics, W3C Trace Context propagation
  • Kubernetes operator — MCPProxy and MCPUpstream CRDs with annotation-based auto-discovery
  • Library-first SDK — embed as a Go library and register custom tool providers
  • Gateway transport — connection pooling, mTLS, HTTP/2, TLS session caching

Quick start

Install

go install github.com/gaarutyunov/mcp-anything/cmd/proxy@latest

Or run with Docker

docker run -v $(pwd)/config.yaml:/etc/mcp-anything/config.yaml \
  ghcr.io/gaarutyunov/mcp-anything:latest

Connect to Kraken Market Data

The Kraken cryptocurrency exchange exposes a public REST API — no API key required. Download the example config files and start the proxy in three commands:

# 1. Download config, OpenAPI spec, and overlay
mkdir -p kraken && cd kraken
curl -sLO https://raw.githubusercontent.com/gaarutyunov/mcp-anything/main/examples/kraken/config.yaml
curl -sLO https://raw.githubusercontent.com/gaarutyunov/mcp-anything/main/examples/kraken/spec.yaml
curl -sLO https://raw.githubusercontent.com/gaarutyunov/mcp-anything/main/examples/kraken/overlay.yaml

# 2. Install and run
go install github.com/gaarutyunov/mcp-anything/cmd/proxy@latest
CONFIG_PATH=config.yaml proxy

Or with Docker:

docker run -p 8080:8080 \
  -v $(pwd):/etc/mcp-anything \
  -w /etc/mcp-anything \
  ghcr.io/gaarutyunov/mcp-anything:latest

Connect any MCP client to http://localhost:8080/mcp. Five tools are now available:

Tool Description
kraken__get_system_status Exchange status and server time
kraken__get_ticker Real-time ask/bid/last price for any pair (e.g. XBTUSD)
kraken__get_ohlc OHLC candlestick data at any interval
kraken__get_order_book Live order book with top 5 bid/ask levels
kraken__get_recent_trades Most recent 10 public trades

The overlay in examples/kraken/overlay.yaml applies jq transforms that flatten Kraken's nested response format into clean named fields — no client-side parsing required.

Use with Claude Code

CONFIG_PATH=config.yaml proxy &
claude mcp add --transport http kraken http://localhost:8080/mcp

Claude can now call Kraken tools directly — ask it to check Bitcoin prices, pull OHLC data, or read the order book.

Configuration

A single YAML file defines everything. Environment variables are expanded with ${VAR} syntax.

server:
  port: 8080
  read_timeout: 30s
  write_timeout: 60s
  transport:
    - streamable-http
    - sse

upstreams:
  # HTTP upstream backed by an OpenAPI spec
  - name: kraken
    type: http
    tool_prefix: kraken
    base_url: https://api.kraken.com
    openapi:
      source: examples/kraken/spec.yaml
      refresh_interval: 5m
    overlay:
      source: examples/kraken/overlay.yaml

  # Shell command upstream — wraps any CLI tool
  - name: cluster
    type: command
    tool_prefix: k8s
    tools:
      - name: get_pods
        description: List pods in a namespace
        command: kubectl get pods -n {{namespace}} -o json
        args:
          namespace:
            type: string
            required: true
        timeout: 30s

  # JavaScript script upstream — custom logic in Sobek runtime
  - name: custom
    type: script
    tool_prefix: ops
    tools:
      - name: health_check
        description: Check service health
        source: scripts/health_check.js
        args:
          service:
            type: string
        timeout: 10s

# Serve different tool sets at different endpoints
groups:
  - name: all
    endpoint: /mcp
    upstreams: [kraken, cluster, custom]

  - name: market
    endpoint: /mcp/market
    upstreams: [kraken]
    filter: "$.paths[?(@['x-mcp-safe'] == true)]"

See examples/ for complete examples including Kubernetes CRDs and Helm values.

Where settings come from

Configuration is loaded by goga/config, which merges its sources in one fixed order — defaults → YAML file → environment — with later sources winning. mcp-anything defines no command-line flags, so the environment has the last word.

CONFIG_PATH selects the file (default /etc/mcp-anything/config.yaml). It keeps its bare name because it decides which file is read, and so cannot itself come from that file.

Every other setting can be overridden by an environment variable named from its key path: the MCP_ANYTHING prefix, __ between path segments, and _ as a literal underscore inside a segment.

Variable Key it sets
MCP_ANYTHING__SERVER__PORT server.port
MCP_ANYTHING__NAMING__MAX_LENGTH naming.max_length
MCP_ANYTHING__TELEMETRY__OTLP_ENDPOINT telemetry.otlp_endpoint

This is a different mechanism from the ${VAR} expansion above: ${VAR} substitutes a value inside the YAML, while MCP_ANYTHING__… replaces a key's value outright, and does so again on every hot reload.

OpenAPI Overlays

Customize how operations are exposed as MCP tools without modifying the original spec. The Kraken overlay shows realistic use:

overlay: 1.0.0
info:
  title: Kraken Market Data Overlay
  version: 1.0.0
x-speakeasy-jsonpath: rfc9535

actions:
  # Override tool name and flatten Kraken's nested result wrapper with jq
  - target: "$.paths[\"/0/public/Ticker\"].get"
    update:
      x-mcp-tool-name: get_ticker
      description: >
        Get current ticker information for a trading pair (e.g. XBTUSD, ETHUSD).
        Returns ask, bid, last price, 24h volume, VWAP, high, low, and trade count.
      x-mcp-response-transform: >
        .result | to_entries[0] | {
          pair: .key,
          ask: .value.a[0],
          bid: .value.b[0],
          lastPrice: .value.c[0],
          volume24h: .value.v[1],
          vwap24h: .value.p[1],
          high24h: .value.h[1],
          low24h: .value.l[1],
          trades24h: .value.t[1],
          openingPrice: .value.o
        }

  # Limit order book depth to top 5 levels
  - target: "$.paths[\"/0/public/Depth\"].get"
    update:
      x-mcp-tool-name: get_order_book
      x-mcp-response-transform: >
        .result | to_entries[0] | {
          pair: .key,
          asks: .value.asks[:5],
          bids: .value.bids[:5]
        }

x-mcp extensions

Extension Type Default Purpose
x-mcp-enabled bool true Exclude operation from tool generation
x-mcp-tool-name string derived Override generated tool name
x-mcp-auth-required bool true Per-operation auth bypass
x-mcp-safe bool false Mark as read-only (for group filters)
x-mcp-response-format string json json | text | image | audio | binary | auto
x-mcp-request-transform string generated Custom jq request expression
x-mcp-response-transform string . Custom jq response expression
x-mcp-error-transform string default Custom jq error handler
x-mcp-tier string — Arbitrary label for group filters

Authentication

Inbound (MCP clients → proxy)

Strategy Description
jwt OIDC JWT validation with JWKS auto-rotation
introspection Token introspection via OIDC discovery endpoint
apikey Static API key from a custom header
lua Custom validation logic in Lua
none No authentication

Outbound (proxy → upstream APIs)

Strategy Description
bearer Static Bearer token from environment variable
oauth2_client_credentials OAuth2 CC flow with automatic token caching and refresh
api_key API key header injection
lua Custom token acquisition logic in Lua

Per-upstream overrides and per-operation bypass (x-mcp-auth-required: false) are supported.

Architecture

MCP Client ──→ mcp-anything proxy ──→ HTTP API (OpenAPI)
               (single binary)    ──→ Shell command
                                  ──→ JavaScript script

The proxy is a single stateless binary. On startup it loads the config, fetches OpenAPI specs, applies overlays, generates MCP tools, compiles jq transforms, and validates everything with dry-run. At runtime it handles the MCP protocol, routes tool calls to the right upstream, manages auth, and validates requests and responses.

Key design properties:

  • Stateless — no shared mutable state; each request is self-contained
  • Atomic hot-reload — config changes don't drop in-flight requests
  • Overlay-as-configuration — all per-operation behavior via OpenAPI Overlay extensions
  • Uniform pipeline — auto-generated and manual tools use identical code paths
  • Double-underscore namespacing — tool names follow {prefix}__{operation} convention

Deployment

Docker

docker run -p 8080:8080 \
  -v $(pwd)/config.yaml:/etc/mcp-anything/config.yaml \
  ghcr.io/gaarutyunov/mcp-anything:latest

Kubernetes

The proxy is designed for Kubernetes. Mount config, specs, and overlays as separate ConfigMaps for independent update cycles:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mcp-anything
spec:
  replicas: 1
  template:
    spec:
      containers:
        - name: proxy
          image: ghcr.io/gaarutyunov/mcp-anything:latest
          ports:
            - containerPort: 8080
          volumeMounts:
            - name: config
              mountPath: /etc/mcp-anything
      volumes:
        - name: config
          configMap:
            name: mcp-anything-config

Use the MCPProxy and MCPUpstream CRDs with the included Helm chart for production deployments. See examples/kraken/ for a complete Kubernetes example including CRD manifests and Helm values.

Development

Requirements: Go 1.25+, Docker (for integration tests)

make check        # lint + vet + unit tests + build
make integration  # integration tests (Docker + Testcontainers)

Design

See SPEC.md for the full architecture document covering all design decisions, configuration model, and acceptance criteria.

License

Apache License 2.0