Skip to content

feat(mcp): trust private-network server certificates on first use - #60031

Closed
karup wants to merge 1 commit into
anomalyco:devfrom
karup:mcp-tls-trust-v2
Closed

karup wants to merge 1 commit into
anomalyco:devfrom
karup:mcp-tls-trust-v2

Conversation

@karup

@karup karup commented Oct 28, 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

Remote MCP servers at private IP addresses can now be trusted on first use instead of requiring a tls config: the first connect fails with the presented certificate's fingerprint and the command to trust it; opencode mcp trust <url> [--force] pins the certificate for the project; later connects verify the pinned certificate, and rotations fail until re-pinned with --force. Hostnames and public IPs never auto-trust; explicit tls config takes precedence.

Adds the mcp_trusted_host table (per project, machine-local), mcp.trust.inspect and mcp.trust.pin endpoints, the CLI command, and docs.
@github-actions github-actions Bot added the needs:compliance This means the issue will auto-close after 2 hours. label Oct 28, 2026
@opencodejr opencodejr Bot closed this Oct 28, 2026
@opencodejr

opencodejr Bot commented Oct 28, 2026

Copy link
Copy Markdown
Contributor

Thanks for porting this to v2, @karup. Trusting self-signed certificates on private networks is a useful feature (see #40111).

This pull request is too large to review as one change (about 1,300 changed lines outside tests, 35 files). It also combines pieces that each work on their own. The description says "explicit tls config takes precedence", but dev has no tls config for MCP servers yet: this pull request adds it as well. Could you split it into smaller, focused pull requests? For example:

  • Explicit per-server tls config for remote MCP servers: CA file and SHA256 fingerprint pinning (packages/core/src/mcp/tls.ts, Mcp.TlsConfig in the schema, the client.ts wiring, tests and docs).
  • Trust-on-first-use for private-IP servers, built on the first one: the mcp_trusted_host table and migration, the mcp.trust.inspect/mcp.trust.pin endpoints with the regenerated client, the opencode mcp trust command, tests and docs.
  • The Windows path-separator fix in packages/core/script/migration.ts as its own small fix.

You're welcome to open those, ideally linking #40111.

@github-actions github-actions Bot removed the needs:compliance This means the issue will auto-close after 2 hours. label Oct 28, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Thanks for updating your PR! It now meets our contributing guidelines. 👍

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