Skip to main content
Glama

mcp-proxy

하나 이상의 업스트림 MCP 서버 앞에 위치하여 주어진 프로파일이 보고 호출하도록 허용된 도구만 노출하는 강화(hardening) MCP 프록시입니다.

하나의 구성 파일로 실제 서버(GitHub, filesystem, Slack, …)와 프로파일(reviewer, implementer, ci-bot, …)을 정의합니다. 각 에이전트는 --profile <name>을 지정해 프록시의 자체 사본을 실행합니다. 또는 serve 모드에서는 단일 공유 HTTP 서버가 인증을 통해 각 연결을 프로파일에 매핑합니다. 이를 통해 해당 서버들의 필터링된, 강제된 뷰를 얻어 컨텍스트 토큰을 절약하고 위험한 도구 호출을 구조적으로 차단합니다.


왜 mcp-proxy인가?

공식 MCP 서버는 모든 에이전트에게 모든 도구를 노출합니다. 클라이언트는 tools/list를 가져와 턴마다 모든 도구의 스키마를 프롬프트에 주입하므로 컨텍스트 토큰을 소모합니다. 그리고 보이는 도구는 호출할 수 있는 도구입니다. 즉, 단단한 경계가 없습니다.

mcp-proxy는 두 문제를 동시에 해결합니다:

  • 토큰 절약 — 프로파일은 명시적으로 허용한 도구만 광고하므로 해당 스키마만 에이전트의 컨텍스트에 들어옵니다.

  • 강력한 가드레일 — 허용되지 않은 도구는 목록에 표시되지도 호출 가능하지도 않습니다. 메뉴에서 숨겨질 뿐만 아니라, 환각으로 생성된 호출도 실행 시점에 거부됩니다.


Related MCP server: Mavryn

이점

혜택

도움이 되는 방식

🔒 Fail-closed 가드레일

block이 우선합니다. 알 수 없는 도구는 기본적으로 거부됩니다. 가시성과 호출 가능성이 동기화됩니다.

📉 토큰 절약

필터링된 tools/list는 더 작은 프롬프트와 더 저렴하고 집중된 세션을 의미합니다.

👥 하나의 구성, 여러 에이전트

reviewer, implementer, CI bot은 동일한 servers 블록을 공유하지만 --profile을 통해 서로 다른 프로파일을 얻습니다.

🧩 다중 서버 집계

여러 업스트림(stdio + HTTP)을 단일 MCP 엔드포인트 뒤에 병합합니다.

🔐 비밀이 저장소에 남지 않음

${VAR} 자리 표시자 + .env; 변수가 없으면 로더가 빠르게 실패합니다.

♻️ 복원력

지수 백오프로 자동 재연결; tools/list_changed 실시간 업데이트는 다시 필터링되어 다운스트림에 전파됩니다.

🛡️ 인자 검증

tools/call 인자는 전달 전에 업스트림 inputSchema에 대해 검증됩니다.

📊 관찰 가능성

--verbose는 요청별 상관관계 ID가 있는 구조화된 JSON-lines 로그를 출력합니다. 공유 서버는 Prometheus /metrics도 노출합니다.

🌐 공유 서버 모드

serve는 여러 에이전트를 위해 하나의 Streamable HTTP 서버를 실행합니다. 연결별 인증이 토큰/헤더를 프로파일에 매핑합니다.

🏷️ 충돌 방지

서버 간에 이름이 같은 도구는 자동으로 접두사가 붙고(github__read_file), 다른 도구는 원래 이름을 유지합니다.


작동 방식

아키텍처

각 에이전트는 stdio를 통해 프록시를 자식 프로세스로 실행합니다. 프록시는 선택된 프로파일에 나열된 모든 업스트림에 연결하고, 각각의 tools/list를 가져와 프로파일의 허용/차단 규칙을 적용한 뒤, 살아남은 도구만 다시 노출합니다.

