ReAct Agent + MCP Code Execution - LangChain 기반 MCP 도구 테스트 Web UI
📋 MCP-UI 시연 가이드: DEMO.md — 시연 순서, 멘트, 트러블슈팅 정리
Anthropic의 Code Execution with MCP 패턴을 LangGraph ReAct Agent로 구현한 시스템입니다. MCP 서버 URL을 입력하면 도구를 자동으로 탐색하고, LLM이 Python 코드를 생성하여 실행합니다.
사용자 질문
|
v
+------------------------------------------+
| LangGraph ReAct Agent |
| |
| 1. Thought: 어떤 MCP 도구를 쓸지 판단 |
| 2. Action: Python 코드 생성 |
| 3. Observation: 코드 실행 결과 확인 |
| 4. (반복 또는 최종 답변) |
+------------------------------------------+
|
v
+------------------------------------------+
| MCPCodeExecutionTool._run() |
| |
| exec(code, {mcp_call: ...}) |
| - mcp_call(url, tool_name, args) |
| - stdout/stderr 캡처 |
+------------------------------------------+
|
v
+------------------------------------------+
| HTTP MCP Client |
| - Streamable HTTP (/mcp) |
| - SSE (/sse, deprecated) |
+------------------------------------------+
기존 tool calling 방식과 달리, LLM이 직접 코드를 생성하여 실행합니다.
mcp_call(url, tool_name, arguments) 함수가 실행 환경에 주입되어
LLM이 자유롭게 MCP 도구를 호출할 수 있습니다.
uv venv
uv synccp .env.example .env
# .env 파일에 API 키 설정OPENAI_API_KEY=sk-your-api-key
OPENAI_BASE_URL=https://openrouter.ai/api/v1 # OpenRouter 사용 시
LLM_MODEL=gpt-4o-mini # 모델 선택# Web UI (포트 8080)
uv run python web_ui.py
# 로컬 테스트 MCP 서버 (포트 8000, 별도 터미널)
uv run python tests/test_mcp_server.py브라우저에서 http://localhost:8080 접속
- MCP URL 입력: 여러 MCP 서버 URL 추가/삭제, 프리셋 버튼
- 도구 자동 탐색: URL 입력 시 서버의 도구 목록 자동 조회
- ReAct 과정 표시: Thought / Action (코드) / Observation 단계별 실시간 표시
- SSE 스트리밍: 중간 과정을 실시간으로 수신
- MCP-UI 렌더링: 도구 결과에 포함된
ui://임베디드 리소스를 sandboxed iframe으로 렌더링
도구 호출 결과에 MCP-UI 임베디드 리소스(ui:// URI)가 포함되면:
text/html→ sandboxed iframe(srcdoc)으로 렌더링text/uri-list→ 첫 번째 http(s) URL을 iframe으로 렌더링- LLM에는 HTML 전문 대신 짧은 플레이스홀더만 전달 (컨텍스트 절약)
- iframe → 호스트 postMessage 프로토콜 지원:
ui-size-change: iframe 높이 자동 조정tool:/api/mcp/call을 통해 MCP 도구 호출 후ui-message-response로 응답prompt/intent: 에이전트에 프롬프트 전달 후 실행link: 새 탭으로 열기notify: 콘솔 로깅
테스트: Web UI의 분홍색 ▶ MCP-UI 데모 버튼을 누르면 서버 연결부터 실행까지 원클릭으로 진행됩니다. 로컬 테스트 서버의 MCP-UI 데모 도구 4종:
| 도구 | 데모 내용 |
|---|---|
show_calculator |
인터랙티브 계산기. tool postMessage로 add 도구 호출, prompt로 에이전트 호출 |
show_chart |
정적 SVG 막대 차트 (순수 HTML 렌더링) |
show_website |
text/uri-list 데모 — 외부 웹사이트를 iframe으로 표시 |
show_feedback_form |
별점+코멘트 폼. 제출 시 prompt postMessage로 에이전트에 전달되어 재실행 |
| 이름 | URL | Transport | 도구 |
|---|---|---|---|
| Local TestServer | http://localhost:8000/mcp |
Streamable HTTP | echo, add, greet + MCP-UI 데모 4종 (calculator, chart, website, feedback_form) |
| DeepWiki | https://mcp.deepwiki.com/mcp |
Streamable HTTP | read_wiki_structure, read_wiki_contents, ask_question |
| Semgrep | https://mcp.semgrep.ai/mcp |
Streamable HTTP | security scan 등 8개 |
| Cloudflare Docs | https://docs.mcp.cloudflare.com/sse |
SSE | search_cloudflare_documentation, migrate_pages_to_workers_guide |
| Time Server | https://mcp-time-server.ajz.workers.dev/sse |
SSE | get_current_time, convert_time |
code_exe_agent/
├── web_ui.py # FastAPI Web UI (메인 진입점)
├── src/
│ ├── react_workflow.py # ReAct Agent 워크플로우
│ ├── agent/
│ │ ├── llm_config.py # ChatOpenAI 설정 (OpenRouter 호환)
│ │ └── mcp_code_tool.py # LangChain Tool - 코드 실행 + mcp_call 주입
│ └── generator/
│ └── http_mcp_client.py # HTTP/SSE MCP 클라이언트
├── tests/
│ └── test_mcp_server.py # FastMCP 테스트 서버
├── pyproject.toml
├── .env.example
└── .env # 환경변수 (API 키 등)
| 파일 | 역할 |
|---|---|
web_ui.py |
FastAPI 서버. HTML UI + /api/react/stream (SSE), /api/mcp/tools 엔드포인트 |
src/react_workflow.py |
ReactCodeExecutionWorkflow - MCP URL 연결, LangGraph ReAct Agent 실행, 단계별 콜백 |
src/agent/llm_config.py |
create_llm() - ChatOpenAI 인스턴스 생성. 환경변수 또는 인자로 설정 |
src/agent/mcp_code_tool.py |
MCPCodeExecutionTool - LangChain BaseTool. exec()로 코드 실행, mcp_call() 주입 |
src/generator/http_mcp_client.py |
HTTPMCPClient - MCP SDK로 도구 목록 조회/실행. Streamable HTTP + SSE 지원 |
tests/test_mcp_server.py |
FastMCP 서버 (echo, add, greet 도구) |
기존 README에서 설명한 "Sandbox에서 코드 실행"은 현재 다음과 같이 동작합니다:
# src/agent/mcp_code_tool.py - MCPCodeExecutionTool._run()
def _run(self, code: str) -> str:
# 1. mcp_call 함수를 실행 환경에 주입
def mcp_call(url, tool_name, arguments):
client = self.mcp_clients.get(url)
return client.call_tool(tool_name, arguments)
exec_globals = {
"__builtins__": __builtins__,
"mcp_call": mcp_call,
}
# 2. LLM이 생성한 코드를 exec()로 실행
with redirect_stdout(capture), redirect_stderr(capture):
exec(code, exec_globals, exec_locals)
# 3. stdout 캡처 결과 반환
return capture.getvalue()LLM이 생성하는 코드 예시:
result = mcp_call("http://localhost:8000/mcp", "add", {"a": 42, "b": 58})
print(result)- Agent: LangGraph
create_react_agent - LLM: ChatOpenAI (OpenAI / OpenRouter 호환)
- MCP Client: MCP Python SDK (
streamablehttp_client,sse_client) - Web: FastAPI + SSE Streaming (
sse-starlette) - Test Server: FastMCP
- 패키지 관리: uv