← Docs

MCP for AI assistants

Nextfarm's Model Context Protocol server lets any MCP-capable assistant (ChatGPT, Claude, Copilot, Cursor, Gemini, Grok…) or your own read farm data. Two ways to connect: just the URL (the user signs in to NextFarm, picks a farm, ticks permissions — OAuth 2.1) or an API key for machines.

Address
Productionhttps://mcp.nextfarm.vn/mcp
Sandboxhttps://mcp-dev.nextfarm.vn/mcp

Option 1 — Just the URL (OAuth)

Paste https://mcp.nextfarm.vn/mcp into the assistant you use — ChatGPT (Apps & Connectors, Developer mode), claude.ai / Claude Code (Connectors), Copilot Studio (Tools › Model Context Protocol), Cursor, Gemini CLI, Grok (Connectors › Custom), VS Code… (per-client config on the AI hub). The assistant opens the NextFarm sign-in → pick a farm → tick permissions → Allow. It can only do what the signed-in person can do on the farm; Write is unticked by default and the owner can switch it off entirely. Disconnect in the app › System › Apps › AI apps ⇒ the next call is refused.

Add an MCP server / connector in your AI assistant
  URL: https://mcp.nextfarm.vn/mcp
→ Connect → sign in to NextFarm → pick a farm → Allow
OAuth scopeAllowsWrite?
gis:readMap, parcels, zones, seasons, farmers
iot:readDevices, sensor readings, alerts
harvest:readHarvests, traceability, QR codes, certificates, prices
office:readFarm books, tasks, calendar, automation rules
reports:readView and export reports

Standards: OAuth 2.1 + PKCE (S256), Protected Resource Metadata (RFC 9728), Authorization Server Metadata (RFC 8414), Dynamic Client Registration (RFC 7591) or Client ID Metadata Document, Resource Indicators (RFC 8707). Access tokens last 1 hour, refresh tokens rotate. Missing scope ⇒ 403 insufficient_scope (the assistant asks for more). The assistant's token never reaches the API: the MCP server exchanges it for a short-lived delegated token via Token Exchange (RFC 8693), capped at exactly what you consented to.

Option 2 — API key (machines, n8n, your server)

Create a key

In System › API keys, create a dedicated key for the assistant with only the read scopes it needs.

Connect the assistant

{
  "url": "https://mcp.nextfarm.vn/mcp",
  "transport": "streamable-http",
  "headers": { "Authorization": "Bearer nfk_…" }
}
Not sure it works? Check the connection right on the AI hub, or open the MCP Tester (it can sign in with OAuth too). Web assistants (ChatGPT, claude.ai…) do not take an API key — use Option 1.

Tools

