Skip to content
This repository was archived by the owner on May 26, 2026. It is now read-only.

feat(kora): KR-MCP-CLIENTS-FLIP — stub → real catalog#108

Merged
rafe-walker merged 1 commit into
feature/phase2-upgradesfrom
feat/kora-KR-MCP-CLIENTS-FLIP
May 22, 2026
Merged

feat(kora): KR-MCP-CLIENTS-FLIP — stub → real catalog#108
rafe-walker merged 1 commit into
feature/phase2-upgradesfrom
feat/kora-KR-MCP-CLIENTS-FLIP

Conversation

@rafe-walker

Copy link
Copy Markdown
Owner

Summary

Wires CC#2's KR-MCP-3 stub at `GET /api/mcp/clients/list` (PR
#106 / `b34b2686`) to CC#1's KR-MCP-1 ST2 real catalog (PR #105
/ `42ca5bc3`). FE STUB banner in MCPClientsPanel.tsx
auto-disappears when `stub: false` per CC#2's panel impl.

Bucket: `17_cc_bucket_prompts/KR-MCP-CLIENTS-FLIP_stub_to_real.md`

Change footprint

File Net Description
`kora_mcp/catalog.py` +23 New `load_effective_catalog()` one-call helper
`kora_cli/web_server.py` +25/-39 Endpoint body: stub → live read
`tests/kora_cli/test_web_server_mcp_clients.py` +137/-30 Flipped stub assertions + status / auth_token_present / operator-override tests

Prod surface ~25 LOC net swap + 23 LOC new helper. Under the
bucket's "<100 LOC + tests" budget.

Payload contract — byte-for-byte compatible

TS `MCPClient` interface (web/src/lib/api.ts:1446):

```typescript
interface MCPClient {
name: string;
transport: "stdio" | "streamable_http";
endpoint: string;
status: "connected" | "configured_but_unconnected" | "error" | "unhealthy";
auth_token_env: string;
auth_token_present: boolean;
allowed_tools_regex: string | null;
tools_count: number | null;
}
```

All 8 fields surfaced; field shapes preserved. Manual smoke
verifies the JSON exactly matches.

Status mapping (post-flip)

Condition status
`auth_token_env` unset / empty / whitespace-only `unhealthy`
`auth_token_env` set + no open connection `configured_but_unconnected`
(future) auth env set + pool has open connection `connected`

`connected` + non-null `tools_count` deferred to KR-MCP-
CONSUMPTION per bucket §3.

Security tests PRESERVED

Both CC#2 security tests stay green without modification:

  1. `test_auth_token_env_carries_env_var_name_not_value` —
    regex pin `^[A-Z][A-Z0-9_]*$` on auth_token_env shape;
    rejects any token-value-looking field
  2. `test_no_token_value_shaped_keys_leak_in_response` —
    walk-all-keys guard against token / secret / access_token /
    api_key / etc. bare OR auth_token without _env/_present suffix

Token VALUES never appear in the response — `auth_token_env` is
the env-var NAME; `auth_token_present` is a bool.

Test plan

  • 14/14 `test_web_server_mcp_clients.py` pass
  • `stub: True` → `stub: False` (live branch engaged)
  • Status mapping: unhealthy vs configured_but_unconnected
  • auth_token_present: false on unset / empty / whitespace; true
    on non-empty
  • Operator config override (replace-by-name + add-new) — 2 new
    tests
  • Security tests preserved + green
  • Manual smoke: curl returns proper shape with stub:false
  • Ruff clean

Cascade

Base: `feature/phase2-upgrades` (Phase 2 long-lived integration
branch).

🤖 Generated with Claude Code

