Skip to main content
Glama
farmos-mcp

farmos-mcp

by c41m4n

farmos-mcp

An MCP server for farmOS 4. It lets an AI assistant look up and record farm data (assets, logs, plans, quantities, taxonomy terms) through farmOS's JSON:API.

It was written against the farmOS 4.0 API changes: assets use the archived boolean instead of a status, plans have planning / active / done / abandoned statuses, and logs can be abandoned. On a farmOS 3 server it falls back to the old status handling for archiving.

Early release (v0.1.0, alpha). Unit-tested against a mock farmOS server, but not yet run against a live farmOS instance. Expect rough edges and possible breaking changes. Try it on a test or demo instance first (see "Verify against your server" below), and do not point write access at production data you can't restore.

Built with AI. This project was written by an AI assistant (Claude, by Anthropic) working with a human maintainer. See AI disclosure.

Tools

Tool

What it does

Needs writes

farm_info

Server name/version, current user, available resource types, whether writes are on

list_resource_types

Entity types and bundles on this server

query_records

Filter / sort / page / include on any one bundle

get_record

One record by UUID

search_assets

Find assets by name across all bundles; active/archived filter

list_logs

Logs across bundles by status, asset, text, date range

list_plans

Plans by status / archived / name

list_terms

Taxonomy terms in a vocabulary (units, categories, plant types...)

create_log

Log with locations, categories and quantities in one call

yes

create_record

Create an asset, log, plan, quantity, term or organization

yes

update_record

Change fields on a record

yes

set_archived

Archive / restore an asset or plan

yes

set_log_status

pending, done or abandoned

yes

delete_record

Permanently delete a record

yes + delete

Related MCP server: drupal-mcp

Safety defaults

  • Read-only by default. Writes need FARMOS_ALLOW_WRITES=true. Deletes additionally need FARMOS_ALLOW_DELETE=true.

  • Writes are limited to asset, log, plan, quantity, taxonomy_term and organization. Users, roles and configuration cannot be written through this server.

  • Credentials are only sent to the configured FARMOS_URL. Pagination links pointing at another host are refused. Plain http:// is rejected for non-local hosts.

  • Everything the assistant can do is bounded by the farmOS account it logs in as. Use a dedicated account with the lowest role that does the job (see Roles below).

farmOS setup

farmOS 4 made the API and OAuth2 server optional, so check these on your instance:

  1. Enable the API module (farm_api) and the OAuth2 server module (farm_api_oauth) under Administration > Modules (or drush en farm_api farm_api_oauth).

  2. Create OAuth2 keys. farmOS 4 no longer generates them at install. See OAuth2 keys.

  3. Pick an auth method:

    • Password grant (simplest). Uses the built-in farm client with a farmOS username and password. This is a legacy grant type: it also requires the simple_oauth_password_grant module, and is only appropriate when the MCP server is a trusted first-party client on your own machine.

    • Client credentials (better for unattended use). Create a client (consumer) in farmOS with a secret and the client credentials grant, mapped to a user. Set FARMOS_CLIENT_ID and FARMOS_CLIENT_SECRET.

Roles

farmOS 4 split the default roles into separate modules and changed what they can do:

  • Viewer: read-only. Right for a read-only deployment.

  • Worker: can create and edit records, but in v4 can no longer delete other users' records or edit/delete taxonomy terms.

  • Manager: full records access including terms and deletes.

The OAuth scope must match a role the user has. The default scope here is farm_manager; change FARMOS_SCOPE to farm_worker or farm_viewer for a narrower token.

Install

cd farmos-mcp
python3 -m venv .venv
.venv/bin/pip install -e .

Requires Python 3.11+ and mcp 2.x (this project uses the 2.x MCPServer API).

Configure

Environment variables (see .env.example):

Variable

Default

Meaning

FARMOS_URL

required

Base URL, e.g. https://farm.example.com

FARMOS_USERNAME / FARMOS_PASSWORD

Password grant credentials

FARMOS_CLIENT_ID

farm

OAuth client id

FARMOS_CLIENT_SECRET

Client secret (client credentials grant)

FARMOS_SCOPE

farm_manager

