An open-source MCP server that gives Claude conversations a persistent, interactive plan/to-do panel.
Project description
Wingman
An open-source MCP server that gives Claude conversations a persistent, interactive plan/to-do panel — rendered inline in the chat via MCP Apps.
Tagline: Sits beside you. Doesn't fly the plane.
Why Wingman?
Long AI conversations lose the plot. You start working on something complex, the thread drifts, and twenty messages later you can't remember what's done and what isn't. Cursor solved this for code with its plan agent. Wingman generalises that experience to any Claude conversation and any MCP host.
You and Claude share a named plan, edit it live, tick tasks off as you go, and one-click "Run" any pending task to send it back to Claude as the next prompt — pre-framed with surrounding context.
What it does
- Named plans, persistent: Plans live in a local SQLite database keyed by name. They survive restarts, conversation pivots, and entire chat threads.
- Interactive inline panel: An MCP Apps panel renders right in the chat — checkboxes, drag-to-reorder, three-dot menu, the works. No plain text.
- Two-way edits: You click checkboxes from the panel. Claude calls
tick_taskafter completing work. State syncs via 2.5s polling. - "Run this task": One click sends a pre-framed prompt back to Claude as your next message: the task, surrounding context, and an instruction to tick the box when done.
- "Build from our conversation": Empty-state CTA that asks Claude to scan the conversation and populate the plan with actionable tasks.
- Text fallback: Every tool returns clean markdown for hosts without MCP Apps support. Nothing breaks; you just lose the panel.
Install
pip install wingman
Or from source:
git clone https://github.com/adeolu/wingman.git
cd wingman
pip install -e .
Configure
Claude Desktop
Add to your claude_desktop_config.json (~/Library/Application Support/Claude/ on macOS, %APPDATA%\Claude\ on Windows):
{
"mcpServers": {
"wingman": { "command": "python", "args": ["-m", "wingman"] }
}
}
Restart Claude Desktop. Wingman's tools show up in the tool picker.
Cursor
Add to ~/.cursor/mcp.json:
{
"mcpServers": {
"wingman": { "command": "python", "args": ["-m", "wingman"] }
}
}
VS Code (Copilot Chat)
Add to your workspace .vscode/mcp.json:
{
"servers": {
"wingman": { "type": "stdio", "command": "python", "args": ["-m", "wingman"] }
}
}
See examples/ for ready-to-copy versions of each.
Usage examples
1. Build a plan with Claude
"Create a plan called 'Launch Footprint' with tasks for writing the spec, building the MVP, and shipping it."
Claude calls create_plan. The panel renders inline.
2. Build from conversation
Create an empty plan, then click "Build from our conversation →" in the empty state. Claude scans the chat, identifies actionable tasks, and calls add_tasks.
3. Run a task end-to-end
Click the ▶ button on any task. The task flips to in-progress, and the next user message is auto-injected: "I'm working on this from my Launch Footprint plan: > Write the spec. Help me complete it...". Claude works on it. When done, Claude calls tick_task and the checkbox flips green.
Tool reference
LLM-visible tools (the model can call these):
| Tool | What it does |
|---|---|
create_plan(name, tasks=[]) |
Create a new plan |
add_task(plan_name, content) |
Append one task |
add_tasks(plan_name, tasks) |
Append many tasks |
show_plan(plan_name) |
Render the panel inline |
get_plan(plan_name) |
Return plan as text (no panel) |
tick_task(plan_name, task_id) |
Mark a task done |
update_task_status(plan_name, task_id, status) |
pending / in_progress / done / blocked |
rename_plan(current_name, new_name) |
Rename |
reorder_tasks(plan_name, ordered_ids) |
Reorder |
list_plans() |
List all plans with counts |
delete_plan(plan_name) |
Delete a plan and its tasks |
The UI panel uses thirteen additional _ui_* tools internally. They're hidden from the model via _meta visibility on hosts that support it.
Architecture
+--------------------------------------------------------------+
| MCP Host (Claude Desktop / Cursor / VS Code) |
| |
| +----------------+ +------------------------------+ |
| | LLM (Claude) |<--->| Wingman MCP Server (stdio) | |
| +----------------+ | - LLM-visible tools | |
| ^ | - UI-only tools | |
| | sendMessage | - ui:// resource | |
| +----------------+ | - SQLite store | |
| | Iframe |<----| -----------------------------+ |
| | (Wingman UI) | JSON-RPC over postMessage |
| +----------------+ |
+--------------------------------------------------------------+
|
v
~/.local/share/wingman/plans.db (or equiv)
Security & privacy
- No telemetry. No phone-home. No network calls anywhere.
- Local-only stdio transport by default.
- All tool inputs validated via Pydantic; plan names are regex-restricted to prevent path traversal.
- All SQL is parameterised. No string-built queries.
- The UI iframe is sandboxed per the MCP Apps spec and self-contained — no external script sources, no remote fonts, no CDN.
Differentiation
| Concern | Existing solutions | Wingman |
|---|---|---|
| Interaction model | Type "mark task 3 done" | Click a checkbox |
| Run a task | Re-prompt manually | One-click "Run" button with framed context |
| Populate from chat | Manual | "Build from our conversation" CTA |
| Visual state | Plain text in chat | Inline interactive panel with progress card |
| Reordering | Edit text, recreate list | Drag-and-drop |
| MCP Apps native | No | Yes (SEP-1865, text/html;profile=mcp-app) |
| Cross-host | Limited | Anywhere MCP Apps is supported, with text fallback |
Host compatibility
Wingman ships an interactive panel via MCP Apps (SEP-1865). Hosts that support MCP Apps render it inline; hosts that don't get a clean markdown text response. You can use Wingman on either tier.
Verified target hosts for v0.1 interactive panel: Claude Desktop (recent versions), Cursor, VS Code Copilot Chat.
Known limitations in v0.1
Three actions in the panel's 3-dot menu are disabled in v0.1 and deferred to v0.2. They appear greyed out with a "Coming in v0.2" tooltip:
- Clear all tasks
- Delete plan
- Export as markdown
These depend on browser capabilities (modal confirmation dialogs and file downloads) that the sandboxed MCP Apps iframe restricts; doing them properly needs an in-panel confirmation flow and a non-download export path, which is v0.2 work.
You can still do all of these through Claude — the LLM-callable tools are unaffected. Ask Claude to delete_plan, or to clear a plan's tasks, or to show the plan as markdown (get_plan). Only the in-panel buttons are deferred, not the underlying capability.
The menu items that work in v0.1: Rename plan and Clear completed tasks.
Roadmap
v0.2 candidates: re-enable the three deferred menu actions (in-panel confirm modal + download-free export), server-pushed updates via MCP notifications, ChatGPT compatibility via dual MIME tagging, sub-tasks, priorities and due dates, plan templates.
v1.0 candidates: React-based UI, multi-plan tabs, search across plans, optional cloud sync, plan sharing.
Contributing
Open a PR. Keep dependencies minimal — mcp, pydantic, platformdirs, plus pytest for dev. Anything else needs a strong justification.
Run tests:
pip install -e ".[dev]"
pytest
Development troubleshooting
If your code changes don't appear in the rendered panel, you're almost certainly hitting one of three caches. Walk them in order:
-
The Wingman server subprocess is long-lived. An editable install (
pip install -e .) makes Python pick up your.pychanges only when the next subprocess starts. The MCP host (Claude Desktop, MCPJam, Cursor, etc.) spawns Wingman once and keeps it alive — so after editing anything undersrc/wingman/, fully quit and relaunch the host so it spawns a fresh subprocess. -
The panel HTML is inlined once at server start.
ui/static/{app.js, index.html, styles.css, mcp-app.js, sortable.min.js}are read and concatenated byui/resource.py:_panel_html(), which is wrapped in@lru_cache(maxsize=1). The bundle is computed on the firstresources/readand re-used for the lifetime of the subprocess. So iframe-behavior changes (anything instatic/) also require a server-subprocess restart — editing app.js without restarting accomplishes nothing. -
The host's iframe caches aggressively. Even after a server restart, the host may still display the previous bundle. After restarting the server, hard-refresh the host's webview (Ctrl+Shift+R in MCPJam / browser-based hosts) to force a fresh
resources/read.
The build marker is the source of truth. The panel footer shows WINGMAN · MCP plan agent · build <unix-timestamp>. The timestamp is captured at server-subprocess start (ui/resource.py:BUILD_TIMESTAMP). If you edit code, restart the host, refresh the iframe — and the build number hasn't changed — then one of the three caches above is still serving the old code. Don't trust visual inspection of the UI until the build number ticks forward.
A one-shot SDK smoke test that confirms the served HTML, the build marker, and show_plan's _meta.ui.resourceUri lives at tests/manual/smoke_panel.py (gitignored). Run it with python tests/manual/smoke_panel.py after any change to the panel pipeline.
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file wingman_mcp-0.1.0.tar.gz.
File metadata
- Download URL: wingman_mcp-0.1.0.tar.gz
- Upload date:
- Size: 136.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
44bf0a3ea980b16bfee422c84be9172b8134c23a6658d3ab4faa9c90c18c3925
|
|
| MD5 |
d2dd8af255e46a45c49c24dc5320ec2e
|
|
| BLAKE2b-256 |
335dbe454b28105788e923d8cb07bc04a07fa203e38e50f7c608c64e9e8952b1
|
File details
Details for the file wingman_mcp-0.1.0-py3-none-any.whl.
File metadata
- Download URL: wingman_mcp-0.1.0-py3-none-any.whl
- Upload date:
- Size: 132.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0bd7f8659808b754c1d30fc77d240ba48d496f752051926b4f53960f26f6918b
|
|
| MD5 |
5312c502ea01f001467070fa98d09119
|
|
| BLAKE2b-256 |
c5a295fe9a5af55430bdad4da5389626ae58fd554aa8e3a95380617845747d0d
|