ToolWhat it doesScope
farm_overviewParcel area grouped by household, zone or crop: number of households, parcels, total area (ha) and parcels without a boundary. Sorted by area, largest first.gis:read
gis_crop_types_listThe farm's crop type catalogue: code, name and category. Use the crop type ID to filter parcels, seasons and yields.gis:read
gis_farmers_listFarmer households / members of the sourcing area: name, zone, group and member type. Filter by zone, group or type.gis:read
gis_parcels_getOne parcel: name, code, area, zone, owner, current crop and status.gis:read
gis_parcels_listThe farm's parcels: code, area (ha), zone, owner, current crop and status. Filter by zone, crop or status.gis:read
gis_searchSearch parcels, seasons, farmers and zones by keyword; groups outside the key's scopes come back empty.gis:read
gis_seasons_groupsSeasons with the same crop and season name across parcels in one year (e.g. Rice · Winter-Spring): parcel count, total area, earliest/latest planting date.gis:read
gis_seasons_listSeasons for one parcel (cultivation history) or for a year: crop, season name, planting date, expected harvest date and status. Provide a parcel or a year.gis:read
gis_zones_statsNumber of parcels and total area (ha) of one zone.gis:read
certification_expiringCertificates (VietGAP, GlobalGAP, organic…) about to expire or already expired, sorted by expiry date.harvest:read
harvest_phi_activeParcels, ponds and pens currently under a pesticide pre-harvest interval or veterinary withdrawal period: earliest safe date and the blocking application.harvest:read
harvest_record_listDeclared harvest records: parcel, crop, declared yield (kg), status (draft · confirmed · verified · collected · void), harvest date and traceability lot.harvest:read
harvest_searchSearch harvest records, QR labels and certificates by keyword (record code, label code, certificate name).harvest:read
harvest_summaryHarvested yield (confirmed records only) grouped by household, zone, crop or parcel within a harvest date range. Sorted by total kg, largest first.harvest:read
harvest_trace_getOne traceability lot: cultivation log, certificates and photos — what a buyer sees when scanning the QR label.harvest:read
harvest_trace_listPublished traceability lots of the farm: parcel, zone, product, certification, harvest date, farmer and number of stages.harvest:read
phi_statusWhether a parcel is still within a pesticide pre-harvest interval, the earliest safe harvest date and the application holding it.harvest:read
iot_alerts_listSensor threshold alerts: device, metric, value, threshold, severity and handling status.iot:read
iot_command_statusLatest commands sent to one controller: command type, status, sent time and whether the device acknowledged it.iot:read
iot_device_listThe farm's IoT devices: name, type, online or offline, last report time. Filter by status, parcel or zone.iot:read
iot_devices_searchSearch devices by name or code.iot:read
iot_irrigation_outputsIrrigation outputs of one controller: type (pump, zone valve, fertigation), index and the user-given name (e.g. 'Block A').iot:read
iot_readings_historySensor reading history for a device or zone within a time range, newest first.iot:read
iot_readings_latestThe latest value of each sensor (temperature, humidity, EC, pH…) for the whole farm or one zone.iot:read
iot_schedule_upcomingUpcoming scheduled irrigation runs: controller, start time, duration (seconds), valves, skipped or already run.iot:read
office_automations_listThe farm's automation rules: name, status, trigger type and last run.office:read
office_books_fieldsColumns of one table: name, data type and options — needed to read row values correctly.office:read
office_books_listThe farm's custom books (logs, inventory, costs…): name, description and number of tables.office:read
office_books_recordsRead rows of a book table, paginated; values keyed by column ID.office:read
office_books_tablesTables inside one farm book.office:read
report_catalogAvailable farm reports: code, name, group and the number of data blocks you can see.reports:read
report_queryRun a report by code over a date range: KPIs, time series, breakdowns and tables. Without dates the last 30 days are used.reports:read
farm_overview — Parcel area summary

Parcel area grouped by household, zone or crop: number of households, parcels, total area (ha) and parcels without a boundary. Sorted by area, largest first.

Parameters (JSON Schema)
{
  "additionalProperties": false,
  "properties": {
    "crop_type_id": {
      "description": "Only one crop type",
      "format": "uuid",
      "type": "string"
    },
    "group_by": {
      "description": "Group by: owner · zone · crop",
      "type": "string"
    },
    "page_size": {
      "description": "Maximum number of groups",
      "type": "integer"
    },
    "status": {
      "description": "Parcel status",
      "type": "string"
    },
    "zone_id": {
      "description": "Only one zone",
      "format": "uuid",
      "type": "string"
    }
  },
  "required": [],
  "type": "object"
}
Example arguments
{
  "group_by": "zone"
}
gis_crop_types_list — Crop types

The farm's crop type catalogue: code, name and category. Use the crop type ID to filter parcels, seasons and yields.

Parameters (JSON Schema)
{
  "additionalProperties": false,
  "properties": {
    "category": {
      "description": "Crop category (e.g. rice, fruit trees)",
      "type": "string"
    }
  },
  "required": [],
  "type": "object"
}
gis_farmers_list — Households

Farmer households / members of the sourcing area: name, zone, group and member type. Filter by zone, group or type.

