Skip to content

fix(claude-agent): strict MCP config filtering to fix mcp_server_status errors - #1157

Open
xu75 wants to merge 28 commits into
zts212653:mainfrom
xu75:fix/claude-mcp-status-filter-v2
Open

fix(claude-agent): strict MCP config filtering to fix mcp_server_status errors#1157
xu75 wants to merge 28 commits into
zts212653:mainfrom
xu75:fix/claude-mcp-status-filter-v2

Conversation

@xu75

@xu75 xu75 commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Summary

Fix secret-mcp, probe-off, and cat-cafe-audio showing as failed in mcp_server_status. Root cause: Claude CLI loaded all servers from .mcp.json at 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.ts

  • New buildClaudeInvocationMcpConfig(catId, workingDirectory?) async method: reads capabilities.json via readCapabilitiesConfig, filters via resolveServersForCat, skips deprecated externals (CLAUDE_RUNTIME_SKIPPED_EXTERNAL_IDS = new Set(['probe-off']))
  • Invocation logic: when callbackEnv present → inject --mcp-config <json> --strict-mcp-config

Workspace root fix — mcp-config-adapters.ts

  • resolveWorkspaceRoot(): return process.cwd()return findMonorepoRoot(process.cwd()) so ALLOWED_WORKSPACE_DIRS always points at the monorepo root, not a packages/* subdir

Test fixes — mcp-config-adapters.test.js

  • Import findMonorepoRoot + update 3 assertions (process.cwd()findMonorepoRoot(process.cwd())) broken by the workspace root change
  • Fix macOS /var/private/var symlink in resolveWorkspaceRoot falls back test: assert.equal(awd, realpathSync(root), ...)

New test — claude-agent-service.test.js

  • builds a strict filtered MCP config from capabilities when callbackEnv is present

Test Results

File Pass Fail
mcp-config-adapters.test.js 73 0
claude-agent-service.test.js (new test)
Pre-existing failures (catId: 'opus' no-model) 29 (unchanged, pre-date this branch)

Notes

frontend-origin.ts (CORS_ORIGINS change) left unstaged — separate PR.

xu75 and others added 28 commits April 2, 2026 15:42
…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>
@xu75
xu75 requested a review from zts212653 as a code owner July 15, 2026 07:27
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