flowchart TB
    subgraph agents["🤖 Agents (MCP clients)"]
        direction LR
        A1["reviewer agent<br/><code>--profile reviewer</code>"]
        A2["implementer agent<br/><code>--profile implementer</code>"]
    end

    subgraph proxy["mcp-proxy — one stdio process per agent"]
        direction TB
        D1["stdio transport"]
        D2["tool filter<br/>(allow/block · globs + regex)"]
        D3["call-time guardrail<br/>+ argument validation"]
        D4["upstream registry<br/>(discovery · reconnect · list_changed)"]
    end

    subgraph up["Upstream MCP servers"]
        direction LR
        U1["filesystem<br/>(stdio)"]
        U2["github<br/>(HTTP)"]
        U3["slack<br/>(HTTP)"]
    end

    A1 -->|"stdin/stdout"| D1
    A2 -->|"stdin/stdout"| D1
    D1 --> D2 --> D3 --> D4
    D4 -->|"spawn"| U1
    D4 -->|"connect"| U2
    D4 -->|"connect"| U3

요청 흐름

sequenceDiagram
    autonumber
    participant A as Agent
    participant P as mcp-proxy
    participant U as Upstream MCP server

    A->>P: tools/list
    P->>U: tools/list (every upstream in profile)
    U-->>P: full tool set
    P->>P: filter + collision resolve
    P-->>A: allowed tools only

    A->>P: tools/call (allowed tool)
    P->>P: guardrail re-check<br/>+ schema validation
    P->>U: forward call
    U-->>P: result
    P-->>A: result

    A->>P: tools/call (blocked tool)
    P-->>A: ❌ rejected with error

    U-->>P: notifications/tools/list_changed
    P->>U: re-fetch tools/list
    P->>P: re-filter
    P-->>A: notifications/tools/list_changed

필터 결정

도구는 다음 우선순위 체인을 통과해야만 허용됩니다:

flowchart LR
    T["tool name"] --> B{"matches a<br/><code>block</code> pattern?"}
    B -- "yes" --> DENY["🔒 DENY"]
    B -- "no" --> A{"matches an<br/><code>allow</code> pattern?"}
    A -- "yes" --> OK["✅ ALLOW"]
    A -- "no" --> D["fallback:<br/>server <code>default</code><br/>→ profile <code>default</code><br/>→ <code>block</code>"]
    D --> F{"fallback is <code>allow</code>?"}
    F -- "yes" --> OK
    F -- "no" --> DENY

block은 항상 우선합니다. 패턴은 글롭(read_*, {get,list}_*) 또는 정규식(/.*delete.*/i)입니다. 프로파일에서 생략된 서버는 어떤 도구도 노출하지 않습니다.


예제: 세 가지 프로파일, 실측 결과

동일한 프록시를 세 가지 프로파일로 구동하고 실제 @modelcontextprotocol/server-filesystem 업스트림(도구 14개)에 대해 실행했습니다. HTTP GitHub 서버 대신 두 번째 filesystem 인스턴스를 사용하여 데모에 토큰이 필요 없게 했습니다. 서버별 필터링은 모든 업스트림에 대해 동일하게 작동합니다.

# mcp-proxy.yaml (demo)
version: 1
servers:
  filesystem:
    type: stdio
    command: npx
    args: ["-y", "@modelcontextprotocol/server-filesystem", "C:/data"]
  github:                     # HTTP in real life; filesystem stand-in in this demo
    type: http
    url: https://api.github.com/mcp
    headers: { Authorization: "${GITHUB_TOKEN}" }

profiles:
  reviewer:
    default: block
    servers:
      filesystem:
        allow: ["read_file", "list_directory", "search_files", "directory_tree", "get_file_info"]
      github:
        block: ["**"]          # GitHub fully disabled for this agent

  implementer:
    default: allow
    servers:
      filesystem:
        block: ["/.*delete.*/i", "remove_*", "edit_file", "write_file"]
      github: {}               # all GitHub tools allowed

  noTools:
    default: block
    servers:
      filesystem: { block: ["**"] }
      github: { block: ["**"] }

실시간 tools/list 핸드셰이크로 측정:

