Skip to content

EPIC: MCP server support #789

Description

@mforce

Important

Amended 2026-10-06. This body predates #514's module contracts. Since it was written, #787 closed, #804 closed with its work split into #806 and #809, and #793 and #794 moved to the OAuth milestone. Read the re-evaluation before picking up a slice. The body below is kept for history.

Note

Picking this up? Start here.

Blocked on #788 for most of it. Slices 1-2 can start now. Slices 3-6 cannot, because no client can
reach a tool until OAuth exists. Slice 6 also needs #787.

The design is finished and merged. Read
docs/plans/770-mcp-server/
in full before writing anything, especially 02-guards.md and 05-adversarial-review.md. The
design went through three rounds of adversarial review. They found six guards that could not go red
on their stated mutations, three of them in fixes for earlier rounds. The corrections are the
valuable part.

Two things will bite immediately if skipped:

  1. IdempotencyMiddleware 400s every MCP request, initialize included, because MCP sends
    everything as POST and no client knows this app's Idempotency-Key contract. Nothing works
    until /mcp is exempted. That is slice 1, and it blocks even a read-only demo.
  2. BodyReadingEndpointTests starts applying the moment /mcp is mapped. It needs
    ReadsRequestBodyAttribute or the suite goes red.

Do not re-derive the guard table from scratch. Six of its rows exist because a mutation was
stated, run, and found not to go red. Rewriting them from first principles loses that.


Expose a curated Cluckwork tool surface over the Model Context Protocol, so an MCP client can drive farm operations under the same account, role and flock-scope model a human uses.

Design: docs/plans/770-mcp-server/. #785 landed it and closed spike #770. Read 01-design.md before picking up any slice. 02-guards.md has the 28 guards with their red mutations.

Blocked on

Scope decisions already taken

What #788 changed about this epic

The identity bridge design in docs/plans/770-mcp-server/ still holds unchanged. McpCallContext reads the resolved ClaimsPrincipal and the scoped tenant, actor and flock-scope services. It does not care whether the caller presented a hand-rolled JWT or an OAuth reference token. The change is upstream of it. The pipeline must authenticate an OAuth token. The checks CredentialEpochMiddleware performs for JWTs (disabled user, suspended farm, must-change-password) must also run for OAuth callers, since that middleware sits on the JWT path.

Scopes are new: role ∩ scope, where scope can only subtract. There are two at launch, read farm data and record daily entries. They map onto the 6 read tools and 1 write tool below.

Slices

Ordered by dependency. Three L, four M, one S.

Wave 1: startable now. Neither slice depends on #788. One is pipeline work, the other is the identity
bridge, and neither cares how a caller authenticated.

Wave 2: needs OAuth

Wave 3: the tools, reads in parallel

Wave 4: closes the surface

Packaging

ModelContextProtocol.AspNetCore 2.2.0 ships a native net10.0 target (verified). The new package goes in Directory.Packages.props with a bare PackageReference. Commit the regenerated packages.lock.json files in the same commit, or CI fails NU1004 (#684 / #146).

Decide before the tool schemas ship

  • Decide how farm-controlled free text is presented to a model before the MCP tool surface exists #792, how farm-controlled free text is presented to a model. It is not a hard blocker on any one slice. But the mitigations are shape decisions (structured fields vs prose, whether free-text is returned by default, delimiting, tool ReadOnly annotations), and shape is expensive to change once clients depend on a published schema. Note the privilege gradient: Customer.Note is writable at SalesFlow (which includes a plain Worker) and readable through tools gated at AdminOnly. Decide during slices 4-5, not after.

Related, not blocking

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:apiAPI/endpoint layerepicPhase-level tracking issueepic-789MCP server support (#789)priority:tier3Real product weight, real cost

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions