Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions .issueflows/03-solved-issues/issue1080_original.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Issue #1080: MCP find_cells tool (no silent raw crawl)

Source: https://github.com/jepegit/cellpy/issues/1080

## Original issue text

## Context

Part of epic #1074 (agent summary-plots SAL cells 10–15 from local files). Stage 2: the library can find (`filefinder.find_by_project`, #1076); the agent still cannot. Add one MCP tool that lists matches from configured dirs and **stops**. Existing `load_cell` / `collect` / `render` finish the plot. No raw crawl in this stage.

## Scope

In `cellpy-mcp`, add a tool (suggested `find_cells`) that calls `filefinder.find_by_project`. Inputs: `project`, `number_min`, `number_max`, `kind` defaulting to `cellpy`. Output: handles/facts only — count, names, numbers, paths the sandbox may read.

If `kind=cellpy` and the list is empty, return `{found: 0, offer_raw: true}` (or equivalent) and **do not** search `rawdatadir`. If `cellpydatadir` is a remote URI, say so (`remote: true`, reason) rather than pretending the sandbox can walk it.

Update `docs/getting_started/agents.md` / MCP chapter and add a short agent-prompt snippet for “summary-plot SAL 10–15” that uses find → load → collect → render.

Implement in the `cellpy-mcp` repo; this GitHub issue stays the tracker on `jepegit/cellpy`.

## Acceptance criteria

- MCP `find_cells(project="SAL", 10, 15)` returns the matching local cellpy files, or a structured empty + `offer_raw` — never a raw listing.

Goal: MCP `find_cells(project="SAL", 10, 15)` returns the matching local cellpy files, or a structured empty + `offer_raw` — never a raw listing.

Model: default

Depends on: #1076

Part of epic #1074.
69 changes: 69 additions & 0 deletions .issueflows/03-solved-issues/issue1080_plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Issue #1080 plan

## Goal

An MCP client can call `find_cells(project="SAL", 10, 15)` and get matching
local `.cellpy` files, or `{found: 0, offer_raw: true}` — never a raw listing.
Existing `load_cell` / `collect` / `render` finish Scenario 1.

## Constraints

