From bb1353bcda93d83380e48aab9d16c41ff987fd0f Mon Sep 17 00:00:00 2001 From: Hanwen Cheng Date: Sun, 7 Jun 2026 23:12:51 +0800 Subject: [PATCH] refactor(mcp-server,daemon): #202 migrate worker-URL env to AGENTKEYS_WORKER_{MEMORY,AUDIT}_URL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Salvage of PR #202, rebased onto current main: - MCP server config.rs: clap env -> canonical AGENTKEYS_WORKER_{MEMORY,AUDIT}_URL with accept-both fallback in from_cli (legacy bare names honored only when the canonical var/flag is unset) for zero-downtime over un-redeployed mcp.env hosts. - setup-mcp-host.sh + README: emit the canonical names. - daemon main.rs: fold in the same memory-url rename (now matches its already- canonical --config-url) with the legacy fallback at consumption. - arch.md §5: add the AGENTKEYS_WORKER__URL canonical-names row. - Dropped the stale docs/plan/issue-107-mcp-demo-runbook.md hunk (file deleted by #207). cargo check -p agentkeys-mcp-server -p agentkeys-daemon: clean. bash -n: ok. --- crates/agentkeys-daemon/src/main.rs | 10 ++++++-- crates/agentkeys-mcp-server/README.md | 4 ++-- crates/agentkeys-mcp-server/src/config.rs | 28 ++++++++++++++++++----- docs/arch.md | 1 + scripts/setup-mcp-host.sh | 8 +++---- 5 files changed, 37 insertions(+), 14 deletions(-) diff --git a/crates/agentkeys-daemon/src/main.rs b/crates/agentkeys-daemon/src/main.rs index 53e9972e..7a4d0e4a 100644 --- a/crates/agentkeys-daemon/src/main.rs +++ b/crates/agentkeys-daemon/src/main.rs @@ -220,7 +220,10 @@ struct Args { /// W3 real-memory: the memory worker base URL (e.g. https://memory.litentry.org). /// Unset ⇒ master-memory plant/list use the in-memory fallback (dev/no-infra). - #[arg(long, env = "AGENTKEYS_MEMORY_URL")] + /// Canonical env is `AGENTKEYS_WORKER_MEMORY_URL` (the AGENTKEYS_WORKER__URL + /// family in operator-workstation.env, matching --config-url below); the legacy + /// bare `AGENTKEYS_MEMORY_URL` is still accepted as a fallback at consumption. + #[arg(long, env = "AGENTKEYS_WORKER_MEMORY_URL")] memory_url: Option, /// W3 real-memory: per-actor memory IAM role ARN for the STS relay (sourced from @@ -1146,7 +1149,10 @@ async fn run_ui_bridge_mode(args: Args) -> anyhow::Result<()> { args.broker_url.clone(), args.signer_url.clone(), args.init_chain_id, - args.memory_url.clone(), + args + .memory_url + .clone() + .or_else(|| std::env::var("AGENTKEYS_MEMORY_URL").ok().filter(|v| !v.is_empty())), args.memory_role_arn.clone(), args.config_url.clone(), args.config_role_arn.clone(), diff --git a/crates/agentkeys-mcp-server/README.md b/crates/agentkeys-mcp-server/README.md index ca1e3089..e2ef5a09 100644 --- a/crates/agentkeys-mcp-server/README.md +++ b/crates/agentkeys-mcp-server/README.md @@ -70,8 +70,8 @@ cargo run -p agentkeys-mcp-server -- \ docker build -t agentkeys-mcp-server -f crates/agentkeys-mcp-server/Dockerfile . docker run --rm -p 8088:8088 \ -e AGENTKEYS_BROKER_URL=https://broker.litentry.org \ - -e AGENTKEYS_MEMORY_URL=https://memory.litentry.org \ - -e AGENTKEYS_AUDIT_URL=https://audit.litentry.org \ + -e AGENTKEYS_WORKER_MEMORY_URL=https://memory.litentry.org \ + -e AGENTKEYS_WORKER_AUDIT_URL=https://audit.litentry.org \ -e MCP_VENDOR_TOKENS="magiclick:demo-tok" \ agentkeys-mcp-server ``` diff --git a/crates/agentkeys-mcp-server/src/config.rs b/crates/agentkeys-mcp-server/src/config.rs index cfa9989b..a328bf6c 100644 --- a/crates/agentkeys-mcp-server/src/config.rs +++ b/crates/agentkeys-mcp-server/src/config.rs @@ -45,12 +45,16 @@ pub struct Cli { #[arg(long, env = "AGENTKEYS_BROKER_URL")] pub broker_url: Option, - /// Memory worker base URL. - #[arg(long, env = "AGENTKEYS_MEMORY_URL")] + /// Memory worker base URL. Canonical env is `AGENTKEYS_WORKER_MEMORY_URL` + /// (the `AGENTKEYS_WORKER__URL` family in operator-workstation.env); + /// the legacy bare `AGENTKEYS_MEMORY_URL` is still accepted as a fallback in + /// `Config::from_cli` for un-redeployed `/etc/agentkeys/mcp.env` hosts. + #[arg(long, env = "AGENTKEYS_WORKER_MEMORY_URL")] pub memory_url: Option, - /// Audit worker base URL. - #[arg(long, env = "AGENTKEYS_AUDIT_URL")] + /// Audit worker base URL. Canonical env is `AGENTKEYS_WORKER_AUDIT_URL`; + /// legacy bare `AGENTKEYS_AUDIT_URL` accepted as a fallback (see above). + #[arg(long, env = "AGENTKEYS_WORKER_AUDIT_URL")] pub audit_url: Option, /// Comma-separated `:` pairs that the HTTP @@ -224,14 +228,26 @@ impl Config { }, }; + // Zero-downtime env-name migration (terminology-drift follow-up): the + // clap `env` above reads the canonical AGENTKEYS_WORKER_{MEMORY,AUDIT}_URL + // (the AGENTKEYS_WORKER__URL family in operator-workstation.env). A + // deployed MCP host still has the LEGACY bare names in + // /etc/agentkeys/mcp.env (written by an older setup-mcp-host.sh) until its + // next redeploy, so accept both: fall back to the legacy + // AGENTKEYS_{MEMORY,AUDIT}_URL only when the canonical var (and the + // --memory-url/--audit-url flag) is unset. + let legacy_env = |key: &str| std::env::var(key).ok().filter(|v| !v.is_empty()); + let memory_url = cli.memory_url.or_else(|| legacy_env("AGENTKEYS_MEMORY_URL")); + let audit_url = cli.audit_url.or_else(|| legacy_env("AGENTKEYS_AUDIT_URL")); + Ok(Self { transport, backend, listen: cli.listen, mcp_endpoint: cli.mcp_endpoint, broker_url: cli.broker_url, - memory_url: cli.memory_url, - audit_url: cli.audit_url, + memory_url, + audit_url, vendor_tokens, default_daily_spend_cap_rmb: cli.default_daily_spend_cap_rmb, default_actor, diff --git a/docs/arch.md b/docs/arch.md index 237986c3..e89790e5 100644 --- a/docs/arch.md +++ b/docs/arch.md @@ -216,6 +216,7 @@ Pinned to disambiguate the same value showing up under different labels across c | `credential_kek` | 32-byte AES-256 key for one operator's credentials. Derived as `HKDF-SHA256(salt="agentkeys.kek-salt.v2", ikm=K3_v[epoch], info="agentkeys.user.v1" \|\| actor_omni)`. | `KEK`, `cred_kek`. | | `credential_envelope` | Wire format of one stored credential: `1B version (0x04) \|\| 1B k3_epoch \|\| 12B nonce \|\| ciphertext \|\| 16B tag`. Stored at `s3://$VAULT_BUCKET/bots//credentials/.enc`. AAD binds `(actor_omni, service)`. | `envelope`, `AEAD blob`, `.enc` (S3 key suffix). | | `vault_bucket` / `memory_bucket` / `config_bucket` / `audit_bucket` / `email_bucket` / `payment_audit_bucket` | One S3 bucket per data class per §17. Per-actor prefix at `bots//` (config is per-operator + master-only, #201). | `$VAULT_BUCKET`, `$MEMORY_BUCKET`, `$CONFIG_BUCKET`, `$AUDIT_BUCKET`, `$EMAIL_BUCKET`, `$PAYMENT_AUDIT_BUCKET`. | +| `AGENTKEYS_WORKER__URL` (`…_MEMORY_URL`, `…_AUDIT_URL`, `…_CRED_URL`, `…_EMAIL_URL`, `…_CONFIG_URL`) | **Per-worker base-URL env vars** clients (daemon, MCP server, harness) use to reach each data-class worker. Canonical family set by `scripts/operator-workstation.env`. `AGENTKEYS_BROKER_URL` is **not** in this family — the broker is not a worker. | Legacy bare `AGENTKEYS_MEMORY_URL` / `AGENTKEYS_AUDIT_URL` — **retired in code with fallback**: both `agentkeys-mcp-server` (`config.rs::from_cli`) and `agentkeys-daemon` (`main.rs` `--memory-url`) read the canonical `AGENTKEYS_WORKER_*` var first and fall back to the bare name only for an un-redeployed `/etc/agentkeys/mcp.env` (the fallback drops out once `setup-mcp-host.sh` rewrites the env file). | | `policy` / `scope` / `namespace` / `category` / `service` (the authorization vocabulary) | **Distinct pipeline stages, NOT synonyms:** **policy** (human intent, off-chain, `DataClass::Config`) → COMPILE → **scope** (on-chain `(operator, actor, serviceHash)` grant, `AgentKeysScope` §19) over **categories/attributes** (the classifier's tag) → **service** (the signed cap string; for memory `service = memory:`, where **namespace** = the memory category). The unifying unit is the **policy attribute (category)** ([`research/universal-gate-pattern.md`](research/universal-gate-pattern.md) four primitives). Full table + pipeline: [`wiki/policy-scope-namespace.md`](wiki/policy-scope-namespace.md). | Confusions this resolves: "scope" used to mean "namespace" or "policy"; **"tag" = classifier *category*** (≠ the AWS **PrincipalTag** of §17 / [`wiki/tag-based-access.md`](wiki/tag-based-access.md)). | The most common confusion this table resolves: **`actor_omni` ≠ `current_master_wallet`**. The first is the immutable cryptographic anchor (Layer 1); the second is the rotation-volatile chain identity (Layer 2). Both are derived from K3, but only `actor_omni` survives K3 rotation unchanged. PrincipalTag, S3 paths, AAD, scope index — everywhere v2 keys identity off — uses `actor_omni`, never `current_master_wallet`. diff --git a/scripts/setup-mcp-host.sh b/scripts/setup-mcp-host.sh index 4a66ca22..ddd6f316 100755 --- a/scripts/setup-mcp-host.sh +++ b/scripts/setup-mcp-host.sh @@ -374,8 +374,8 @@ MCP_TRANSPORT=mcp-endpoint MCP_BACKEND=http MCP_ENDPOINT=${XIAOZHI_ENDPOINT} AGENTKEYS_BROKER_URL=https://broker.litentry.org -AGENTKEYS_MEMORY_URL=https://memory.litentry.org -AGENTKEYS_AUDIT_URL=https://audit.litentry.org +AGENTKEYS_WORKER_MEMORY_URL=https://memory.litentry.org +AGENTKEYS_WORKER_AUDIT_URL=https://audit.litentry.org EOF ) else @@ -388,8 +388,8 @@ MCP_ENDPOINT=ws://127.0.0.1:${RELAY_PORT}/mcp_endpoint/mcp/?token=${TOKEN} # These three are placeholders — paste the live broker / worker URLs in # after running setup-broker-host.sh on the same host. AGENTKEYS_BROKER_URL=https://broker.litentry.org -AGENTKEYS_MEMORY_URL=https://memory.litentry.org -AGENTKEYS_AUDIT_URL=https://audit.litentry.org +AGENTKEYS_WORKER_MEMORY_URL=https://memory.litentry.org +AGENTKEYS_WORKER_AUDIT_URL=https://audit.litentry.org EOF ) fi