Parameters (JSON Schema)
{
  "additionalProperties": false,
  "properties": {
    "groupId": {
      "description": "Only one household group",
      "format": "uuid",
      "type": "string"
    },
    "memberType": {
      "description": "Member type",
      "type": "string"
    },
    "pageSize": {
      "description": "Maximum rows",
      "type": "integer"
    },
    "zoneId": {
      "description": "Only one zone",
      "format": "uuid",
      "type": "string"
    }
  },
  "required": [],
  "type": "object"
}
gis_parcels_get — Parcel detail

One parcel: name, code, area, zone, owner, current crop and status.

Parameters (JSON Schema)
{
  "additionalProperties": false,
  "properties": {
    "id": {
      "description": "Parcel ID (UUID)",
      "format": "uuid",
      "type": "string"
    }
  },
  "required": [
    "id"
  ],
  "type": "object"
}
Example arguments
{
  "id": "0190a3c2-5b1e-7c3d-8e4f-000000000001"
}
gis_parcels_list — Parcels

The farm's parcels: code, area (ha), zone, owner, current crop and status. Filter by zone, crop or status.

Parameters (JSON Schema)
{
  "additionalProperties": false,
  "properties": {
    "crop_type_id": {
      "description": "Only one crop type",
      "format": "uuid",
      "type": "string"
    },
    "page": {
      "description": "Page, from 1",
      "type": "integer"
    },
    "page_size": {
      "description": "Rows per page",
      "type": "integer"
    },
    "status": {
      "description": "Parcel status",
      "type": "string"
    },
    "zone_id": {
      "description": "Only one zone",
      "format": "uuid",
      "type": "string"
    }
  },
  "required": [],
  "type": "object"
}
Example arguments
{
  "page": 1,
  "page_size": 50
}
gis_seasons_groups — Season groups of a year

Seasons with the same crop and season name across parcels in one year (e.g. Rice · Winter-Spring): parcel count, total area, earliest/latest planting date.

Parameters (JSON Schema)
{
  "additionalProperties": false,
  "properties": {
    "branchId": {
      "description": "Only one branch / cooperative",
      "format": "uuid",
      "type": "string"
    },
    "year": {
      "description": "Year",
      "type": "integer"
    }
  },
  "required": [
    "year"
  ],
  "type": "object"
}
Example arguments
{
  "year": 2026
}
gis_seasons_list — Seasons

Seasons for one parcel (cultivation history) or for a year: crop, season name, planting date, expected harvest date and status. Provide a parcel or a year.

Parameters (JSON Schema)
{
  "additionalProperties": false,
  "properties": {
    "parcelId": {
      "description": "Parcel ID",
      "format": "uuid",
      "type": "string"
    },
    "year": {
      "description": "Year (e.g. 2026)",
      "type": "integer"
    }
  },
  "required": [],
  "type": "object"
}
Example arguments
{
  "year": 2026
}
gis_zones_stats — Zone statistics

Number of parcels and total area (ha) of one zone.

Parameters (JSON Schema)
{
  "additionalProperties": false,
  "properties": {
    "id": {
      "description": "Zone ID (UUID)",
      "format": "uuid",
      "type": "string"
    }
  },
  "required": [
    "id"
  ],
  "type": "object"
}
certification_expiring — Expiring certificates

Certificates (VietGAP, GlobalGAP, organic…) about to expire or already expired, sorted by expiry date.

Parameters (JSON Schema)
{
  "additionalProperties": false,
  "properties": {
    "include_expired": {
      "description": "Include already expired certificates",
      "type": "boolean"
    },
    "within_days": {
      "description": "Expiring within this many days (default 30)",
      "type": "integer"
    }
  },
  "required": [],
  "type": "object"
}
Example arguments
{
  "within_days": 60
}
harvest_phi_active — Parcels under pre-harvest interval

Parcels, ponds and pens currently under a pesticide pre-harvest interval or veterinary withdrawal period: earliest safe date and the blocking application.