- Two repos: tool in `cellpy-mcp`; docs + this tracker on `jepegit/cellpy`.
- Do not search `rawdatadir` when `kind` is `cellpy` (even if empty).
- Sandbox stays local-only. Remote `cellpydatadir` → `remote: true` + reason,
no pretend walk. Remote *load* is Stage 3 / Later.
- Handles/facts only — no file bytes.
- `find_by_project` is on cellpy `master` (#1079) but not a released pin yet.
Do not bump `cellpy>=` to an unreleased version.

### Prior art

- `cellpy.filefinder.find_by_project` (#1076) — call it; do not re-walk.
- MCP `list_cells` is **session** only (already loaded). New tool is disk find.
- `sandbox.default_roots` / `_is_local_dir` — reuse for remote honesty.
- `tests/test_cell_tools.py` `drive` harness — same pattern.
- Agent prompts live in cellpy `docs/getting_started/agent_prompts.md` (#1064).

## Approach

**cellpy-mcp** (branch `1080-mcp-find-cells` on that repo):

1. Tool `find_cells(project, number_min, number_max, kind="cellpy")`.
2. If `kind` not in `cellpy`/`raw` → `Refused`.
3. If `kind=cellpy` and `config.paths.cellpydatadir` is a remote URI →
`{found: 0, remote: true, reason: "…"}` and stop.
4. Else call `filefinder.find_by_project(...)`. If the attribute is missing
(old cellpy), `Refused` naming #1076 / `find_by_project`.
5. Filter returned paths through `sandbox.resolve` (drop anything outside
roots; do not crash the whole list).
6. Empty + `kind=cellpy` → `{found: 0, offer_raw: true, cells: []}`.
Hits → `{found: N, offer_raw: false, cells: [{name, number, path}]}`.
`kind=raw` may list raw (Stage 3 will add `needs_metadata`); this stage
still must not auto-switch from cellpy-empty to raw.

**cellpy** (this worktree):

- `docs/getting_started/mcp.md` — document `find_cells`.
- `docs/getting_started/agent_prompts.md` — SAL 10–15: find → load → collect
→ render (`<!-- agent-doc: … -->` + latest URL if that page’s convention
requires it).
- One line in `agents.md` / `AGENTS.md` if the MCP tool list is mirrored.

## Files to touch

- `cellpy-mcp/src/cellpy_mcp/cells.py` — register `find_cells`
- `cellpy-mcp/tests/test_cell_tools.py` — empty/`offer_raw`, hits, remote
- `docs/getting_started/mcp.md`, `agent_prompts.md`, maybe `agents.md` / `AGENTS.md`
- `HISTORY.md` (cellpy close); cellpy-mcp changelog if they have one

## Test strategy

- cellpy-mcp: `uv run pytest` (existing essential mark on cell-tool tests).
Monkeypatch `find_by_project` so tests do not need a released cellpy.
- cellpy: no new library tests; docs checker if the new prompt gets an
`agent-doc` comment (`00-tools/check_rtd_latest_links.py` after zensical).

## Open questions

None that block. `kind=raw` on this tool is allowed but unused by Scenario 1;
Stage 3 will extend the empty-cellpy dialogue.
6 changes: 6 additions & 0 deletions .issueflows/03-solved-issues/issue1080_status.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Issue #1080 status

- [x] Done

`find_cells` in cellpy-mcp (empty → `offer_raw`, remote honesty).
Docs + SAL 10–15 prompt on cellpy.
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,7 @@ Quick facts:
- Find by project + number range: `from cellpy import filefinder` then
`filefinder.find_by_project("SAL", 10, 15, kind="cellpy")` (or `kind="raw"`).
Uses `cellpydatadir` / `rawdatadir`; empty list if none match.
MCP: `find_cells` (empty cellpy → `offer_raw`, no silent raw crawl).
- Metadata peek (no frames): `cellpy.read_meta(path)` → dict with `cell` / `tests`.
- Ingestion form fields: `cellpy.instrument_meta_schema(instrument)` → `fields` / `units`.
- Frames: `c.data.raw` / `.steps` / `.summary`; columns via `c.schema.*`.
Expand Down
3 changes: 3 additions & 0 deletions HISTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## [Unreleased]

* Docs: MCP `find_cells` (project + number range; empty cellpy offers raw,
never a silent crawl) and a SAL 10–15 agent prompt. (#1080)

* `filefinder.find_by_project` lists cellpy or raw files by project token
and inclusive number range. (#1076)

Expand Down
12 changes: 12 additions & 0 deletions docs/getting_started/agent_prompts.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,18 @@ Use `c.schema` for column names, not hardcoded header strings. Follow
https://cellpy.readthedocs.io/en/latest/getting_started/agents/.
```

## How to summary-plot SAL cells 10–15

<!-- agent-doc: getting_started/mcp.md -->
```text
Using cellpy MCP, find project SAL cells numbered 10–15 (names like
<date>_SAL<number>), load them, and write a summary plot. Call find_cells
first (kind=cellpy). If found is 0 and offer_raw is true, ask before
searching raw — do not crawl rawdatadir yourself. Then load_cell, collect
kind=summary with a plot family, and render. Follow
https://cellpy.readthedocs.io/en/latest/getting_started/mcp/.
```

## How to fetch the agent docs map

<!-- agent-doc: getting_started/agents.md -->
Expand Down
4 changes: 4 additions & 0 deletions docs/getting_started/agents.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,10 @@ hits = filefinder.find_by_project("SAL", 10, 15, kind="cellpy")
raw_hits = filefinder.find_by_project("SAL", 10, 15, kind="raw")
```

MCP equivalent: `find_cells` (same arguments). Empty `kind=cellpy` returns
`offer_raw: true` and does not search raw. See
[Connect an agent IDE to cellpy](mcp.md).

## Core mental model for app code

```text
Expand Down
2 changes: 1 addition & 1 deletion docs/getting_started/mcp.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ the last line.
cellpy mcp check --client cursor
```

Success prints the handshake, the tool names (`load_cell`,
Success prints the handshake, the tool names (`find_cells`, `load_cell`,
`search_api`, …) and how many instruments the server can see. A failure
names the cause: an interpreter path that does not exist, a server that
printed to stdout, or one that died (its last stderr line is quoted).
Expand Down
Loading