MCP Hub
Back to servers

turn-mcp

Achieve infinite conversation turns in a single API request via turn-mcp. Self-hosted MCP server with browser console for human-in-the-loop AI agents.

GitHub
Stars
21
Forks
6
Updated
Mar 22, 2026
Validated
Mar 24, 2026

turn-mcp-web

One model API request, unlimited conversations and interactions. A vulnerability in the MCP protocol can amplify resource usage in API billing model schemes. AI agents call turn.wait to pause execution

License: MIT Node.js

中文文档

How it works: Open the project folder and launch the server → configure the MCP endpoint in the browser console for your AI client → go to your AI tool and send it SKILL.md → the AI calls turn.wait and you reply in the browser — repeat for as many turns as you need.


Quick Start

Each script checks for Node.js, installs dependencies, and builds the project on the first run, then starts the server and opens the browser.

macOS — double-click start.command

Windows — double-click start.bat

Linux

bash start.sh

From source

npm install
npm run build
npm start

Browser console → http://127.0.0.1:3737/
MCP endpoint → http://127.0.0.1:3737/mcp


MCP Client Setup

Streamable HTTP

For IDE-based clients (Cursor, Windsurf, Claude Code, VS Code Copilot, Antigravity). Add to the client’s MCP config file:

{
  "mcpServers": {
    "turn-mcp-web": {
      "url": "http://127.0.0.1:3737/mcp"
    }
  }
}

Windsurf uses "serverUrl" instead of "url".

stdio

For clients that spawn MCP servers as child processes (Claude Desktop, Cline, Continue). The process also binds the browser console on HTTP so you can still reply via http://127.0.0.1:3737/.

{
  "mcpServers": {
    "turn-mcp-web": {
      "command": "node",
      "args": ["/path/to/turn-mcp-web-universal/dist/server-stdio.js"]
    }
  }
}

Python Client

For Python agent frameworks that don’t use MCP (LangChain, LangGraph, AutoGen, plain scripts). The client calls the long-poll REST endpoint POST /api/waits/create-and-wait and blocks until the operator replies in the browser console.

pip install ./python-client
from turn_mcp_client import TurnMcpClient, TurnMcpTimeout, TurnMcpCanceled

client = TurnMcpClient("http://127.0.0.1:3737")
reply = client.wait(
    context="About to drop table `old_users` (32 rows, no FK references).",
    question="Proceed with DROP TABLE?",
    options=["Yes", "No", "Show migration first"],
)

Async variant and LangChain / LangGraph integration examples: python-client/README.md


Features

  • MCP tool turn.wait with aliases turn_wait, turn
  • Dual transport: Streamable HTTP and stdio
  • Browser console: view, reply, cancel, extend pending waits
  • Session sidebar: active sessions above, history below (read-only preview)
  • SSE real-time push with exponential backoff reconnect
  • Desktop and sound notifications, title-bar flash
  • Quick reply templates, agent-defined option buttons
  • Session naming (stored in browser localStorage)
  • History persistence (optional JSONL)
  • Webhook: HMAC-SHA256 signing, automatic retry (×3), Slack format
  • API key auth: operator / viewer roles
  • Per-IP rate limiting (sliding window)
  • Structured event log (optional JSONL)
  • One-click auto-configure for 8 MCP clients + system-wide shell/registry
  • i18n: English and Chinese, runtime-switchable
  • PWA: installable, Service Worker background notifications

Environment Variables

VariableDefaultDescription
TURN_MCP_HTTP_HOST127.0.0.1Bind host
TURN_MCP_HTTP_PORT3737Bind port
TURN_MCP_HTTP_PATH/mcpMCP endpoint path
TURN_MCP_DEFAULT_TIMEOUT_SECONDS600Default wait timeout (0–3600)
TURN_MCP_API_KEYOperator key
TURN_MCP_VIEWER_API_KEYViewer key (read-only)
TURN_MCP_REQUIRE_API_KEYautoEnable auth (auto if any key is set)
TURN_MCP_EVENT_LOG_FILEEvent log JSONL path
TURN_MCP_HISTORY_FILEHistory JSONL path
TURN_MCP_WEBHOOK_URLWebhook target URL
TURN_MCP_WEBHOOK_EVENTSwait_createdComma-separated event types
TURN_MCP_WEBHOOK_SECRETHMAC-SHA256 signing secret
TURN_MCP_WEBHOOK_FORMATjsonjson or slack
TURN_MCP_RATE_LIMIT_MAX120Max requests per IP per window
TURN_MCP_RATE_LIMIT_WINDOW_SECONDS60Rate-limit window (seconds)
TURN_MCP_MAX_CONCURRENT_WAITS_PER_SESSION10Max concurrent waits per session
TURN_MCP_REINFORCEMENT_SUFFIX(built-in)Text appended to every reply

