Metadata-Version: 2.4
Name: wingman-mcp
Version: 0.1.0
Summary: An open-source MCP server that gives Claude conversations a persistent, interactive plan/to-do panel.
Author: Adeolu Adesina
License: MIT
Project-URL: Homepage, https://github.com/adeolu/wingman
Project-URL: Repository, https://github.com/adeolu/wingman
Keywords: mcp,claude,plan,todo,agent,model-context-protocol
Classifier: Development Status :: 3 - Alpha
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Operating System :: OS Independent
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: mcp>=1.2.0
Requires-Dist: pydantic>=2.0
Requires-Dist: platformdirs>=4.0
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Requires-Dist: pytest-asyncio>=0.21; extra == "dev"
Dynamic: license-file

# 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_task` after 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

```bash
pip install wingman
```

Or from source:

```bash
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):

```json
{
  "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`:

```json
{
  "mcpServers": {
    "wingman": { "command": "python", "args": ["-m", "wingman"] }
  }
}
```

### VS Code (Copilot Chat)

Add to your workspace `.vscode/mcp.json`:

```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:

```bash
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:

1. **The Wingman server subprocess is long-lived.** An editable install (`pip install -e .`) makes Python pick up your `.py` changes 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 under `src/wingman/`, fully quit and relaunch the host so it spawns a fresh subprocess.

2. **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 by `ui/resource.py:_panel_html()`, which is wrapped in `@lru_cache(maxsize=1)`. The bundle is computed on the first `resources/read` and re-used for the lifetime of the subprocess. So iframe-behavior changes (anything in `static/`) **also require a server-subprocess restart** — editing app.js without restarting accomplishes nothing.

3. **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](LICENSE).