프로파일

노출된 도구

tools/list 페이로드

~토큰

reviewer

5

2,926 chars

~732

implementer

26

15,762 chars

~3,941

noTools

0

2 chars

~1

토큰은 ~4자/토큰 휴리스틱을 사용했습니다. 실제 절약은 에이전트가 매 턴 컨텍스트에 다시 로드하는 스키마 표면입니다.

각 프로파일이 실제로 받은 도구:

  • reviewer (읽기 전용, GitHub 차단됨): read_file, list_directory, directory_tree, search_files, get_file_info

  • implementer (차단 목록, GitHub 허용됨): filesystem__read_file, github__read_file, filesystem__read_text_file, github__read_text_file, filesystem__read_media_file, github__read_media_file, filesystem__read_multiple_files, github__read_multiple_files, filesystem__create_directory, github__create_directory, filesystem__list_directory, github__list_directory, filesystem__list_directory_with_sizes, github__list_directory_with_sizes, filesystem__directory_tree, github__directory_tree, filesystem__move_file, github__move_file, filesystem__search_files, github__search_files, filesystem__get_file_info, github__get_file_info, filesystem__list_allowed_directories, github__list_allowed_directories, write_file, edit_file

  • noTools (모두 차단됨): (없음)

주목할 만한 두 가지 세부 사항:

  • 충돌 자동 접두사read_file는 두 서버 모두에 존재하므로 filesystem__read_filegithub__read_file이 됩니다. 그러나 write_file/edit_filefilesystem에서 차단되어 github만이 유일한 소스가 되므로 원래 이름을 유지합니다.

  • 빈 프로파일 뷰도 유효합니다noTools(또는 block: ["**"]이 있는 프로파일, 또는 서버가 생략된 경우)는 0개의 도구를 노출합니다. 에이전트는 여전히 연결되지만 호출할 도구가 없을 뿐입니다.


빠른 시작

1. 설치 및 빌드

npm install
npm run build          # compiles TypeScript to dist/

2. 비밀을 .env에 넣으세요(구성 파일에는 절대 넣지 마세요)

cp .env.example .env   # then fill in your tokens

3. mcp-proxy.yaml 작성

version: 1

servers:
  filesystem:
    type: stdio
    command: npx
    args: ["-y", "@modelcontextprotocol/server-filesystem", "C:/repo"]
    env:
      ROOT: "C:/repo"

  github:
    type: http
    url: https://api.github.com/mcp
    headers:
      Authorization: "${GITHUB_TOKEN}"   # env-var reference, not a literal secret

profiles:
  reviewer:                 # read-only, fail-closed
    description: "Read-only agent"
    default: block
    servers:
      filesystem:
        allow: ["read_file", "list_directory", "directory_tree", "get_file_info"]
      github:
        allow: ["get_*", "list_*", "search_*"]

  implementer:              # deny-list, fail-open minus dangerous ops
    description: "Full access minus destructive ops"
    default: allow
    servers:
      filesystem:
        block: ["/.*delete.*/i", "edit_file", "write_file"]
      github:
        block: ["merge_pull_request", "delete_*"]

defaultProfile: reviewer

4. 실행

node dist/cli/index.js --profile reviewer
# add --verbose for structured debug logging
node dist/cli/index.js --profile reviewer --verbose

프로파일 우선순위: --profile > MCP_PROFILE > defaultProfile.


구성 참조

servers — 업스트림 MCP 서버

stdio(자식 프로세스로 실행):

filesystem:
  type: stdio
  command: npx
  args: ["-y", "@modelcontextprotocol/server-filesystem", "C:/repo"]
  env: { ROOT: "C:/repo" }
  prefix: fs__          # optional: override collision-prefix namespace

http(Streamable HTTP):

github:
  type: http
  url: https://api.github.com/mcp
  headers:
    Authorization: "${GITHUB_TOKEN}"
  prefix: gh__          # optional

profiles — 명명된 도구 뷰

