Skip to content

Agents hard-fail at MCP gateway startup when Distillery is unconfigured #285

Description

@norrietaylor

Root cause

Every sdd-* agent that imports shared/sdd-mcp-distillery.md compiles the Distillery MCP server into its lock with:

url: "${{ vars.DISTILLERY_MCP_URL }}"

When a consumer has not set DISTILLERY_MCP_URL, the expression resolves to the empty string at runtime. The MCP gateway validates its config before starting and rejects an empty url:

/mcpServers/distillery/url  Error: '' is not valid 'uri'
                            Error: does not match pattern '^https?://.+'

The gateway exits 1, so the agent job fails before the agent runs. A consumer that does not run Distillery cannot run any sdd-* agent — the whole pipeline is dead at sdd-spec.

This contradicts the fragment's own outage contract, which already says:

if the store is unreachable, skip the pass and note the omission per the outage rule

The agent is built to tolerate an unreachable store, but it never gets the chance because the gateway dies on an unconfigured (not merely unreachable) store.

Reproduction

Fresh install pinned to main, no DISTILLERY_MCP_URL set, open a feature issue. sdd-specroute/activation pass, agent job fails at "start MCP gateway" with the schema error above. Surfaced by the issue #89 E2E harness.

Fix

Fall the URL back to a non-routable placeholder when the variable is unset, so an unconfigured store degrades into the existing unreachable-store path instead of a hard gateway failure:

url: "${{ vars.DISTILLERY_MCP_URL || 'https://distillery.disabled.invalid/' }}"
  • .invalid is reserved (RFC 6761) and never resolves.
  • It satisfies the gateway's ^https?://.+ format check, so the gateway starts.
  • The first distillery_search then fails unreachable, and the agent applies the documented outage rule and continues.

Applies to shared/sdd-mcp-distillery.md (covers sdd-spec, sdd-derive, sdd-triage-arch) and the equivalent line in .github/workflows/distillery-sync.md. Locks recompile from the fragment edit.

A configured consumer is unaffected: a non-empty DISTILLERY_MCP_URL always wins the ||.

Acceptance

  • A main-pinned install with no Distillery config runs sdd-spec past gateway startup; the agent completes and notes the Distillery pass was skipped.
  • A configured consumer's runs are byte-identical in behavior (the fallback is never taken).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions