Skip to content

MCP surface narrower than the CLI: unlink rejects brownfield relations, ingest refuses a directory source #504

Description

@explosivebit

Two places where the MCP surface is narrower than the CLI for the same operation. Both are
schema/validation choices, so an agent driven over MCP cannot do what the CLI documents.

1. forgeplan_unlink (MCP) rejects the brownfield relation set

crates/forgeplan-mcp/src/server.rs:1276 defines the accepted argument set as exactly five
variants:

enum RelationKind { Informs, BasedOn, Supersedes, Contradicts, Refines }

The core recognizes two more names as coverage relations - crates/forgeplan-core/src/brownfield.rs:493:

"informs" | "based_on" | "refines" | "demonstrates" | "covers"

The CLI reaches core's wider set (its relation argument is normalized by
link::normalize_relation, crates/forgeplan-cli/src/commands/link.rs:14), so demonstrates and
covers round-trip on the CLI but are rejected at the MCP schema layer as an invalid enum value -
a schema rejection, not a domain error, which makes it look like a bad request rather than an
unsupported relation.

2. forgeplan_ingest (MCP) refuses a directory source; the CLI walks it

phase5_validate_path (crates/forgeplan-mcp/src/server.rs:10398-10405) requires a regular file:

if !canon.is_file() { return Err("path is not a regular file"); }

The CLI's ingest walks directories - crates/forgeplan-cli/src/commands/ingest.rs:355-362
descends into ft.is_dir() entries and collects files. So the same command with a directory source
works from the shell and fails over MCP.

Why it matters

Agent-facing surfaces are where these get hit: an orchestrator that learned a workflow from the CLI
docs writes the same call over MCP and gets a rejection it cannot interpret from the message.

Fix

Either widen the MCP argument types to match core/CLI, or document the narrower contract on the MCP
tool descriptions. Deciding which takes an owner's call: widening changes a security-adjacent
schema, documenting leaves two surfaces that differ.

Revisit trigger

Act if an MCP-driven run reports "invalid value" for a relation the CLI accepts, or if the ingest
engine's MCP surface is described in a release note as equivalent to the CLI's.

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions