Skip to content

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

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.
@opencodejr opencodejr Bot closed this Oct 28, 2026
@opencodejr

opencodejr Bot commented Oct 28, 2026

Copy link
Copy Markdown
Contributor

Thanks for working on this, @karup. Per-server trust for self-signed and private-CA MCP servers is a useful feature (see #40111).

This pull request has the same changes as #60031, which was closed because it is too large to review as one change: about 1,300 changed lines outside tests, across 35 files. It also bundles parts that each work on their own. Could you split it into smaller, focused pull requests? For example:

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

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

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