@sebamomann/plants-mcp 2.7.0 → 2.8.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/CHANGELOG.md +24 -0
- package/README.md +23 -4
- package/dist/index.js +5 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,30 @@
|
|
|
3
3
|
Notable changes to `@sebamomann/plants-mcp`. Versioning is semver against the **tool surface** —
|
|
4
4
|
see the table in `AGENTS.md` for what counts as major, minor, and patch.
|
|
5
5
|
|
|
6
|
+
## 2.8.0 — 2026-09-27
|
|
7
|
+
|
|
8
|
+
**Is it still a cutting?** 78 tools registered overall (28 read, 32 write, 18 admin). A **minor**
|
|
9
|
+
bump — one new tool and one new enum value, nothing renamed or removed:
|
|
10
|
+
|
|
11
|
+
- `establish_propagation` — promote a `PROPAGATING` plant to `ESTABLISHED`, stamping
|
|
12
|
+
`establishedAt` to now. The same one-way transition the app's plant edit form applies manually,
|
|
13
|
+
and the action behind the new `propagationCheckDue` care recommendation.
|
|
14
|
+
- `list_care_recommendations`/`dismiss_care_recommendation` gain `propagationCheckDue`: a plant
|
|
15
|
+
left `PROPAGATING` long enough is now flagged, asking whether it should be promoted. Its
|
|
16
|
+
dismissal is deliberately temporary (it re-fires a few weeks later) rather than permanent, so a
|
|
17
|
+
stale `PROPAGATING` row can't silently skew the propagation success rate in `collection_stats`
|
|
18
|
+
forever.
|
|
19
|
+
|
|
20
|
+
## 2.7.1 — 2026-09-26
|
|
21
|
+
|
|
22
|
+
**A moved watering carries its feeding.** Tool count unchanged (77 overall). A **patch** bump —
|
|
23
|
+
nothing renamed or removed, and the change is in the app's behaviour plus `snooze_care`'s wording:
|
|
24
|
+
|
|
25
|
+
- `snooze_care` on the `water` axis now also snoozes a fertilizing due date that falls between today
|
|
26
|
+
and the watering's new day — fertilizer goes into the watering can, so a feeding left in between
|
|
27
|
+
would have nothing to deliver it. The extra row is **added** to the response as `fertRider` (`null`
|
|
28
|
+
when nothing moved), so existing callers are unaffected. An already-overdue feeding stays put.
|
|
29
|
+
|
|
6
30
|
## 2.7.0 — 2026-09-24
|
|
7
31
|
|
|
8
32
|
**Nudges.** 77 tools registered overall (28 read, 31 write, 18 admin). A **minor** bump — one new
|
package/README.md
CHANGED
|
@@ -60,7 +60,7 @@ needs a running Sprig instance and an API key from it. Start at the
|
|
|
60
60
|
|
|
61
61
|
## What an assistant can do
|
|
62
62
|
|
|
63
|
-
**
|
|
63
|
+
**78 tools** over your collection: 28 that read it, 32 that write to it. **18 admin tools** are also
|
|
64
64
|
available — but only to a key created by an admin — for finding and understanding duplicates in the
|
|
65
65
|
shared global plant type catalog, restructuring its genus/species/cultivar tree, reading, directly
|
|
66
66
|
editing, merging, and reviewing proposals and duplicate candidates in that catalog, and (7 read-only,
|
|
@@ -111,7 +111,7 @@ healthy server, not a hang — press Ctrl-C.
|
|
|
111
111
|
The scope lives on the API key, is enforced by the app, and cannot be widened from this side.
|
|
112
112
|
|
|
113
113
|
- **`read`** — on every key. Gates all 28 read tools.
|
|
114
|
-
- **`write`** — opt-in when you create the key. Gates the
|
|
114
|
+
- **`write`** — opt-in when you create the key. Gates the 32 write tools.
|
|
115
115
|
- **`admin`** — only offered when the key's creator is themselves an admin, and only while they
|
|
116
116
|
still are one (the app re-checks this on every admin-tool call, not just at key creation). Gates
|
|
117
117
|
the 18 admin catalog tools — 7 read-only, 11 that write — see **Admin tools** below. `admin` alone
|
|
@@ -380,6 +380,12 @@ hub offers. `originalDueAt` is the due date being pushed out (`nextDue` from `li
|
|
|
380
380
|
an overdue plant means three days from now) or `snoozedUntil` (an explicit day: tomorrow at the
|
|
381
381
|
earliest, at most a year out).
|
|
382
382
|
|
|
383
|
+
Moving a **watering** past a feeding that was due before it moves that feeding too: fertilizer goes
|
|
384
|
+
into the watering can, so a feeding left between today and the watering's new day would have nothing
|
|
385
|
+
to deliver it. The second snooze comes back as `fertRider` on the response (`null` when nothing rode
|
|
386
|
+
along), so it can be reported rather than discovered later. An already-overdue feeding is left where
|
|
387
|
+
it is — that backlog is not the watering's doing.
|
|
388
|
+
|
|
383
389
|
### Plant edits
|
|
384
390
|
|
|
385
391
|
| Tool | Endpoint | Arguments |
|
|
@@ -432,6 +438,7 @@ don't exist yet, `propagate_plant` creates them *and* sets the link in one call.
|
|
|
432
438
|
| `unmerge_plant` | `POST /api/v1/plants/:id/unmerge` | `plantId` **(required)** |
|
|
433
439
|
| `set_plant_status` | `PATCH /api/v1/plants/:id/status` | `plantId`, `status` (`LIVING`\|`DEAD`\|`LOST`) **(both required)**, plus `deadDeclaredAt`/`deathCause` (only apply when `status` is `DEAD`) |
|
|
434
440
|
| `set_plant_reference` | `PATCH /api/v1/plants/:id/reference` | `plantId`, `reference` (boolean) **(both required)** |
|
|
441
|
+
| `establish_propagation` | `PATCH /api/v1/plants/:id/establish` | `plantId` **(required)** |
|
|
435
442
|
|
|
436
443
|
`create_plant`'s `plantTypeId` is now **optional**: pass an existing global type id (from
|
|
437
444
|
`list_plant_types`/`search_plant_types`) when the species is known, or omit it (or pass `null`) to
|
|
@@ -468,6 +475,11 @@ Marking a plant as a reference also removes it from any vacation plan, since a r
|
|
|
468
475
|
never cared for. `create_plant`'s `reference: true` covers making a *new* reference plant; this is
|
|
469
476
|
for converting one already in the collection.
|
|
470
477
|
|
|
478
|
+
`establish_propagation` promotes a `PROPAGATING` plant to `ESTABLISHED` and stamps `establishedAt`
|
|
479
|
+
to now — the same one-way transition the app's plant edit form applies manually, and the action
|
|
480
|
+
behind the `propagationCheckDue` recommendation ("is it still a cutting?", see **Recommendations**
|
|
481
|
+
below) on the Improvements page. It answers HTTP 400 if the plant isn't currently `PROPAGATING`.
|
|
482
|
+
|
|
471
483
|
### Health entries
|
|
472
484
|
|
|
473
485
|
| Tool | Endpoint | Arguments |
|
|
@@ -491,8 +503,15 @@ Pass all three **exactly as returned by `list_care_recommendations`**. The `fing
|
|
|
491
503
|
that specific occurrence, so dismissing one never suppresses a later, different recurrence.
|
|
492
504
|
|
|
493
505
|
Dismissible `type` values: `wateringOftenLate`, `fertilizingOftenLate`, `noFertilizerThisSeason`,
|
|
494
|
-
`recentlyRepottedAvoidFertilizer`, `noRecentPhoto`. `wateringCycleMismatch` is
|
|
495
|
-
it is a configuration contradiction, fixed by editing the plant rather than
|
|
506
|
+
`recentlyRepottedAvoidFertilizer`, `noRecentPhoto`, `propagationCheckDue`. `wateringCycleMismatch` is
|
|
507
|
+
**not** dismissible — it is a configuration contradiction, fixed by editing the plant rather than
|
|
508
|
+
hidden.
|
|
509
|
+
|
|
510
|
+
`propagationCheckDue` ("is it still a cutting?") fires for a plant that has been `PROPAGATING` for a
|
|
511
|
+
while and asks whether it has rooted. Dismissing it only hides it for a few weeks, not permanently —
|
|
512
|
+
it re-fires periodically rather than letting a stale `PROPAGATING` row silently skew the propagation
|
|
513
|
+
success rate in `collection_stats`. `establish_propagation` (see **Plant lifecycle** above) is how an
|
|
514
|
+
assistant acts on it — promoting the plant is the actual fix, not just dismissing the prompt.
|
|
496
515
|
|
|
497
516
|
### Wishlist
|
|
498
517
|
|
package/dist/index.js
CHANGED
|
@@ -176,7 +176,7 @@ server.tool("record_hydro_event", "WRITE: log a hydro-culture event for a hydro-
|
|
|
176
176
|
recordedAt: optionalPlantDate(""),
|
|
177
177
|
notes: z.string().max(2000).optional().describe("Free-text notes."),
|
|
178
178
|
}, async ({ plantId, ...body }) => apiSend("POST", `/api/v1/plants/${plantId}/hydro`, body));
|
|
179
|
-
server.tool("snooze_care", "WRITE: postpone a plant's next watering or fertilizing due date — the same snooze picker the care hub offers. originalDueAt is the due date being pushed out (the nextDue value from list_due_care/get_care_calendar for that plant/careType), not today's date. Pass exactly one of durationDays (a preset: 1, 3, 7, or 14 days, counted from originalDueAt or from today when that date has already passed) or snoozedUntil (an explicit YYYY-MM-DD day, tomorrow at the earliest and at most a year out). Requires a write-scoped API key.", {
|
|
179
|
+
server.tool("snooze_care", "WRITE: postpone a plant's next watering or fertilizing due date — the same snooze picker the care hub offers. originalDueAt is the due date being pushed out (the nextDue value from list_due_care/get_care_calendar for that plant/careType), not today's date. Pass exactly one of durationDays (a preset: 1, 3, 7, or 14 days, counted from originalDueAt or from today when that date has already passed) or snoozedUntil (an explicit YYYY-MM-DD day, tomorrow at the earliest and at most a year out). Moving a WATERING past a feeding that was due before it moves that feeding onto the same day too — fertilizer goes into the watering can, so a feeding left in between would have nothing to deliver it; that second snooze comes back as fertRider (null when nothing moved), and an already-overdue feeding is left where it is. Requires a write-scoped API key.", {
|
|
180
180
|
plantId: z.number().int().positive().describe("Plant id."),
|
|
181
181
|
careType: z.enum(["water", "fert"]).describe("Which schedule to postpone."),
|
|
182
182
|
durationDays: z.union([z.literal(1), z.literal(3), z.literal(7), z.literal(14)]).optional().describe("Snooze duration in days — one of the app's presets, counted from originalDueAt, or from today if that date has passed. Omit when passing snoozedUntil."),
|
|
@@ -238,6 +238,7 @@ server.tool("dismiss_care_recommendation", "WRITE: hide one care recommendation,
|
|
|
238
238
|
"noFertilizerThisSeason",
|
|
239
239
|
"recentlyRepottedAvoidFertilizer",
|
|
240
240
|
"noRecentPhoto",
|
|
241
|
+
"propagationCheckDue",
|
|
241
242
|
])
|
|
242
243
|
.describe("Recommendation type, from list_care_recommendations."),
|
|
243
244
|
fingerprint: z.string().min(1).describe("Occurrence fingerprint, from list_care_recommendations."),
|
|
@@ -289,6 +290,9 @@ server.tool("set_plant_reference", "WRITE: flip a plant between LIVING (the call
|
|
|
289
290
|
plantId: z.number().int().positive().describe("Plant id."),
|
|
290
291
|
reference: z.boolean().describe("true: mark as a reference plant (must be LIVING now). false: turn a reference plant back into the caller's own (must be EXTERNAL now)."),
|
|
291
292
|
}, async ({ plantId, reference }) => apiSend("PATCH", `/api/v1/plants/${plantId}/reference`, { reference }));
|
|
293
|
+
server.tool("establish_propagation", "WRITE: promote a plant from PROPAGATING to ESTABLISHED, stamping establishedAt to now. This is the same one-way transition the app's plant edit form applies manually, and the action behind the 'is it still a cutting?' recommendation (propagationCheckDue, from list_care_recommendations) on the Improvements page. Fails with a 400 if the plant is not currently PROPAGATING. Requires a write-scoped API key.", {
|
|
294
|
+
plantId: z.number().int().positive().describe("The PROPAGATING plant to promote."),
|
|
295
|
+
}, async ({ plantId }) => apiSend("PATCH", `/api/v1/plants/${plantId}/establish`));
|
|
292
296
|
// --- Wishlist ----------------------------------------------------------
|
|
293
297
|
/**
|
|
294
298
|
* The caller's personal wishlist (R2-15) — plants they want but don't own
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sebamomann/plants-mcp",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "MCP server for the Sprig plant app:
|
|
3
|
+
"version": "2.8.0",
|
|
4
|
+
"description": "MCP server for the Sprig plant app: 78 tools to read a plant collection, browse the shared global plant type catalog, log care (watering, fertilizing, repotting, refills, hydro events), edit a plant's identity/care/lifecycle status, add, propagate or merge plants, snooze a due date, check for nudges worth mentioning, manage a wishlist and notifications, watch a plant type for changes, check vacation status, read past problem diagnoses, create a location/soil/fertilizer/pot, and contribute a new species to the catalog. Read-only by default; writes need a write-scoped API key. Two tools can delete a watering/fertilization event; nothing else deletes collection history. 18 more tools read, edit, merge and review the shared global plant type catalog and the instance's operational status (queues, catalog health, activity, growth, community, trade and content aggregates) for an admin-scoped key.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": "sebamomann <github@sebamomann.de>",
|