Parameters (JSON Schema)
{
  "additionalProperties": false,
  "properties": {
    "on": {
      "description": "Check date (yyyy-MM-dd, default today)",
      "format": "date",
      "type": "string"
    }
  },
  "required": [],
  "type": "object"
}
harvest_record_list — Harvest records

Declared harvest records: parcel, crop, declared yield (kg), status (draft · confirmed · verified · collected · void), harvest date and traceability lot.

Parameters (JSON Schema)
{
  "additionalProperties": false,
  "properties": {
    "page": {
      "description": "Page, from 1",
      "type": "integer"
    },
    "page_size": {
      "description": "Rows per page",
      "type": "integer"
    },
    "status": {
      "description": "Filter by status",
      "type": "string"
    }
  },
  "required": [],
  "type": "object"
}
Example arguments
{
  "status": "confirmed"
}
harvest_summary — Yield summary

Harvested yield (confirmed records only) grouped by household, zone, crop or parcel within a harvest date range. Sorted by total kg, largest first.

Parameters (JSON Schema)
{
  "additionalProperties": false,
  "properties": {
    "crop_type_id": {
      "description": "Only one crop type",
      "format": "uuid",
      "type": "string"
    },
    "from": {
      "description": "Harvest date from (yyyy-MM-dd)",
      "format": "date",
      "type": "string"
    },
    "group_by": {
      "description": "parcel · crop · zone · owner",
      "type": "string"
    },
    "to": {
      "description": "Harvest date to (yyyy-MM-dd)",
      "format": "date",
      "type": "string"
    },
    "zone_id": {
      "description": "Only one zone",
      "format": "uuid",
      "type": "string"
    }
  },
  "required": [],
  "type": "object"
}
Example arguments
{
  "from": "2026-10-01",
  "group_by": "crop",
  "to": "2026-10-31"
}
harvest_trace_get — Traceability lot detail

One traceability lot: cultivation log, certificates and photos — what a buyer sees when scanning the QR label.

Parameters (JSON Schema)
{
  "additionalProperties": false,
  "properties": {
    "id": {
      "description": "Traceability lot ID (UUID)",
      "format": "uuid",
      "type": "string"
    }
  },
  "required": [
    "id"
  ],
  "type": "object"
}
harvest_trace_list — Traceability lots

Published traceability lots of the farm: parcel, zone, product, certification, harvest date, farmer and number of stages.

Parameters (JSON Schema)
{
  "additionalProperties": false,
  "properties": {},
  "required": [],
  "type": "object"
}
phi_status — Pre-harvest interval of a parcel

Whether a parcel is still within a pesticide pre-harvest interval, the earliest safe harvest date and the application holding it.

Parameters (JSON Schema)
{
  "additionalProperties": false,
  "properties": {
    "on": {
      "description": "Check date (yyyy-MM-dd, default today)",
      "format": "date",
      "type": "string"
    },
    "parcel_id": {
      "description": "Parcel ID (UUID)",
      "format": "uuid",
      "type": "string"
    }
  },
  "required": [
    "parcel_id"
  ],
  "type": "object"
}
iot_alerts_list — Sensor alerts

Sensor threshold alerts: device, metric, value, threshold, severity and handling status.

Parameters (JSON Schema)
{
  "additionalProperties": false,
  "properties": {
    "device_id": {
      "description": "One device",
      "format": "uuid",
      "type": "string"
    },
    "from": {
      "description": "From",
      "format": "date",
      "type": "string"
    },
    "page": {
      "description": "Page",
      "type": "integer"
    },
    "page_size": {
      "description": "Rows per page",
      "type": "integer"
    },
    "severity": {
      "description": "Severity",
      "type": "string"
    },
    "status": {
      "description": "Status (e.g. triggered, acknowledged, resolved)",
      "type": "string"
    },
    "to": {
      "description": "To",
      "format": "date",
      "type": "string"
    }
  },
  "required": [],
  "type": "object"
}
Example arguments
{
  "status": "triggered"
}
iot_command_status — Device commands