profiles:
  my-profile:
    description: "..."           # optional
    default: allow               # allow | block (fallback when no rule matches)
    servers:
      github:
        allow: ["get_*"]         # optional allow-list
        block: ["delete_*"]      # optional block-list (always wins)
        default: block           # optional per-server fallback override
      # filesystem omitted → none of its tools are exposed

http — Streamable HTTP 다운스트림(serve 모드)

선택적 최상위 블록으로, 프록시를 하나의 프로세스에서 여러 에이전트를 제공하는 공유 HTTP 서버로 전환합니다. 공유 서버(HTTP)를 참조하세요.

http:
  host: 0.0.0.0             # default 127.0.0.1
  port: 3000                # default 3000
  path: /mcp                # MCP endpoint (default /mcp)
  metricsPath: /metrics     # Prometheus metrics (default /metrics)
  healthPath: /health       # liveness (default /health)
  readyPath: /ready         # readiness (default /ready)
  auth:
    header: authorization   # selector header (default authorization)
    scheme: Bearer          # optional prefix to strip
    tokens:                 # token -> profile map (values may use ${VAR})
      tok-reviewer: reviewer
      tok-impl: implementer
    defaultProfile: reviewer # optional fallback (fail-closed without it)

tokens가 설정되면 스킴이 제거된 헤더 값이 맵에서 조회됩니다. tokens가 없으면 제거된 헤더 값이 프로파일 이름으로 직접 사용됩니다. 누락되었거나 알 수 없는 셀렉터는 defaultProfile로 폴백되며, 적용할 프로파일이 없으면 거부됩니다(401/403).

비밀

${VAR} 자리 표시자는 로드 시 환경(또는 .env)에서 해석됩니다. YAML에는 변수 이름만 들어 있으므로 커밋해도 안전합니다. 변수가 없으면 로더는 **즉시 실패(fail fast)**합니다 — 조용히 빈 헤더가 생성되지 않습니다.


에이전트에 연결하기

프록시는 stdio를 통한 MCP 서버 그 자체입니다. 실제 서버 대신 프록시 진입점을 에이전트에 지정하고 프로파일 플래그를 전달하세요.

// .mcp.json — reviewer agent
{
  "mcpServers": {
    "proxy": {
      "command": "node",
      "args": ["C:/Dev/mcp-proxy/dist/cli/index.js", "--profile", "reviewer"]
    }
  }
}
// .mcp.json — implementer agent (same proxy, different profile)
{
  "mcpServers": {
    "proxy": {
      "command": "node",
      "args": ["C:/Dev/mcp-proxy/dist/cli/index.js", "--profile", "implementer"]
    }
  }
}

각 에이전트는 자체 stdio 프로세스를 가지므로 프로파일은 에이전트별로 완전히 격리되고 자격 증명은 결코 프로세스 경계를 넘지 않습니다.

공유 서버(HTTP)

중앙 배포의 경우 serve를 실행하여 여러 에이전트가 공유하는 하나의 Streamable HTTP 서버를 노출하세요. 각 연결은 인증 헤더에서 프로파일로 매핑됩니다:

node dist/cli/index.js serve --config mcp-proxy.yaml
# options: --host, --port (override http.host/http.port)

엔드포인트:

경로

용도

/mcp

Streamable HTTP MCP 엔드포인트(연결당 세션)

/health

Liveness — 프로세스가 구동되면 항상 200

/ready

Readiness — 모든 프로파일의 업스트림이 연결된 경우에만 200

/metrics

Prometheus 텍스트 메트릭(도구 나열/호출/차단, 지연 시간, 업스트림 상태)

연결별 프로파일 해석은 fail-closed 방식입니다. http.auth.defaultProfile이 설정되지 않은 한 사용 가능한 셀렉터가 없는 연결은 거부되고(401), 알 수 없는 프로파일로 매핑되는 셀렉터는 거부됩니다(403).

공유 배포를 위한 클라이언트 구성(Streamable HTTP를 지원하는 모든 클라이언트):

