카테고리 없음

agentgateway 에 Langflow MCP 등록하기 – route not found, accept header, 도구 21개 헤맨 회고

임마누엘한 2026. 5. 14. 15:43

들어가며

LangFlow 에서 만든 MCP (Model Context Protocol) 서버를 agentgateway 라는 MCP 게이트웨이를 통해 노출하고, 그 게이트웨이를 다른 LLM 클라이언트(다른 LangFlow flow, 사내 챗 포털 등)에서 backend 로 등록해서 쓰려고 했다. 그림은 단순하다.

LLM Client ── MCP ──> agentgateway ── MCP ──> LangFlow MCP server (도구 21개)
                                   └────────> 다른 MCP 서버 (mcpbin 등)

실제 작업은 단순하지 않았다. route not found, client must accept both application/json and text/event-stream, Tool requires task augmentation, 그리고 도구 카운트는 21이지만 개별 도구가 안 보이는 현상까지, 한 세션 안에서 줄줄이 만났다. 다른 분들이 같은 함정에 빠지지 않도록 디테일하게 정리한다.

핵심 키워드: agentgateway, MCP server, mcp-proxy, streamableHTTP, MCP Inspector, route not found.

시스템 컨텍스트

  • MCP = Anthropic 이 주도하는 LLM ↔ tool 간 표준 프로토콜. JSON-RPC 위에서 도구 목록·도구 호출·리소스 가져오기 등을 정의.
  • agentgateway = MCP 트래픽 전용 게이트웨이/프록시. 여러 MCP backend 를 하나의 endpoint 아래로 묶고, path-prefix 라우팅·인증·rate limit 등을 적용.
  • LangFlow = flow 단위로 묶인 도구를 자체적으로 MCP server 처럼 노출할 수 있다. project UUID 단위로 endpoint 가 갈린다.
  • 목표: agentgateway 의 한 path 에 LangFlow MCP 를 backend 로 등록 → 외부에서 https://gateway.example.com/agentgateway/mcp 로 접근 → LangFlow 의 도구들이 노출되어 호출 가능.

문제 상황

작업 중 마주친 주요 증상 다섯 가지.

  1. https://gateway.example.com/agentgateway/mcp 호출 시 route not found.
  2. 도메인은 도는데 mcp: client must accept both application/json and text/event-stream.
  3. backend 추가 후 게이트웨이 UI 에 "도구 21개" 라고 뜨는데 개별 도구가 LangFlow 의 MCP Tools 리스트에 안 보임.
  4. agent 에서 도구 호출 시 MCP error -32601: Tool simulate-research-query requires task augmentation (taskSupport: 'required').
  5. 같은 도구를 한 번 호출했는데 동일 응답이 두 번씩 출력 되는 현상.

각각의 원인이 다 다르다. 하나씩 좁혀가야 한다.

시도한 것들

시도 1 — Path 잘못 잡음 (route not found)

처음에 외부 URL 을 https://gateway.example.com/agentgateway/mcp 로 쳤는데 route not found 가 떴다. 처음엔 게이트웨이가 안 떠 있는 줄 알았지만 /agentgateway/ui/ 는 멀쩡히 응답. listener 는 떠 있는데 그 path 에 route 가 안 잡혀 있는 상황.

agentgateway 의 URL 모델을 잠시 정리:

