What is MCP?

The Model Context Protocol is Anthropic’s open spec for letting LLMs call external tools over JSON-RPC. garden.gg hosts a Streamable HTTP MCP server at https://garden.gg/mcp so any MCP-aware client can connect to your account and act on your data.

What you can ask Claude to do:

  • “What’s due in my garden today?”
  • “List my plots.”
  • “What plants are in my main bed?”
  • “I just watered Plot A — log it.”
  • “Did I harvest anything this week?”
  • “What’s the weather like?”

The server is OAuth-only — no API keys to paste anywhere. You click Authorize once per client; everything else is invisible.


Connecting Claude.ai

In Claude.ai:

  1. Open Settings → Connectors.
  2. Click Add custom connector.
  3. Server URL: https://garden.gg/mcp.
  4. Save. Claude.ai will redirect you to garden.gg/authorize — sign in if prompted, review what the connector wants access to, click Authorize.
  5. You’ll land back in Claude.ai with the connection live. Try asking “what plots do I have on garden.gg?”

Connecting Claude Desktop

Claude Desktop reads claude_desktop_config.json. Add an entry like:

{
  "mcpServers": {
    "garden-gg": {
      "url": "https://garden.gg/mcp"
    }
  }
}

Restart Claude Desktop. The first time it tries to call a tool, it’ll open the OAuth flow in your browser. Same drill: sign in, review, Authorize.

Connecting Cursor / Continue / other clients

Any MCP client that supports HTTP transport with OAuth will work. Point it at https://garden.gg/mcp and let the OAuth discovery do the rest — the server publishes RFC 9728 + RFC 8414 metadata at /.well-known/oauth-protected-resource and /.well-known/oauth-authorization-server.


Tools available

ToolTypeArgsDescription
list_plotsreadAll your plots with summary metadata
get_plotreadplot_idDrill down into one plot — schedules, last_watered/fertilized, plant count, hero image
list_plants_in_plotreadplot_idWhat’s growing in a specific plot
list_recent_eventsreadoptional plot_id, event_type, sinceRead your activity log. since accepts RFC 3339 (2026-04-29T00:00:00Z) or relative (7d, 24h)
list_harvestsreadoptional plot_id, since, untilHarvest history with plot + plant names joined and weight_grams surfaced
list_seed_inventoryreadoptional search, supplierUp to 100 of your seed packets
list_seedlingsreadoptional statusSeedlings pipeline (active/germinated/hardening/transplanted)
get_sensor_readingsreadplot_idLatest reading + 24h min/max per sensor kind for a plot. Empty sensors: [] if no IoT kit attached
list_tasks_todayreadWatering, fertilizing, harvest readiness due today
list_tasks_this_weekreadSame, 7-day window
get_weatherreadCurrent conditions + 3-day forecast for your zone
search_plant_varietiesreadquerySearch your variety library
log_eventwriteevent_type, target idLog a care or observation event. See log_event verbs below
create_seed_inventory_itemswriteitems (1-50)Create seed packets in bulk
update_seed_inventory_itemswriteitems with id (1-50)Update owned seed packets in bulk
delete_seed_inventory_itemswriteids (1-50), confirm: trueDelete owned seed packets
create_seedlingwriteone of seed_inventory_id/plant_id + fieldsStart a seedling (decrements inventory if from a packet)
update_seedlingwriteseedling_id + fieldsUpdate an owned seedling
delete_seedlingwriteseedling_id, confirm: trueDelete an owned seedling
create_plotwriteplot fieldsCreate a new plot
update_plotwriteplot_id + fieldsUpdate an owned plot
delete_plotwriteplot_id, confirm: true, confirm_plot_nameDelete an owned plot (name match required)
add_plant_to_plotwriteplot_id, plant_id + fieldsPlace a plant in an owned plot
update_plot_plantwriteplot_plant_id + fieldsUpdate a plot_plant
remove_plant_from_plotwriteplot_plant_id, confirm: trueRemove a plot_plant
create_plant_varietywritevariety fieldsAdd a variety to your library
update_plant_varietywritevariety_id + fieldsUpdate an owned variety
delete_plant_varietywritevariety_id, confirm: trueDelete an unused owned variety
delete_eventwriteevent_id, confirm: trueDelete a logged event; recomputes last_watered_on, harvest totals

