mcp-mrtr-devops-demo
Enables stateless human-in-the-loop DevOps automation, demonstrating MCP SEP-2322 multi-round trip requests for emergency database migration authorization.
README
mcp-mrtr-devops-demo
End-to-end demo of Multi Round-Trip Requests (MRTR) under MCP SEP-2322, using LangGraph, agentgateway, LM Studio, and Spec-Kit in Cursor IDE.
Stateless human-in-the-loop (HITL) DevOps agent: yield for confirmation, resume on any server instance, no sticky SSE sessions.
Executive summary
This repository demonstrates a production-shaped pattern for mid-call HITL under the 2026-07-28 MCP specification. When an agent hits a destructive operation, the MCP server returns a signed continuation handle and closes the connection. The client pauses, collects operator input, then resubmits—routable to any backend behind a load balancer.
Use case: emergency database migration agent
An autonomous DevOps AI agent receives a prompt to run an emergency migration on production cluster prod-db-01. The migration file V004__drop_legacy_users.sql contains destructive operations (DROP TABLE).
Before executing, the agent must obtain human authorization. Under MRTR, that pause is stateless: no open SSE GET stream and no in-memory paused thread on a specific pod.
Legacy bottleneck (pre-2026 / e.g. MCP 2025-11-25)
Older MCP HITL patterns typically required:
- Open, persistent Server-Sent Events (SSE) GET streams for mid-call authorization
- An MCP server that held the execution thread in memory while waiting for user confirmation
Failure mode: If an API gateway or load balancer dropped the idle SSE socket—or server pods auto-scaled—the paused thread died, agent state was lost, and operators had to restart the whole flow manually.
How MRTR (SEP-2322) resolves it
Under the 2026-07-28 MCP specification (SEP-2322):
- Stateless yield — On a destructive operation, the MCP server does not hold a connection open. It packages the user input schema (
inputRequests) and an HMAC-signed continuation token (requestState), returns HTTP 200 withresultType: "input_required", and terminates the socket immediately. - Non-blocking client pause — The LangGraph client receives
input_required, pauses its graph, and releases system resources. - Stateless resubmission — The operator completes the confirmation prompt (UI/terminal). LangGraph re-issues
tools/callas an HTTP POST withinputResponsesand the echoedrequestState. - Unpinned load balancing — Round-robin via agentgateway can route the retry to any available server instance. That instance validates the HMAC, runs the migration, and returns
resultType: "complete".
Mcp-Session-Id and sticky session headers are not used.
Technical stack
| Layer | Choice |
|---|---|
| IDE / orchestration | Cursor IDE + GitHub Spec-Kit (specify-cli) |
| Agent framework | LangGraph (Python) — workflow state, non-blocking pauses, retry loops |
| LLM | LM Studio — qwen/qwen3.6-35b-a3b at http://127.0.0.1:1234/v1 |
| API gateway / L7 | agentgateway — Streamable HTTP proxy on port 8080 (statefulMode: stateless) |
| MCP protocol | MCP 2026-07-28 stateless core + SEP-2322 MRTR payloads |
Architecture (logical)
Operator terminal
│
▼
main.py (harness)
├── validates LM Studio :1234
├── starts MCP server :8000
└── starts agentgateway :8080
│
▼
LangGraph agent ── tools/call ──► agentgateway :8080 ──► MCP server :8000
│ │
│◄── input_required + requestState ───────────────┤
│ │
terminal HITL (confirm_drop + environment_tag) │
│ │
└── retry + inputResponses + requestState ────────┘
│
▼
resultType: complete
End-to-end setup and run
Follow these steps in order on macOS or Linux.
Step 0 — Prerequisites checklist
| Requirement | Why |
|---|---|
| Python 3.11+ | Runtime for MCP server, agent, and harness |
uv |
Installs deps and runs the project |
| LM Studio | Local OpenAI-compatible LLM |
Model qwen/qwen3.6-35b-a3b (or matching MODEL_NAME) |
Used by the LangGraph agent |
agentgateway on PATH |
L7 proxy for tool calls (constitution: no gateway bypass) |
| Free local ports 1234, 8000, 8080 | LLM, MCP server, agentgateway |
Step 1 — Clone the repository
git clone https://github.com/caldeirav/mcp-mrtr-devops-demo.git
cd mcp-mrtr-devops-demo
(Or open the existing checkout and cd into the repo root.)
Step 2 — Install uv (if needed)
# macOS (Homebrew)
brew install uv
# or official installer
curl -LsSf https://astral.sh/uv/install.sh | sh
Confirm:
uv --version
python3 --version # should be 3.11+
Step 3 — Install agentgateway
curl -sL https://agentgateway.dev/install | bash
agentgateway --version
Ensure the binary is on your PATH (the installer typically places it in /usr/local/bin).
Step 4 — Start LM Studio and load the model
- Open LM Studio.
- Download / select model
qwen/qwen3.6-35b-a3b(or the id you will put in.envasMODEL_NAME). - Start the local server (OpenAI-compatible API) on
http://127.0.0.1:1234. - Confirm the server is up (LM Studio UI shows listening, or):
curl -s http://127.0.0.1:1234/v1/models | head
You should see JSON listing available models. Leave LM Studio running for the rest of the demo.
Step 5 — Configure environment
cp .env.example .env
Edit .env and set at least:
OPENAI_API_BASE=http://127.0.0.1:1234/v1
OPENAI_API_KEY=lm-studio
MODEL_NAME=qwen/qwen3.6-35b-a3b
AGENTGATEWAY_PORT=8080
MCP_SERVER_PORT=8000
MCP_HMAC_SECRET=<long-random-secret>
Generate a secret if you do not have one:
# example: 64 hex chars
openssl rand -hex 32
Paste the value into MCP_HMAC_SECRET. Do not commit .env (it is gitignored).
Step 6 — Install Python dependencies
From the repo root:
uv sync --group dev
This creates .venv and installs langgraph, fastapi, httpx, and the rest of the stack (see pyproject.toml).
Step 7 — (Optional) Run automated tests
These do not require agentgateway or a live demo session (integration test skips if gateway is down):
uv run pytest
Expect unit/contract tests to pass.
Step 8 — Run the end-to-end demo
One command starts MCP, agentgateway, validates the LLM, and runs the agent:
uv run python main.py
What the harness does automatically:
- Fail-fast check that LM Studio answers at
OPENAI_API_BASE - Ensures
agentgateway.yamlexists (statefulMode: stateless,:8080→ MCP:8000/mcp) - Starts the MCP server on
MCP_SERVER_PORT(default 8000) - Starts
agentgateway -f agentgateway.yamlon 8080 (logs redirected to.demo_logs/) - Runs the LangGraph agent for defaults
prod-db-01/V004__drop_legacy_users.sql - On Ctrl+C / exit, stops child processes
Terminal output is banded so you can tell layers apart:
| Band | Meaning |
|---|---|
TRACE |
Harness / LangGraph / HTTP execution |
AGENT |
LLM narrative and packaged answers |
HITL |
Your operator prompts (no open SSE socket) |
SEP |
Detailed request/response + ★ what changed in 2026-07-28 / SEP-2322 |
SEP panels highlight new fields (resultType, requestState, inputRequests / inputResponses, per-request _meta, Mcp-Method / Mcp-Name) and call out removed sticky-session behavior (Mcp-Session-Id absent). Set NO_COLOR=1 to disable ANSI colors.
Step 9 — Complete the human-in-the-loop prompts
When the destructive migration is detected you will see a terminal block similar to:
=== Human-in-the-loop authorization required ===
Confirm destructive migration ...
confirm_drop [true/false]:
environment_tag ['dev', 'staging', 'prod']:
Happy-path answers:
confirm_drop [true/false]: true
environment_tag ['dev', 'staging', 'prod']: prod
Then the agent retries through agentgateway with inputResponses + echoed requestState and prints a complete summary (simulated apply).
Other useful answers to try
| Input | Expected outcome |
|---|---|
confirm_drop=false |
complete with denied/cancelled text; migration not applied |
environment_tag=qa |
complete with denied text (tag outside allow-list) |
| Wait longer than 5 minutes before answering | Resume fails (expired requestState) |
Step 10 — Shut down
Press Ctrl+C if the process is still running. The harness tears down MCP and agentgateway. You can quit LM Studio when finished.
What you just demonstrated
- Destructive tool call →
resultType: input_required+ HMACrequestState - Socket closed; no sticky
Mcp-Session-Id - Operator input in the terminal
- Retry via agentgateway → any-ready MCP instance can verify state and finish with
resultType: complete
Manual component checks (optional)
Use these if you want to inspect layers separately (stop main.py first to free ports):
# Terminal A — MCP server
export $(grep -v '^#' .env | xargs) # or set MCP_HMAC_SECRET in the shell
uv run uvicorn mcp_server.server:app --host 127.0.0.1 --port 8000
# Terminal B — gateway
agentgateway -f agentgateway.yaml
# Terminal C — smoke tools/call (should return input_required)
curl -s http://127.0.0.1:8080/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-H 'MCP-Protocol-Version: 2026-07-28' \
-H 'Mcp-Method: tools/call' \
-H 'Mcp-Name: apply_db_migration' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"apply_db_migration","arguments":{"cluster_id":"prod-db-01","script_name":"V004__drop_legacy_users.sql"},"_meta":{"io.modelcontextprotocol/protocolVersion":"2026-07-28","io.modelcontextprotocol/clientInfo":{"name":"curl","version":"0"},"io.modelcontextprotocol/clientCapabilities":{"elicitation":{}}}}}'
Repository layout
main.py # one-command harness
agentgateway.yaml # L7 proxy (stateless)
mcp_server/ # FastAPI MCP tool + HMAC crypto
agent/ # LangGraph client + httpx MCP client
.env.example # config template
specs/001-mrtr-db-migration/ # Spec Kit artifacts (spec, plan, tasks, contracts)
Governing principles
Project rules live in .specify/memory/constitution.md:
- Connection Statelessness — no persistent SSE GET sockets;
Mcp-Session-Idprohibited - Protocol Precision — top-level
resultType:complete|input_required - HMAC Integrity — HMAC-SHA256 continuation handles (
requestState) - Infrastructure Integration — tools via agentgateway
:8080; LM Studio as above - Modular Verification — separable MCP server, agentgateway, and LangGraph runloop
More detail: specs/001-mrtr-db-migration/quickstart.md.
Troubleshooting
| Symptom | What to check |
|---|---|
| Fail-fast: LLM unreachable | LM Studio server running on :1234; model loaded; OPENAI_API_BASE / MODEL_NAME match |
agentgateway not found |
Re-run install script; confirm which agentgateway |
| Port already in use | Stop other listeners on 8000/8080/1234 |
HMAC / invalid requestState |
Same MCP_HMAC_SECRET for the whole process; answer within 5 minutes |
| Invalid environment tag | Exactly dev, staging, or prod (case-sensitive) |
| Gateway returns unexpected session behavior | agentgateway.yaml must keep statefulMode: stateless |
| HTTP 406 from gateway | Client must send Accept: application/json, text/event-stream |
_meta.protocolVersion is required |
Include MCP 2026-07-28 _meta keys under params (see contracts) |
License
See LICENSE.
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。