hortusfox-mcp
This MCP server exposes the complete HortusFox REST API as tools, enabling AI assistants to manage a self-hosted plant management system across 7 domains:
Plants: Get details, add, update, or remove plants; list with filtering/pagination/sorting; free-text search; manage custom attributes; update main photo; manage gallery photos; add, edit, remove, or fetch plant log/journal entries.
Locations: List all locations (with optional plant counts/lists) and get details of a specific location.
Tasks: Fetch tasks (including completed ones), add with optional due dates, recurrence, and plant associations, edit (including toggling completion), and remove.
Inventory: Fetch full inventory, add new items, edit existing items, increment/decrement item amounts, and remove items.
Calendar: Fetch entries within a date range, add entries with start/end dates and optional class, edit, and remove.
Chat: Fetch recent workspace chat messages and post new messages as a bot.
Backup: Export backup archives for selected data categories (locations, plants, gallery, tasks, inventory, calendar) and import previously staged backup data.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@hortusfox-mcp list all plants in the living room"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
HortusFox MCP Server
A Model Context Protocol (MCP) stdio server for
HortusFox, the self-hosted plant
management system. It exposes the complete HortusFox REST API (/api/*) as MCP tools so
AI assistants can read and manage your plants, locations, tasks, inventory, calendar,
chat and backups.
Written in TypeScript for Node.js, using the official
@modelcontextprotocol/sdk.
Features
Every endpoint of the HortusFox ApiController is covered — 42 tools across 7 domains:
Domain | Tools |
Plants (22) | get, add, update, remove, list, search; custom attributes add/edit/remove; main photo update; gallery list/add/edit/remove; attachments fetch/add/edit/remove; log add/edit/remove/fetch |
Locations (2) | list, get info |
Tasks (4) | fetch, add, edit, remove |
Inventory (6) | fetch, add, edit, increment, decrement, remove |
Calendar (4) | fetch, add, edit, remove |
Chat (2) | fetch, post message |
Backup (2) | export, import |
Related MCP server: MCP Enterprise Architecture Practice 01
Prerequisites
Node.js 18+ (uses the built-in
fetch).A running HortusFox instance.
A HortusFox API key. In HortusFox, go to Admin → API and create a key.
Installation
npm install
npm run buildThis produces the runnable server at dist/index.js.
Configuration
The server is configured entirely through environment variables:
Variable | Required | Description |
| ✅ | Base URL of your HortusFox instance, e.g. |
| ✅ | API key created in the HortusFox admin panel |
| ❌ | Request timeout in milliseconds (default |
| ❌ | Directory local files may be uploaded from. Unset, every upload is refused |
| ❌ | Upload size ceiling in MiB (default |
See .env.example.
Usage
Run directly
HORTUSFOX_URL=https://garden.example.com \
HORTUSFOX_API_TOKEN=your-token \
node dist/index.jsThe server speaks MCP over stdio. Diagnostic messages are written to stderr; the
JSON-RPC protocol uses stdout.
Run with npx
Once published to npm, the server can be run without a local checkout:
HORTUSFOX_URL=https://garden.example.com \
HORTUSFOX_API_TOKEN=your-token \
npx @tomfrenzel/hortusfox-mcpRegister with an MCP client
Add the server to your client's MCP configuration. The recommended way is via
npx:
{
"mcpServers": {
"hortusfox": {
"command": "npx",
"args": ["-y", "@tomfrenzel/hortusfox-mcp"],
"env": {
"HORTUSFOX_URL": "https://garden.example.com",
"HORTUSFOX_API_TOKEN": "your-token"
}
}
}
}Alternatively, point at a local build:
{
"mcpServers": {
"hortusfox": {
"command": "node",
"args": ["/absolute/path/to/hortusfox-mcp/dist/index.js"],
"env": {
"HORTUSFOX_URL": "https://garden.example.com",
"HORTUSFOX_API_TOKEN": "your-token"
}
}
}
}If installed globally (npm install -g .), you can use the hortusfox-mcp binary
instead of node dist/index.js.
Tool reference
All tools are prefixed with hortusfox_. Each returns the raw HortusFox JSON response
(pretty-printed). Errors (network failures, auth rejection, or API error codes) are
returned as MCP tool errors with a descriptive message.
Plants
Tool | Endpoint | Key arguments |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Photos and attachments: the photo tools accept either an external image URL (
external: truewith aphotoURL) or a local file (path), sent asmultipart/form-data. Attachments are always local files. Local uploads are only allowed fromHORTUSFOX_UPLOAD_DIR: the path is resolved withrealpathfirst, so neither..nor a symlink can reach outside it, and files aboveHORTUSFOX_MAX_UPLOAD_MBare refused before being read.
Locations
Tool | Endpoint | Key arguments |
|
|
|
|
|
|
Tasks
Tool | Endpoint | Key arguments |
|
|
|
|
|
|
|
|
|
|
|
|
Inventory
Tool | Endpoint | Key arguments |
|
| – |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Calendar
Tool | Endpoint | Key arguments |
|
|
|
|
|
|
|
|
|
|
|
|
Chat
Tool | Endpoint | Key arguments |
|
|
|
|
|
|
Backup
Tool | Endpoint | Key arguments |
|
|
|
|
| same category flags |
Development
npm run dev # tsc --watch
npm run typecheck # type-check without emitting
npm run build # compile to dist/A dev container config is provided in
.devcontainer/ for a ready-to-use Node.js + TypeScript
environment.
Releasing
Releases are published to npm automatically by the
Release GitHub Actions workflow whenever a
v* tag is pushed. The workflow type-checks, builds, verifies the tag matches
the package.json version, and publishes with
npm provenance.
To cut a release:
npm version patch # or minor / major — bumps package.json and creates a tag
git push --follow-tagsThis requires an NPM_TOKEN secret to be configured in the repository settings.
How it works
The Asatru framework behind HortusFox merges POST body, query string and JSON body into a
single request argument bag, and the API authenticates via a token parameter. This
server therefore sends each request as an application/x-www-form-urlencoded POST
(including the token and all parameters), which works uniformly for every route and avoids
URL-length limits for larger text fields. Requests are retried up to 3 times on transient
network/timeout failures; deterministic API and auth errors are surfaced immediately.
License
MIT — see LICENSE.
Available Tools
38 toolshortusfox_add_calendar_entryAdd calendar entryB
Add a calendar entry with a name, start date and optional end date and class. Returns the new item ID. Endpoint: /api/calendar/add.
Inputs: name (required), date_from (required), class, date_till.
hortusfox_add_chat_messagePost chat messageB
Post a message to the workspace chat (sent via the API/bot identity). Endpoint: /api/chat/message/add.
Inputs: message (required).
hortusfox_add_inventory_itemAdd inventory itemB
Add a new inventory item. Returns the new item ID. Endpoint: /api/inventory/add.
Inputs: name (required), tags, group, photo, +3 more.
hortusfox_add_plantAdd plantB
Create a new plant with a name and a location ID. Returns the new plant ID. Endpoint: /api/plants/add.
Inputs: name (required), location (required).
hortusfox_add_plant_attributeAdd custom plant attributeB
Add a custom attribute to a plant. Endpoint: /api/plants/attributes/add.
Inputs: label (required), plant (required), content (required), datatype (required).
hortusfox_add_plant_gallery_photoAdd plant gallery photoB
Add a photo to a plant gallery. Set external=true and provide a photo URL to add an external image. Endpoint: /api/plants/gallery/add.
Inputs: plant (required), label, photo, external.
hortusfox_add_plant_log_entryAdd plant log entryB
Add a log/journal entry to a plant. Returns the new log entry ID. Endpoint: /api/plants/log/add.
Inputs: plant (required), content (required).
hortusfox_add_taskAdd taskA
Create a task. Supports an optional due date, recurrence, and association with a plant. Returns the new task ID. Endpoint: /api/tasks/add.
Inputs: title (required), plant, due_date, description, +2 more.
hortusfox_decrement_inventory_itemDecrement inventory amountA
Decrement the amount of an inventory item by one. Returns the new amount. Endpoint: /api/inventory/amount/dec.
Inputs: item (required).
hortusfox_edit_calendar_entryEdit calendar entryB
Edit an existing calendar entry by its identifier. Endpoint: /api/calendar/edit.
Inputs: ident (required), date_from (required), name, class, +1 more.
hortusfox_edit_inventory_itemEdit inventory itemB
Edit an existing inventory item by ID. Endpoint: /api/inventory/edit.
Inputs: item (required), name, tags, group, +4 more.
hortusfox_edit_plant_attributeEdit custom plant attributeB
Edit an existing custom attribute of a plant, identified by its label. Endpoint: /api/plants/attributes/edit.
Inputs: label (required), plant (required), content (required), datatype (required).
hortusfox_edit_plant_gallery_photoEdit plant gallery photo labelB
Edit the label of a gallery photo item. Endpoint: /api/plants/gallery/edit.
Inputs: item (required), label (required), plant (required).
hortusfox_edit_plant_log_entryEdit plant log entryB
Edit an existing plant log entry by its ID. Endpoint: /api/plants/log/edit.
Inputs: logid (required), content (required).
hortusfox_edit_taskEdit taskB
Edit an existing task by ID, including toggling its done state. Endpoint: /api/tasks/edit.
Inputs: task (required), done, title, due_date, +3 more.
hortusfox_export_backupExport backupA
Export a backup archive for the selected data categories. Returns a downloadable file URL. Endpoint: /api/backup/export.
Inputs: tasks, plants, gallery, calendar, +2 more.
hortusfox_fetch_calendarFetch calendar entriesB
Fetch calendar entries within a date range. Defaults to today through the next 30 days when omitted. Endpoint: /api/calendar/fetch.
Inputs: date_from, date_till.
hortusfox_fetch_chatFetch chat messagesB
Fetch recent workspace chat messages. Endpoint: /api/chat/fetch.
Inputs: limit.
hortusfox_fetch_inventoryFetch inventoryA
Fetch the full inventory list. Endpoint: /api/inventory/fetch.
Inputs: no named parameters.
hortusfox_fetch_plant_logFetch plant log entriesB
Fetch log entries for a plant, with optional pagination. Endpoint: /api/plants/log/fetch.
Inputs: plant (required), limit, paginate.
hortusfox_fetch_tasksFetch tasksA
Fetch tasks, optionally including completed ones. Endpoint: /api/tasks/fetch.
Inputs: done, limit.
hortusfox_get_locationGet location infoB
Fetch details of a single location by ID, optionally including its plants. Endpoint: /api/locations/info.
Inputs: location (required), include_plants.
hortusfox_get_plantGet plant detailsA
Fetch full details of a single plant by its ID, including default fields and any custom attributes. Endpoint: /api/plants/get.
Inputs: plant (required).
hortusfox_import_backupImport backupB
Import previously staged backup data for the selected categories. Endpoint: /api/backup/import.
Inputs: tasks, plants, gallery, calendar, +2 more.
hortusfox_increment_inventory_itemIncrement inventory amountA
Increment the amount of an inventory item by one. Returns the new amount. Endpoint: /api/inventory/amount/inc.
Inputs: item (required).
hortusfox_list_locationsList locationsB
List locations, optionally including the plants at each location. Endpoint: /api/locations/list.
Inputs: limit, paginate, only_active, include_info, +1 more.
hortusfox_list_plant_galleryList plant gallery photosB
List all gallery photos for a plant. Endpoint: /api/plants/gallery/list.
Inputs: plant (required).
hortusfox_list_plantsList plantsB
List plants, optionally filtered by location, with paging and sorting. Endpoint: /api/plants/list.
Inputs: from, sort, limit, location.
hortusfox_remove_calendar_entryRemove calendar entryC
Remove a calendar entry by its identifier. Endpoint: /api/calendar/remove.
Inputs: ident (required).
hortusfox_remove_inventory_itemRemove inventory itemB
Remove an inventory item by ID. Endpoint: /api/inventory/remove.
Inputs: item (required).
hortusfox_remove_plantRemove plantB
Delete a plant by its ID. Endpoint: /api/plants/remove.
Inputs: plant (required).
hortusfox_remove_plant_attributeRemove custom plant attributeB
Remove a custom attribute from a plant by its label. Endpoint: /api/plants/attributes/remove.
Inputs: label (required), plant (required).
hortusfox_remove_plant_gallery_photoRemove plant gallery photoC
Remove a gallery photo by its item ID. Endpoint: /api/plants/gallery/remove.
Inputs: item (required).
hortusfox_remove_plant_log_entryRemove plant log entryB
Remove a plant log entry by its ID. Endpoint: /api/plants/log/remove.
Inputs: logid (required).
hortusfox_remove_taskRemove taskB
Remove a task by ID. Endpoint: /api/tasks/remove.
Inputs: task (required).
hortusfox_search_plantsSearch plantsA
Search plants by a free-text expression (matches name, location, attributes and more). Endpoint: /api/plants/search.
Inputs: expression (required), limit.
hortusfox_update_plantUpdate plant attributeC
Update a single attribute of a plant by name (e.g. name, location, description, humidity, etc.). Endpoint: /api/plants/update.
Inputs: plant (required), value (required), attribute (required).
hortusfox_update_plant_photoUpdate plant main photoA
Update the main preview photo of a plant. Set external=true and provide a photo URL to use an external image. Optionally move the current photo into the gallery first. Endpoint: /api/plants/photo/update.
Inputs: plant (required), photo, external, move_to_gallery.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 38 tools
Most tools are clearly separated by resource and action, so an agent can usually pick the right one. The main overlap is hortusfox_update_plant vs hortusfox_edit_plant_attribute, both of which can look like attribute modification, and the numerous read variants (get/list/fetch/search) require careful description reading.
Every tool uses the hortusfox_<verb>_<noun> snake_case pattern, and CRUD verbs are mostly consistent. However, reads mix get, list, fetch, and search, and modifications mix update and edit, so the verb choice is not fully predictable.
38 tools is a high count, but it is organized into logical modules (plants, locations, calendar, tasks, inventory, chat, backup) and each tool maps to a distinct endpoint. Even so, the set is larger than ideal for an MCP server and may feel heavy to an agent.
Core plant management is well covered: plant CRUD, custom attributes, gallery photos, log entries, plus tasks, calendar, inventory, and backup. The notable gap is locations only support list/get, with no create/update/delete, which can block workflows that need to set up or modify locations.
Maintenance
Related MCP Connectors
MCP server for your apps' tools and custom tools, plus hosted AI agents and approval-gated workflows
Nifty's MCP server — exposes tasks, projects, messages, and files as tools for AI agents.
MCP server for progressive tool usage at any scale (see https://klavis.ai)
Hosted MCP server for live public-data APIs and Skills for AI agents.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceAn MCP server and CLI for controlling FarmBot hardware, enabling AI agents to manage gardening tasks through tools like gantry movement and device status monitoring. It supports executing Lua scripts and core hardware commands like homing and emergency stops via the Model Context Protocol.3MIT
- FlicenseNot gradedqualityDmaintenanceEnterprise MCP server providing a suite of tools including file, database, GitHub, Slack, calendar, email, vector search, and Python execution, with safe defaults and OpenAI integration for automatic tool selection.-
- AlicenseAqualityDmaintenanceMCP server for managing houseplants by recording waterings and observations, providing care reminders and diagnosis through natural language.9MIT
- AlicenseNot gradedqualityDmaintenanceA local-first MCP server for tracking indoor horticulture metrics, enabling cold-stratification timelines, ericaceous soil pH validation, and transplant-shock recovery through a LangGraph agent with a local LLM.MIT