Write tools — destructive confirmation

Every delete_* and remove_* tool requires confirm: true. delete_plot also requires confirm_plot_name to exactly match the plot’s current name — anti-typo guard so a fat-fingered plot_id doesn’t silently nuke the wrong garden.

log_event verbs

log_event is one tool but supports eight verbs, each with its own required-arg shape:

event_typeTargetsRequiredOptional
watera plotplot_idnotes
fertilizea plotplot_idnotes
mulcha plotplot_idnotes
harvesta plot_plantplot_plant_idweight_grams, notes
transplanta plot_plantplot_plant_iddestination_plot_id (must be your plot), notes
prunea plot_plantplot_plant_idnotes
pest_observationa plot OR plot_plantone of plot_id/plot_plant_id plus descriptionseverity (low/medium/high), notes
problema plot OR plot_plantone of plot_id/plot_plant_id plus descriptionseverity, notes

Result shape

Every list tool returns a stable envelope:

{
  "items": [...],     // up to the tool's documented cap (50 or 100)
  "count": 23,        // == items.length
  "has_more": false   // true means narrow your filters and call again
}

Single-entity tools (get_plot, get_sensor_readings, get_weather) return the entity directly without a wrapper.

If has_more: true, the tool found more matching rows than fit in its cap. The right move is a tighter filter — pass a narrower since window, or scope to one plot_id. We do not paginate with cursors; real-world MCP clients drop them too often, and LLMs naturally reason in filtered queries anyway.

When a tool’s arguments are malformed (bad UUID, missing required field, unknown enum value), the response has isError: true and the admin observability log records error_code: "invalid_args". When a target id doesn’t exist or isn’t yours, the response is not_found with the same shape — there’s no way to enumerate other users’ ids by poking the tool.


Daily limits

MCP calls count against a per-day quota that varies by plan:

PlanDaily MCP calls
Sprout (free)50
Bloom500
Harvest5000

Quotas reset at UTC midnight. If you hit the limit, the tool returns an error message Claude can recover from — your account isn’t suspended. You can see your current usage on the Settings page in the Connected Applications section.


Privacy

The MCP server logs only which tool was called and whether it succeeded — never the arguments or result payloads. We do not retain your search queries, plot names, or any free-text content you ask Claude to send through.

Specifically, the mcp_usage_log table holds (user_id, oauth_client_id, tool_name, success, latency_ms, error_code, created_at) and nothing else.


Managing connected clients

You can see and revoke every authorized client from Settings → Connected Applications. Revoke is immediate — the next request from that client returns 401 within one cycle.

If a client’s tokens are ever leaked, revoking from the Settings page invalidates every access token AND every refresh token for that client in one shot. The user re-authorizes from the consent screen on next use.


How the OAuth flow works (technical)

For developers building their own MCP clients:

  1. Discovery: GET https://garden.gg/.well-known/oauth-protected-resource to learn the auth-server URL.
  2. Dynamic Client Registration (RFC 7591): POST to /oauth/register with client_name + redirect_uris. You get a client_id (no client_secret — public clients only).
  3. Authorization (RFC 6749 with PKCE-S256): redirect the user to /oauth/authorize with the standard params. PKCE is requiredplain is banned. redirect_uri must exact-match what you registered.
  4. Token exchange: POST to /oauth/token with the code + verifier. You get an access token (1h TTL) and a refresh token (90d TTL).
  5. Use the access token: Authorization: Bearer … on POST /mcp.
  6. Refresh: POST to /oauth/token with the refresh. The old refresh is single-use and rotates on every call. Replaying a used refresh invalidates the entire chain — both the legitimate client and the attacker get logged out, the user re-authorizes.

Tokens are opaque (gg_at_…, gg_rt_…) and stored hashed at rest. Plaintext is never logged.


Troubleshooting

“Authorization failed” on the consent screen. The pending request expired (10-minute TTL) or the redirect_uri doesn’t match what was registered. Restart the flow from your MCP client.

Tool calls return 401. Your access token expired (1h TTL) or you revoked the client from Settings. Refresh tokens are good for 90 days; your client should rotate them automatically.

“Daily limit reached”. Wait until UTC midnight or upgrade your plan. Admins can grant per-user overrides for support tickets.


Built something interesting with the garden.gg MCP server? We’d love to hear about it: [email protected].