[ ingress ] ── /agentgateway/* ──> [ gateway listener :3000 ]
                                          │
                                          ├── route prefix /agentgateway/mcp ──> backend A
                                          ├── route prefix /agentgateway/ui  ──> built-in UI
                                          └── (그 외 path)                    ──> 404 또는 root

즉 path 가 3중 매핑이다.

  1. 외부 ingress  /agentgateway/* 를 게이트웨이 서비스로 흘림 (ingress controller 설정).
  2. gateway listener 가 :3000 에서 받는다.
  3. route 가 path prefix 로 backend 를 매칭한다 (/agentgateway/mcp → backend A).

처음에는 route 가 아예 등록 안 되어 있었다. UI 에서 backend 만 추가하고 route 를 안 연결한 상태. 해결: UI 의 Routes 탭에서 pathPrefix: /agentgateway/mcp 의 route 를 명시적으로 추가하고 backend 와 wire.

시도 2 — Accept 헤더 누락 (브라우저 GET 의 함정)

route 를 잡고 나니 다른 에러로 갈아탔다.

mcp: client must accept both application/json and text/event-stream

이 메시지가 뜨는 건 사실 정상 동작 이다. MCP streamable HTTP transport 는 두 콘텐츠 타입을 동시에 요구한다. 브라우저로 그냥 GET 하면 Accept: text/html,... 가 가서 거절된다.

검증은 curl 로:

curl -X POST https://gateway.example.com/agentgateway/mcp \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

이 요청에서 도구 리스트가 떨어지면 게이트웨이는 정상.

이 단계에서 "왜 안되지" 라고 브라우저로 새로고침만 반복하다가 30분을 날린 적이 있다. MCP endpoint 디버깅의 1번 도구는 항상 curl + Accept 헤더.

시도 3 — LangFlow MCP endpoint 의 정확한 모양

LangFlow 는 project 단위로 MCP endpoint 를 자동 생성한다.

http://<langflow-host>:7860/api/v1/mcp/project/<PROJECT_UUID>/streamable

agentgateway 의 backend target 에 이걸 그대로 넣어야 도구가 노출된다. 작업 중 두 개의 프로젝트 UUID 가 섞여서 한참 디버깅 했다.

project-A 의 UUID: 0e976add-b22c-...    ← 이 프로젝트에 도구가 가득
project-B 의 UUID: c8428d40-a404-...    ← 빈 프로젝트

agentgateway 에 B 의 UUID 를 넣고는 "도구가 0개네?" 라고 한참 헤맸다. project 가 여러 개일 때는 LangFlow UI 의 MCP Servers 탭에서 어떤 UUID 가 어떤 project 에 매핑되는지 먼저 확인할 것.

시도 4 — 도구 카운트는 21인데 개별 도구가 안 보임

LangFlow 의 MCP Tools 등록 화면에서 게이트웨이 URL 을 backend 로 추가했을 때, "도구 21개" 라고 뜨지만 개별 도구가 리스트로 안 펼쳐지는 경우. 새로고침하면 사라졌다가 다른 MCP server (예: langflow-starter_basic_prompting) 를 클릭하면 다시 등장.

이건 LangFlow MCP Tools 화면의 캐싱 이슈에 가까운 UI 버그. 회피책:

  1. 새 backend 등록 후 다른 MCP server 를 한 번 클릭했다가 돌아온다.
  2. 또는 새로고침 두 번 (한 번은 미스, 두 번째에 정상 로딩되는 케이스가 있다).
  3. 그래도 안 되면 LangFlow 의 backend 관리 페이지에서 해당 entry 를 지웠다 다시 추가.

근본 해결책은 LangFlow 가 MCP Inspector 처럼 lazy load → eager load 로 바꿔야 하지만, 일단 운영 회피책으로 충분.

시도 5 — taskSupport: required 에러

MCP error -32601: Tool simulate-research-query 
  requires task augmentation (taskSupport: 'required')

이건 MCP server (여기서는 LangFlow) 가 해당 도구를 "task" 컨텍스트 안에서만 호출 가능하다고 선언했는데, 클라이언트가 그 컨텍스트를 안 만들어준 경우. MCP 스펙의 advanced 기능 중 하나로, 보통은 long-running task 를 진행률과 함께 호출할 때 쓴다.

세 가지 대응:

  • (a) 클라이언트 측에서 task 컨텍스트를 만들어서 호출 (구현 복잡).
  • (b) 게이트웨이의 Authorization 으로 해당 도구만 차단 (다음 날 포스트 주제).
  • (c) MCP server 측에서 해당 도구의 taskSupport  optional 로 바꿔 expose.

PoC 에서는 (b) 로 빠르게 차단하고, 운영용은 (c) 로 picking.

시도 6 — 중복 응답 문제

같은 도구 호출이 두 번씩 응답하는 현상. 디버깅 단계는:

  1. 게이트웨이 로그를 켜고 tools/call 요청이 몇 번 들어오는지 본다 → 1번.
  2. backend MCP server 로 forward 되는 횟수 → 1번.
  3. 그런데 응답이 2개로 클라이언트에 도착.

원인: LangFlow 의 flow 가 자체적으로 tool 호출 결과를 다시 LLM 으로 합성 하면서 한 번, MCP envelope 응답으로 한 번 보내는 케이스. flow 안에 "tool 결과 → LLM agent → 사용자" 가 있고, 그 LLM agent 가 또 사용자에게 응답하는 구조면 중복으로 보인다.

해결: flow 에서 합성 노드를 빼거나, agentgateway 에서 backend 응답을 그대로 passthrough 하도록 정리. 게이트웨이는 passthrough 가 default 여야 깔끔하다.

해결 — 최종 동작 구성

# agentgateway 라우팅 의사 코드
listener:
  port: 3000
  routes:
    - name: langflow-mcp
      pathPrefix: /agentgateway/mcp
      backend:
        type: mcp
        upstream: http://langflow:7860/api/v1/mcp/project/0e976add-b22c-.../streamable
        transport: streamable-http
    - name: ui
      pathPrefix: /agentgateway/ui
      backend: builtin-ui
    - name: fallback
      pathPrefix: /
      response: 404

외부 ingress 가 /agentgateway/* 를 게이트웨이로 흘리도록 설정 후, 클라이언트는 https://gateway.example.com/agentgateway/mcp 를 MCP server URL 로 등록.

검증 절차

# 1. tools/list 가 떨어지는지
curl -sS -X POST https://gateway.example.com/agentgateway/mcp \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | jq '.result.tools | length'
# 21 이 나오면 OK

# 2. 특정 도구 호출
curl -sS -X POST https://gateway.example.com/agentgateway/mcp \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{
    "jsonrpc":"2.0","id":2,"method":"tools/call",
    "params":{"name":"search","arguments":{"query":"hello"}}
  }' | jq '.result'

# 3. LangFlow 측 MCP Tools 화면에서 도구 21개가 펼쳐서 보이는지
# 4. agent flow 에서 실제 도구 호출 → 응답 단일 (중복 없음) 확인

디버깅 체크리스트 (같은 문제 다시 만났을 때)

  1. curl + Accept 로 게이트웨이 자체를 먼저 검증. 브라우저 GET 으로 판단 금지.
  2. route not found 가 떠도 ingress 가 도는지 / listener 가 떠 있는지 / route 가 등록 됐는지를 분리해서 확인.
  3. LangFlow MCP URL 은 project UUID 단위. project 가 여러 개면 어떤 UUID 인지부터 확인.
  4. "도구 N개" 라고만 뜨고 개별이 안 보이면 UI 캐싱 의심. 다른 server 클릭했다 돌아오거나 새로고침 2회.
  5. 중복 응답이 보이면 flow 안에 합성 노드가 있는지 확인. 게이트웨이는 passthrough 가 default.
  6. taskSupport: required 는 클라이언트가 task 컨텍스트 안 만든 경우. 운영용은 server 측 optional 또는 게이트웨이 deny.

배운 점

  • MCP streamable HTTP 디버깅의 1번 도구는 curl + Accept 헤더. 브라우저 GET 은 항상 client-error 처럼 보여서 헷갈린다.
  • agentgateway 의 내부/외부 URL 을 분리해서 표로 그려두자. ingress path / listener port / route prefix / backend URL 네 개를 한 문서에 정리해두면 디버깅 시간이 절반으로 줄어든다.
  • LangFlow MCP endpoint 는 project UUID 단위. 도구가 0개면 UUID 부터 의심.
  • 게이트웨이는 passthrough 가 default 여야 깔끔하다. 중복 응답이 보이면 backend 측이 자체 합성을 하는지부터 의심.
  • taskSupport: required 같은 advanced 기능은 클라이언트 구현이 따라줘야 한다. PoC 단계에서 막히면 일단 deny 로 차단하고, 운영에서 spec 매칭.

다음 단계

  • MCP Authorization 으로 특정 도구만 차단 (다음 날 포스트 주제). taskSupport: required 같은 운영 부적합 도구 일괄 deny.
  • 여러 MCP backend 를 path-prefix 로 멀티플렉싱 해서 tenant 별로 갈라 노출.
  • 게이트웨이의 traffic 모니터링 (어떤 도구가 가장 많이 호출되는지) 셋업.

참고