OAuth scope (farm_manager, farm_worker, farm_viewer, ...)

FARMOS_TOKEN_PATH

/oauth/token

Token endpoint path

FARMOS_ALLOW_WRITES

false

Enable create/update/archive/status tools

FARMOS_ALLOW_DELETE

false

Enable delete_record (also needs writes)

FARMOS_TIMEOUT

30

Request timeout, seconds

FARMOS_INSECURE_TLS

false

Skip TLS verification (not recommended)

FARMOS_ALLOW_INSECURE_HTTP

false

Allow http:// to a non-local host

If a password is set it wins; otherwise a client secret selects the client credentials grant.

Claude Desktop / Claude Code

{
  "mcpServers": {
    "farmos": {
      "command": "/absolute/path/to/farmos-mcp/.venv/bin/farmos-mcp",
      "env": {
        "FARMOS_URL": "https://farm.example.com",
        "FARMOS_USERNAME": "claude-assistant",
        "FARMOS_PASSWORD": "...",
        "FARMOS_SCOPE": "farm_worker",
        "FARMOS_ALLOW_WRITES": "false"
      }
    }
  }
}

For Claude Code: claude mcp add farmos --env FARMOS_URL=https://farm.example.com --env FARMOS_USERNAME=... --env FARMOS_PASSWORD=... -- /absolute/path/to/farmos-mcp/.venv/bin/farmos-mcp

Verify against your server

Do these in order against a test instance (the public demo is a reasonable target for reads):

  1. Ask for farm_info. You should see version 4.x and a list of resource types. A token error here means a setup problem from the section above, not a code problem.

  2. search_assets with no arguments, then list_logs with status: done.

  3. Enable writes on a throwaway instance and try create_log with a quantity.

Parts most worth checking on a real server, because they follow documented behavior but were only exercised against the mock:

  • boolean filters (archived is sent as 0/1),

  • quantity value written as {"decimal": "..."},

  • timestamp filters as epoch seconds, timestamp writes as ISO 8601,

  • the token endpoint path (/oauth/token, overridable).

Development

.venv/bin/pip install -e ".[dev]"
.venv/bin/pytest

Tests use httpx.MockTransport, so no farmOS server is needed.

AI disclosure

This repository was developed with substantial use of AI:

  • The code, tests and documentation were written by Claude (Claude Sonnet 5.5, Anthropic) in an interactive session with the maintainer, who directed the work. The design choices, API behavior and docs were drafted by the model from farmOS's public documentation.

  • The farmOS behavior is based on documentation, not on a live server. The model had no access to a real farmOS instance, so request shapes (filters, quantity values, timestamps, the OAuth token endpoint) follow the published docs and have only been exercised against a mock written alongside the code. The mock encodes the same assumptions as the code, so passing tests do not prove the server matches real farmOS behavior.

  • Human review is limited. The code has not had a full independent audit. Treat it as you would any unreviewed third-party code: read it before running it, especially before giving it credentials or write access.

  • Security-relevant choices to check: this server sends your farmOS credentials to the configured URL, can create/modify/delete records when enabled, and is driven by an AI model that can make mistakes. Use a dedicated low-privilege farmOS account (farm_viewer or farm_worker), keep FARMOS_ALLOW_WRITES and FARMOS_ALLOW_DELETE off unless you need them, and keep backups.

Issues and pull requests that fix incorrect farmOS behavior are especially welcome. Please say in your PR if AI tools were used.

Not included

  • Uploading files/images, geometry editing, and data streams.

  • farmOS add-on modules with custom fields are reachable through query_records / create_record, but have no dedicated tools.

  • Only the stdio transport. Remote/HTTP hosting would need mcp.run(transport="streamable-http") plus your own authentication in front.

Available Tools

14 tools
create_logA

Create a log, optionally with locations, categories and quantities. Quantities are created first and then linked; if the log fails to save, the new quantities are removed again. Requires writes to be enabled.

Inputs: name (required), bundle (required), notes, assets, +7 more. Returns: object

create_recordA

Create any record. Prefer create_log for logs with quantities. Requires writes to be enabled. Names are not unique in farmOS, so search first to avoid duplicates.

