@mseep/csv-editor 1.0.0
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.
- package/.github/ISSUE_TEMPLATE/bug_report.md +53 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +38 -0
- package/.github/workflows/deploy-docs.yml +62 -0
- package/.github/workflows/publish-github.yml +52 -0
- package/.github/workflows/publish.yml +44 -0
- package/.github/workflows/test.yml +32 -0
- package/.pre-commit-config.yaml +157 -0
- package/ALTERNATIVE_PUBLISHING.md +175 -0
- package/ARCHITECTURE.md +1011 -0
- package/CHANGELOG.md +99 -0
- package/CODE_OF_CONDUCT.md +41 -0
- package/CONTRIBUTING.md +427 -0
- package/Dockerfile +22 -0
- package/LICENSE +21 -0
- package/MCP_CONFIG.md +505 -0
- package/PUBLISHING.md +210 -0
- package/README.md +400 -0
- package/SECURITY.md +61 -0
- package/docs/README.md +41 -0
- package/docs/blog/2019-05-28-first-blog-post.md +12 -0
- package/docs/blog/2019-05-29-long-blog-post.md +44 -0
- package/docs/blog/2021-08-01-mdx-blog-post.mdx +24 -0
- package/docs/blog/2021-08-26-welcome/docusaurus-plushie-banner.jpeg +0 -0
- package/docs/blog/2021-08-26-welcome/index.md +29 -0
- package/docs/blog/authors.yml +25 -0
- package/docs/blog/tags.yml +19 -0
- package/docs/docs/api/overview.md +183 -0
- package/docs/docs/installation.md +252 -0
- package/docs/docs/intro.md +87 -0
- package/docs/docs/tutorial-basics/_category_.json +8 -0
- package/docs/docs/tutorial-basics/congratulations.md +23 -0
- package/docs/docs/tutorial-basics/create-a-blog-post.md +34 -0
- package/docs/docs/tutorial-basics/create-a-document.md +57 -0
- package/docs/docs/tutorial-basics/create-a-page.md +43 -0
- package/docs/docs/tutorial-basics/deploy-your-site.md +31 -0
- package/docs/docs/tutorial-basics/markdown-features.mdx +152 -0
- package/docs/docs/tutorial-extras/_category_.json +7 -0
- package/docs/docs/tutorial-extras/img/docsVersionDropdown.png +0 -0
- package/docs/docs/tutorial-extras/img/localeDropdown.png +0 -0
- package/docs/docs/tutorial-extras/manage-docs-versions.md +55 -0
- package/docs/docs/tutorial-extras/translate-your-site.md +88 -0
- package/docs/docs/tutorials/quickstart.md +365 -0
- package/docs/docusaurus.config.ts +163 -0
- package/docs/package-lock.json +17493 -0
- package/docs/package.json +48 -0
- package/docs/sidebars.ts +33 -0
- package/docs/src/components/HomepageFeatures/index.tsx +71 -0
- package/docs/src/components/HomepageFeatures/styles.module.css +11 -0
- package/docs/src/css/custom.css +30 -0
- package/docs/src/pages/index.module.css +23 -0
- package/docs/src/pages/index.tsx +44 -0
- package/docs/src/pages/markdown-page.md +7 -0
- package/docs/static/.nojekyll +0 -0
- package/docs/static/img/docusaurus-social-card.jpg +0 -0
- package/docs/static/img/docusaurus.png +0 -0
- package/docs/static/img/favicon.ico +0 -0
- package/docs/static/img/logo.svg +1 -0
- package/docs/static/img/undraw_docusaurus_mountain.svg +171 -0
- package/docs/static/img/undraw_docusaurus_react.svg +170 -0
- package/docs/static/img/undraw_docusaurus_tree.svg +40 -0
- package/docs/tsconfig.json +8 -0
- package/examples/README.md +48 -0
- package/examples/auto_save_demo.py +206 -0
- package/examples/auto_save_overwrite.py +201 -0
- package/examples/basic_usage.py +135 -0
- package/examples/demo.py +139 -0
- package/examples/history_demo.py +317 -0
- package/examples/test_default_autosave.py +124 -0
- package/examples/update_consignee_example.py +179 -0
- package/package.json +51 -0
- package/plans/2026-04-19-fastmcp3-migration-plan.md +1045 -0
- package/pyproject.toml +331 -0
- package/requirements-dev.txt +30 -0
- package/requirements.txt +22 -0
- package/scripts/publish.py +67 -0
- package/smithery.yaml +15 -0
- package/specs/2026-04-19-fastmcp3-migration-design.md +243 -0
- package/src/csv_editor/__init__.py +8 -0
- package/src/csv_editor/models/__init__.py +39 -0
- package/src/csv_editor/models/auto_save.py +246 -0
- package/src/csv_editor/models/csv_session.py +468 -0
- package/src/csv_editor/models/data_models.py +244 -0
- package/src/csv_editor/models/history_manager.py +456 -0
- package/src/csv_editor/prompts/__init__.py +0 -0
- package/src/csv_editor/prompts/data_prompts.py +13 -0
- package/src/csv_editor/resources/__init__.py +0 -0
- package/src/csv_editor/resources/csv_resources.py +22 -0
- package/src/csv_editor/server.py +640 -0
- package/src/csv_editor/tools/__init__.py +5 -0
- package/src/csv_editor/tools/analytics.py +700 -0
- package/src/csv_editor/tools/auto_save_operations.py +235 -0
- package/src/csv_editor/tools/data_operations.py +3 -0
- package/src/csv_editor/tools/history_operations.py +315 -0
- package/src/csv_editor/tools/io_operations.py +431 -0
- package/src/csv_editor/tools/transformations.py +663 -0
- package/src/csv_editor/tools/validation.py +822 -0
- package/src/csv_editor/utils/__init__.py +0 -0
- package/src/csv_editor/utils/validators.py +205 -0
- package/tests/README.md +65 -0
- package/tests/__init__.py +7 -0
- package/tests/conftest.py +50 -0
- package/tests/test_auto_save.py +378 -0
- package/tests/test_basic.py +103 -0
- package/tests/test_integration.py +356 -0
- package/tests/test_server_boot.py +50 -0
- package/tests/test_settings.py +184 -0
|
@@ -0,0 +1,1045 @@
|
|
|
1
|
+
# FastMCP 3 Migration + v2.0.0 Implementation Plan
|
|
2
|
+
|
|
3
|
+
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
|
4
|
+
|
|
5
|
+
**Goal:** Ship `csv-editor` v2.0.0 with Python 3.11 floor, FastMCP 3.2, non-breaking dep bumps, SSE transport removed, and automated test CI — as four sequential PRs against `main`.
|
|
6
|
+
|
|
7
|
+
**Architecture:** Phased rollout — each PR is independently reviewable, lands on `main`, and is green in CI before the next begins. No long-lived release branch. Four PRs total:
|
|
8
|
+
1. Add CI test workflow
|
|
9
|
+
2. Python floor 3.11 + non-breaking dep bumps
|
|
10
|
+
3. FastMCP 2 → 3 migration + SSE removal
|
|
11
|
+
4. CHANGELOG + version bump + v2.0.0 tag
|
|
12
|
+
|
|
13
|
+
**Tech Stack:** Python 3.11+, FastMCP 3.2, pydantic 2.13, pyarrow 23, pytest 8, uv, GitHub Actions.
|
|
14
|
+
|
|
15
|
+
**Spec:** [`specs/2026-04-19-fastmcp3-migration-design.md`](../specs/2026-04-19-fastmcp3-migration-design.md)
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## File Structure
|
|
20
|
+
|
|
21
|
+
**New files:**
|
|
22
|
+
- `.github/workflows/test.yml` — pytest matrix workflow
|
|
23
|
+
- `tests/test_server_boot.py` — regression tests for server boot, tool registry, SSE rejection
|
|
24
|
+
|
|
25
|
+
**Modified files:**
|
|
26
|
+
- `pyproject.toml` — Python floor, classifiers, deps, tool target-versions, version bump
|
|
27
|
+
- `src/csv_editor/server.py` — argparse `--transport` choices, `health_check` version
|
|
28
|
+
- `README.md` — Python badge, remove 3.8/3.9 claims, remove SSE references
|
|
29
|
+
- `Dockerfile` — pin base image to `python:3.11-slim-bookworm`
|
|
30
|
+
- `MCP_CONFIG.md` — remove SSE references
|
|
31
|
+
- `CONTRIBUTING.md` — add `.venv` rebuild note
|
|
32
|
+
- `CHANGELOG.md` — new `[2.0.0]` section
|
|
33
|
+
|
|
34
|
+
**Unchanged (verify only):**
|
|
35
|
+
- `smithery.yaml` — uses stdio transport only; no SSE reference
|
|
36
|
+
- `.github/workflows/publish.yml`, `publish-github.yml`, `deploy-docs.yml` — unrelated
|
|
37
|
+
- `src/csv_editor/tools/*.py` — no code changes needed
|
|
38
|
+
- `src/csv_editor/models/*.py` — no code changes needed
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Pre-flight: Fix local dev environment
|
|
43
|
+
|
|
44
|
+
The maintainer's `.venv` points at a removed conda interpreter. This blocks local test runs. Fix once before starting.
|
|
45
|
+
|
|
46
|
+
### Task 0: Rebuild local venv
|
|
47
|
+
|
|
48
|
+
**Files:** none (local only)
|
|
49
|
+
|
|
50
|
+
- [ ] **Step 1: Remove broken venv**
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
rm -rf .venv
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
- [ ] **Step 2: Verify uv is installed**
|
|
57
|
+
|
|
58
|
+
Run: `uv --version`
|
|
59
|
+
Expected: prints a version (e.g., `uv 0.5.x`). If not: `curl -LsSf https://astral.sh/uv/install.sh | sh`
|
|
60
|
+
|
|
61
|
+
- [ ] **Step 3: Sync dependencies**
|
|
62
|
+
|
|
63
|
+
Run: `uv sync --all-extras`
|
|
64
|
+
Expected: creates fresh `.venv/`, installs deps, exits 0.
|
|
65
|
+
|
|
66
|
+
- [ ] **Step 4: Verify tests can run**
|
|
67
|
+
|
|
68
|
+
Run: `uv run pytest tests/ --collect-only -q`
|
|
69
|
+
Expected: pytest collects test files without import errors. Record the total count in a scratch note (needed for PR 1 baseline).
|
|
70
|
+
|
|
71
|
+
- [ ] **Step 5: Run full suite to establish baseline**
|
|
72
|
+
|
|
73
|
+
Run: `uv run pytest tests/ -v`
|
|
74
|
+
Expected: tests execute; record PASS/FAIL counts. Any failures are pre-existing and not this plan's concern — they'll be tracked as a follow-up issue in Task 5.
|
|
75
|
+
|
|
76
|
+
No commit for Task 0 (local-only, `.venv` is gitignored).
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## PR 1: CI Workflow Baseline
|
|
81
|
+
|
|
82
|
+
**Branch name:** `ci/add-test-workflow`
|
|
83
|
+
**Goal:** add pytest matrix GitHub Actions workflow that runs on every PR and push to main.
|
|
84
|
+
|
|
85
|
+
### Task 1: Add test workflow file
|
|
86
|
+
|
|
87
|
+
**Files:**
|
|
88
|
+
- Create: `.github/workflows/test.yml`
|
|
89
|
+
|
|
90
|
+
- [ ] **Step 1: Create branch**
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
git checkout main
|
|
94
|
+
git pull --ff-only origin main
|
|
95
|
+
git checkout -b ci/add-test-workflow
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
- [ ] **Step 2: Write the workflow file**
|
|
99
|
+
|
|
100
|
+
Create `.github/workflows/test.yml` with:
|
|
101
|
+
|
|
102
|
+
```yaml
|
|
103
|
+
name: test
|
|
104
|
+
|
|
105
|
+
on:
|
|
106
|
+
pull_request:
|
|
107
|
+
push:
|
|
108
|
+
branches: [main]
|
|
109
|
+
|
|
110
|
+
jobs:
|
|
111
|
+
pytest:
|
|
112
|
+
runs-on: ubuntu-latest
|
|
113
|
+
strategy:
|
|
114
|
+
fail-fast: false
|
|
115
|
+
matrix:
|
|
116
|
+
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
|
|
117
|
+
steps:
|
|
118
|
+
- uses: actions/checkout@v4
|
|
119
|
+
|
|
120
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
121
|
+
uses: actions/setup-python@v5
|
|
122
|
+
with:
|
|
123
|
+
python-version: ${{ matrix.python-version }}
|
|
124
|
+
|
|
125
|
+
- name: Install uv
|
|
126
|
+
uses: astral-sh/setup-uv@v4
|
|
127
|
+
with:
|
|
128
|
+
enable-cache: true
|
|
129
|
+
|
|
130
|
+
- name: Sync dependencies
|
|
131
|
+
run: uv sync --all-extras
|
|
132
|
+
|
|
133
|
+
- name: Run pytest
|
|
134
|
+
run: uv run pytest tests/ -v --tb=short
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
- [ ] **Step 3: Commit**
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
git add .github/workflows/test.yml
|
|
141
|
+
git commit -m "ci: add pytest matrix workflow (3.10-3.14 on ubuntu)"
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
- [ ] **Step 4: Push and open PR**
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
git push -u origin ci/add-test-workflow
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Then open a PR on GitHub with title `ci: add pytest matrix workflow` and body describing: "Adds a GitHub Actions workflow that runs pytest on Python 3.10–3.14 for every PR and push to main. Prerequisite for PR 2 (dep bumps) and PR 3 (FastMCP 3 migration)."
|
|
151
|
+
|
|
152
|
+
- [ ] **Step 5: Verify workflow triggers**
|
|
153
|
+
|
|
154
|
+
On the PR page, confirm a `test` check appears. Wait for matrix to complete.
|
|
155
|
+
|
|
156
|
+
Expected: All 5 matrix rows complete (green or red is both OK — the runner existing is the deliverable).
|
|
157
|
+
|
|
158
|
+
- [ ] **Step 6: Document baseline result**
|
|
159
|
+
|
|
160
|
+
If any rows are red, open a new GitHub issue titled "Pre-existing test failures on main" listing the failing tests per Python version. Link the issue in the PR description.
|
|
161
|
+
|
|
162
|
+
If all green: note that in the PR description ("baseline clean").
|
|
163
|
+
|
|
164
|
+
- [ ] **Step 7: Merge PR 1**
|
|
165
|
+
|
|
166
|
+
Merge via GitHub UI (squash merge). Confirm `main` now runs the workflow on subsequent pushes.
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## PR 2: Python 3.11 Floor + Non-Breaking Dep Bumps
|
|
171
|
+
|
|
172
|
+
**Branch name:** `deps/python-311-and-bumps`
|
|
173
|
+
**Goal:** bump Python floor and non-breaking dependencies; update tooling target-versions; CI matrix drops 3.10.
|
|
174
|
+
|
|
175
|
+
### Task 2: Create branch and bump Python floor in pyproject.toml
|
|
176
|
+
|
|
177
|
+
**Files:**
|
|
178
|
+
- Modify: `pyproject.toml`
|
|
179
|
+
|
|
180
|
+
- [ ] **Step 1: Create branch**
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
git checkout main
|
|
184
|
+
git pull --ff-only origin main
|
|
185
|
+
git checkout -b deps/python-311-and-bumps
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
- [ ] **Step 2: Bump `requires-python` and classifiers**
|
|
189
|
+
|
|
190
|
+
In `pyproject.toml`:
|
|
191
|
+
|
|
192
|
+
Change:
|
|
193
|
+
```toml
|
|
194
|
+
requires-python = ">=3.10"
|
|
195
|
+
```
|
|
196
|
+
to:
|
|
197
|
+
```toml
|
|
198
|
+
requires-python = ">=3.11"
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Change classifiers from:
|
|
202
|
+
```toml
|
|
203
|
+
"Programming Language :: Python :: 3.8",
|
|
204
|
+
"Programming Language :: Python :: 3.9",
|
|
205
|
+
"Programming Language :: Python :: 3.10",
|
|
206
|
+
"Programming Language :: Python :: 3.11",
|
|
207
|
+
"Programming Language :: Python :: 3.12",
|
|
208
|
+
"Programming Language :: Python :: 3.13",
|
|
209
|
+
```
|
|
210
|
+
to:
|
|
211
|
+
```toml
|
|
212
|
+
"Programming Language :: Python :: 3.11",
|
|
213
|
+
"Programming Language :: Python :: 3.12",
|
|
214
|
+
"Programming Language :: Python :: 3.13",
|
|
215
|
+
"Programming Language :: Python :: 3.14",
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
(Delete the 3.8, 3.9, 3.10 lines; add the 3.14 line.)
|
|
219
|
+
|
|
220
|
+
- [ ] **Step 3: Commit**
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
git add pyproject.toml
|
|
224
|
+
git commit -m "chore: bump Python floor to 3.11, add 3.14 classifier"
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### Task 3: Bump non-breaking dependencies
|
|
228
|
+
|
|
229
|
+
**Files:**
|
|
230
|
+
- Modify: `pyproject.toml`
|
|
231
|
+
|
|
232
|
+
- [ ] **Step 1: Update dependency pins**
|
|
233
|
+
|
|
234
|
+
In `pyproject.toml`, change the `dependencies` block from:
|
|
235
|
+
|
|
236
|
+
```toml
|
|
237
|
+
dependencies = [
|
|
238
|
+
"fastmcp>=2.11.3",
|
|
239
|
+
"pandas>=2.2.3",
|
|
240
|
+
"numpy>=2.1.3",
|
|
241
|
+
"pydantic>=2.10.4",
|
|
242
|
+
"aiofiles>=24.1.0",
|
|
243
|
+
"python-dateutil>=2.9.0",
|
|
244
|
+
"httpx>=0.27.0",
|
|
245
|
+
"openpyxl>=3.1.5",
|
|
246
|
+
"pyarrow>=17.0.0",
|
|
247
|
+
"tabulate>=0.9.0",
|
|
248
|
+
"pytz>=2024.2",
|
|
249
|
+
"pydantic-settings>=2.10.1",
|
|
250
|
+
]
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
to (note: `fastmcp` pin is **unchanged** in this PR; PR 3 handles it):
|
|
254
|
+
|
|
255
|
+
```toml
|
|
256
|
+
dependencies = [
|
|
257
|
+
"fastmcp>=2.11.3",
|
|
258
|
+
"pandas>=2.2.3",
|
|
259
|
+
"numpy>=2.1.3",
|
|
260
|
+
"pydantic>=2.13",
|
|
261
|
+
"aiofiles>=25",
|
|
262
|
+
"python-dateutil>=2.9.0",
|
|
263
|
+
"httpx>=0.28",
|
|
264
|
+
"openpyxl>=3.1.5",
|
|
265
|
+
"pyarrow>=23",
|
|
266
|
+
"tabulate>=0.10",
|
|
267
|
+
"pytz>=2024.2",
|
|
268
|
+
"pydantic-settings>=2.13",
|
|
269
|
+
]
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
- [ ] **Step 2: Sync and run tests locally**
|
|
273
|
+
|
|
274
|
+
```bash
|
|
275
|
+
uv sync --all-extras
|
|
276
|
+
uv run pytest tests/ -v --tb=short
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
Expected: tests execute; pass rate matches PR 1 baseline (from Task 0 Step 5 / Task 1 Step 6).
|
|
280
|
+
|
|
281
|
+
If any test that was green on baseline now fails, **stop**: the bump introduced a regression. Bisect by reverting dep pins one at a time to identify which dep caused it. Most likely suspect: pydantic 2.13 union serialization. Hotfix by pinning `pydantic<2.13` and opening a follow-up issue.
|
|
282
|
+
|
|
283
|
+
- [ ] **Step 3: Commit**
|
|
284
|
+
|
|
285
|
+
```bash
|
|
286
|
+
git add pyproject.toml
|
|
287
|
+
git commit -m "chore: bump non-breaking deps (pydantic 2.13, pyarrow 23, httpx 0.28, aiofiles 25, tabulate 0.10)"
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
### Task 4: Bump tool target-versions
|
|
291
|
+
|
|
292
|
+
**Files:**
|
|
293
|
+
- Modify: `pyproject.toml`
|
|
294
|
+
|
|
295
|
+
- [ ] **Step 1: Update black target-version**
|
|
296
|
+
|
|
297
|
+
In `pyproject.toml`:
|
|
298
|
+
|
|
299
|
+
Change:
|
|
300
|
+
```toml
|
|
301
|
+
[tool.black]
|
|
302
|
+
line-length = 100
|
|
303
|
+
target-version = ["py38", "py39", "py310", "py311", "py312", "py313"]
|
|
304
|
+
```
|
|
305
|
+
to:
|
|
306
|
+
```toml
|
|
307
|
+
[tool.black]
|
|
308
|
+
line-length = 100
|
|
309
|
+
target-version = ["py311", "py312", "py313", "py314"]
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
- [ ] **Step 2: Update ruff target-version**
|
|
313
|
+
|
|
314
|
+
Change:
|
|
315
|
+
```toml
|
|
316
|
+
[tool.ruff]
|
|
317
|
+
line-length = 100
|
|
318
|
+
target-version = "py38"
|
|
319
|
+
```
|
|
320
|
+
to:
|
|
321
|
+
```toml
|
|
322
|
+
[tool.ruff]
|
|
323
|
+
line-length = 100
|
|
324
|
+
target-version = "py311"
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
- [ ] **Step 3: Update mypy python_version**
|
|
328
|
+
|
|
329
|
+
Change:
|
|
330
|
+
```toml
|
|
331
|
+
[tool.mypy]
|
|
332
|
+
python_version = "3.8"
|
|
333
|
+
```
|
|
334
|
+
to:
|
|
335
|
+
```toml
|
|
336
|
+
[tool.mypy]
|
|
337
|
+
python_version = "3.11"
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
- [ ] **Step 4: Run linters to confirm no regressions**
|
|
341
|
+
|
|
342
|
+
```bash
|
|
343
|
+
uv run ruff check src/ tests/
|
|
344
|
+
uv run black --check src/ tests/
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
Expected: both exit 0 (no formatting/lint changes needed from the target-version bump alone).
|
|
348
|
+
|
|
349
|
+
If ruff suggests any `UP` (pyupgrade) rule changes because 3.11+ is now the floor, accept them as a separate step below.
|
|
350
|
+
|
|
351
|
+
- [ ] **Step 5: If ruff proposed UP fixes, apply them**
|
|
352
|
+
|
|
353
|
+
```bash
|
|
354
|
+
uv run ruff check src/ tests/ --fix
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
- [ ] **Step 6: Re-run tests**
|
|
358
|
+
|
|
359
|
+
```bash
|
|
360
|
+
uv run pytest tests/ -v --tb=short
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
Expected: pass rate matches baseline.
|
|
364
|
+
|
|
365
|
+
- [ ] **Step 7: Commit**
|
|
366
|
+
|
|
367
|
+
```bash
|
|
368
|
+
git add pyproject.toml src/ tests/
|
|
369
|
+
git commit -m "chore: bump black/ruff/mypy target-version to Python 3.11"
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
### Task 5: Update Dockerfile, README, CONTRIBUTING
|
|
373
|
+
|
|
374
|
+
**Files:**
|
|
375
|
+
- Modify: `Dockerfile`
|
|
376
|
+
- Modify: `README.md`
|
|
377
|
+
- Modify: `CONTRIBUTING.md`
|
|
378
|
+
|
|
379
|
+
- [ ] **Step 1: Pin Dockerfile base image**
|
|
380
|
+
|
|
381
|
+
In `Dockerfile`, change line 2 from:
|
|
382
|
+
```dockerfile
|
|
383
|
+
FROM python:3.11-slim
|
|
384
|
+
```
|
|
385
|
+
to:
|
|
386
|
+
```dockerfile
|
|
387
|
+
FROM python:3.11-slim-bookworm
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
- [ ] **Step 2: Update README Python badge**
|
|
391
|
+
|
|
392
|
+
In `README.md`, find the Python badge near the top:
|
|
393
|
+
```markdown
|
|
394
|
+
[](https://www.python.org/)
|
|
395
|
+
```
|
|
396
|
+
Change to:
|
|
397
|
+
```markdown
|
|
398
|
+
[](https://www.python.org/)
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
- [ ] **Step 3: Scrub 3.8/3.9/3.10 claims from README**
|
|
402
|
+
|
|
403
|
+
Grep: `grep -n "3\.8\|3\.9\|3\.10" README.md`
|
|
404
|
+
|
|
405
|
+
For each match, update the sentence to reflect the 3.11 floor (or delete if the line is an obsolete compatibility note). Do **not** touch version numbers of libraries that happen to contain these digits.
|
|
406
|
+
|
|
407
|
+
- [ ] **Step 4: Add .venv rebuild note to CONTRIBUTING.md**
|
|
408
|
+
|
|
409
|
+
In `CONTRIBUTING.md`, find the "Development Setup" or equivalent section. Add (or update if one exists) a subsection:
|
|
410
|
+
|
|
411
|
+
```markdown
|
|
412
|
+
### Rebuilding the local virtualenv
|
|
413
|
+
|
|
414
|
+
If your `.venv/` points at a missing Python interpreter (common after upgrading Python or removing a conda env), rebuild it:
|
|
415
|
+
|
|
416
|
+
```bash
|
|
417
|
+
rm -rf .venv
|
|
418
|
+
uv sync --all-extras
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
This requires Python 3.11+ available on your PATH (3.14 recommended).
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
If `CONTRIBUTING.md` has no "Development Setup" section, append the subsection at the end of the file with a `## Development` heading.
|
|
425
|
+
|
|
426
|
+
- [ ] **Step 5: Commit**
|
|
427
|
+
|
|
428
|
+
```bash
|
|
429
|
+
git add Dockerfile README.md CONTRIBUTING.md
|
|
430
|
+
git commit -m "docs: pin Dockerfile base, update README badge, add venv rebuild guide"
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
### Task 6: Drop Python 3.10 from CI matrix
|
|
434
|
+
|
|
435
|
+
**Files:**
|
|
436
|
+
- Modify: `.github/workflows/test.yml`
|
|
437
|
+
|
|
438
|
+
- [ ] **Step 1: Remove 3.10 from matrix**
|
|
439
|
+
|
|
440
|
+
In `.github/workflows/test.yml`, change:
|
|
441
|
+
```yaml
|
|
442
|
+
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
|
|
443
|
+
```
|
|
444
|
+
to:
|
|
445
|
+
```yaml
|
|
446
|
+
python-version: ["3.11", "3.12", "3.13", "3.14"]
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
- [ ] **Step 2: Commit**
|
|
450
|
+
|
|
451
|
+
```bash
|
|
452
|
+
git add .github/workflows/test.yml
|
|
453
|
+
git commit -m "ci: drop Python 3.10 from matrix (floor bumped to 3.11)"
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
### Task 7: Push and merge PR 2
|
|
457
|
+
|
|
458
|
+
- [ ] **Step 1: Push branch**
|
|
459
|
+
|
|
460
|
+
```bash
|
|
461
|
+
git push -u origin deps/python-311-and-bumps
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
- [ ] **Step 2: Open PR**
|
|
465
|
+
|
|
466
|
+
Title: `deps: bump Python floor to 3.11 and non-breaking dependencies`
|
|
467
|
+
Body: "Bumps Python floor from 3.10 to 3.11. Bumps pydantic, pydantic-settings, pyarrow, httpx, aiofiles, tabulate to current major versions. FastMCP and pandas are **not** bumped in this PR. Drops 3.10 from CI matrix. Part of v2.0.0 preparation (spec: `specs/2026-04-19-fastmcp3-migration-design.md`)."
|
|
468
|
+
|
|
469
|
+
- [ ] **Step 3: Wait for CI green**
|
|
470
|
+
|
|
471
|
+
All four matrix rows (3.11, 3.12, 3.13, 3.14) must be green.
|
|
472
|
+
|
|
473
|
+
If red on pydantic 2.13: follow the risk mitigation in the spec (pin `pydantic<2.13`, open issue).
|
|
474
|
+
|
|
475
|
+
- [ ] **Step 4: Merge**
|
|
476
|
+
|
|
477
|
+
Squash merge via GitHub UI. Delete the branch.
|
|
478
|
+
|
|
479
|
+
---
|
|
480
|
+
|
|
481
|
+
## PR 3: FastMCP 3 Migration + SSE Removal
|
|
482
|
+
|
|
483
|
+
**Branch name:** `feat/fastmcp-3-migration`
|
|
484
|
+
**Goal:** bump FastMCP to 3.2; remove `sse` from CLI `--transport` choices; add boot regression tests.
|
|
485
|
+
|
|
486
|
+
### Task 8: Create branch and add failing boot tests
|
|
487
|
+
|
|
488
|
+
**Files:**
|
|
489
|
+
- Create: `tests/test_server_boot.py`
|
|
490
|
+
|
|
491
|
+
- [ ] **Step 1: Create branch**
|
|
492
|
+
|
|
493
|
+
```bash
|
|
494
|
+
git checkout main
|
|
495
|
+
git pull --ff-only origin main
|
|
496
|
+
git checkout -b feat/fastmcp-3-migration
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
- [ ] **Step 2: Write test file**
|
|
500
|
+
|
|
501
|
+
Create `tests/test_server_boot.py`:
|
|
502
|
+
|
|
503
|
+
```python
|
|
504
|
+
"""Smoke tests for server boot, tool registry, and CLI argument handling."""
|
|
505
|
+
|
|
506
|
+
import pytest
|
|
507
|
+
|
|
508
|
+
|
|
509
|
+
def test_server_imports_clean():
|
|
510
|
+
"""Importing the server module must not raise."""
|
|
511
|
+
import csv_editor.server # noqa: F401
|
|
512
|
+
|
|
513
|
+
|
|
514
|
+
def test_tool_registry_populated():
|
|
515
|
+
"""After import, the FastMCP instance must have at least 40 registered tools."""
|
|
516
|
+
from csv_editor.server import mcp
|
|
517
|
+
|
|
518
|
+
# FastMCP exposes registered tools via _tool_manager in 3.x; fall back to list_tools-style APIs
|
|
519
|
+
# if the attribute name differs. We probe several plausible locations to stay robust.
|
|
520
|
+
tool_count = _count_registered_tools(mcp)
|
|
521
|
+
|
|
522
|
+
assert tool_count >= 40, f"Expected at least 40 tools registered, got {tool_count}"
|
|
523
|
+
|
|
524
|
+
|
|
525
|
+
def test_cli_rejects_sse_transport():
|
|
526
|
+
"""The CLI must reject --transport sse with a non-zero exit."""
|
|
527
|
+
from csv_editor.server import main
|
|
528
|
+
|
|
529
|
+
with pytest.raises(SystemExit) as exc_info:
|
|
530
|
+
main(["--transport", "sse"]) # argparse exits on invalid choice
|
|
531
|
+
|
|
532
|
+
# argparse uses exit code 2 for argument errors
|
|
533
|
+
assert exc_info.value.code == 2
|
|
534
|
+
|
|
535
|
+
|
|
536
|
+
def _count_registered_tools(mcp) -> int:
|
|
537
|
+
"""Robustly count registered tools across FastMCP 2.x/3.x attribute naming."""
|
|
538
|
+
for attr in ("_tool_manager", "tool_manager", "_tools", "tools"):
|
|
539
|
+
obj = getattr(mcp, attr, None)
|
|
540
|
+
if obj is None:
|
|
541
|
+
continue
|
|
542
|
+
tools = getattr(obj, "_tools", None) or getattr(obj, "tools", None) or obj
|
|
543
|
+
try:
|
|
544
|
+
return len(tools)
|
|
545
|
+
except TypeError:
|
|
546
|
+
continue
|
|
547
|
+
# Fall back to calling a list-tools coroutine if present (FastMCP 3)
|
|
548
|
+
list_tools = getattr(mcp, "list_tools", None)
|
|
549
|
+
if callable(list_tools):
|
|
550
|
+
import asyncio
|
|
551
|
+
result = asyncio.run(list_tools())
|
|
552
|
+
return len(result)
|
|
553
|
+
raise RuntimeError("Could not locate FastMCP tool registry")
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
- [ ] **Step 3: Run the tests — two must fail**
|
|
557
|
+
|
|
558
|
+
```bash
|
|
559
|
+
uv run pytest tests/test_server_boot.py -v
|
|
560
|
+
```
|
|
561
|
+
|
|
562
|
+
Expected:
|
|
563
|
+
- `test_server_imports_clean` — **PASS** (server already imports cleanly)
|
|
564
|
+
- `test_tool_registry_populated` — **PASS or FAIL** depending on how FastMCP 2.11 exposes the registry; if FAIL, the `_count_registered_tools` helper needs adjustment. If you cannot locate the registry in 2.x, mark the test `@pytest.mark.skip(reason="registry location verified after FastMCP 3 migration")` and remove the skip in Task 10.
|
|
565
|
+
- `test_cli_rejects_sse_transport` — **FAIL**: `sse` is currently a valid choice, so `main` will proceed rather than SystemExit. This is the red we want — PR 3 will turn it green.
|
|
566
|
+
|
|
567
|
+
Note: `main` is defined but does not currently accept `argv` as a parameter. You will need to refactor `main` in Task 9 to accept `argv: list[str] | None = None` so tests can invoke it. Record this as a prerequisite for Task 9.
|
|
568
|
+
|
|
569
|
+
- [ ] **Step 4: Commit the failing tests**
|
|
570
|
+
|
|
571
|
+
```bash
|
|
572
|
+
git add tests/test_server_boot.py
|
|
573
|
+
git commit -m "test: add server boot + CLI regression tests (one intentionally failing)"
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
### Task 9: Refactor `main` to accept argv and drop `sse` choice
|
|
577
|
+
|
|
578
|
+
**Files:**
|
|
579
|
+
- Modify: `src/csv_editor/server.py` (lines around 635–679)
|
|
580
|
+
|
|
581
|
+
- [ ] **Step 1: Refactor `main` signature**
|
|
582
|
+
|
|
583
|
+
In `src/csv_editor/server.py`, change the `def main():` line to accept an optional argv parameter. Change the `parser.parse_args()` call to pass `argv` through.
|
|
584
|
+
|
|
585
|
+
Find:
|
|
586
|
+
```python
|
|
587
|
+
def main():
|
|
588
|
+
"""Main entry point for the server."""
|
|
589
|
+
import argparse
|
|
590
|
+
|
|
591
|
+
parser = argparse.ArgumentParser(description="CSV Editor")
|
|
592
|
+
```
|
|
593
|
+
|
|
594
|
+
Change to:
|
|
595
|
+
```python
|
|
596
|
+
def main(argv: list[str] | None = None):
|
|
597
|
+
"""Main entry point for the server."""
|
|
598
|
+
import argparse
|
|
599
|
+
|
|
600
|
+
parser = argparse.ArgumentParser(description="CSV Editor")
|
|
601
|
+
```
|
|
602
|
+
|
|
603
|
+
Find:
|
|
604
|
+
```python
|
|
605
|
+
args = parser.parse_args()
|
|
606
|
+
```
|
|
607
|
+
|
|
608
|
+
Change to:
|
|
609
|
+
```python
|
|
610
|
+
args = parser.parse_args(argv)
|
|
611
|
+
```
|
|
612
|
+
|
|
613
|
+
- [ ] **Step 2: Drop `sse` from `--transport` choices**
|
|
614
|
+
|
|
615
|
+
Find:
|
|
616
|
+
```python
|
|
617
|
+
parser.add_argument(
|
|
618
|
+
"--transport",
|
|
619
|
+
choices=["stdio", "http", "sse"],
|
|
620
|
+
default="stdio",
|
|
621
|
+
help="Transport method"
|
|
622
|
+
)
|
|
623
|
+
```
|
|
624
|
+
|
|
625
|
+
Change to:
|
|
626
|
+
```python
|
|
627
|
+
parser.add_argument(
|
|
628
|
+
"--transport",
|
|
629
|
+
choices=["stdio", "http"],
|
|
630
|
+
default="stdio",
|
|
631
|
+
help="Transport method (stdio for local clients, http for Streamable HTTP remote)"
|
|
632
|
+
)
|
|
633
|
+
```
|
|
634
|
+
|
|
635
|
+
- [ ] **Step 3: Run tests — expect test_cli_rejects_sse_transport to pass now**
|
|
636
|
+
|
|
637
|
+
```bash
|
|
638
|
+
uv run pytest tests/test_server_boot.py -v
|
|
639
|
+
```
|
|
640
|
+
|
|
641
|
+
Expected: `test_cli_rejects_sse_transport` now **PASS**.
|
|
642
|
+
|
|
643
|
+
- [ ] **Step 4: Commit**
|
|
644
|
+
|
|
645
|
+
```bash
|
|
646
|
+
git add src/csv_editor/server.py
|
|
647
|
+
git commit -m "feat: drop sse from --transport CLI choices, refactor main to accept argv"
|
|
648
|
+
```
|
|
649
|
+
|
|
650
|
+
### Task 10: Bump FastMCP pin to 3.2
|
|
651
|
+
|
|
652
|
+
**Files:**
|
|
653
|
+
- Modify: `pyproject.toml`
|
|
654
|
+
|
|
655
|
+
- [ ] **Step 1: Update FastMCP pin**
|
|
656
|
+
|
|
657
|
+
In `pyproject.toml`, change:
|
|
658
|
+
```toml
|
|
659
|
+
"fastmcp>=2.11.3",
|
|
660
|
+
```
|
|
661
|
+
to:
|
|
662
|
+
```toml
|
|
663
|
+
"fastmcp>=3.2,<4",
|
|
664
|
+
```
|
|
665
|
+
|
|
666
|
+
- [ ] **Step 2: Sync**
|
|
667
|
+
|
|
668
|
+
```bash
|
|
669
|
+
uv sync --all-extras
|
|
670
|
+
```
|
|
671
|
+
|
|
672
|
+
Expected: resolves to FastMCP 3.2.x, no conflicts.
|
|
673
|
+
|
|
674
|
+
- [ ] **Step 3: Run full test suite**
|
|
675
|
+
|
|
676
|
+
```bash
|
|
677
|
+
uv run pytest tests/ -v --tb=short
|
|
678
|
+
```
|
|
679
|
+
|
|
680
|
+
Expected:
|
|
681
|
+
- All three tests in `test_server_boot.py` pass (including `test_tool_registry_populated` — if it was skipped in Task 8 Step 3, remove the skip marker now and confirm pass).
|
|
682
|
+
- Other tests pass at the rate matching baseline.
|
|
683
|
+
|
|
684
|
+
If any tool-decorator test fails due to FastMCP API drift (e.g., `Context` API changed), consult the [FastMCP 3 upgrade guide](https://gofastmcp.com/getting-started/upgrading/from-fastmcp-2) and patch `src/csv_editor/server.py` or the affected tool module. Common fixes:
|
|
685
|
+
- `Context` import path unchanged.
|
|
686
|
+
- Tool decorator (`@mcp.tool`) unchanged.
|
|
687
|
+
- Constructor already minimal (`FastMCP("CSV Editor")`), no kwargs to strip.
|
|
688
|
+
|
|
689
|
+
- [ ] **Step 4: Manually smoke-test stdio transport**
|
|
690
|
+
|
|
691
|
+
Start the server in one terminal:
|
|
692
|
+
```bash
|
|
693
|
+
uv run csv-editor --transport stdio
|
|
694
|
+
```
|
|
695
|
+
|
|
696
|
+
In a second terminal, send a `tools/list` JSON-RPC request via stdin (or use an MCP client like Claude Desktop configured against the local build).
|
|
697
|
+
|
|
698
|
+
Expected: server responds with a list of ≥40 tools.
|
|
699
|
+
|
|
700
|
+
Kill the server with Ctrl-C.
|
|
701
|
+
|
|
702
|
+
- [ ] **Step 5: Manually smoke-test http transport**
|
|
703
|
+
|
|
704
|
+
```bash
|
|
705
|
+
uv run csv-editor --transport http --port 8765
|
|
706
|
+
```
|
|
707
|
+
|
|
708
|
+
In a second terminal:
|
|
709
|
+
```bash
|
|
710
|
+
curl -sv http://127.0.0.1:8765/mcp
|
|
711
|
+
```
|
|
712
|
+
|
|
713
|
+
Expected: HTTP response (likely 400 or 405 for a bare GET, since Streamable HTTP expects JSON-RPC POST — the point is the server bound and is listening, not that curl completes a handshake).
|
|
714
|
+
|
|
715
|
+
Kill the server.
|
|
716
|
+
|
|
717
|
+
- [ ] **Step 6: Commit**
|
|
718
|
+
|
|
719
|
+
```bash
|
|
720
|
+
git add pyproject.toml tests/test_server_boot.py
|
|
721
|
+
git commit -m "feat: migrate to FastMCP 3.2"
|
|
722
|
+
```
|
|
723
|
+
|
|
724
|
+
(`tests/test_server_boot.py` is included in case the skip marker was removed in Step 3.)
|
|
725
|
+
|
|
726
|
+
### Task 11: Scrub SSE references from docs
|
|
727
|
+
|
|
728
|
+
**Files:**
|
|
729
|
+
- Modify: `README.md`
|
|
730
|
+
- Modify: `MCP_CONFIG.md`
|
|
731
|
+
|
|
732
|
+
- [ ] **Step 1: Find SSE references**
|
|
733
|
+
|
|
734
|
+
```bash
|
|
735
|
+
grep -n -i "sse\|server-sent" README.md MCP_CONFIG.md
|
|
736
|
+
```
|
|
737
|
+
|
|
738
|
+
Record each match.
|
|
739
|
+
|
|
740
|
+
- [ ] **Step 2: Update each reference**
|
|
741
|
+
|
|
742
|
+
For each match:
|
|
743
|
+
- If the line documents `--transport sse` as a valid option: **delete** the line or replace with `--transport http`.
|
|
744
|
+
- If the line explains SSE as a transport alternative: **delete** the paragraph.
|
|
745
|
+
- If the line is in a table of transports: **remove the SSE row**.
|
|
746
|
+
|
|
747
|
+
Do not touch any line that happens to contain "SSE" as part of an unrelated word (search is case-insensitive to catch `sse` fragments; verify context before editing).
|
|
748
|
+
|
|
749
|
+
- [ ] **Step 3: Verify no remaining SSE references**
|
|
750
|
+
|
|
751
|
+
```bash
|
|
752
|
+
grep -n -i "sse\|server-sent" README.md MCP_CONFIG.md
|
|
753
|
+
```
|
|
754
|
+
|
|
755
|
+
Expected: no matches (or only matches in unrelated words you've already verified).
|
|
756
|
+
|
|
757
|
+
- [ ] **Step 4: Commit**
|
|
758
|
+
|
|
759
|
+
```bash
|
|
760
|
+
git add README.md MCP_CONFIG.md
|
|
761
|
+
git commit -m "docs: remove SSE transport references"
|
|
762
|
+
```
|
|
763
|
+
|
|
764
|
+
### Task 12: Verify Dockerfile and Smithery config
|
|
765
|
+
|
|
766
|
+
**Files:** none changed (verification only)
|
|
767
|
+
|
|
768
|
+
- [ ] **Step 1: Confirm Dockerfile CMD uses stdio**
|
|
769
|
+
|
|
770
|
+
```bash
|
|
771
|
+
grep "CMD\|ENTRYPOINT" Dockerfile
|
|
772
|
+
```
|
|
773
|
+
|
|
774
|
+
Expected: `CMD ["csv-editor", "--transport", "stdio"]` — no SSE reference.
|
|
775
|
+
|
|
776
|
+
- [ ] **Step 2: Confirm smithery.yaml uses stdio**
|
|
777
|
+
|
|
778
|
+
```bash
|
|
779
|
+
grep -i "transport\|sse\|http" smithery.yaml
|
|
780
|
+
```
|
|
781
|
+
|
|
782
|
+
Expected: references to `stdio` only; no `sse`. If any `sse` appears, fix by replacing with `stdio` (or `http` if the intent was remote) and commit separately with message `fix: update smithery config to stdio-only transport`.
|
|
783
|
+
|
|
784
|
+
### Task 13: Push and merge PR 3
|
|
785
|
+
|
|
786
|
+
- [ ] **Step 1: Push branch**
|
|
787
|
+
|
|
788
|
+
```bash
|
|
789
|
+
git push -u origin feat/fastmcp-3-migration
|
|
790
|
+
```
|
|
791
|
+
|
|
792
|
+
- [ ] **Step 2: Open PR**
|
|
793
|
+
|
|
794
|
+
Title: `feat: FastMCP 3 migration + SSE transport removal`
|
|
795
|
+
Body:
|
|
796
|
+
|
|
797
|
+
```markdown
|
|
798
|
+
## Summary
|
|
799
|
+
- Bumps FastMCP to `>=3.2,<4`
|
|
800
|
+
- Removes `sse` from `--transport` CLI choices (breaking — users should migrate to `--transport http` for remote)
|
|
801
|
+
- Refactors `main()` to accept `argv` for testability
|
|
802
|
+
- Adds `tests/test_server_boot.py` with three regression tests
|
|
803
|
+
- Scrubs SSE references from README and MCP_CONFIG docs
|
|
804
|
+
|
|
805
|
+
## Breaking changes
|
|
806
|
+
- `--transport sse` is no longer accepted. Use `--transport http` (Streamable HTTP) instead.
|
|
807
|
+
- Consumers importing FastMCP APIs transitively may need updates per the [FastMCP 3 upgrade guide](https://gofastmcp.com/getting-started/upgrading/from-fastmcp-2).
|
|
808
|
+
|
|
809
|
+
## Test plan
|
|
810
|
+
- [x] `uv run pytest tests/` green on all four Python matrix rows
|
|
811
|
+
- [x] Manual stdio smoke test via `uv run csv-editor --transport stdio`
|
|
812
|
+
- [x] Manual http smoke test via `uv run csv-editor --transport http --port 8765`
|
|
813
|
+
- [ ] Claude Desktop smoke test — will verify post-merge on a release candidate build
|
|
814
|
+
|
|
815
|
+
Part of v2.0.0 preparation (spec: `specs/2026-04-19-fastmcp3-migration-design.md`).
|
|
816
|
+
```
|
|
817
|
+
|
|
818
|
+
- [ ] **Step 3: Wait for CI green**
|
|
819
|
+
|
|
820
|
+
All four matrix rows must be green.
|
|
821
|
+
|
|
822
|
+
- [ ] **Step 4: Manual Claude Desktop smoke test**
|
|
823
|
+
|
|
824
|
+
Before merging, install the PR branch locally into Claude Desktop:
|
|
825
|
+
|
|
826
|
+
1. Build: `uv build`
|
|
827
|
+
2. Point Claude Desktop's `claude_desktop_config.json` at the built wheel or a local `uv tool install` of the branch.
|
|
828
|
+
3. Restart Claude Desktop.
|
|
829
|
+
4. Invoke `health_check` — expect `status: "healthy"`.
|
|
830
|
+
5. Invoke `load_csv` on a small fixture file — expect success with shape/columns returned.
|
|
831
|
+
|
|
832
|
+
If either invocation fails, **do not merge**. Diagnose the FastMCP 3 API call, patch, push.
|
|
833
|
+
|
|
834
|
+
- [ ] **Step 5: Merge**
|
|
835
|
+
|
|
836
|
+
Squash merge via GitHub UI. Delete the branch.
|
|
837
|
+
|
|
838
|
+
---
|
|
839
|
+
|
|
840
|
+
## PR 4: v2.0.0 Release Cut
|
|
841
|
+
|
|
842
|
+
**Branch name:** `release/v2.0.0`
|
|
843
|
+
**Goal:** finalize CHANGELOG, bump version string in two places, merge, tag, push.
|
|
844
|
+
|
|
845
|
+
### Task 14: Create branch and bump version
|
|
846
|
+
|
|
847
|
+
**Files:**
|
|
848
|
+
- Modify: `pyproject.toml`
|
|
849
|
+
- Modify: `src/csv_editor/server.py` (`health_check` response)
|
|
850
|
+
|
|
851
|
+
- [ ] **Step 1: Create branch**
|
|
852
|
+
|
|
853
|
+
```bash
|
|
854
|
+
git checkout main
|
|
855
|
+
git pull --ff-only origin main
|
|
856
|
+
git checkout -b release/v2.0.0
|
|
857
|
+
```
|
|
858
|
+
|
|
859
|
+
- [ ] **Step 2: Bump version in pyproject.toml**
|
|
860
|
+
|
|
861
|
+
In `pyproject.toml`, find:
|
|
862
|
+
```toml
|
|
863
|
+
version = "1.0.1"
|
|
864
|
+
```
|
|
865
|
+
Change to:
|
|
866
|
+
```toml
|
|
867
|
+
version = "2.0.0"
|
|
868
|
+
```
|
|
869
|
+
|
|
870
|
+
- [ ] **Step 3: Bump version in health_check**
|
|
871
|
+
|
|
872
|
+
In `src/csv_editor/server.py`, find the `health_check` function (around line 28–54) and locate the `"version": "1.0.0"` line. Change to:
|
|
873
|
+
```python
|
|
874
|
+
"version": "2.0.0",
|
|
875
|
+
```
|
|
876
|
+
|
|
877
|
+
- [ ] **Step 4: Run tests**
|
|
878
|
+
|
|
879
|
+
```bash
|
|
880
|
+
uv run pytest tests/ -v
|
|
881
|
+
```
|
|
882
|
+
|
|
883
|
+
Expected: all green (if any tests assert against the version string, they should already be using `csv_editor.__version__` or similar — if they assert the literal `"1.0.0"`, update them in this task).
|
|
884
|
+
|
|
885
|
+
- [ ] **Step 5: Commit**
|
|
886
|
+
|
|
887
|
+
```bash
|
|
888
|
+
git add pyproject.toml src/csv_editor/server.py
|
|
889
|
+
git commit -m "chore: bump version to 2.0.0"
|
|
890
|
+
```
|
|
891
|
+
|
|
892
|
+
### Task 15: Write CHANGELOG entry
|
|
893
|
+
|
|
894
|
+
**Files:**
|
|
895
|
+
- Modify: `CHANGELOG.md`
|
|
896
|
+
|
|
897
|
+
- [ ] **Step 1: Add [2.0.0] section**
|
|
898
|
+
|
|
899
|
+
In `CHANGELOG.md`, insert after the header comment and before `## [1.0.1]`:
|
|
900
|
+
|
|
901
|
+
```markdown
|
|
902
|
+
## [2.0.0] - 2026-04-DD
|
|
903
|
+
|
|
904
|
+
### BREAKING CHANGES
|
|
905
|
+
- **Python floor raised to 3.11.** Users on 3.8, 3.9, or 3.10 must upgrade. Users who pinned `csv-editor>=1,<2` are unaffected.
|
|
906
|
+
- **`--transport sse` CLI option removed.** Use `--transport http` (Streamable HTTP) for remote deployments. This aligns with the MCP 2025-11-25 spec and FastMCP 3 guidance.
|
|
907
|
+
- **FastMCP dependency bumped to `>=3.2,<4`.** Any code importing FastMCP APIs transitively may require updates per the [FastMCP 3 upgrade guide](https://gofastmcp.com/getting-started/upgrading/from-fastmcp-2).
|
|
908
|
+
|
|
909
|
+
### Added
|
|
910
|
+
- GitHub Actions `test.yml` workflow: pytest matrix on Python 3.11–3.14.
|
|
911
|
+
- `tests/test_server_boot.py` regression tests for server import, tool registry, and CLI argument handling.
|
|
912
|
+
- Python 3.14 classifier and test coverage.
|
|
913
|
+
- Contributing guide: local virtualenv rebuild instructions.
|
|
914
|
+
|
|
915
|
+
### Changed
|
|
916
|
+
- Python floor: `>=3.10` → `>=3.11`.
|
|
917
|
+
- `fastmcp`: `>=2.11.3` → `>=3.2,<4`.
|
|
918
|
+
- `pydantic`: `>=2.10.4` → `>=2.13`.
|
|
919
|
+
- `pydantic-settings`: `>=2.10.1` → `>=2.13`.
|
|
920
|
+
- `pyarrow`: `>=17.0.0` → `>=23`.
|
|
921
|
+
- `httpx`: `>=0.27.0` → `>=0.28`.
|
|
922
|
+
- `aiofiles`: `>=24.1.0` → `>=25`.
|
|
923
|
+
- `tabulate`: `>=0.9.0` → `>=0.10`.
|
|
924
|
+
- `black`/`ruff`/`mypy` target-version: Python 3.8 → 3.11.
|
|
925
|
+
- Dockerfile base image pinned to `python:3.11-slim-bookworm`.
|
|
926
|
+
- `main()` signature: now accepts optional `argv` for testability.
|
|
927
|
+
|
|
928
|
+
### Removed
|
|
929
|
+
- `--transport sse` CLI option.
|
|
930
|
+
- Python 3.8, 3.9, 3.10 classifier entries.
|
|
931
|
+
|
|
932
|
+
### Unchanged
|
|
933
|
+
- `pandas>=2.2.3` and `numpy>=2.1.3` — upgrading to 3.0/2.4 is deferred to a follow-up release (Sub-project 1b) due to pandas' Copy-on-Write behavioral change requiring focused testing.
|
|
934
|
+
```
|
|
935
|
+
|
|
936
|
+
Replace `2026-04-DD` with the actual release date when you push the tag.
|
|
937
|
+
|
|
938
|
+
- [ ] **Step 2: Commit**
|
|
939
|
+
|
|
940
|
+
```bash
|
|
941
|
+
git add CHANGELOG.md
|
|
942
|
+
git commit -m "docs: add v2.0.0 CHANGELOG entry"
|
|
943
|
+
```
|
|
944
|
+
|
|
945
|
+
### Task 16: Push, open PR, and merge
|
|
946
|
+
|
|
947
|
+
- [ ] **Step 1: Push**
|
|
948
|
+
|
|
949
|
+
```bash
|
|
950
|
+
git push -u origin release/v2.0.0
|
|
951
|
+
```
|
|
952
|
+
|
|
953
|
+
- [ ] **Step 2: Open PR**
|
|
954
|
+
|
|
955
|
+
Title: `release: v2.0.0`
|
|
956
|
+
Body: paste the CHANGELOG `[2.0.0]` section.
|
|
957
|
+
|
|
958
|
+
- [ ] **Step 3: Wait for CI green**
|
|
959
|
+
|
|
960
|
+
All four matrix rows must be green.
|
|
961
|
+
|
|
962
|
+
- [ ] **Step 4: Merge**
|
|
963
|
+
|
|
964
|
+
Squash merge via GitHub UI.
|
|
965
|
+
|
|
966
|
+
### Task 17: Tag and verify release
|
|
967
|
+
|
|
968
|
+
**Files:** none (tagging and publishing)
|
|
969
|
+
|
|
970
|
+
- [ ] **Step 1: Update CHANGELOG date**
|
|
971
|
+
|
|
972
|
+
Checkout main, pull, and if the `2026-04-DD` placeholder is still in CHANGELOG.md, make a quick follow-up commit with the real date (e.g., `2026-04-22`):
|
|
973
|
+
|
|
974
|
+
```bash
|
|
975
|
+
git checkout main
|
|
976
|
+
git pull --ff-only origin main
|
|
977
|
+
# If CHANGELOG still has 2026-04-DD:
|
|
978
|
+
sed -i.bak 's/2026-04-DD/2026-04-22/' CHANGELOG.md && rm CHANGELOG.md.bak
|
|
979
|
+
git add CHANGELOG.md
|
|
980
|
+
git commit -m "docs: set v2.0.0 release date"
|
|
981
|
+
git push origin main
|
|
982
|
+
```
|
|
983
|
+
|
|
984
|
+
Skip this step if the date was already correct in PR 4.
|
|
985
|
+
|
|
986
|
+
- [ ] **Step 2: Create and push tag**
|
|
987
|
+
|
|
988
|
+
```bash
|
|
989
|
+
git tag -a v2.0.0 -m "Release v2.0.0: FastMCP 3 + Python 3.11 floor"
|
|
990
|
+
git push origin v2.0.0
|
|
991
|
+
```
|
|
992
|
+
|
|
993
|
+
- [ ] **Step 3: Wait for publish workflow**
|
|
994
|
+
|
|
995
|
+
`publish.yml` (existing) should trigger on the tag and publish to PyPI. Watch the Actions tab.
|
|
996
|
+
|
|
997
|
+
Expected: green publish run; `csv-editor 2.0.0` visible on PyPI.
|
|
998
|
+
|
|
999
|
+
- [ ] **Step 4: Verify pip install in a clean venv**
|
|
1000
|
+
|
|
1001
|
+
```bash
|
|
1002
|
+
cd /tmp
|
|
1003
|
+
python3.11 -m venv verify-venv
|
|
1004
|
+
./verify-venv/bin/pip install csv-editor==2.0.0
|
|
1005
|
+
./verify-venv/bin/csv-editor --help
|
|
1006
|
+
```
|
|
1007
|
+
|
|
1008
|
+
Expected: `--help` output lists `--transport {stdio,http}` (no `sse`).
|
|
1009
|
+
|
|
1010
|
+
- [ ] **Step 5: Verify Smithery listing**
|
|
1011
|
+
|
|
1012
|
+
Open https://smithery.ai/server/@santoshray02/csv-editor in a browser. Confirm the version badge shows `2.0.0` (may take minutes to refresh; manually redeploy via Smithery dashboard if stale).
|
|
1013
|
+
|
|
1014
|
+
- [ ] **Step 6: Announce**
|
|
1015
|
+
|
|
1016
|
+
Optional but recommended: post a GitHub Release note (copy the CHANGELOG `[2.0.0]` section) at https://github.com/santoshray02/csv-editor/releases/new with tag `v2.0.0`.
|
|
1017
|
+
|
|
1018
|
+
---
|
|
1019
|
+
|
|
1020
|
+
## Post-release: Follow-up Issues to Open
|
|
1021
|
+
|
|
1022
|
+
After v2.0.0 ships, open these GitHub issues to track the rest of the roadmap:
|
|
1023
|
+
|
|
1024
|
+
- [ ] **Issue: Sub-project 0 — Migrate docs from Docusaurus to MkDocs-Material**
|
|
1025
|
+
- [ ] **Issue: Sub-project 1b — pandas 3.0 + numpy 2.4 migration**
|
|
1026
|
+
- [ ] **Issue: Sub-project 2 — Add DuckDB engine (default for files >100 MB) + Polars engine**
|
|
1027
|
+
- [ ] **Issue: Sub-project 3 — Adopt MCP async Tasks for `load_csv`, `export_csv`, `profile_data`; Resource Links for large outputs**
|
|
1028
|
+
- [ ] **Issue: Sub-project 4 — Remote HTTP + OAuth (CIMD) deployment mode for ChatGPT Connectors reach**
|
|
1029
|
+
- [ ] **Issue: Sub-project 5 — Elicitation for ambiguous CSV dialect/encoding detection**
|
|
1030
|
+
|
|
1031
|
+
For each, paste the relevant sections from the April 2026 relevance audit as the issue body, link the design spec once written.
|
|
1032
|
+
|
|
1033
|
+
---
|
|
1034
|
+
|
|
1035
|
+
## Self-Review Checklist (meta)
|
|
1036
|
+
|
|
1037
|
+
Before starting implementation:
|
|
1038
|
+
|
|
1039
|
+
- [ ] Spec and plan locations match user preference (specs/, plans/ — not docs/ which is Docusaurus).
|
|
1040
|
+
- [ ] Every task has exact file paths and complete code in every code step.
|
|
1041
|
+
- [ ] No "TBD", "similar to Task N", or "implement appropriate error handling" placeholders.
|
|
1042
|
+
- [ ] Types and function signatures referenced late in the plan (e.g., `main(argv)`) are defined in an earlier task.
|
|
1043
|
+
- [ ] PR 1 → PR 2 → PR 3 → PR 4 ordering is enforced (each PR 2+ task assumes the previous PR merged).
|
|
1044
|
+
- [ ] CI matrix in `test.yml` matches the Python floor at each point (3.10–3.14 in PR 1, 3.11–3.14 after PR 2).
|
|
1045
|
+
- [ ] Manual Claude Desktop smoke test is called out explicitly as a gate before merging PR 3.
|