Latest commands sent to one controller: command type, status, sent time and whether the device acknowledged it.

Parameters (JSON Schema)
{
  "additionalProperties": false,
  "properties": {
    "device_id": {
      "description": "Controller ID (UUID)",
      "format": "uuid",
      "type": "string"
    },
    "limit": {
      "description": "Number of commands (max 20)",
      "type": "integer"
    }
  },
  "required": [
    "device_id"
  ],
  "type": "object"
}
iot_device_list — IoT devices

The farm's IoT devices: name, type, online or offline, last report time. Filter by status, parcel or zone.

Parameters (JSON Schema)
{
  "additionalProperties": false,
  "properties": {
    "page": {
      "description": "Page, from 1",
      "type": "integer"
    },
    "page_size": {
      "description": "Rows per page",
      "type": "integer"
    },
    "parcel_id": {
      "description": "Only devices of one parcel",
      "format": "uuid",
      "type": "string"
    },
    "status": {
      "description": "online · offline · active · inactive · maintenance",
      "type": "string"
    },
    "zone_id": {
      "description": "Only devices of one zone",
      "format": "uuid",
      "type": "string"
    }
  },
  "required": [],
  "type": "object"
}
Example arguments
{
  "status": "offline"
}
iot_irrigation_outputs — Controller valves and pumps

Irrigation outputs of one controller: type (pump, zone valve, fertigation), index and the user-given name (e.g. 'Block A').

Parameters (JSON Schema)
{
  "additionalProperties": false,
  "properties": {
    "device_id": {
      "description": "Controller ID (UUID)",
      "format": "uuid",
      "type": "string"
    }
  },
  "required": [
    "device_id"
  ],
  "type": "object"
}
iot_readings_history — Reading history

Sensor reading history for a device or zone within a time range, newest first.

Parameters (JSON Schema)
{
  "additionalProperties": false,
  "properties": {
    "device_id": {
      "description": "One device",
      "format": "uuid",
      "type": "string"
    },
    "from": {
      "description": "From (ISO 8601)",
      "format": "date",
      "type": "string"
    },
    "page": {
      "description": "Page, from 1",
      "type": "integer"
    },
    "page_size": {
      "description": "Rows per page (max 500)",
      "type": "integer"
    },
    "to": {
      "description": "To (ISO 8601)",
      "format": "date",
      "type": "string"
    },
    "zone_id": {
      "description": "One zone",
      "format": "uuid",
      "type": "string"
    }
  },
  "required": [],
  "type": "object"
}
Example arguments
{
  "from": "2026-10-27",
  "to": "2026-10-28"
}
iot_readings_latest — Latest readings

The latest value of each sensor (temperature, humidity, EC, pH…) for the whole farm or one zone.

Parameters (JSON Schema)
{
  "additionalProperties": false,
  "properties": {
    "zone_id": {
      "description": "Only sensors of one zone",
      "format": "uuid",
      "type": "string"
    }
  },
  "required": [],
  "type": "object"
}
iot_schedule_upcoming — Upcoming irrigation runs

Upcoming scheduled irrigation runs: controller, start time, duration (seconds), valves, skipped or already run.

Parameters (JSON Schema)
{
  "additionalProperties": false,
  "properties": {
    "days": {
      "description": "Number of days ahead (1–7)",
      "type": "integer"
    },
    "device_id": {
      "description": "Only one controller",
      "format": "uuid",
      "type": "string"
    },
    "from": {
      "description": "From date (yyyy-MM-dd, default today)",
      "format": "date",
      "type": "string"
    }
  },
  "required": [],
  "type": "object"
}
Example arguments
{
  "days": 2
}
office_automations_list — Automation rules

The farm's automation rules: name, status, trigger type and last run.

