feat(project): Project.llmProvider as Llm reference #55

Merged
michal merged 2 commits from feat/project-llm-ref into main 2026-04-19 21:39:55 +00:00
Owner

Summary

Phase 4 of the Llm plan. Completes the in-repo scope: `Project.llmProvider` now semantically names a centralised `Llm` resource. No schema change — the column stays a free-form string for backward compat, and unknown values still fall back to the consumer's registry default (current behavior).

Based on `feat/llm-failover` (PR #54) — tops off the chain.

  • `mcpctl create project --llm ` + `--llm-model `.
  • `mcpctl describe project` fetches the Llm catalogue and flags values that don't resolve. `none` is treated as an explicit disable.
  • New `resolveProjectLlmReference()` helper in mcplocal's discovery; returns `registered / disabled / unregistered / unreachable`. Ready for the HTTP-mode proxy-model pipeline pivot to mcpd's `/api/v1/llms/:name/infer`.
  • `apply -f` doc comments updated.

Test plan

  • 6 resolver unit tests (none / empty / registered / 404 / 500 / URL encoding)
  • 3 new describe-warning tests (registered-no-warning, orphan-with-warning, 'none'-no-warning)
  • Full workspace suite: 1853/1853 passing (+9 from Phase 3's 1844)
  • TypeScript clean across mcpd + mcplocal + cli
  • Completions regenerated for new --llm / --llm-model flags
  • End-to-end: deploy, create an Llm, point a project's `--llm` at it, confirm `describe project` shows no warning; create a second project with an unknown name and confirm the warning fires

🤖 Generated with Claude Code

## Summary Phase 4 of the Llm plan. Completes the in-repo scope: \`Project.llmProvider\` now semantically names a centralised \`Llm\` resource. No schema change — the column stays a free-form string for backward compat, and unknown values still fall back to the consumer's registry default (current behavior). **Based on \`feat/llm-failover\` (PR #54)** — tops off the chain. - \`mcpctl create project --llm <name>\` + \`--llm-model <override>\`. - \`mcpctl describe project\` fetches the Llm catalogue and flags values that don't resolve. \`none\` is treated as an explicit disable. - New \`resolveProjectLlmReference()\` helper in mcplocal's discovery; returns \`registered / disabled / unregistered / unreachable\`. Ready for the HTTP-mode proxy-model pipeline pivot to mcpd's \`/api/v1/llms/:name/infer\`. - \`apply -f\` doc comments updated. ## Test plan - [x] 6 resolver unit tests (none / empty / registered / 404 / 500 / URL encoding) - [x] 3 new describe-warning tests (registered-no-warning, orphan-with-warning, 'none'-no-warning) - [x] Full workspace suite: **1853/1853 passing** (+9 from Phase 3's 1844) - [x] TypeScript clean across mcpd + mcplocal + cli - [x] Completions regenerated for new --llm / --llm-model flags - [ ] End-to-end: deploy, create an Llm, point a project's \`--llm\` at it, confirm \`describe project\` shows no warning; create a second project with an unknown name and confirm the warning fires 🤖 Generated with [Claude Code](https://claude.com/claude-code)
michal changed target branch from feat/llm-failover to main 2026-04-19 21:39:52 +00:00
michal added 2 commits 2026-04-19 21:39:52 +00:00
Why: Phases 0-3 built the server-managed Llm registry; this phase pivots the
existing Project.llmProvider column from "local provider hint" to "named Llm
reference" so operators can pick a centralised Llm per project. No schema
change — the column stays a free-form string for backward compat.

- `mcpctl create project --llm <name>` (+ `--llm-model <override>`) sets
  llmProvider/llmModel to a centralised Llm reference, or 'none' to disable.
- `mcpctl describe project` fetches the Llm catalogue alongside prompts and
  flags values that don't resolve with a visible warning. 'none' is treated
  as an explicit disable, not an orphan.
- `apply -f` doc comments updated; --llm-provider still accepted but now
  documented as naming an Llm resource.
- New `resolveProjectLlmReference(mcpdClient, name)` helper in mcplocal's
  discovery: returns `registered`/`disabled`/`unregistered`/`unreachable`.
  The HTTP-mode proxy-model pipeline will consume this when it pivots to
  mcpd's /api/v1/llms/:name/infer proxy.
- project-mcp-endpoint.ts cache-namespace path gets a comment explaining
  the new resolution order — behavior unchanged, just clarified.

Tests: 6 resolver unit tests + 3 new describe-warning cases. Full suite
1853/1853 (+9 from Phase 3's 1844). TypeScript clean; completions
regenerated for the new create-project flags.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Covers the Phase 0-4 CLI contract against live mcpd. Matches the existing
mcptoken.smoke pattern: skip gracefully on unreachable /healthz, cleanup
fixtures in afterAll, use --direct to bypass mcplocal for admin operations.

- secretbackend.smoke.test.ts
  · seeded plaintext default exists + isDefault
  · create/describe/delete round-trip
  · refuses to delete the default backend (409 shape)
  · get -o yaml output starts with `kind: secretbackend` (apply-compatible)

- llm.smoke.test.ts
  · create secret + llm with --api-key-ref, verify describe hides the
    raw value but surfaces secret://name/key
  · yaml round-trip: get -o yaml > file → amend → apply -f → describe shows change
  · deleting the llm leaves the underlying Secret intact (onDelete: SetNull)

- llm-infer.smoke.test.ts
  · 404 for unknown name, 400 for missing messages
  · 5xx when upstream url is unreachable (proxy returns a structured error)
  · opt-in happy-path gated on LLM_INFER_SMOKE_REAL=1 + LLM_INFER_SMOKE_LLM=<name>
    so CI doesn't need a real provider key

- project-llm-ref.smoke.test.ts
  · describe project with --llm <registered> — no warning
  · describe project with --llm <nonexistent> — shows "warning: …registry default"
  · describe project with --llm none — explicit disable, no warning

These require PRs #51-55 to be merged and fulldeploy.sh run before they'll
find the new endpoints on live mcpd. Until then they skip or fail with
"Not Found". Unit tests for the same code paths (1853 total) continue to
pass against mocks.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
michal merged commit e27a0e695e into main 2026-04-19 21:39:55 +00:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: michal/mcpctl#55