Authentication

Auth is disabled by default. Set TURN_MCP_API_KEY (and optionally TURN_MCP_VIEWER_API_KEY) to enable it. Pass the key on every request via either header:

x-turn-mcp-api-key: <key>
Authorization: Bearer <key>

Two roles are supported:

  • operator — full access: call MCP tools, submit replies, cancel waits, read event log
  • viewer — read-only: inspect pending waits and session history, subscribe to SSE

Webhook Security (HMAC)

When TURN_MCP_WEBHOOK_SECRET is set, every outbound webhook POST is signed with HMAC-SHA256. The signature is sent in the x-turn-mcp-signature header as sha256=<hex>. Verify it on the receiving end to ensure the payload has not been tampered with.

import hmac, hashlib

def verify(body: bytes, header: str, secret: str) -> bool:
    expected = "sha256=" + hmac.new(secret.encode(), body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, header)

API

All endpoints return JSON. Error responses include an error string field. Paginated endpoints return total, count, and pagination.hasMore.

MethodPathAuthDescription
GET/api/public-confignonePublic config
GET/api/auth-checkviewer+Current role
GET/api/waitsviewer+Pending waits
GET/api/waits/:idviewer+Single pending wait
GET/api/historyviewer+Completed history
GET/api/history/timelineviewer+Session timeline
GET/api/sessionsviewer+All sessions summary
POST/api/waits/:id/respondoperatorSubmit reply
POST/api/waits/:id/canceloperatorCancel wait
POST/api/waits/:id/extendoperatorExtend timeout
POST/api/waits/cancel-alloperatorCancel all pending
POST/api/waits/create-and-waitoperatorLong-poll: create and wait for reply
POST/api/settingsoperatorUpdate runtime settings
POST/api/auto-configureoperatorWrite client config files
POST/api/auto-unconfigureoperatorRemove from client config files
GET/api/streamviewer+SSE event stream
GET/api/eventsoperatorEvent log
GET/healthznoneHealth check

Testing

test:unit runs directly against the compiled dist/ output and requires no running server. test:ui starts a real server on a temporary port and tests browser interactions end-to-end.

npm test               # unit tests + UI integration tests
npm run test:unit      # WaitStore unit tests only
npm run test:ui        # UI integration tests

Docker

Set TURN_MCP_HTTP_HOST=0.0.0.0 when running inside a container so the port is accessible from the host. Mount a volume to /app/logs if you want history and event log files to survive container restarts.

docker build -t turn-mcp-web .
docker run --rm -p 3737:3737 \
  -e TURN_MCP_HTTP_HOST=0.0.0.0 \
  -e TURN_MCP_API_KEY=your_key \
  -e TURN_MCP_HISTORY_FILE=/app/logs/history.jsonl \
  -v "$(pwd)/logs:/app/logs" \
  turn-mcp-web

Alternatively, use the included Compose file:

docker compose up --build

Architecture

The entire stack runs in a single node dist/server.js process. wait-store.ts is the core: it keeps pending waits as in-memory Promises and resolves them when the operator replies via the REST API. SSE pushes events to the browser in real time. History is optionally persisted to JSONL files so it survives restarts.

src/
  server.ts              HTTP entry: MCP + REST API + static files
  server-stdio.ts        stdio entrypoint (for IDE clients)
  auto-configure.ts      Write/remove client config files
  turn-mcp-server.ts     MCP tool implementation
  wait-store.ts          In-memory wait state machine (Promise-based)
  event-log.ts           Structured event logger
  sse-manager.ts         SSE broadcast manager
  history-persistence.ts JSONL history persistence
  webhook.ts             Outbound webhook (HMAC, retry, Slack)
  config.ts              Environment config + Logger

public/
  app.js                 Browser console (vanilla JS)
  styles.css             UI design system
  i18n.js                EN/ZH runtime switcher
  sw.js                  Service Worker (PWA)

python-client/           pip install turn-mcp-client
examples/python/         LangChain, LangGraph integration examples

Agent Usage Guide

Before deploying turn-mcp-web with an AI agent, share the skill document with the agent so it knows when and how to call turn.wait, what context to provide, and what rules to follow.

Paste the document into the agent’s system prompt, or reference it with @SKILL.md in clients that support file context.


License

MIT

Reviews

No reviews yet

Sign in to write a review