feat(mcp): real echo MCP server image — makes mcps/echo_server operational - #24
Merged
Conversation
…ional end-to-end The ``mcps/echo_server`` manifest has shipped since Phase 4.2 as a loader / TUI / role-allow-list fixture, but no actual server backed the URL. ``coding_agent``'s ``allowed_mcps=["echo_server"]`` declaration was a smoke target that 404'd at run time, and the manual-smoke recipe in PR #20's prompt-pane help doc had to inject synthetic events because the [MCP: echo_server.echo {...}] markers the agent emits couldn't reach a real server. This PR ships: container/production/echo_mcp_server/main.py (NEW) Tiny diagnostic JSON-RPC 2.0 server. stdlib http.server only — no Flask, aiohttp, mcp, or json-rpc deps. Implements exactly the three methods :class:`acc.mcp.client.MCPClient` exercises: * initialize → returns canonical protocolVersion + serverInfo * tools/list → advertises one ``echo`` tool with valid JSON Schema for its input * tools/call → name=echo round-trips arguments.text in MCP's canonical { content: [{type, text}] } envelope Listens on ACC_MCP_ECHO_HOST / _PORT (default 0.0.0.0:8080). Logs go through the standard logging pipeline at ACC_LOG_LEVEL (default INFO). GET / returns a banner so curl /health-style probes don't 404. container/production/Containerfile.echo-mcp-server (NEW) UBI10 python-312-minimal base, ~1 MB on top of the base layer (no pip deps). Non-root UID 1001, EXPOSE 8080, USER 1001, CMD python3 /app/main.py. container/production/podman-compose.yml + acc-mcp-echo service behind ``--profile mcp-echo``. Container name matches the hostname referenced in the manifest's ``url: http://acc-mcp-echo:8080/rpc`` so agents resolve it on the acc-net bridge with zero manifest edits. Healthcheck via GET / using stdlib urllib so we don't add curl to the image. Auto-built alongside the others by ``./acc-deploy.sh build``. acc-deploy.sh + MCP_ECHO env var (default false) wires through to the --profile mcp-echo activation. Header echoes the flag when set. + Profile auto-attaches on build/rebuild so a single ``./acc-deploy.sh rebuild`` produces the image without needing MCP_ECHO=true. + Header docstring documents the new env var. mcps/echo_server/mcp.yaml Header rewritten — the manifest is no longer a "stub example", it describes a live diagnostic server. Manual-smoke recipe added (MCP_ECHO=true ./acc-deploy.sh up + nats sub). Tests (tests/test_echo_mcp_server.py — NEW, 8 cases all green): Pure JSON-RPC dispatch (7): * initialize returns protocolVersion + serverInfo, * tools/list advertises echo with valid JSON Schema, * tools/call name=echo round-trips text, * unknown tool name → JSON-RPC error with name in message, * tools/call with non-string text → param error -32602, * unknown method → method-not-found -32601, * response id always matches request id (across int / str / "" / None so ACC client's id-mismatch check never fires). End-to-end round-trip (1): * Spin up the real HTTPServer on 127.0.0.1:<ephemeral_port> in a background thread, drive it via :class:`acc.mcp.client.MCPClient` with a real ``MCPManifest``. Confirms wire-format compatibility on both sides — server response shape passes the client's JSON-RPC envelope validation, MCPClient.list_tools + call_tool return the expected dicts. Combined regression: 265 unit tests pass on Windows (test_echo_mcp_server + test_mcp_stdio_transport + the four coding_agent tier files + test_task_progress_* + the prompt-pane suite + the redis-compat suite + telemetry + ecosystem + file-picker + config + role-store + guardrails + compliance, with TestEd25519Validation deselected for the lighthouse OpenSSL platform limit). acc1 verification deferred — host SSH still unreachable (timeout to 10.199.12.91:22 since PR #21). Tests are pure-Python + stdlib HTTP — local Windows result transfers cleanly when the host is back. Manual smoke recipe for acc1 is in mcps/echo_server/mcp.yaml. Out of scope: * Resources / prompts methods (the MCP spec covers more than tools; ACC only consumes tools today, so this server only implements the three methods the client exercises). * HTTPS / mTLS — diagnostic server, host-network only. * SSE / streamable HTTP transport — current ACC HTTPTransport posts one JSON-RPC envelope per request; SSE would require wiring on the client side too (separate PR if needed).
flg77
added a commit
that referenced
this pull request
Jun 5, 2026
…surface)
Eighth and final sub-slice of Stage 1
(openspec/changes/20260605-acc-pkg-trust-and-assistant/). Lands the
declarative DC install API surface — the GitOps seam for Stage
1.5.3's pkg-install code path.
What ships:
* operator/api/v1alpha1/acccatalog_types.go (NEW):
- AccCatalog CRD mirroring acc.pkg.catalog.Catalog Pydantic
model so the operator's rendered YAML validates cleanly
against the Python loader.
- Spec fields: catalogId, tier (trusted|tp|community|self),
mode (https|file), url|path, requiredSigner (issuer +
subjectPattern + optional keyPath), priority.
- Status fields: observedGeneration, conditions[],
lastRenderedAt.
- Printcolumns + shortNames for kubectl-friendly UX.
* operator/api/v1alpha1/accpackageinstall_types.go (NEW):
- AccPackageInstall CRD — one @scope/name@constraint install.
- Spec fields: name (regex-validated), constraint, catalogRef
(optional pin), targetCorpus (optional scope), allowUnsigned
(operator-explicit bypass).
- Status fields: phase (Pending|Installing|Installed|Failed),
installedVersion, installPath, contentSha256, lastInstalledAt,
conditions[].
* operator/api/v1alpha1/zz_generated_stage1_6_deepcopy.go (NEW):
- Hand-written DeepCopy / DeepCopyObject methods following
controller-gen's emission style. Replace on next
`make generate`.
* gitops/argocd/applications/accpackage-sample.yaml (NEW):
- End-to-end ArgoCD Application driving two AccCatalog entries
(canonical https + corp-internal file-mode) + two
AccPackageInstall objects. Operators copy + adjust the
catalog URL + signer pattern for their environment.
* gitops/argocd/applications/README.md (NEW):
- Documents what Stage 1.6 ships (API + sample) vs what's
deferred to 1.6b (reconcilers + RBAC + OLM bundle +
envtest). The deferred reconciler consumes the same
fetch_and_install Python entry point that 1.5.3 and 1.4
already use — single seam, no parallel logic.
Design choices:
* API surface lands now so downstream GitOps tooling can import
the types; reconciler logic (exec-into-pod, leader election,
status patching) is multi-day Go work and ships as 1.6b.
* AccCatalog Spec mirrors acc.pkg.catalog.Catalog 1:1 — operator
renders directly to /etc/acc/catalogs.yaml ConfigMap, no
translation layer.
* AccPackageInstall.spec.constraint accepts the same range syntax
acc.pkg._semver implements; operator does shape validation, the
installer is the resolution authority.
* AllowUnsigned at the CR level so dev-environment opt-out is
declarative + audit-logged via the controller's events.
Tests: no new Python tests (Go-only changes; Python pkg suite
unchanged at 415/1 green). Go envtest integration tests land in
1.6b alongside the reconciler. Manifest sample YAML parses (5
documents: Application + 2 AccCatalog + 2 AccPackageInstall).
This completes Stage 1's eight sub-slices:
1.5.1 dual-source role loader (#21)
1.5.2 required_packages (#22)
1.5.3 acc-deploy.sh boot-time fetch (#23)
1.4 PROPOSE_INFUSE marker (#24)
1.1 eval format (#25)
1.2 EC policy depth (#26)
1.3 OIDC keyless publish (#27)
1.6 operator CRDs (this)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
flg77
added a commit
that referenced
this pull request
Jun 5, 2026
…I variant End-to-end runner that walks the operator through the five-phase acc1 K8s hub smoke after PRs #20-#28 land. Hermetic CI variant exercises the same chain in-process against a file-mode catalog so PR-time tests prove the wiring without a running cluster. What ships: * tools/smoke-acc1-hub.sh (NEW): - Phase 0 preflight — checks cosign / kubectl / python / jq / curl / acc-pkg on PATH. - Phase 1 — applies gitops/acc-hub/ if not present; waits for rollout; curls /index.json. - Phase 2 — generates pilot cosign keypair via tools/cosign-pilot-keygen.sh if not on disk. - Phase 3 — builds pilot pkg, signs with cosign sign-blob, publishes via gitops/acc-hub/publish-to-hub.sh; verifies the hub now advertises the package via jq on the live index. - Phase 4 — downloads tarball + sig from live hub, runs acc-pkg install into a tmp sandbox, exercises cosign verify. - Phase 5 — RoleLoader resolves coding_agent from the installed-package path (proves the dual-source loader chain from PRs #21-#23). - Coloured logging + idempotent steps + smoke-specific exit codes (7 = hub deploy fail, 8 = roundtrip verification fail). * tests/pkg/test_live_smoke_hermetic.py (NEW): - Mirrors the bash script's Phase 3-5 in-process against a file-mode catalog with mocked cosign so CI exercises the chain without acc1 reachability. - 7 tests: build determinism, end-to-end install + load, idempotent re-install, signing-floor refusal, --allow-unsigned bypass, PROPOSE_INFUSE shares the same fetch_and_install seam, and smoke script wiring sanity (script references the right helpers). * tools/SMOKE.md (NEW): - Operator runbook: prerequisites, run command, what each phase does, exit codes, troubleshooting matrix. Test growth: 2979/37 (PR #27 baseline) -> 422/1 pkg suite (this PR adds +7 hermetic tests on top of the operator-only script). Full sweep impact is +7 (since #28 was Go-only, no Python tests). Stage 1 close-out — every code path the eight sub-slices ship is now exercised by a single hermetic test that proves they compose correctly: Build (#20) -> Sign (#27) -> Publish (#27) -> Catalog resolve (#20) -> Verify (#20 + #26) -> Install (#20) -> Registry (#20) -> RoleLoader (#21) -> PROPOSE_INFUSE dispatch (#24) all hit the same code path. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
flg77
added a commit
that referenced
this pull request
Jun 5, 2026
…rface) Closes the visual gap deferred from PR #24 (Stage 1.4 PROPOSE_INFUSE). The dispatcher was wired but operators had no panel to act in; this adds a projection over the existing oversight queue with infuse-specific columns. Design — projection, not parallel queue: * The new Collapsible reads from the SAME oversight_pending_items list the main oversight queue uses. * Approve / reject post the SAME _OversightAction message → existing dispatch path → dispatch_approved_proposal → _dispatch_infuse (#24) → fetch_and_install (#23). * One dispatch path invariant pinned by test_decide_pkg_proposal_uses_same_oversight_action_envelope. What ships in acc/tui/screens/compliance.py: * New Collapsible "Package Proposals (PROPOSE_INFUSE)" added next to "Rule Proposals" inside the gov-left column. * #pkg-proposals-table DataTable with columns: ID | Package | Constraint | Tier | Signer | Status * #pkg-proposals-actions Horizontal with Approve / Reject buttons. * #pkg-proposals-status Static for action feedback. * _is_pkg_proposal(item) classifier: - Prefers explicit kind="infuse" field. - Falls back to summary prefix "Install @" for compat with mixed-version arbiter fleets (older HEARTBEATs lack `kind`). - Case-insensitive on kind. * _pkg_proposal_columns(item) extractor: - Reads params.{name,constraint} when present (canonical case). - Falls back to summary parsing for name + constraint. - Accepts tier OR catalog_tier; signer_identity OR signer. - Returns "—" placeholders on missing fields (never raises). * _render_pkg_proposals(snap) — filtered render hooked into the main snapshot rendering after _render_oversight_queue. * _decide_pkg_proposal(approve=True/False) — extracts highlighted row's oversight_id, posts _OversightAction. * on_button_pressed wired to btn-pkg-proposal-approve|reject. Tests: 14 new (tests/pkg/test_compliance_pkg_proposals.py). Full sweep 3000/37 (vs 2986/37 baseline — exact +14 delta, no regressions). Existing 139 compliance-related tests unaffected. What's NOT in this PR: * WebGUI parity — the dispatch is via _OversightAction so the existing WebGUI oversight queue already serves these proposals as plain rows; a dedicated React surface is a follow-up once Stage 2 Marketplace work scopes UI. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
flg77
added a commit
that referenced
this pull request
Jun 29, 2026
…cryptography (#141) Resolves the Python (pip) Dependabot alerts on flg77/acc-spearhead. Most were a stale uv.lock (last generated 2026-06-14) whose pins lagged the already-permissive pyproject constraints; one needed a constraint widening. Lockfile refresh (constraints already allowed the fix — `uv lock --upgrade-package`): aiohttp 3.14.0 → 3.14.1 (#15-22, 8 alerts) pyjwt 2.12.1 → 2.13.0 (#9-13, 5 alerts) starlette 1.0.1 → 1.3.1 (#24-27, 4 alerts; transitive via fastapi) msgpack 1.1.2 → 1.2.1 (#37, high) joserfc 1.6.5 → 1.7.2 (#39; transitive via authlib) Constraint widening (fix was outside the pin): cryptography 46.0.7 → 48.0.1 (#14/#23, two HIGH) — pyproject `<47`→`>=48.0.1,<49`. The Ed25519 arbiter sign/verify API is stable across 46→48; operator "pin and bump" one major at a time. The lock also catches up on the speech/turbovec optional-deps added since 06-14 (faster-whisper/piper-tts/ctranslate2/onnxruntime/av/turbovec) — no security content, just lock/pyproject reconciliation. No downgrades. Not fixed here (separate handling): transformers (#1) — vulnerable `Trainer` not in our execution path; ST<5.0 blocks the 5.0.0rc3 fix → dismissed on GitHub with that reason (intent already in pyproject). torch (#7, low) — no patched release exists → dismissed "no fix available". npm console-plugin (7 alerts) — need npm/node (absent here) → fleet hand-off. Verified with the bumped libs installed: signatures/spiffe 153 ✓, a2a/messenger/ slack/webgui/redis 168 ✓ (321 total, 0 failures). Co-authored-by: flg <flg@acc1.ic3net.internal> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Ships the diagnostic JSON-RPC echo server that backs
mcps/echo_server/mcp.yaml. Until now the manifest was a fixture: it round-tripped through the loader, lit up the TUI Ecosystem row, and let `coding_agent` allow-list `echo_server` — but agents dispatching `[MCP: echo_server.echo {...}]` markers got `connection refused`, and the manual smoke recipe in PR #20's prompt-pane help had to inject synthetic events.After this PR, a single env flag spins up a real server:
```bash
MCP_ECHO=true ./acc-deploy.sh up
```
…and `coding_agent`'s LLM-emitted MCP markers actually round-trip through a real container.
What lands
Tests (8 new, all green)
Combined regression: 265 passed locally on Windows
(test_echo_mcp_server + test_mcp_stdio_transport + the four coding_agent tier files + test_task_progress_* + prompt-pane suite + redis-compat + telemetry + ecosystem + file-picker + config + role-store + guardrails + compliance, with `TestEd25519Validation` deselected for the lighthouse OpenSSL platform limit).
Test plan
```bash
MCP_ECHO=true ./acc-deploy.sh rebuild
MCP_ECHO=true ./acc-deploy.sh up
podman ps # acc-mcp-echo healthy
curl http://acc-mcp-echo:8080/ # banner reachable from agent net
./acc-deploy.sh cli nats sub 'acc.sol-01.>' &
Send a prompt via screen 7 that yields [MCP: echo_server.echo {"text":"X"}]
→ response carries the canonical {content:[{type,text,X}]} envelope
```acc1 verification
Still deferred — SSH timeout to `10.199.12.91:22` since PR #21 (3 PRs ago). Tests are pure-Python + stdlib HTTP, no platform-specific code; the local Windows result transfers cleanly when the host is back.
Out of scope (future enhancements)