claude-handoff-manager 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,6 @@
1
+ __pycache__/
2
+ *.pyc
3
+ *.egg-info/
4
+ dist/
5
+ build/
6
+ .venv/
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Country Delight Engineering
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,162 @@
1
+ Metadata-Version: 2.4
2
+ Name: claude-handoff-manager
3
+ Version: 0.1.0
4
+ Summary: MCP server that automates Claude Code conversation handoffs — no more manual copy-paste when you hit the message cap.
5
+ Project-URL: Homepage, https://github.com/AashiDutt/claude-handoff-manager
6
+ Author: Country Delight Engineering
7
+ License-Expression: MIT
8
+ License-File: LICENSE
9
+ Keywords: claude,claude-code,handoff,mcp,model-context-protocol
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Requires-Python: >=3.10
19
+ Requires-Dist: mcp>=1.0.0
20
+ Description-Content-Type: text/markdown
21
+
22
+ # claude-handoff-manager
23
+
24
+ MCP server that automates Claude Code conversation handoffs. No more manual copy-paste when you hit the message cap.
25
+
26
+ ## The Problem
27
+
28
+ When a Claude Code conversation reaches the message limit, it produces a handoff summary. You then have to:
29
+ 1. Copy the handoff text
30
+ 2. Exit / clear the conversation
31
+ 3. Start a new session
32
+ 4. Paste the handoff as the first message
33
+
34
+ This is tedious and breaks your flow.
35
+
36
+ ## The Solution
37
+
38
+ This MCP server automates the entire handoff cycle:
39
+
40
+ 1. **End of conversation**: Claude calls `save_handoff` - the message is saved to disk and copied to your clipboard
41
+ 2. **New conversation**: Say `"continue from last handoff"` - Claude calls `load_handoff` and picks up exactly where you left off
42
+
43
+ Zero manual copy-paste.
44
+
45
+ ## Installation
46
+
47
+ ### Option A: `uvx` from Git (recommended for teams)
48
+
49
+ Push this repo to your team's Git host, then each developer adds it to their `~/.mcp.json`:
50
+
51
+ ```json
52
+ {
53
+ "mcpServers": {
54
+ "handoff-manager": {
55
+ "command": "uvx",
56
+ "args": ["--from", "git+https://github.com/YOUR_ORG/claude-handoff-manager", "claude-handoff-manager"],
57
+ "type": "stdio"
58
+ }
59
+ }
60
+ }
61
+ ```
62
+
63
+ ### Option B: `uvx` from PyPI
64
+
65
+ ```json
66
+ {
67
+ "mcpServers": {
68
+ "handoff-manager": {
69
+ "command": "uvx",
70
+ "args": ["claude-handoff-manager"],
71
+ "type": "stdio"
72
+ }
73
+ }
74
+ }
75
+ ```
76
+
77
+ ### Option C: Run directly (local development)
78
+
79
+ ```json
80
+ {
81
+ "mcpServers": {
82
+ "handoff-manager": {
83
+ "command": "python3",
84
+ "args": ["/path/to/handoff-manager/src/handoff_manager/server.py"],
85
+ "type": "stdio"
86
+ }
87
+ }
88
+ }
89
+ ```
90
+
91
+ After editing `~/.mcp.json`, **restart Claude Code** to pick up the new server.
92
+
93
+ ## Tools
94
+
95
+ | Tool | What it does |
96
+ |------|-------------|
97
+ | `save_handoff` | Saves handoff message to `~/.claude/handoffs/` + copies to clipboard |
98
+ | `load_handoff` | Loads the latest (or a specific) handoff in a new conversation |
99
+ | `copy_handoff_to_clipboard` | Copies a saved handoff to the system clipboard |
100
+ | `list_handoffs` | Lists all saved handoffs with previews |
101
+ | `delete_handoff` | Deletes a specific or all handoffs |
102
+
103
+ ## Usage
104
+
105
+ ### Saving (end of a conversation)
106
+
107
+ Claude will automatically call `save_handoff` when it generates a handoff summary at the message cap. You can also manually trigger it:
108
+
109
+ > "Save a handoff with the current context"
110
+
111
+ ### Loading (start of a new conversation)
112
+
113
+ > "Continue from last handoff"
114
+
115
+ or
116
+
117
+ > "Load handoff"
118
+
119
+ Claude calls `load_handoff` and gets the full context from your previous session.
120
+
121
+ ### Listing saved handoffs
122
+
123
+ > "Show me my saved handoffs"
124
+
125
+ ### Clipboard
126
+
127
+ > "Copy the last handoff to my clipboard"
128
+
129
+ ## Storage
130
+
131
+ Handoffs are stored as JSON files in `~/.claude/handoffs/`:
132
+
133
+ ```
134
+ ~/.claude/handoffs/
135
+ 20260611_143022_home-user-myproject.json
136
+ 20260611_100515_home-user-otherproject.json
137
+ ```
138
+
139
+ Each file contains:
140
+ - `id`: Unique identifier (timestamp + project slug)
141
+ - `created_at`: UTC timestamp
142
+ - `working_dir`: The project directory
143
+ - `project_name`: Human-friendly name
144
+ - `message`: The full handoff text
145
+
146
+ ## Clipboard Support
147
+
148
+ Automatically copies to clipboard on save using:
149
+ - **macOS**: `pbcopy`
150
+ - **Linux X11**: `xclip` or `xsel`
151
+ - **Linux Wayland**: `wl-copy`
152
+ - **Windows**: `clip`
153
+
154
+ ## Requirements
155
+
156
+ - Python >= 3.10
157
+ - `mcp` SDK >= 1.0.0
158
+ - Claude Code CLI
159
+
160
+ ## License
161
+
162
+ MIT
@@ -0,0 +1,141 @@
1
+ # claude-handoff-manager
2
+
3
+ MCP server that automates Claude Code conversation handoffs. No more manual copy-paste when you hit the message cap.
4
+
5
+ ## The Problem
6
+
7
+ When a Claude Code conversation reaches the message limit, it produces a handoff summary. You then have to:
8
+ 1. Copy the handoff text
9
+ 2. Exit / clear the conversation
10
+ 3. Start a new session
11
+ 4. Paste the handoff as the first message
12
+
13
+ This is tedious and breaks your flow.
14
+
15
+ ## The Solution
16
+
17
+ This MCP server automates the entire handoff cycle:
18
+
19
+ 1. **End of conversation**: Claude calls `save_handoff` - the message is saved to disk and copied to your clipboard
20
+ 2. **New conversation**: Say `"continue from last handoff"` - Claude calls `load_handoff` and picks up exactly where you left off
21
+
22
+ Zero manual copy-paste.
23
+
24
+ ## Installation
25
+
26
+ ### Option A: `uvx` from Git (recommended for teams)
27
+
28
+ Push this repo to your team's Git host, then each developer adds it to their `~/.mcp.json`:
29
+
30
+ ```json
31
+ {
32
+ "mcpServers": {
33
+ "handoff-manager": {
34
+ "command": "uvx",
35
+ "args": ["--from", "git+https://github.com/YOUR_ORG/claude-handoff-manager", "claude-handoff-manager"],
36
+ "type": "stdio"
37
+ }
38
+ }
39
+ }
40
+ ```
41
+
42
+ ### Option B: `uvx` from PyPI
43
+
44
+ ```json
45
+ {
46
+ "mcpServers": {
47
+ "handoff-manager": {
48
+ "command": "uvx",
49
+ "args": ["claude-handoff-manager"],
50
+ "type": "stdio"
51
+ }
52
+ }
53
+ }
54
+ ```
55
+
56
+ ### Option C: Run directly (local development)
57
+
58
+ ```json
59
+ {
60
+ "mcpServers": {
61
+ "handoff-manager": {
62
+ "command": "python3",
63
+ "args": ["/path/to/handoff-manager/src/handoff_manager/server.py"],
64
+ "type": "stdio"
65
+ }
66
+ }
67
+ }
68
+ ```
69
+
70
+ After editing `~/.mcp.json`, **restart Claude Code** to pick up the new server.
71
+
72
+ ## Tools
73
+
74
+ | Tool | What it does |
75
+ |------|-------------|
76
+ | `save_handoff` | Saves handoff message to `~/.claude/handoffs/` + copies to clipboard |
77
+ | `load_handoff` | Loads the latest (or a specific) handoff in a new conversation |
78
+ | `copy_handoff_to_clipboard` | Copies a saved handoff to the system clipboard |
79
+ | `list_handoffs` | Lists all saved handoffs with previews |
80
+ | `delete_handoff` | Deletes a specific or all handoffs |
81
+
82
+ ## Usage
83
+
84
+ ### Saving (end of a conversation)
85
+
86
+ Claude will automatically call `save_handoff` when it generates a handoff summary at the message cap. You can also manually trigger it:
87
+
88
+ > "Save a handoff with the current context"
89
+
90
+ ### Loading (start of a new conversation)
91
+
92
+ > "Continue from last handoff"
93
+
94
+ or
95
+
96
+ > "Load handoff"
97
+
98
+ Claude calls `load_handoff` and gets the full context from your previous session.
99
+
100
+ ### Listing saved handoffs
101
+
102
+ > "Show me my saved handoffs"
103
+
104
+ ### Clipboard
105
+
106
+ > "Copy the last handoff to my clipboard"
107
+
108
+ ## Storage
109
+
110
+ Handoffs are stored as JSON files in `~/.claude/handoffs/`:
111
+
112
+ ```
113
+ ~/.claude/handoffs/
114
+ 20260611_143022_home-user-myproject.json
115
+ 20260611_100515_home-user-otherproject.json
116
+ ```
117
+
118
+ Each file contains:
119
+ - `id`: Unique identifier (timestamp + project slug)
120
+ - `created_at`: UTC timestamp
121
+ - `working_dir`: The project directory
122
+ - `project_name`: Human-friendly name
123
+ - `message`: The full handoff text
124
+
125
+ ## Clipboard Support
126
+
127
+ Automatically copies to clipboard on save using:
128
+ - **macOS**: `pbcopy`
129
+ - **Linux X11**: `xclip` or `xsel`
130
+ - **Linux Wayland**: `wl-copy`
131
+ - **Windows**: `clip`
132
+
133
+ ## Requirements
134
+
135
+ - Python >= 3.10
136
+ - `mcp` SDK >= 1.0.0
137
+ - Claude Code CLI
138
+
139
+ ## License
140
+
141
+ MIT
@@ -0,0 +1,37 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "claude-handoff-manager"
7
+ version = "0.1.0"
8
+ description = "MCP server that automates Claude Code conversation handoffs — no more manual copy-paste when you hit the message cap."
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ requires-python = ">=3.10"
12
+ authors = [
13
+ { name = "Country Delight Engineering" },
14
+ ]
15
+ keywords = ["claude", "mcp", "handoff", "claude-code", "model-context-protocol"]
16
+ classifiers = [
17
+ "Development Status :: 4 - Beta",
18
+ "Intended Audience :: Developers",
19
+ "License :: OSI Approved :: MIT License",
20
+ "Programming Language :: Python :: 3",
21
+ "Programming Language :: Python :: 3.10",
22
+ "Programming Language :: Python :: 3.11",
23
+ "Programming Language :: Python :: 3.12",
24
+ "Programming Language :: Python :: 3.13",
25
+ ]
26
+ dependencies = [
27
+ "mcp>=1.0.0",
28
+ ]
29
+
30
+ [project.scripts]
31
+ claude-handoff-manager = "handoff_manager.server:main"
32
+
33
+ [tool.hatch.build.targets.wheel]
34
+ packages = ["src/handoff_manager"]
35
+
36
+ [project.urls]
37
+ Homepage = "https://github.com/AashiDutt/claude-handoff-manager"
@@ -0,0 +1,3 @@
1
+ """Handoff Manager - MCP server for Claude Code conversation handoffs."""
2
+
3
+ __version__ = "0.1.0"
@@ -0,0 +1,310 @@
1
+ """
2
+ Handoff Manager MCP Server
3
+ ===========================
4
+ Automates the conversation handoff workflow in Claude Code.
5
+
6
+ When a conversation hits the message cap:
7
+ 1. Claude calls save_handoff() with the handoff summary
8
+ 2. User starts a new session
9
+ 3. User says "continue from last handoff" -> load_handoff() returns the context
10
+ 4. No more manual copy-paste
11
+
12
+ Storage: ~/.claude/handoffs/<timestamp>_<project_slug>.json
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ import json
18
+ import os
19
+ import platform
20
+ import shutil
21
+ import subprocess
22
+ from datetime import datetime, timezone
23
+ from pathlib import Path
24
+
25
+ from mcp.server.fastmcp import FastMCP
26
+
27
+ # ---------------------------------------------------------------------------
28
+ # Constants
29
+ # ---------------------------------------------------------------------------
30
+ HANDOFFS_DIR = Path.home() / ".claude" / "handoffs"
31
+ HANDOFFS_DIR.mkdir(parents=True, exist_ok=True)
32
+
33
+ # ---------------------------------------------------------------------------
34
+ # MCP Server
35
+ # ---------------------------------------------------------------------------
36
+ mcp = FastMCP(
37
+ "handoff-manager",
38
+ instructions=(
39
+ "This server manages conversation handoffs for Claude Code. "
40
+ "Use save_handoff at the end of a conversation to persist the handoff "
41
+ "summary. Use load_handoff at the start of a new conversation to "
42
+ "retrieve the context. Use copy_handoff_to_clipboard to copy to the "
43
+ "system clipboard."
44
+ ),
45
+ )
46
+
47
+
48
+ # ---------------------------------------------------------------------------
49
+ # Helpers
50
+ # ---------------------------------------------------------------------------
51
+ def _project_slug(working_dir: str) -> str:
52
+ """Create a filesystem-safe slug from a working directory path."""
53
+ return working_dir.strip("/").replace("/", "-").replace(" ", "_") or "default"
54
+
55
+
56
+ def _handoff_path(handoff_id: str) -> Path:
57
+ return HANDOFFS_DIR / f"{handoff_id}.json"
58
+
59
+
60
+ def _list_handoff_files() -> list[Path]:
61
+ """Return handoff files sorted newest-first."""
62
+ files = sorted(
63
+ HANDOFFS_DIR.glob("*.json"),
64
+ key=lambda p: p.stat().st_mtime,
65
+ reverse=True,
66
+ )
67
+ return files
68
+
69
+
70
+ def _copy_to_clipboard(text: str) -> str:
71
+ """Copy text to system clipboard. Returns status message."""
72
+ system = platform.system()
73
+ try:
74
+ if system == "Darwin":
75
+ proc = subprocess.Popen(["pbcopy"], stdin=subprocess.PIPE)
76
+ proc.communicate(text.encode("utf-8"))
77
+ return "Copied to clipboard (pbcopy)."
78
+ elif system == "Linux":
79
+ for cmd in [
80
+ ["xclip", "-selection", "clipboard"],
81
+ ["xsel", "--clipboard", "--input"],
82
+ ]:
83
+ if shutil.which(cmd[0]):
84
+ proc = subprocess.Popen(cmd, stdin=subprocess.PIPE)
85
+ proc.communicate(text.encode("utf-8"))
86
+ return f"Copied to clipboard ({cmd[0]})."
87
+ if shutil.which("wl-copy"):
88
+ proc = subprocess.Popen(["wl-copy"], stdin=subprocess.PIPE)
89
+ proc.communicate(text.encode("utf-8"))
90
+ return "Copied to clipboard (wl-copy)."
91
+ return "No clipboard tool found. Install xclip, xsel, or wl-copy."
92
+ elif system == "Windows":
93
+ proc = subprocess.Popen(["clip"], stdin=subprocess.PIPE)
94
+ proc.communicate(text.encode("utf-16le"))
95
+ return "Copied to clipboard (clip)."
96
+ else:
97
+ return f"Unsupported platform for clipboard: {system}"
98
+ except Exception as e:
99
+ return f"Clipboard copy failed: {e}"
100
+
101
+
102
+ # ---------------------------------------------------------------------------
103
+ # Tools
104
+ # ---------------------------------------------------------------------------
105
+ @mcp.tool()
106
+ def save_handoff(
107
+ message: str,
108
+ working_dir: str = "",
109
+ project_name: str = "",
110
+ ) -> str:
111
+ """Save a conversation handoff message for later retrieval.
112
+
113
+ Call this at the end of a conversation when the message cap is reached.
114
+ The handoff message is persisted to disk so the next conversation can
115
+ pick up where this one left off.
116
+
117
+ Args:
118
+ message: The full handoff summary text (the fenced code block content).
119
+ working_dir: The working directory of the current project (auto-detected if empty).
120
+ project_name: Optional human-friendly project name for easier identification.
121
+ """
122
+ if not message.strip():
123
+ return "Error: handoff message cannot be empty."
124
+
125
+ now = datetime.now(timezone.utc)
126
+ ts = now.strftime("%Y%m%d_%H%M%S")
127
+ wd = working_dir or os.getcwd()
128
+ slug = _project_slug(wd)
129
+ handoff_id = f"{ts}_{slug}"
130
+
131
+ payload = {
132
+ "id": handoff_id,
133
+ "created_at": now.isoformat(),
134
+ "working_dir": wd,
135
+ "project_name": project_name or slug,
136
+ "message": message,
137
+ }
138
+
139
+ path = _handoff_path(handoff_id)
140
+ path.write_text(json.dumps(payload, indent=2, ensure_ascii=False), encoding="utf-8")
141
+
142
+ clip_status = _copy_to_clipboard(message)
143
+
144
+ return (
145
+ f"Handoff saved successfully.\n"
146
+ f" ID: {handoff_id}\n"
147
+ f" Path: {path}\n"
148
+ f" Project: {payload['project_name']}\n"
149
+ f" Clipboard: {clip_status}\n\n"
150
+ f"To resume in a new conversation, the user can say:\n"
151
+ f' "continue from last handoff" or "load handoff"'
152
+ )
153
+
154
+
155
+ @mcp.tool()
156
+ def load_handoff(
157
+ handoff_id: str = "",
158
+ working_dir: str = "",
159
+ ) -> str:
160
+ """Load the most recent handoff message to continue a previous conversation.
161
+
162
+ Call this at the start of a new conversation to restore context from a
163
+ previous session that hit the message cap.
164
+
165
+ Args:
166
+ handoff_id: Specific handoff ID to load. If empty, loads the most recent one.
167
+ working_dir: Filter handoffs by working directory. If empty, returns the most recent regardless of project.
168
+ """
169
+ if handoff_id:
170
+ path = _handoff_path(handoff_id)
171
+ if not path.exists():
172
+ return f"Error: No handoff found with ID '{handoff_id}'."
173
+ payload = json.loads(path.read_text(encoding="utf-8"))
174
+ return (
175
+ f"Handoff loaded (ID: {payload['id']}).\n"
176
+ f"Project: {payload['project_name']}\n"
177
+ f"Saved at: {payload['created_at']}\n"
178
+ f"Working dir: {payload['working_dir']}\n\n"
179
+ f"--- HANDOFF MESSAGE ---\n\n"
180
+ f"{payload['message']}"
181
+ )
182
+
183
+ files = _list_handoff_files()
184
+ if not files:
185
+ return "No handoffs found. Nothing to resume."
186
+
187
+ if working_dir:
188
+ slug = _project_slug(working_dir)
189
+ files = [f for f in files if slug in f.stem]
190
+
191
+ if not files:
192
+ return f"No handoffs found for working directory: {working_dir}"
193
+
194
+ path = files[0]
195
+ payload = json.loads(path.read_text(encoding="utf-8"))
196
+
197
+ return (
198
+ f"Handoff loaded (ID: {payload['id']}).\n"
199
+ f"Project: {payload['project_name']}\n"
200
+ f"Saved at: {payload['created_at']}\n"
201
+ f"Working dir: {payload['working_dir']}\n\n"
202
+ f"--- HANDOFF MESSAGE ---\n\n"
203
+ f"{payload['message']}"
204
+ )
205
+
206
+
207
+ @mcp.tool()
208
+ def copy_handoff_to_clipboard(
209
+ handoff_id: str = "",
210
+ ) -> str:
211
+ """Copy a handoff message to the system clipboard.
212
+
213
+ Useful when you want to manually paste the handoff into another tool
214
+ or conversation.
215
+
216
+ Args:
217
+ handoff_id: Specific handoff ID. If empty, copies the most recent one.
218
+ """
219
+ if handoff_id:
220
+ path = _handoff_path(handoff_id)
221
+ if not path.exists():
222
+ return f"Error: No handoff found with ID '{handoff_id}'."
223
+ payload = json.loads(path.read_text(encoding="utf-8"))
224
+ else:
225
+ files = _list_handoff_files()
226
+ if not files:
227
+ return "No handoffs found."
228
+ payload = json.loads(files[0].read_text(encoding="utf-8"))
229
+
230
+ status = _copy_to_clipboard(payload["message"])
231
+ return f"Handoff '{payload['id']}': {status}"
232
+
233
+
234
+ @mcp.tool()
235
+ def list_handoffs(
236
+ working_dir: str = "",
237
+ limit: int = 10,
238
+ ) -> str:
239
+ """List saved handoff messages.
240
+
241
+ Args:
242
+ working_dir: Filter by working directory. If empty, lists all.
243
+ limit: Max number of handoffs to return (default 10).
244
+ """
245
+ files = _list_handoff_files()
246
+ if not files:
247
+ return "No handoffs saved yet."
248
+
249
+ if working_dir:
250
+ slug = _project_slug(working_dir)
251
+ files = [f for f in files if slug in f.stem]
252
+
253
+ if not files:
254
+ return f"No handoffs found for: {working_dir}"
255
+
256
+ files = files[:limit]
257
+ lines = []
258
+ for f in files:
259
+ payload = json.loads(f.read_text(encoding="utf-8"))
260
+ preview = payload["message"][:80].replace("\n", " ")
261
+ lines.append(
262
+ f" [{payload['id']}]\n"
263
+ f" Project: {payload['project_name']}\n"
264
+ f" Saved: {payload['created_at']}\n"
265
+ f" Dir: {payload['working_dir']}\n"
266
+ f" Preview: {preview}..."
267
+ )
268
+
269
+ return f"Found {len(files)} handoff(s):\n\n" + "\n\n".join(lines)
270
+
271
+
272
+ @mcp.tool()
273
+ def delete_handoff(
274
+ handoff_id: str = "",
275
+ delete_all: bool = False,
276
+ ) -> str:
277
+ """Delete a saved handoff or all handoffs.
278
+
279
+ Args:
280
+ handoff_id: The ID of the handoff to delete. Required unless delete_all is True.
281
+ delete_all: If True, deletes ALL saved handoffs. Use with caution.
282
+ """
283
+ if delete_all:
284
+ files = _list_handoff_files()
285
+ count = len(files)
286
+ for f in files:
287
+ f.unlink()
288
+ return f"Deleted all {count} handoff(s)."
289
+
290
+ if not handoff_id:
291
+ return "Error: provide a handoff_id or set delete_all=True."
292
+
293
+ path = _handoff_path(handoff_id)
294
+ if not path.exists():
295
+ return f"Error: No handoff found with ID '{handoff_id}'."
296
+
297
+ path.unlink()
298
+ return f"Deleted handoff: {handoff_id}"
299
+
300
+
301
+ # ---------------------------------------------------------------------------
302
+ # Entry point
303
+ # ---------------------------------------------------------------------------
304
+ def main() -> None:
305
+ """CLI entry point for the MCP server."""
306
+ mcp.run(transport="stdio")
307
+
308
+
309
+ if __name__ == "__main__":
310
+ main()