Wires CC#2's KR-MCP-3 stub at `GET /api/mcp/clients/list`
(PR #106) to CC#1's KR-MCP-1 ST2 real catalog at
`kora_mcp/catalog.py` (PR #105). FE STUB banner auto-disappears
when `stub: false` per CC#2's panel implementation.

# Catalog helper added

`kora_mcp/catalog.py:load_effective_catalog()` — one-call wrapper
that reads `~/.kora/config.yaml` via `kora_cli.config.load_config`
and merges with DEFAULT_CATALOG. Defaults still surface when no
operator config exists; operator entries override by name +
new names are appended. Pydantic `extra="forbid"` rejects unknown
keys at load. Tolerates unreadable config (returns just the
defaults) so the endpoint surfaces "no clients configured" rather
than crashing.

# Endpoint body swap

`kora_cli/web_server.py:list_mcp_clients` — replaces the hardcoded
github+cloudflare stub with:

  - Read live registry via `load_effective_catalog()`
  - Per-endpoint compute `EndpointHealth` via ST2's
    `check_endpoint_health`
  - Build the FE payload row matching the TS `MCPClient` interface
    in `web/src/lib/api.ts` exactly:
      name / transport / endpoint / status / auth_token_env /
      auth_token_present / allowed_tools_regex / tools_count
  - `status` mapping:
      auth env unset / empty → "unhealthy"
      auth env set           → "configured_but_unconnected"
    The "connected" status surfaces once the daemon's MCP-client-
    pool listener is wired (deferred to KR-MCP-CONSUMPTION per
    spec §3).
  - `tools_count` stays `null` for now (same deferral).
  - `auth_token_present`: True only when auth_token_env is
    configured AND the env var resolves to a non-empty stripped
    value. Empty string / whitespace-only treated as unset per
    ST2's contract (Doppler injection corner case).
  - `stub: False` + `generated_at` set to current UTC ISO

# HARD CONSTRAINT preserved

Token VALUES never appear in the response. `auth_token_env` is the
env-var NAME; `auth_token_present` is a bool. CC#2's two security
tests stay green:

  1. test_auth_token_env_carries_env_var_name_not_value
     (regex pin: `^[A-Z][A-Z0-9_]*$` shape; rejects token-value-
     looking field values)
  2. test_no_token_value_shaped_keys_leak_in_response
     (walk-all-keys guard against token/secret/api_key/etc. bare
     OR auth_token without _env/_present suffix)

# Test plan

`tests/kora_cli/test_web_server_mcp_clients.py` — 14 tests pass:

  - 1 contract assertion FLIPPED: `stub: True` → `stub: False`
  - 2 stub-period tests REPLACED with status-mapping tests:
    - status=unhealthy when auth env unset
    - status=configured_but_unconnected when auth env set
  - 3 new auth_token_present tests:
    - false when env unset
    - true when env set
    - false when env empty / whitespace-only
  - 2 new operator-override tests:
    - operator entry by name REPLACES default
    - operator entry with new name ADDS to catalog
  - 2 security tests PRESERVED (regex pin + walk-all-keys)
  - Existing shape / enums / required-keys / cron-regression tests
    pass without change

# LOC summary

  - Endpoint body swap: ~30 LOC net (web_server.py)
  - Catalog helper: ~25 LOC (load_effective_catalog)
  - Tests: ~120 LOC net (new tests + flipped assertions)

Manual smoke: `curl localhost:9119/api/mcp/clients/list` (no
Doppler-injected tokens locally) returns github + cloudflare with
`auth_token_present: false` + `status: "unhealthy"`. Verified
the JSON shape matches the TS `MCPClient` interface byte-for-byte.

# Closes

  - KR-MCP-CLIENTS-FLIP bucket
  - Open follow-on from KR-MCP-1 ST2 dispatch ("real
    /api/mcp/clients/list endpoint" that was missed in the original
    bucket)
  - FE STUB banner in MCPClientsPanel.tsx auto-disappears once
    this merges

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@rafe-walker rafe-walker merged commit 21f9a7c into feature/phase2-upgrades May 22, 2026
@rafe-walker rafe-walker deleted the feat/kora-KR-MCP-CLIENTS-FLIP branch May 22, 2026 05:56
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant