Skip to content

feat(cli): official CLI container image + MCP registry entry (2-E4 PR A+B) - #1228

Open
Manuel-Jentic wants to merge 2 commits into
mainfrom
feat/cli-image-registry
Open

Manuel-Jentic wants to merge 2 commits into
mainfrom
feat/cli-image-registry

Conversation

@Manuel-Jentic

@Manuel-Jentic Manuel-Jentic commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

Re-proposal of #1224 (merged prematurely, backed out by #1227) — identical content, held for manual review. Do not merge until Manuel signs off.

What this ships (issue #1214, PR A + B)

Item Where
CLI container image, built from source, Recipe-3 contract (uid 10001, HOME=/home/jentic, pre-owned ~/.config/jentic), CMD ["jentic","mcp"] deploy/docker/cli.Dockerfile
MCP ownership label io.modelcontextprotocol.server.name=one.jentic/jentic + OCI labels deploy/docker/cli.Dockerfile
publish-cli-image job — step-for-step mirror of publish-image (per-arch Trivy pre-push, cosign keyless, syft SBOM, :latest on stable tags only) + jentic --version==tag gate + label==server.json assertion .github/workflows/release.yml
release widened to need the CLI image; publish-registry strictly last in the DAG .github/workflows/release.yml
MCP registry entry (2025-12-11 schema, one.jentic/jentic, OCI package, version stamped at release) cli/server.json
publish-registry — pinned mcp-publisher v1.8.1 (sha256-verified), validate → login dns → publish, dormant-gated: skips green until the publisher secret is provisioned .github/workflows/release.yml
Branch-CI drift gate: mcp-registry-validate (path-filtered) + cli-image-scan (amd64 build + Trivy of the CLI Dockerfile) .github/workflows/ci.yml
Recipe 3 docs flipped to the official image; G6 flip-back note docs/security/mcp-same-host-hardening.md

PR A+B coupling

#1214 sliced this as two PRs; they are landed together deliberately — the image gate reads cli/server.json, and one commit guarantees the label↔registry-name lockstep lands atomically. Reviewer verdict: coupling safe.

Adversarial review (all findings addressed)

  • F1 (MAJOR) Dockerfile never built in branch CI → added the path-gated cli-image-scan job (green on this branch, 1m35s).
  • F2 (MAJOR) publish-registry went red when unprovisioned → dormant-gated on the secret's presence; loud red only when configured-and-broken.
  • F3 --version gates were not prerelease-aware (incl. the pre-existing release twin) → full-semver comparison, verified against 0.0.0-ci and 1.2.3-rc.1.
  • F4 mcp-publisher download now sha256-pinned in both workflows (checksum independently verified against upstream's registry_1.8.1_checksums.txt).
  • F5 validate step calls the live registry API (no offline mode in v1.8.1) — commented; known trade-off.
  • F6 secret lands on login dns argv (no env/stdin alternative in v1.8.1; KMS noted) — comment reworded.
  • F7 redundant needs kept, self-documenting.

Human prerequisites (due Fri 5 Sep)

  1. Actions secret MCP_REGISTRY_ED25519_KEY — 64-hex-char Ed25519 private key of the publisher keypair.
  2. DNS TXT on jentic.one: v=MCPv1; k=ed25519; p=<base64 pubkey> (verify: dig TXT jentic.one).
  3. GHCR jentic-one-cli package set public after first push (registry ownership verification pulls anonymously).

Until (1) exists, publish-registry skips green; images and binaries ship regardless.

Why

The hosted MCP server sunsets 20 Sep. After that, MCP support means running jentic mcp locally — a thin shim that speaks MCP on stdio and proxies everything real to your Jentic One instance (default 127.0.0.1:8000). The CLI alone does nothing: with no instance, get_started returns no_config and tells the operator to deploy one. That's by design.

Why an image: two reasons, neither of which is "people want to run a CLI in Docker".

  1. The MCP registry only accepts npm/pypi/nuget/mcpb/OCI packages — OCI is the only fit for a Go binary. The registry verifies ownership by pulling the image anonymously and checking the server.name label (hence the label↔server.json lockstep gate, and why A+B land in one commit).
  2. The Recipe-3 container-isolation rung needs an official image to exist — it was demoted in feat(cli): auto-register MCP entries per runtime with optional isolation #1191 precisely because none did. This PR unblocks re-enabling it (PR C).

Why a registry entry: succession, not acquisition. The existing io.github.jentic/mcp-server entry points at the hosted server and gets deprecated at sunset; without a replacement, Jentic shows up dead in every MCP client catalog. For people already running Jentic One it's a verified install path instead of copy-pasting JSON from docs. Marginal cost on top of the image: ~20 lines of JSON and one dormant CI job.

DNS verification is namespace-ownership proof, nothing is hosted: public key in a TXT record on jentic.one, CI signs with the private key, the registry checks the signature.

Made with Cursor

Manuel-Jentic and others added 2 commits September 2, 2026 12:43
… entry

The jentic-one half of 2-E4 (#1214), scheduled against the 20 Sep 2026
hosted-MCP sunset: a from-source, multi-arch CLI image and an official
MCP registry entry that tracks every release automatically.

- deploy/docker/cli.Dockerfile: multi-stage build of the jentic CLI
  (cross-compiled on the build platform, Ubuntu runtime matching the app
  images), implementing Recipe 3's container contract (non-root uid
  10001, HOME=/home/jentic, pre-owned ~/.config/jentic for named-volume
  seeding) and carrying the io.modelcontextprotocol.server.name label
  the registry's OCI ownership verification checks.
- release.yml publish-cli-image: mirrors publish-image step-for-step
  (needs gate+smoke, per-arch Trivy before any push, login after all
  installers, cosign keyless + syft SBOM by index digest, :latest last
  on stable tags) plus a pre-push gate asserting jentic --version == tag
  and label == server.json name; the release job now needs both publish
  jobs so a release never half-ships.
- cli/server.json (schema 2025-12-11): one.jentic/jentic with the OCI
  package; version-stamped and published by the new publish-registry job
  running last in the DAG via mcp-publisher login dns (secret:
  MCP_REGISTRY_ED25519_KEY), stable tags only.
- ci.yml mcp-registry-validate: mcp-publisher validate drift gate on
  PRs touching cli/server.json, wired into ci-status.
- docs: Recipe 3 now points at ghcr.io/jentic/jentic-one-cli with the
  BYO image kept as a fallback.

Co-authored-by: Cursor <cursoragent@cursor.com>
…gistry publish, hardened gates

Review fixes for the 2-E4 CLI image + MCP registry entry commit:

- F1: new path-gated cli-image-scan job in ci.yml (amd64 build + Trivy
  scan of deploy/docker/cli.Dockerfile on cli/** changes), so the
  Dockerfile's first-ever build is no longer on a release tag.
- F2: publish-registry is dormant-gated — a step checks the env-injected
  MCP_REGISTRY_ED25519_KEY and every publish step gates on its output,
  so unprovisioned = green skip (in kind with the ECR tail), configured
  + broken = loud red. Misleading "fails at login" comment fixed.
- F3: both `jentic --version` gates (publish-cli-image + release) now
  extract the full semver incl. prerelease suffix, so v1.2.3-rc.1 tags
  can pass.
- F4: mcp-publisher downloads verified against the pinned sha256 from
  upstream's registry_1.8.1_checksums.txt in both workflows, with a
  lockstep comment tying the two version literals together.
- F5/F6/F7: comment fixes — validate's live-registry call acknowledged,
  the "never argv" secret claim corrected (v1.8.1 login dns offers no
  env/stdin input), the transitively redundant needs entry annotated.

Co-authored-by: Cursor <cursoragent@cursor.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant