Conversation
Fixes Nano-Collective#1248 The validateProjectConfigSecurity function was never running because the .source field it filters on was being stripped during config unwrapping. Root cause: loadAppConfig called loadAllMCPConfigs() which returns MCPServerWithSource[] (wrapper type with separate .source field), then unwrapped with .map(item => item.server), discarding the .source field before passing to validateProjectConfigSecurity. Fix: Preserve .source by spreading it onto the unwrapped server object: .map(item => ({ ...item.server, source: item.source })) This ensures validateProjectConfigSecurity's filter (server.source === 'project') works as intended and hardcoded credential warnings fire for project configs.
Add test case verifying that the source field is correctly preserved when MCPServerWithSource objects are unwrapped in loadAppConfig.
nc-review: needs work — 1 blocking, 1 important@addyCooks — there is a blocking item below. The fix in source/config/index.ts is correct and resolves issue #1248: preserving the .source field through the loadAppConfig unwrap means validateProjectConfigSecurity will actually receive project-level entries. However, the regression test added to validation.spec.ts reproduces the exact failure mode the issue warned about — it hand-constructs objects with 🔴 blocking · The new test is titled "source field is preserved through loadAppConfig" but it never calls
If the unwrap bug regressed in 🟠 important · Even on its own terms, the test only asserts 🔴 blocking · 🟠 a reviewer would ask for a change · ⚪ optional Automated code review — correctness, security, design, tests, plus duplicates and scope. A human still decides; this is not a substitute for review and is not exhaustive. The required status checks separately cover lint, formatting, types, unused dependencies, the test suite and the build. This bot never merges. Maintainers can rerun with |
Description
Fixes #1248
The
validateProjectConfigSecurityfunction was never executing because the.sourcefield (which identifies whether an MCP server config is project-level, global, or environment-based) was being stripped during config loading inloadAppConfig.Root cause: In
source/config/index.ts, the function unwrappedMCPServerWithSource[]objects by mapping to justitem.server, which discarded the wrapper's.sourcefield that the security validator depended on. The validator filtered forserver.source === 'project', but this field was alwaysundefinedin production.The fix: Preserve the
sourcefield when unwrapping by spreading bothitem.serverandsource: item.source.The hardcoded-credential scanner now correctly receives the source field and will warn users about project-level MCP configs containing apparent secrets (hardcoded API keys, tokens, passwords, etc.).
Type of Change
Changeset
pnpm changeset) describing this change for the changelogChangeset file:
.changeset/fix-mcp-config-security-validation.mdTesting
Automated Tests
.spec.ts/tsxfilespnpm test:allcompletes successfully)Manual Testing
Checklist