// .mcp.json — reviewer agent (token maps to the `reviewer` profile)
{
  "mcpServers": {
    "proxy": {
      "type": "http",
      "url": "https://proxy.example.com/mcp",
      "headers": { "Authorization": "Bearer ${PROXY_TOKEN}" }
    }
  }
}
// .mcp.json — implementer agent (same server, different token/profile)
{
  "mcpServers": {
    "proxy": {
      "type": "http",
      "url": "https://proxy.example.com/mcp",
      "headers": { "Authorization": "Bearer ${PROXY_TOKEN_IMPL}" }
    }
  }
}

Copilot 코딩 에이전트는 저장소의 .mcp.json을 읽습니다. 다른 에이전트의 경우 고유한 MCP 서버 필드를 사용하세요(context/AGENT-SETUP.mdcontext/VENDOR-AGENTS.md 참조).


관찰 가능성

--verbose와 함께 실행하면 구조화된 JSON-lines 로그가 stderr로 출력됩니다(stdout의 MCP stdio 채널은 깨끗하게 유지됨):

{"timestamp":"2026-08-23T17:22:26.976Z","level":"info","message":"connected to upstream","server":"filesystem","tools":14}
{"timestamp":"2026-08-23T17:22:26.980Z","level":"debug","message":"tools/call","correlationId":"42","tool":"read_file","server":"filesystem"}

모든 tools/listtools/call 항목에는 MCP 요청의 correlationId가 포함되어, 단일 요청을 프록시와 해당 업스트림에 걸쳐 추적할 수 있습니다.

프로파일의 컨텍스트 비용을 확인하려면 프로파일 간에 도구 수와 tools/list 페이로드 크기를 비교하세요(위의 실측 예제 참조). 광고되는 도구가 적을수록 매 턴 프롬프트에 주입되는 스키마가 줄어듭니다.

serve 모드에서는 /metrics를 스크레이핑하여 Prometheus 카운터, 게이지, 히스토그램을 수집하세요: mcp_proxy_tools_listed_total, mcp_proxy_tools_called_total, mcp_proxy_tools_blocked_total, mcp_proxy_tool_call_duration_seconds, mcp_proxy_upstream_connections(모두 profile/server/tool 라벨로 구분됨).


복원력

  • 자동 재연결 — 업스트림(특히 생성된 stdio 프로세스)이 중단되면 프록시는 지수 백오프(500ms → 15초 상한, 무제한 재시도)로 재연결합니다.

  • 실시간 도구 업데이트 — 업스트림이 notifications/tools/list_changed를 보내면 프록시는 변경 사항을 다시 가져오고, 다시 필터링하여 다운스트림으로 전달하므로 에이전트는 항상 정확한 도구 목록을 볼 수 있습니다.

  • 인자 검증tools/call 인자는 전달 전에 업스트림의 inputSchema에 대해 검사됩니다. 유효하지 않은 호출은 로컬에서 거부됩니다.


개발

npm run typecheck    # tsc --noEmit
npm test             # vitest (unit + integration + filesystem smoke)
npm run build        # tsc → dist/

더 보기

Maintenance

ActivityMaintained
ResponsivenessSyncing

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    B
    maintenance
    Self-hosted MCP proxy and aggregation platform. Register multiple upstream MCP servers and expose them through a single unified endpoint with namespace routing, multi-transport support (HTTP/SSE, stdio, OpenAPI→MCP), per-tool overrides, and a web admin UI.
    16
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Centralized MCP control plane that proxies multiple upstream MCP servers with tool namespacing, filtering, policy enforcement, audit logging, and health checks.
    16
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    An authorizing reverse proxy for MCP servers that enforces per-call policy rules on tool arguments with audit logging, dry-run, and rate limiting.
    Apache 2.0
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables serving multiple MCP toolkits behind one server with capability-based access control, so different callers see and can call only the tools they are authorized for, over stdio or streamable HTTP with bearer-token auth.
    MIT

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/DawidNowak/mcp-proxy'

If you have feedback or need assistance with the MCP directory API, please join our Discord server