Skip to content

feat(opencode): Allow per-MCP-server trust configuration - #40125

Open
karup wants to merge 26 commits into
anomalyco:devfrom
karup:mcp-tls-trust
Open

feat(opencode): Allow per-MCP-server trust configuration#40125
karup wants to merge 26 commits into
anomalyco:devfrom
karup:mcp-tls-trust

Conversation

@karup

@karup karup commented Aug 2, 2026

Copy link
Copy Markdown

Issue for this PR

Closes #40111

Also partially addresses
#23506
Rather than disabling verification globally, fingerprint pinning achieves the same goal — trusting a specific self-signed cert — without insecure: true. caFile handles private CAs cleanly without a blanket bypass.

#14696
#26862
The createTlsFetch() wrapper and per-server TLS config injection proves the transport-layer plumbing needed for mTLS. Adding cert/key fields to the tls config block follows the same pattern — caFile validates PEM; cert+key would too.

#1694
Provides a portable alternative. Instead of relying on OS-specific trust stores, caFile: "~/ca.pem" lets users point to their corporate CA explicitly, working identically across macOS/Linux/Windows without NODE_EXTRA_CA_CERTS.

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

Adds per-MCP-server TLS trust configuration for remote MCP servers using self-signed certificates or private CAs. Three options: caFile (path to CA cert), caPem (inline CA cert), and fingerprint (SHA256 certificate pinning, like SSH host keys).

Config schema is added to both V1 and V2 MCP configs. A buildTlsCa() helper reads files, validates PEM content, and verifies fingerprints, then createTlsFetch() injects the trusted CA into a custom fetch wrapper scoped to that transport only — no global TLS changes.

Fingerprint verification uses a one-time pre-flight TLS socket to retrieve the server cert, compares it against the user-provided fingerprint, and promotes the verified cert to a trusted CA. Trust applies only to that transport instance and does not leak across MCP servers.

How did you verify your code works?

  • Unit tests cover PEM validation, fingerprint format validation, file reading, DER-to-PEM conversion, and buildTlsCa integration
  • Three-pass code review (security, style/contribution guidelines, architectural design)
  • TOCTOU in file reads fixed via fd-based atomic stat+read
  • Performance review confirmed zero overhead on the no-TLS path (the guard if (mcp.tls) prevents any new allocations or yields when TLS is not configured)

Screenshots / recordings

Not a UI change.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

karup added 3 commits August 1, 2026 21:33
Add per-MCP-server TLS trust configuration supporting custom CA files, embedded CA certificates, and certificate fingerprint pinning.

- Add Tls config schema (caFile, caPem, fingerprint) to V1 and V2 MCP configs
- Build TLS CA from config and inject via custom fetch into transports
- Validate PEM certs, fingerprint format, and file type before use
- Pre-flight TLS connection for fingerprint verification with cert pinning
- TLS trust is scoped per-fetch-instance; does not affect global TLS
…w findings

Extract duplicated TLS config assembly (caPem validation + caFile read + fingerprint verify) into a single buildTlsCa() async helper, eliminating 3 identical ~20-line blocks across connectRemote, startAuth, and McpDebugCommand.

Also address code review findings:
- Fix test any types with proper RequestInit intersection
- Deduplicate fingerprint normalization (validate once, pass through)
- Add parseInt radix (use Number() instead)
- Add derToPem and buildTlsCa unit tests
- Pre-compute tls options object in createTlsFetch to reduce per-request allocations
- Export derToPem for testability
- Add security doc comment noting custom CA follows redirects
Use openSync + fstatSync + readFileSync(fd) to stat and read the same inode, eliminating the TOCTOU gap between existsSync/statSync and readFileSync where a file swap could occur.

Also:
- Add security doc comment to resolveFilePath about path traversal being by design
- Replace for loop with Uint8Array.from in derToPem test
@github-actions

github-actions Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Hey! Your PR title Allow per-MCP-server trust configuration doesn't follow conventional commit format.

Please update it to start with one of:

  • feat: or feat(scope): new feature
  • fix: or fix(scope): bug fix
  • docs: or docs(scope): documentation changes
  • chore: or chore(scope): maintenance tasks
  • refactor: or refactor(scope): code refactoring
  • test: or test(scope): adding or updating tests

Where scope is the package name (e.g., app, desktop, opencode).

See CONTRIBUTING.md for details.

karup added 3 commits August 1, 2026 21:48
Add TLS Trust section with three options (caFile, caPem, fingerprint) and examples for each. Users can now discover per-server TLS trust from the docs.
readCaFile trims trailing whitespace, so match against trimmed cert in expectations. Fix derToPem body line extraction to use lines.slice(1, -2). Fix concatenation test to use valid PEM for caPem instead of plain text.
@karup karup changed the title Allow per-MCP-server trust configuration feat: Allow per-MCP-server trust configuration Aug 3, 2026
@karup karup changed the title feat: Allow per-MCP-server trust configuration feat(opencode): Allow per-MCP-server trust configuration Aug 3, 2026
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.

[FEATURE]: Allow per-MCP-server trust configuration

1 participant