-
-
Notifications
You must be signed in to change notification settings - Fork 16
Description
Summary
The current MCP integration is a minimal HTTP-only gateway: users manually add an MCP server URL + optional bearer token, and the agent calls it via JSON-RPC over HTTP. This works for the rare remote/hosted MCP server, but most real-world MCP servers are stdio-based (Gmail, Slack, Granola, Brave Search, filesystem, etc.) and unreachable from the Excel WebView.
For non-technical AI power users — the target audience — the current UX is a dead end. They can't use the MCPs they know from Claude Desktop or Claude Code.
Goal: make MCP a "just works" experience where enabling a popular MCP server requires minimal setup (ideally just an API key or OAuth), no extra processes beyond the CORS proxy, and no restart.
Current architecture
Excel WebView (browser)
│
│ POST JSON-RPC to server URL
│
├── direct ──────────────→ Remote HTTP MCP server (rare)
│
└── via CORS proxy ──────→ localhost:3003 ──→ Remote HTTP MCP server
(proxy.enabled=true) cors-proxy-server.mjs
Limitations:
- HTTP-only transport — can't reach stdio MCP servers (the vast majority)
- CORS proxy host allowlist —
DEFAULT_ALLOWED_TARGET_HOSTSonly includes LLM provider domains; arbitrary MCP server hosts are blocked - No hot-reload — adding a server mid-session requires config + proxy restart
- Manual-only setup — user must know the exact server URL and token format
Proposed architecture: MCP Hub in the CORS proxy
Extend cors-proxy-server.mjs into an MCP hub that manages stdio server lifecycles:
Excel WebView
│
│ POST /mcp/{server-id}/rpc (tool calls)
│ GET /mcp/servers (discovery)
│
▼
┌────────────────────────────────────────┐
│ localhost:3003 (existing proxy) │
│ │
│ Existing: /?url=... (CORS proxy) │
│ │
│ New: MCP Hub layer │
│ ┌──────────┐ ┌──────────┐ │
│ │ gmail │ │ slack │ ... │
│ │ (stdio) │ │ (stdio) │ │
│ └──────────┘ └──────────┘ │
│ │
│ Config: mcp-servers.json │
│ (file-watched for hot-reload) │
└────────────────────────────────────────┘
Config format (mcp-servers.json)
{
"gmail": {
"command": "npx",
"args": ["-y", "@anthropic/gmail-mcp"],
"env": { "GMAIL_OAUTH_CREDENTIALS": "~/.config/gmail-oauth.json" }
},
"slack": {
"command": "npx",
"args": ["-y", "@anthropic/slack-mcp"],
"env": { "SLACK_BOT_TOKEN": "xoxb-..." }
},
"brave-search": {
"command": "npx",
"args": ["-y", "@anthropic/brave-search-mcp"],
"env": { "BRAVE_API_KEY": "..." }
}
}Key design decisions
Lazy spawn: Don't start all servers on boot. Spawn a child process on first connect or tool call. This keeps startup fast and avoids wasted processes.
File-watch hot-reload: fs.watch("mcp-servers.json") detects changes → diffs config → spawns new servers, kills removed ones. No proxy restart needed to add/remove servers mid-session.
Stdio ↔ HTTP translation: The hub receives HTTP JSON-RPC from the WebView, writes it as newline-delimited JSON to the child's stdin, reads the response from stdout, and returns it as HTTP.
CORS is a non-issue: All /mcp/ routes are loopback through the proxy the user already trusts. No host allowlist changes needed.
Management API (stretch): POST /mcp/servers / DELETE /mcp/servers/{id} so the Excel UI can add/remove servers without the user touching JSON.
Ship a curated mcp-servers.example.json
Pre-configure ~8 popular servers (commented out / disabled by default) so users just uncomment and add credentials:
| Category | Server | Package | Auth |
|---|---|---|---|
| Gmail | @anthropic/gmail-mcp |
OAuth | |
| Files | Google Drive | @anthropic/gdrive-mcp |
OAuth |
| Calendar | Google Calendar | @anthropic/gcalendar-mcp |
OAuth |
| Chat | Slack | @anthropic/slack-mcp |
Bot token |
| Search | Brave Search | @anthropic/brave-search-mcp |
API key |
| Notes | Notion | @anthropic/notion-mcp |
Integration token |
| Files | Filesystem | @anthropic/filesystem-mcp |
None |
| Data | SQLite | @anthropic/sqlite-mcp |
None |
(Exact package names TBD — verify against the MCP server registry before implementation.)
Phases
Phase 1 — Stdio bridge in the proxy
/mcp/{server-id}/rpcroute incors-proxy-server.mjs- Child process spawn/lifecycle management (lazy start, graceful shutdown)
mcp-servers.jsonconfig loadingfs.watchhot-reloadGET /mcp/serversdiscovery endpoint- Ship
mcp-servers.example.jsonwith curated popular servers
Phase 2 — Wire Excel client
mcptool auto-discovers servers fromGET /mcp/servers(bridge-managed servers appear alongside manually-added HTTP servers)/integrationsUI shows bridge-managed servers with status (running/stopped/error)- "Test connection" triggers lazy spawn + MCP handshake
Phase 3 — Management API + zero-JSON UX
POST /mcp/servers/DELETE /mcp/servers/{id}for CRUD from Excel UI- Browse/search a curated server catalog from the
/integrationsoverlay - One-click enable with inline credential prompts
- Auto-install npm packages on first use
Out of scope (for now)
- OAuth broker in the proxy (users handle OAuth setup per-server for now)
- SSE / Streamable HTTP transport for remote servers (existing HTTP path covers this)
- Sandboxing / capability restrictions on stdio servers
Context
- Current MCP tool:
src/tools/mcp.ts(HTTP JSON-RPC only) - Config store:
src/tools/mcp-config.ts(mcp.servers.v1settings key) - CORS proxy:
scripts/cors-proxy-server.mjs - Proxy target policy:
scripts/proxy-target-policy.mjs - Integration catalog:
src/integrations/catalog.ts - UI overlay:
src/commands/builtins/integrations-overlay.ts+integrations-overlay-elements.ts - MCP probe (test connection):
src/commands/builtins/integrations-overlay-mcp-probe.ts - Agent Skill:
skills/mcp-gateway/SKILL.md - Docs:
docs/integrations-external-tools.md,docs/agent-skills-interop.md