Model Context Protocol

Grove Speaks MCP — Both Directions

Workflows and skills surface to MCP clients (Claude Desktop, Claude Code, Cursor) as tools and prompts. The new grove__* provisioning built-ins let an MCP client author workflows and agents over the protocol — no Grove-specific dialect, no REST proxy, no SDK. Point your LLM at /mcp/rpc and it can build the workflow it then invokes.

01

Grove Is Both an MCP Client and an MCP Server

Most MCP coverage talks about Grove consuming MCP servers — that still works. What's new is the reverse: Grove is an MCP server, and any MCP-compatible client can drive it.

Outbound — Grove as MCP Client

Register external MCP servers and their tools auto-discover into the unified tool registry alongside built-in, connector, and external tools. Autonomous agents reach them through a per-tenant server catalog — each agent declares which servers it may use, and Grove calls out on its behalf mid-run.

Inbound — Grove as MCP Server

POST /mcp/rpc implements the JSON-RPC protocol with Streamable HTTP SSE, prompts, resources, completion, subscribe/updated, and an audit log. Multi-replica notification fanout via Redis pubsub. OAuth 2.1 client_credentials grant alongside long-lived bearer keys.

02

What's Exposed to MCP Clients

Every workflow tagged mcp_exposed appears under tools/list with its input schema. Skills appear as MCP prompts; runs and sessions appear as resources (with subscribe for live updates). The whole thing is standard MCP — no client-side awareness of Grove needed.

Workflows → Tools

Each mcp_exposed=true workflow appears in tools/list using its name and input schema. tools/call starts a run and returns the outputs; with Accept: text/event-stream the response is a live SSE of notifications/progress events followed by the final result.

Skills → Prompts

Reusable skill templates surface under prompts/list and prompts/get. Placeholders become prompt arguments; the response is the rendered Portable Text as user messages, ready for the client's chat composer.

Runs & Sessions → Resources

Active runs and sessions appear under resources/list with templated URIs (grove://runs/<id>, grove://sessions/<id>). resources/subscribe pushes resources/updated on new session messages.

Forever-Retained Audit Log

Every JSON-RPC dispatch appends a row to mcp_audit_log: caller, method, request id, status, duration, the touched tool/resource/prompt/target. Queryable under GET /mcp/audit-log with owner / key / method / time filters.

03

Provisioning Built-Ins: Let the LLM Author

The grove__* built-in tools turn an MCP session into an authoring surface. From a Provision-scoped key, an LLM can build a workflow from scratch, validate it, publish it, run it, and clean up. Same loop authors agents.

Built-in
Scope
What it does
grove__list_workflows_all
Provision
Lists every workflow visible to the caller, published or not.
grove__get_workflow
Provision
Returns the full DAG for one workflow by id or name.
grove__validate_workflow
Invoke
Dry-run validation of a workflow body. No write. Broadly available.
grove__create_workflow
Provision
Creates a workflow. Always plants mcp_exposed=false regardless of body — publication is a separate call.
grove__publish_workflow
Provision
Flips mcp_exposed=true. Requires expected_version. Fires the (coalesced) tools/list_changed notification.
grove__unpublish_workflow
Provision
Mirror of publish.
grove__update_workflow_metadata
Provision
Description, purpose, category, etc. Cannot change mcp_exposed — that's the publish tools' job.
grove__delete_workflow
Provision
Soft-delete with expected_version. Fires tools/list_changed if the workflow was published.
grove__upsert_agent
Provision
Create or replace an agent definition. Allowlist validated against the same rules as the REST surface.
grove__list_agents_all / grove__get_agent / grove__delete_agent
Provision
The rest of the agent CRUD surface, same shape as the workflow tools.
grove__register_tool_provider / grove__list_tool_providers / grove__unregister_tool_provider
Provision
Manage the tenant's catalog of external MCP servers that agents can call. Registered servers become available to any agent that names them in its tool providers.
grove__list_available_agent_tools
Invoke
Categorised list of tool names an agent allowlist may contain: built-in, workspace, git, special. Helps the LLM construct a valid allowlist.
04

Safety Properties Baked In

An LLM with both invoke and create powers is one prompt injection away from authoring and silently invoking a malicious tool. The provisioning surface is designed against that scenario.

Default-Unpublished

grove__create_workflow always plants mcp_exposed=false — the body's mcp_exposed is ignored. Publication is a separately-auditable grove__publish_workflow call. Breaks the inject → self-invoke chain.

Optimistic Concurrency

Mutating tools require expected_version. Mismatch returns -32602 invalid_params with both versions in data, so a client can refetch and retry instead of clobbering a concurrent writer.

Tenant Fence

Provisioning tools refuse calls from tenantless keys with -32602 invalid_params. The dispatcher checks requires_tenant() on every call; cross-tenant rows are indistinguishable from missing ones.

Secrets Carve-Out

There is no grove__create_secret, and there won't be. Writing plaintext secret material through a bearer-token JSON-RPC surface is a needless attack-surface enlargement. Secrets stay REST-only.

05

Scope Tiers & the Two-Key Pattern

MCP keys carry one of four scopes — read-only, invoke, provision, admin. Provision sits between Invoke and Admin: it gates the grove__* authoring surface without granting operator-level powers (audit-log reads, key rotation). Methods above the caller's scope return method_not_found so the wire response doesn't leak which methods exist.

Long-lived Invoke key

For the everyday runtime client that calls published workflows. Survives session restarts. Cannot create or modify anything.

Short-lived Provision key

Issued only when the operator wants the LLM to author. Revoked when the authoring session ends. Even if the LLM is prompt-injected, the blast radius is bounded by the key's lifetime.

The recipe in the KB — kb/external/mcp-clients.md — walks through minting both keys, configuring each of the three common clients, and revoking when done.

06

Wiring It Up

Three of the most common MCP clients out today — Claude Desktop, Claude Code, Cursor — configure the same way. Point them at POST /mcp/rpc with a bearer token. The server speaks streamable HTTP; SSE just upgrades on a per-call basis.

# Claude Code — register Grove as a project-scoped MCP server
claude mcp add grove-author \
  --transport http \
  --url https://<your-grove>/mcp/rpc \
  --header "Authorization: Bearer <provision-raw-key>"

claude mcp add grove-runtime \
  --transport http \
  --url https://<your-grove>/mcp/rpc \
  --header "Authorization: Bearer <invoke-raw-key>"
// Claude Desktop — claude_desktop_config.json
{
  "mcpServers": {
    "grove-author": {
      "url": "https://<your-grove>/mcp/rpc",
      "headers": { "Authorization": "Bearer <provision-raw-key>" }
    },
    "grove-runtime": {
      "url": "https://<your-grove>/mcp/rpc",
      "headers": { "Authorization": "Bearer <invoke-raw-key>" }
    }
  }
}

Cursor's ~/.cursor/mcp.json uses the same shape as Claude Desktop. Both keys get minted through Grove's existing POST /mcp/keys REST surface; only Admin callers may bind a key to a specific tenant_id — preventing escalation by minting keys for other tenants.

07

Multi-Replica Notification Fanout

When Grove runs N replicas behind a load balancer, a mutation on replica A still has to wake the tools/list_changed subscriber connected to replica B. Set GROVE_MCP_REDIS_URL and notifications publish to a Redis pubsub channel; each replica re-injects incoming messages into its local broadcast, suppressing self-echo by replica id. Publish failures are logged and dropped — the Redis bus must not break the request that triggered the emit.

Ready to deploy AI workflows in your cloud?

Contact Sales