koala73 / koala73/worldmonitor

chore(mcp): get_chokepoint_status serves chokepoint-flows raw — the FlowSource taxonomy is neither declared nor enforced on the MCP surface

Open
#6,113 2 comments 0 reactions 0 assignees View on GitHub
enhancement P3
Dominant language
TypeScript
Stars
86.6k
Forks
13.1k
Avg merge
8h 4m
Merged PRs (30d)
825

Description

## Summary

Priority: **P3**. Found while shipping #6101. `FlowEstimate.source` is now a closed `FlowSource` enum, discoverable from the OpenAPI (`enum:`) and the generated TS (literal union), and the REST handler narrows the untyped seeder value so the served response cannot fall outside it. **The MCP surface gets none of that.**

`get_chokepoint_status` is a *cache tool*: it has no `_execute`, so `executeTool` reads its `_cacheKeys` straight from Upstash and never touches the sebuf handler.

```js
// api/mcp/dispatch.ts:43
const reads = tool._cacheKeys.map(k => readJsonFromUpstash(k));
```

Consequences for the `chokepoint-flows` dataset (which is `energy:chokepoint-flows:v1`, the raw seeder blob):

1. **Not discoverable.** The output schema declares no `source` property at all:
```js
// api/mcp/registry/cache-tools.ts:2032-2035
'chokepoint-flows': {
type: ['object', 'null'],
additionalProperties: { type: 'object' },
},
```
An agent calling `tools/list` or `describe_tool('get_chokepoint_status')` sees nothing about the taxonomy — on the one surface built specifically for agents.
2. **Not narrowed.** `toFlowSource` never runs on this path, so an undeclared seeder value reaches an MCP client verbatim.

This is pre-existing architecture, not a regression from #6101 — `cache-tools.ts` was already decoupled from the sebuf handlers (same raw-Redis pattern as `chokepoint_transits`, `ref`). #6101 simply made the asymmetry visible.

## The trap in the obvious fix

"Just add `enum: ['FLOW_SOURCE_UNSPECIFIED','portwatch-dwt','portwatch-counts']` to the schema" is **wrong on its own**, and it is the exact defect class #6078/#6084 documented in `docs/solutions/design-patterns/contract-gate-field-names-miss-value-axis.md`: it would declare a closed set on a path that does not enforce it. The MCP tool serves the raw blob, so the schema would be a promise the code does not keep — a fresh declare-vs-serve divergence, on a second surface, created by fixing the first one.

Whatever is chosen, the declaration and the served bytes must move together.

## Options

1. **Narrow + declare.** Add the `enum` to the schema AND normalize `source` in the tool's `_postFilter` (that seam already exists on this tool). Declaration and behavior stay in step, and MCP matches REST.
2. **Declare it open, honestly.** Leave the value un-narrowed but document in the `chokepoint-flows` dataset description that it is the raw seeder payload and may carry values outside the `FlowSource` taxonomy the REST endpoint serves. Cheapest; keeps the two surfaces deliberately different rather than accidentally different.
3. **Leave as-is.** No schema shape for the dataset at all, as today.

Note for whoever takes this: the sebuf empty-`enum_value` limitation that blocks `hazard_alert_level` on the OpenAPI path (#6106) does **not** apply here — `cache-tools.ts` is hand-authored JSON Schema, so `hazardAlertLevel: { enum: ['RED','ORANGE',''] }` is expressible on this surface today if option 1 is taken.

## Acceptance

- [ ] Pick an option; if 1, the narrowing and the `enum:` land in the same change.
- [ ] If 1: a test drives the MCP tool with an out-of-taxonomy `source` and asserts the served value is narrowed — not just that the schema validates.
- [ ] `tests/mcp-output-schema-coverage.test.mjs` still passes, and its fixture (`tests/fixtures/jmespath-samples/thin-get-chokepoint-status.response.json`) exercises the new shape rather than passing trivially through `additionalProperties: {type:'object'}`.

## Related

- #6101 — promoted `FlowEstimate.source` on the REST/OpenAPI/TS path
- #6106 — the `hazard_alert_level` half, blocked on sebuf codegen
- `docs/solutions/design-patterns/contract-gate-field-names-miss-value-axis.md`

Contributor guide

Open the contributing guide

Research direction

Start with api/mcp/dispatch.ts and the chokepoint-flows entry in api/mcp/registry/cache-tools.ts, then inspect the existing _postFilter seam and related tests. Run tests/mcp-output-schema-coverage.test.mjs and review its thin-get-chokepoint-status fixture. Done means one selected option is implemented consistently, with an out-of-taxonomy source case covered if narrowing is chosen.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
api, tooling
Issue type
Refactor
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.