fix(claude-agent): strict MCP config filtering to fix mcp_server_status errors - #1157
Open
xu75 wants to merge 28 commits into
Open
fix(claude-agent): strict MCP config filtering to fix mcp_server_status errors#1157xu75 wants to merge 28 commits into
xu75 wants to merge 28 commits into
Conversation
…ult port) When accessed behind Nginx/Caddy on port 80/443, location.port is empty and the old fallback (3001→3002) produced a wrong API address. Now when port is absent the frontend uses same-origin, letting the reverse proxy route /api/ and /socket.io/ to the API server. Direct-port access (e.g. :3003→:3004) remains unchanged. Closes zts212653#346 [宪宪/Opus-46🐾] Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… add tests Address review feedback from PR zts212653#347: P1: When NEXT_PUBLIC_API_URL is a localhost default (baked in at build time) but the browser hostname is remote, skip the env var and fall through to runtime auto-detection. This prevents setup.sh / .env defaults from short-circuiting the reverse-proxy same-origin path. P2: Update SETUP.md / SETUP.zh-CN.md docs — reverse proxy scenarios no longer require NEXT_PUBLIC_API_URL; troubleshooting reflects auto-detect behavior. P2: Add 8 vitest cases covering Cloudflare Tunnel, explicit env, localhost-skip, same-origin (reverse proxy), and port+1 derivation. [宪宪/Opus-46🐾] Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…cts reverse proxy [宪宪/Opus-46🐾] Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…nfig for unknown models Previously, providers in BUILTIN_OPENCODE_PROVIDERS (anthropic, openai, google, openrouter) were trusted to handle all models natively. When opencode's builtin model list is outdated (e.g. doesn't include claude-opus-4-6), invocations fail with "Model not found". Now runtime config with explicit model registration is always generated for opencode cats with api_key auth, regardless of whether the provider is builtin. Also infers apiType from the provider name parsed from the model string as fallback when resolvedAccount.protocol is not set. Upstream issue: anomalyco/opencode#21019 [孟加拉猫/Opus-46🐾]
…(env var fallback)
The initial fix only covered the api_key provider profile case. When no profile
is bound (resolvedAccount is null), the runtime config was still skipped, causing
opencode to fall back to its builtin model list which doesn't include claude-opus-4-6.
Now also generates runtime config when ANTHROPIC_API_KEY is available in the parent
process env, forwarding it as CAT_CAFE_OC_API_KEY for the runtime config's
{env:...} substitution.
[孟加拉猫/Opus-46🐾]
2026-04-09 incident: untracked 480-line research doc silently deleted by git stash -u during merge-gate Step 8 cleanup. The stash pop failed due to same-name file conflict (all-or-nothing for untracked files), causing collateral loss of innocent files. Recovered from dangling object. Changes: - merge-gate/SKILL.md: Step 8 now checks for untracked docs/ files and commits them before pull; stash without -u only - shared-rules.md: §5 adds "Write ≠ persistence" rule and git stash -u ban - deep-research/SKILL.md: new Step 5 requires commit after Write Why: multi-session shared worktree + git stash -u = data killer [宪宪/Opus-46🐾]
# Conflicts: # packages/api/src/domains/cats/services/agents/invocation/invoke-single-cat.ts # packages/api/test/invoke-single-cat.test.js # packages/web/src/utils/__tests__/api-client-resolve.test.ts # packages/web/src/utils/api-client.ts
Upstream maintainer correctly identified that Step 8 never had git stash -u. The incident was caused by a cat improvising off-SOP, not a SKILL.md bug. Revert merge-gate to upstream's original Step 8. Also stages resolved stash-pop conflicts in ConnectorRouter (took upstream's last-active-participant routing over WIP preferredCats approach). Retained fixes (shared-rules "Write ≠ persistence" + deep-research Step 5) address the actual root causes (L1: uncommitted files, L3: no persistence step). See: zts212653#403 (closed with analysis) [宪宪/Opus-46🐾]
Why: prevent ad-hoc git stash -u cleanup that can delete untracked outputs in shared main workspace. [砚砚/gpt-5.3-codex🐾]
# Conflicts: # cat-cafe-skills/deep-research/SKILL.md # cat-cafe-skills/refs/shared-rules.md
Registry entries were lost (likely due to SynologyDrive sync conflict), causing projects to re-trigger governance bootstrap prompts. Tracking this file in git provides history and conflict visibility. [宪宪/Opus-46🐾] Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
# Conflicts: # cat-template.json # packages/api/src/routes/messages.ts # packages/api/test/codex-agent-service.test.js # packages/api/test/messages-delivery-mode.test.js
Snapshot of in-progress work prior to merging upstream/main: - health activity-route-filter + runtime-health-routes tests - connector invoke error-delivery test + ConnectorInvokeTrigger changes - clowder-launchd.sh autostart helper + tests - governance pack/skill-sync tweaks, useConnectionStatus proxy paths - materialized lesson markers under docs/markers/ Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
# Conflicts: # packages/api/src/config/governance/governance-pack.ts # packages/api/src/config/governance/skill-sync.ts # packages/api/src/domains/cats/services/agents/providers/CodexAgentService.ts # packages/api/test/codex-agent-service.test.js
opus-47 was a local trial Ragdoll variant superseded by upstream's fable-5. Remove all opus-47 footprint from cat-template.json: - standalone "opus-47" cat entry + opus-47-default variant - two roster entries (one a duplicate "opus-47" key — JSON defect) - claude-opus-4-7 from the claude models list Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Merge of local error-delivery block with upstream left a reference to try-local createResult inside the catch block, where only the function-scoped invocationId is visible (TS2304). Use invocationId and guard the cleanup call on it. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Three issues fixed for fork-based repo workflows: 1. Label handling: track successfully-created labels and only pass those to `gh pr create`. Previously, failed label creation (e.g. insufficient permissions on upstream repo) was swallowed, but the label was still passed to `gh pr create` which then failed with "label not found". 2. Source base detection: when `upstream` remote exists, fetch from it and use `upstream/main` as the worktree source base. Previously, always used `origin/main` which in a fork workflow points to the fork's main (potentially diverged), causing massive unrelated file diffs in PRs. 3. Cross-fork PR syntax: detect when origin owner differs from the repo `gh` resolves to, and use `--head owner:branch` syntax. Previously, `--head branchName` alone caused "Head sha can't be blank" because the branch exists on the fork but not on the upstream. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…us errors Why: secret-mcp, probe-off, and cat-cafe-audio appeared as `failed` in mcp_server_status because Claude CLI loaded ALL servers from .mcp.json (including ones that have no local binary / runtime path). We now build a filtered MCP config at invocation time and pass it via --mcp-config <json> --strict-mcp-config so Claude CLI only sees servers that are actually available for the current invocation. Changes: - ClaudeAgentService: add buildClaudeInvocationMcpConfig (async, filters capabilities via readCapabilitiesConfig + resolveServersForCat) and inject --mcp-config + --strict-mcp-config when callbackEnv is present - mcp-config-adapters: resolveWorkspaceRoot now returns findMonorepoRoot(process.cwd()) so ALLOWED_WORKSPACE_DIRS always points at the monorepo root, not a packages/* subdir - capability-orchestrator: minor guard alignment (version check) - Test: new 'builds a strict filtered MCP config' case in claude-agent-service.test.js (73/73 mcp-config-adapters pass; new test ✔) - Test: fix 3 mcp-config-adapters assertions broken by resolveWorkspaceRoot change (process.cwd() → findMonorepoRoot(process.cwd())) - Test: fix macOS /var→/private/var symlink in resolveWorkspaceRoot test (use realpathSync(root) for expected value) Co-Authored-By: Claude Opus 4.6 <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
Fix
secret-mcp,probe-off, andcat-cafe-audioshowing asfailedinmcp_server_status. Root cause: Claude CLI loaded all servers from.mcp.jsonat startup, including ones with no local binary or runtime path.Approach: build a filtered MCP config at invocation time (
buildClaudeInvocationMcpConfig) and pass it via--mcp-config <json> --strict-mcp-config, so Claude CLI only sees servers actually available for the current invocation.Changes
Core fix —
ClaudeAgentService.tsbuildClaudeInvocationMcpConfig(catId, workingDirectory?)async method: readscapabilities.jsonviareadCapabilitiesConfig, filters viaresolveServersForCat, skips deprecated externals (CLAUDE_RUNTIME_SKIPPED_EXTERNAL_IDS = new Set(['probe-off']))callbackEnvpresent → inject--mcp-config <json> --strict-mcp-configWorkspace root fix —
mcp-config-adapters.tsresolveWorkspaceRoot():return process.cwd()→return findMonorepoRoot(process.cwd())soALLOWED_WORKSPACE_DIRSalways points at the monorepo root, not apackages/*subdirTest fixes —
mcp-config-adapters.test.jsfindMonorepoRoot+ update 3 assertions (process.cwd()→findMonorepoRoot(process.cwd())) broken by the workspace root change/var→/private/varsymlink inresolveWorkspaceRoot falls backtest:assert.equal(awd, realpathSync(root), ...)New test —
claude-agent-service.test.jsbuilds a strict filtered MCP config from capabilities when callbackEnv is present✔Test Results
mcp-config-adapters.test.jsclaude-agent-service.test.js(new test)catId: 'opus'no-model)Notes
frontend-origin.ts(CORS_ORIGINS change) left unstaged — separate PR.