들어가며
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 의 도구들이 노출되어 호출 가능.
문제 상황
작업 중 마주친 주요 증상 다섯 가지.
- https://gateway.example.com/agentgateway/mcp 호출 시 route not found.
- 도메인은 도는데 mcp: client must accept both application/json and text/event-stream.
- backend 추가 후 게이트웨이 UI 에 "도구 21개" 라고 뜨는데 개별 도구가 LangFlow 의 MCP Tools 리스트에 안 보임.
- agent 에서 도구 호출 시 MCP error -32601: Tool simulate-research-query requires task augmentation (taskSupport: 'required').
- 같은 도구를 한 번 호출했는데 동일 응답이 두 번씩 출력 되는 현상.
각각의 원인이 다 다르다. 하나씩 좁혀가야 한다.
시도한 것들
시도 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중 매핑이다.
- 외부 ingress 가 /agentgateway/* 를 게이트웨이 서비스로 흘림 (ingress controller 설정).
- gateway listener 가 :3000 에서 받는다.
- 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 버그. 회피책:
- 새 backend 등록 후 다른 MCP server 를 한 번 클릭했다가 돌아온다.
- 또는 새로고침 두 번 (한 번은 미스, 두 번째에 정상 로딩되는 케이스가 있다).
- 그래도 안 되면 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 — 중복 응답 문제
같은 도구 호출이 두 번씩 응답하는 현상. 디버깅 단계는:
- 게이트웨이 로그를 켜고 tools/call 요청이 몇 번 들어오는지 본다 → 1번.
- backend MCP server 로 forward 되는 횟수 → 1번.
- 그런데 응답이 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 에서 실제 도구 호출 → 응답 단일 (중복 없음) 확인
디버깅 체크리스트 (같은 문제 다시 만났을 때)
- curl + Accept 로 게이트웨이 자체를 먼저 검증. 브라우저 GET 으로 판단 금지.
- route not found 가 떠도 ingress 가 도는지 / listener 가 떠 있는지 / route 가 등록 됐는지를 분리해서 확인.
- LangFlow MCP URL 은 project UUID 단위. project 가 여러 개면 어떤 UUID 인지부터 확인.
- "도구 N개" 라고만 뜨고 개별이 안 보이면 UI 캐싱 의심. 다른 server 클릭했다 돌아오거나 새로고침 2회.
- 중복 응답이 보이면 flow 안에 합성 노드가 있는지 확인. 게이트웨이는 passthrough 가 default.
- 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 모니터링 (어떤 도구가 가장 많이 호출되는지) 셋업.
참고
- MCP spec - streamable HTTP transport: https://spec.modelcontextprotocol.io/specification/
- agentgateway 프로젝트: https://github.com/agentgateway/agentgateway
- LangFlow MCP integration 문서: https://docs.langflow.org/mcp-server
- MCP Inspector (디버깅 도구): https://github.com/modelcontextprotocol/inspector