VOOZH about

URL: https://deepwiki.com/ppl-ai/modelcontextprotocol/10.3-security-architecture

⇱ Security Architecture | ppl-ai/modelcontextprotocol | DeepWiki


Loading...
Last indexed: 28 February 2026 (95c7a8)
Menu

Security Architecture

This page documents the security-relevant design decisions in the @perplexity-ai/mcp-server codebase. It covers credential handling at runtime, publish-time authentication mechanisms, network-layer access controls, and the OAuth/PKCE capabilities available through the SDK dependency tree.

For details on the environment variables themselves (including PERPLEXITY_API_KEY and ALLOWED_ORIGINS), see 5.1. For the CI/CD workflows referenced here, see 9.


Security Boundary Overview

The server sits between MCP clients and the Perplexity API. The primary security responsibilities are:

  • Protecting the outbound PERPLEXITY_API_KEY credential
  • Controlling which clients can reach the HTTP transport endpoint
  • Protecting the npm and MCP Registry publishing credentials

Diagram: Security Trust Boundaries


Sources: .github/workflows/publish.yml1-38 .github/workflows/publish-mcp.yml1-33


API Key Handling

Startup Guard

In src/index.ts, the server checks for PERPLEXITY_API_KEY immediately at startup before creating any server objects or transports. If the variable is absent, the process logs an error to stderr and exits with code 1. The key is never written to stdout.

Transmission

The key is passed by src/server.ts as a Bearer token in the Authorization header of every outbound request to api.perplexity.ai. It is interpolated directly into the header at call time and is not stored in any intermediate structure or log record.

Logging

The logger in src/logger.ts writes exclusively to stderr. The MCP protocol message framing uses stdout. This separation ensures that even at DEBUG level, no secret content leaks into the MCP message stream. The logger does not print request headers.

Diagram: API Key Flow Through Code Entities


Sources: .github/workflows/publish.yml1-38


CORS Policy (HTTP Mode)

The HTTP transport in src/http.ts uses the cors npm package as Express middleware. Origin filtering is controlled by the ALLOWED_ORIGINS environment variable.

ScenarioBehavior
ALLOWED_ORIGINS not setAll origins permitted (*)
ALLOWED_ORIGINS=https://app.example.comOnly that origin allowed
ALLOWED_ORIGINS=https://a.com,https://b.comComma-separated list, each allowed

The /health endpoint is not gated by the CORS middleware — it is intended for infrastructure-level health checks only and returns no sensitive data.

The ALLOWED_ORIGINS parsing logic and the cors middleware setup live in src/http.ts. See 3.3 for the full HTTP server documentation.


npm Publishing: OIDC Authentication

The npm publish workflow at `.github/workflows/publish.yml` uses GitHub's OpenID Connect (OIDC) token mechanism rather than a static npm token.

Key configuration:


.github/workflows/publish.yml14-17

The id-token: write permission causes GitHub Actions to mint a short-lived OIDC token for the job. The setup-node action exchanges this with the npm registry to obtain a scoped publish credential. No long-lived npm token secret is stored in the repository.

The publish command includes --provenance, which attaches a signed build provenance attestation (linking the published artifact to the specific commit and workflow run) to the npm package entry.

.github/workflows/publish.yml38

Diagram: npm OIDC Publish Flow


Sources: .github/workflows/publish.yml1-38


MCP Registry Publishing: Private Key Handling

The MCP registry publish workflow at `.github/workflows/publish-mcp.yml` uses a DNS-based domain ownership proof combined with an asymmetric private key.

The key handling sequence:

  1. The MCP_REGISTRY_PRIVATE_KEY secret is written to a temporary file key.pem.
  2. openssl pkey extracts the raw private key bytes inline as a shell argument.
  3. key.pem is immediately deleted with rm key.pem.

.github/workflows/publish-mcp.yml27-29

The private key material is never left on disk after the login step completes.


.github/workflows/publish-mcp.yml27-29

Diagram: MCP Registry Key Lifecycle


Sources: .github/workflows/publish-mcp.yml1-33

The workflow also restricts the job to the production environment, which can be configured in GitHub to require manual approvals before the job runs.

.github/workflows/publish-mcp.yml12-13


SDK OAuth and PKCE Capabilities

The @modelcontextprotocol/sdk dependency tree includes two libraries relevant to OAuth flows:

PackageVersionRole
jose^6.1.3JWT signing, verification, and JWK handling
pkce-challenge^5.0.0PKCE (Proof Key for Code Exchange) code verifier and challenge generation

package-lock.json577-616

These are used by the MCP SDK's own OAuth authorization server and client support. The @perplexity-ai/mcp-server itself does not implement an OAuth flow — it uses simple Bearer token authentication for the Perplexity API. However, if the SDK's OAuth capabilities are exercised by a client connecting to this server, jose and pkce-challenge provide the cryptographic primitives.


Security Controls Summary

ControlMechanismLocation
API key guard at startupprocess.exit(1) if missingsrc/index.ts
API key transmissionAuthorization: Bearer headersrc/server.ts
API key confidentialityLogger writes to stderr onlysrc/logger.ts
HTTP origin restrictioncors middleware + ALLOWED_ORIGINSsrc/http.ts
npm publish credentialGitHub OIDC (no static token).github/workflows/publish.yml
npm package integrity--provenance attestation.github/workflows/publish.yml
MCP registry credentialEphemeral key.pem, deleted post-login.github/workflows/publish-mcp.yml
OAuth/PKCE (SDK layer)jose, pkce-challenge@modelcontextprotocol/sdk deps