workspace-agent-relay-mcp
A local relay and dashboard that enables ChatGPT Workspace Agents to stream real-time updates—plan, progress, tool calls, and results—back to the user's machine via MCP and SSE.
README
workspace-agent-relay-mcp
A local relay + dashboard that lets a ChatGPT Workspace Agent report its plan, progress, tool calls, questions, and final result back to your machine — in real time, while it works.

The left side is the relay dashboard: the user's message, the agent's plan checklist (all steps done), the tool calls it ran locally (write_file, run_command with durations), and the final result. The right side is the ChatGPT Workspace Agent itself — which the local operator otherwise cannot see. The relay mirrors the agent's work into a live, readable view.
Why this exists: the Workspace Agent trigger API is fire-and-forget. You POST a task and get a
202 Acceptedwith no body and no way to retrieve the agent's answer. So an agent running in ChatGPT has no built-in channel to show you what it's doing or hand you a result. This relay gives it that channel: a tiny MCP server the agent calls back into, plus a live dashboard you watch.
How it fits together
Three pieces, two of them on your machine:
you (browser) your machine ChatGPT cloud
┌────────────┐ ┌──────────────────────────┐ ┌──────────────────┐
│ dashboard │◀── │ workspace-agent-relay │ ◀──MCP─ │ Workspace Agent │
│ :8799 │ │ (MCP + web + SSE) │ calls │ (triggered runs)│
└────────────┘ └─────────────┬────────────┘ └──────────────────┘
│ HTTP /internal/tool-trace
▲
│ fire-and-forget trace per tool call
┌────────┴─────────────┐
│ notion-local-ops-mcp │ ← the agent's "hands"
│ (file/git/shell tools)│ (separate repo, optional)
└──────────────────────┘
- workspace-agent-relay-mcp (this repo): the MCP server the agent writes into, the dashboard you read from, and the SSE bus that pushes updates live.
- notion-local-ops-mcp (separate repo, optional): the agent's working tools — files, git, shell. When paired with this relay, every tool call the agent makes there is auto-mirrored here as a trace, so you watch it work without the agent manually reporting anything.
- ChatGPT Workspace Agent: the cloud brain. Triggered by this relay, calls back into both MCPs.
What the agent sees (MCP tools)
Six tools, all narrow on purpose — no shell, no arbitrary file access, no secrets:
| Tool | When the agent calls it |
|---|---|
record_plan |
At the start of a run, with its step plan (stable ids + titles). |
record_progress |
After a few steps, batch-updating step statuses + an optional one-line note. |
record_result |
Once at the end, with status (done/blocked/failed), title, and full Markdown. |
ask_user |
Only when genuinely blocked on a human decision. |
get_run_context |
To recover the current run's summary if it loses context. |
server_info |
Introspection — relay URL, auth mode, registered tools. |
What you see (dashboard)
Open http://127.0.0.1:8799/ in a browser. For each run, in reading order:
-
Your message (what you sent the agent).
-
Plan checklist — the steps the agent committed to, with live
in_progress / done / skippedstates.
-
Tool calls — a collapsible list of tool-call traces auto-mirrored from the agent's working MCP (apply_patch, git_commit, run_command, …), each with args, result summary, and duration. Failed calls are flagged red.
-
Notes — the agent's own one-line progress narrations (only when it has something worth saying).
-
Question — if the agent asked you something via
ask_user. -
Result — the final Markdown deliverable.
Everything streams in over SSE while the agent works — you don't refresh.
Quick start
1. Install
python3.11 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
cp .env.example .env
2. Configure .env
# Protects /api/* and /mcp. Generate with: openssl rand -hex 32
WORKSPACE_AGENT_RELAY_AUTH_TOKEN=replace-me
# From your ChatGPT Workspace Agent settings:
WORKSPACE_AGENT_RELAY_TRIGGER_URL=https://api.chatgpt.com/v1/workspace_agents/agtch_your_id/trigger
WORKSPACE_AGENT_RELAY_AGENT_TOKEN=your-workspace-agent-access-token
Two tokens, two jobs:
| Variable | Protects | Lives in |
|---|---|---|
WORKSPACE_AGENT_RELAY_AUTH_TOKEN |
/api/* and /mcp |
.env and the dashboard "Relay API Token" field |
WORKSPACE_AGENT_RELAY_AGENT_TOKEN |
Outbound trigger calls to ChatGPT | .env only — never the browser |
3. Run
workspace-agent-relay-mcp # serves MCP + dashboard on 127.0.0.1:8799
Or behind a tunnel:
./scripts/dev-tunnel.sh # uses cloudflared if cloudflared.local.yml exists, else a quick tunnel
4. Configure the ChatGPT Workspace Agent
This is the part that turns the relay from a blank dashboard into a live one. Three things to set in ChatGPT: the trigger, the MCP connector, and the Instructions.
a. Create the Workspace Agent and copy its trigger credentials
- In ChatGPT, create (or open) a Workspace Agent.
- Copy its Trigger URL (
https://api.chatgpt.com/v1/workspace_agents/agtch_…/trigger) intoWORKSPACE_AGENT_RELAY_TRIGGER_URL. - Copy its access token into
WORKSPACE_AGENT_RELAY_AGENT_TOKEN(server-side only — never paste this into the browser dashboard).
The relay uses these to POST new tasks to the agent when you hit Send in the dashboard.
b. Add the relay as an MCP connector
In the Workspace Agent's MCP connectors section, add:
| Field | Value |
|---|---|
| URL | http://127.0.0.1:8799/mcp locally, or your tunnel URL https://<your-host>/mcp |
| Auth type | Bearer |
| Token | the value of WORKSPACE_AGENT_RELAY_AUTH_TOKEN |
After connecting, confirm the tool list includes record_plan, record_progress, record_result, ask_user, get_run_context, server_info. If a tool is missing, reconnect the MCP so ChatGPT re-fetches tools/list.
c. Paste the collaboration Instructions
Open docs/agent-instructions.md, copy the fenced block under "指令正文", and paste it into the Agent's Instructions field (append to, or replace, any existing relay section). This tells the agent the workflow it must follow on every run:
record_plan → bind_relay_run → batch record_progress → record_result
Without this, the agent will silently do work in ChatGPT that the dashboard can't see.
d. (Optional, for live tool traces) Connect notion-local-ops-mcp too
If you want the Tool calls panel to stream the agent's real file/git/shell actions, also connect notion-local-ops-mcp as a second MCP connector and paste its bind_relay_run step — see Pairing with notion-local-ops-mcp below.
5. Smoke test
- Start the relay, open
http://127.0.0.1:8799/, paste the auth token. - Send a short task from the dashboard (e.g. "create /tmp/hello.txt with one line, then read it back").
- Watch the plan checklist appear, tool traces stream in, then the final result.
Pairing with notion-local-ops-mcp
This relay only exposes reporting tools (plan/progress/result) — it deliberately has no shell, file, or git access. To let the agent actually do work and have those actions show up live in the dashboard, pair it with its sibling project:
notion-local-ops-mcp — a local MCP that gives the agent file reads/writes, patch editing, git, shell, and delegated tasks. It lives in a separate repo and works standalone; the relay integration is opt-in.
What the pairing enables
On its own, this relay shows the agent's plan + progress + result. With notion-local-ops-mcp paired, it additionally shows every tool call the agent makes (write_file, apply_patch, git_commit, run_command, …) streaming in live — without the agent manually reporting any of them.
How they talk
ChatGPT Agent ──MCP──▶ notion-local-ops-mcp ──POST /internal/tool-trace──▶ this relay ──SSE──▶ dashboard
- The agent calls
record_planon this relay (the plan shows up). - The agent calls
bind_relay_runon notion-local-ops-mcp, passing therequest_id+callback_tokenfrom the trigger. It does not pass a relay URL — that's configured on the notion-local-ops side viaNOTION_LOCAL_OPS_RELAY_URL(defaulthttp://127.0.0.1:8799). - From then on, every
@tracedtool the agent runs on notion-local-ops fires a fire-and-forget trace POST to this relay. - This relay stores each trace as a progress event and pushes it over SSE to the dashboard.
The internal endpoint authenticates with the per-run callback_token in the body (not the dashboard bearer), and a closed/terminal run rejects traces with 409. The relay being unreachable never blocks the agent's tool execution — traces are best-effort.
Setup on the notion-local-ops side
See notion-local-ops-mcp → Relay Bridge for its env knobs (NOTION_LOCAL_OPS_RELAY_URL, NOTION_LOCAL_OPS_RELAY_BRIDGE_ENABLED, NOTION_LOCAL_OPS_RELAY_BRIDGE_TIMEOUT). Default values point at this relay's default port, so a same-machine install works with no extra config.
Project layout
src/workspace_agent_relay_mcp/
server.py # FastMCP server + the six agent-facing tools + global instructions
app.py # Starlette app: routes, middleware, SSE event bus
api/routes/ # /api/agents, /api/conversations, /api/runs (SSE), /internal/tool-trace
store/relay_store.py # SQLite layer: runs, events, plans, artifacts, redaction
trigger.py # Builds the input_text sent to the ChatGPT trigger API
config.py # Env-driven config
oauth.py # Optional OAuth mode for ChatGPT web developer mode
frontend/ # React + Vite dashboard (TypeScript, TanStack Query, SSE)
scripts/dev-tunnel.sh # supervisor + cloudflared rolling-reload launcher
docs/ # design specs + agent instructions
tests/ # pytest suite
Trigger semantics (the short version)
conversation_key— the stable continuation key for a thread. Reuse it to keep one conversation.request_id— per-run trace key, echoed in every callback.idempotency_key— per-message retry key. New logical message → new key.conversation_url— saved as human-readable metadata only; not the continuation key.
The dashboard shows both the current conversation_key and the latest conversation_url so you don't accidentally fork a thread by reusing the wrong one.
Security notes
.env,cloudflared.local.yml, and*.sqlite*are git-ignored — keep them out of commits.- The per-run
callback_tokenis stored only as a hash; it's redacted from logs and API responses. - Use a high-entropy
WORKSPACE_AGENT_RELAY_AUTH_TOKEN. - Rotate any Workspace Agent access token that ever leaks into chat or logs.
- Debug MCP logging redacts common token/secret/authorization/key fields before writing summaries.
Status
Early, single-user, local-first. Not a product. Built to learn and prototype the Workspace Agent callback gap.
推荐服务器
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 模型以安全和受控的方式获取实时的网络信息。