Parameters (JSON Schema)
{
  "additionalProperties": false,
  "properties": {
    "page": {
      "description": "Page, from 1",
      "type": "integer"
    },
    "page_size": {
      "description": "Rows per page",
      "type": "integer"
    },
    "search": {
      "description": "Keyword",
      "type": "string"
    },
    "status": {
      "description": "Status",
      "type": "string"
    }
  },
  "required": [],
  "type": "object"
}
office_books_fields — Table columns

Columns of one table: name, data type and options — needed to read row values correctly.

Parameters (JSON Schema)
{
  "additionalProperties": false,
  "properties": {
    "table_id": {
      "description": "Table ID (UUID)",
      "format": "uuid",
      "type": "string"
    }
  },
  "required": [
    "table_id"
  ],
  "type": "object"
}
office_books_list — Farm books

The farm's custom books (logs, inventory, costs…): name, description and number of tables.

Parameters (JSON Schema)
{
  "additionalProperties": false,
  "properties": {
    "page": {
      "description": "Page, from 1",
      "type": "integer"
    },
    "page_size": {
      "description": "Rows per page",
      "type": "integer"
    },
    "search": {
      "description": "Keyword",
      "type": "string"
    }
  },
  "required": [],
  "type": "object"
}
office_books_records — Table rows

Read rows of a book table, paginated; values keyed by column ID.

Parameters (JSON Schema)
{
  "additionalProperties": false,
  "properties": {
    "page": {
      "description": "Page, from 1",
      "type": "integer"
    },
    "page_size": {
      "description": "Rows per page",
      "type": "integer"
    },
    "table_id": {
      "description": "Table ID (UUID)",
      "format": "uuid",
      "type": "string"
    }
  },
  "required": [
    "table_id"
  ],
  "type": "object"
}
office_books_tables — Book tables

Tables inside one farm book.

Parameters (JSON Schema)
{
  "additionalProperties": false,
  "properties": {
    "app_id": {
      "description": "Book ID (UUID)",
      "format": "uuid",
      "type": "string"
    }
  },
  "required": [
    "app_id"
  ],
  "type": "object"
}
report_catalog — Report catalogue

Available farm reports: code, name, group and the number of data blocks you can see.

Parameters (JSON Schema)
{
  "additionalProperties": false,
  "properties": {},
  "required": [],
  "type": "object"
}
report_query — Run a report

Run a report by code over a date range: KPIs, time series, breakdowns and tables. Without dates the last 30 days are used.

Parameters (JSON Schema)
{
  "additionalProperties": false,
  "properties": {
    "code": {
      "description": "Report code (from the report catalogue)",
      "type": "string"
    },
    "from": {
      "description": "From date (yyyy-MM-dd)",
      "format": "date",
      "type": "string"
    },
    "grain": {
      "description": "Time grain: day · week · month · quarter · year",
      "type": "string"
    },
    "to": {
      "description": "To date (yyyy-MM-dd)",
      "format": "date",
      "type": "string"
    }
  },
  "required": [
    "code"
  ],
  "type": "object"
}
Example arguments
{
  "code": "SX-01",
  "from": "2026-10-01",
  "grain": "week",
  "to": "2026-10-28"
}
There are no device-control tools. If a key lacks the scope for a tool, the tool answers plainly "key is missing a scope (needs …)" so the assistant can tell you instead of guessing.

The server is stateless and never stores keys: each request uses exactly the key you send, and every scope rule applies as if you called the API directly.

Debugging MCP

SymptomFix
401 at initializeWrong / revoked / expired key, or a sandbox key on production — create a new key in the app.
Empty tools/listThe key has no matching scope — edit scopes in System › API keys.
406 / 415Your client misses Accept: application/json, text/event-stream or Content-Type.
405 on GETThe server is stateless (no SSE GET stream) — use POST only.
429Over 600 calls/minute for the key — slow down.
AI assistant "couldn't connect"OAuth is not live yet — use a client that takes an API key.

Full table and live checks: MCP Tester →

Full security rules for partners: Security →