Inputs: bundle (required), entity_type (required), attributes, relationships. Returns: object

delete_recordA
DestructiveIdempotent

Permanently delete a record. This cannot be undone and may leave other records with dangling references. For assets and plans, set_archived is almost always what is wanted. Requires FARMOS_ALLOW_DELETE=true; confirm with the user first.

Inputs: id (required), bundle (required), entity_type (required). Returns: object

farm_infoA
Read-only

Show the farmOS server name, version, the authenticated user, which resource types exist, and whether this MCP server currently allows writes and deletes. Call this first when unsure what the instance supports.

Inputs: no named parameters. Returns: object

get_recordB
Read-only

Fetch a single record by UUID.

Inputs: id (required), bundle (required), entity_type (required), include. Returns: object

list_logsA
Read-only

List logs across bundles, newest first by default, filtered by status, asset, text or date range.

Inputs: end, sort, limit, start, +4 more. Returns: object

list_plansA
Read-only

List plans (e.g. crop or grazing plans). Plan types only exist when the matching farmOS modules are installed.

Inputs: limit, status, bundles, archived, +1 more. Returns: object

list_resource_typesA
Read-only

List entity types and their bundles (e.g. asset: land, plant, animal; log: activity, harvest, ...). Which bundles exist depends on the farmOS modules that are enabled.

Inputs: refresh, entity_type. Returns: object

list_termsA
Read-only

List taxonomy terms in one vocabulary. Use the returned UUIDs when linking logs and assets to categories, units, seasons and plant types.

Inputs: vocabulary (required), limit, offset, name_contains. Returns: object

query_recordsA
Read-only

Query one bundle of records with filtering, sorting and paging. This is the general read tool; search_assets, list_logs and list_plans cover the common cases.

Inputs: bundle (required), entity_type (required), sort, limit, +5 more. Returns: object

search_assetsA
Read-only

Find assets across bundles (land, plants, animals, equipment, structures, ...) by name, optionally restricted to active or archived assets.

Inputs: limit, query, bundles, archived. Returns: object

set_archivedA
Idempotent

Archive or restore an asset or plan. In farmOS 4 this sets the 'archived' boolean (assets no longer have a status). On farmOS 3 it falls back to the status field. Requires writes to be enabled.

Inputs: id (required), bundle (required), entity_type (required), archived. Returns: object

set_log_statusA
Idempotent

Mark a log pending, done, or abandoned (never going to happen, kept for history). Requires writes to be enabled.

Inputs: id (required), bundle (required), status (required). Returns: object

update_recordA
Idempotent

Update fields on an existing record (PATCH). Only the fields you pass change. Requires writes to be enabled.

Inputs: id (required), bundle (required), entity_type (required), attributes, +1 more. Returns: object

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A3.9/5.0

    Scored across 14 tools

    Disambiguation5/5

    The tools are highly differentiated by their scope and action. General record operations are distinct from specific asset, log, and plan operations, making selection intuitive.

    Naming Consistency4/5

    The majority of tools follow the 'verb_noun' convention (e.g., list_logs, create_record). While there are variations like 'set_archived', these follow a predictable pattern for state modification.

    Tool Count5/5

    With 14 tools, the set is perfectly scoped. It covers the entire lifecycle and metadata needs of a complex system without being overly granular or sparse.

    Completeness4/5

    The set provides solid CRUD and state management coverage for its core entities (records, logs, assets). While highly complete, advanced relational query logic might require chaining multiple tools.

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      D
      maintenance
      Enables AI assistants to interact with your local Logseq knowledge base through advanced search, content creation, template management, and knowledge organization with privacy-first, local-only operations.
      23 npm
      7
      MIT
    • A
      license
      A
      quality
      D
      maintenance
      Enables AI assistants to read, write, and manage Obsidian notes, folders, and periodic notes via the Local REST API, including search and command execution.
      14
      MIT
    • A
      license
      Not graded
      quality
      D
      maintenance
      A read-only MCP server for the Auralogs logging platform, enabling AI agents to query production logs, search errors, and retrieve AI analyses without write access. It allows you to ask your coding assistant 'what's broken in production right now?' by connecting to your logs via a simple bearer auth key.
      MIT