VOOZH about

URL: https://deepwiki.com/ppl-ai/modelcontextprotocol/3.1-server-implementation-(srcserver.ts)

⇱ Server Implementation (src/server.ts) | ppl-ai/modelcontextprotocol | DeepWiki


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

Server Implementation (src/server.ts)

This document provides a comprehensive overview of the core server implementation in src/server.ts, which contains the primary business logic for the Perplexity MCP Server. This file implements tool registration, API communication with Perplexity services, request/response processing, SSE streaming, and network transport abstractions.

For transport-specific implementations, see page 3.2 (STDIO Entry Point) and page 3.3 (HTTP Server). For detailed type definitions, see page 3.5 (Data Types and Validation). For proxy configuration details, see page 5.2.

Sources: src/server.ts1-532


Server Factory Function

The createPerplexityServer() function is the central factory that constructs and configures an MCP server instance with all four Perplexity tools registered.


Diagram: Server Factory and Tool Registration Flow

The function signature accepts an optional serviceOrigin parameter that is propagated to all API calls via the X-Service header, enabling service-level tracking:


The server is instantiated with metadata defined at src/server.ts299-303:

  • Name: "ai.perplexity/mcp-server"
  • Version: "0.8.3" (synchronized with package.json)

Each tool registration follows a consistent pattern: define input/output schemas using Zod, specify tool metadata (title, description, annotations), and provide an async handler function. The function returns server.server (the raw MCP server handle) at src/server.ts531

Sources: src/server.ts298-532


Tool Registration Architecture

The server exposes four distinct tools, each mapped to specific Perplexity API endpoints and models. The registration uses shared schema components to ensure consistency.

Shared Schema Components

Reusable Zod field definitions are declared once inside createPerplexityServer() and composed into per-tool input schemas src/server.ts315-339

Schema composition for tool input validation


The base messageSchema is defined at src/server.ts315-318 and composed into field definitions at src/server.ts320-336 The three input schema objects are assembled at src/server.ts341-359

Tool Registration Summary

Tool NameModelInput Schemastrip_thinkingExtra ParamsLocation
perplexity_asksonar-promessagesOnlyInputSchemaNosearch_recency_filter, search_domain_filter, search_context_sizesrc/server.ts361-399
perplexity_researchsonar-deep-researchresearchInputSchemaOptionalreasoning_effortsrc/server.ts401-437
perplexity_reasonsonar-reasoning-promessagesWithStripThinkingInputSchemaOptionalsearch_recency_filter, search_domain_filter, search_context_sizesrc/server.ts439-479
perplexity_searchN/A (Search API)searchInputSchemaN/Amax_results, max_tokens_per_page, countrysrc/server.ts495-529

All tools include four standard annotations: readOnlyHint: true, openWorldHint: true, idempotentHint: false, destructiveHint: false.

Sources: src/server.ts315-529


Internal API Request Layer

Before performChatCompletion() and performSearch(), the private makeApiRequest() function centralises all outbound HTTP calls to the Perplexity API src/server.ts63-116

Responsibilities of makeApiRequest():

ConcernImplementation
API key guardThrows if PERPLEXITY_API_KEY is unset src/server.ts68-70
TimeoutReads PERPLEXITY_TIMEOUT_MS fresh each call; creates AbortController src/server.ts73-77
URL constructionnew URL(PERPLEXITY_BASE_URL + "/" + endpoint) src/server.ts75
Auth headerAuthorization: Bearer <key> src/server.ts83-84
Service headerOptional X-Service header when serviceOrigin is set src/server.ts85-87
Proxy-aware fetchDelegates to proxyAwareFetch() src/server.ts88-93
Timeout errorCatches AbortError → descriptive message src/server.ts96-98
Network errorWraps other fetch errors src/server.ts99
HTTP status errorReads response body for non-ok responses src/server.ts103-113

Chat Completion Flow

performChatCompletion() handles the three conversational tools (perplexity_ask, perplexity_reason, perplexity_research). The sonar-deep-research model uses SSE streaming; all other models use standard JSON responses.

Chat completion request processing sequence


Function Signature

performChatCompletion() is defined at src/server.ts189-247:

performChatCompletion(
 messages: Message[],
 model: string = "sonar-pro",
 stripThinking: boolean = false,
 serviceOrigin?: string,
 options?: ChatCompletionOptions
): Promise<string>

The ChatCompletionOptions interface (from src/types.ts) carries search_recency_filter, search_domain_filter, search_context_size, and reasoning_effort. Options are spread conditionally into the request body at src/server.ts202-205:

  • search_recency_filter → top-level search_recency_filter
  • search_domain_filter → top-level search_domain_filter
  • search_context_size → nested inside web_search_options.search_context_size
  • reasoning_effort → top-level reasoning_effort

Streaming flag: stream: true is added to the body only when model === "sonar-deep-research" src/server.ts196-201

Response validation: Zod errors from ChatCompletionResponseSchema.parse() are mapped to specific messages at src/server.ts219-228:

  • "Invalid API response: missing message content"
  • "Invalid API response: missing or empty choices array"

Citation appending: If data.citations is a non-empty array, numbered citations are appended to messageContent at src/server.ts239-244:

Citations:
[1] https://example.com/source1
[2] https://example.com/source2

Sources: src/server.ts189-247 src/server.ts63-116


SSE Streaming (consumeSSEStream)

sonar-deep-research responses arrive as a Server-Sent Events stream. consumeSSEStream() src/server.ts118-187 reads this stream and assembles a single ChatCompletionResponse.

SSE stream assembly logic


Key implementation details:

  • Content is accumulated as contentParts: string[] from each choices[0].delta.content chunk src/server.ts161-164
  • citations, usage, id, model, and created are overwritten by the latest chunk that carries them src/server.ts155-159
  • Malformed JSON chunks (e.g. keep-alive pings) are silently skipped src/server.ts165-167
  • The final assembled object is validated through ChatCompletionResponseSchema.parse() src/server.ts186

Sources: src/server.ts118-187


Search Flow

The performSearch() function implements interaction with Perplexity's Search API, which returns structured search results rather than conversational responses.

Search API request and response formatting flow


Function Signature

performSearch() is defined at src/server.ts271-296:

performSearch(
 query: string,
 maxResults: number = 10,
 maxTokensPerPage: number = 1024,
 country?: string,
 serviceOrigin?: string
): Promise<string>

Request Body Structure

The search request body is constructed at src/server.ts278-283:

FieldTypeConstraintsDefault
querystringrequired
max_resultsnumber1–2010
max_tokens_per_pagenumber256–20481024
countrystringISO 3166-1 alpha-2omitted if undefined

The country field is conditionally included using object spread syntax.

Result Formatting

formatSearchResults() src/server.ts249-269 transforms a SearchResponse into readable text:

Found N search results:

1. **[Title]**
 URL: [URL]
 [Snippet]
 Date: [Date]

Sources: src/server.ts249-296


Message Validation

The validateMessages() function provides runtime type checking for message arrays before they are sent to the Perplexity API. This is a TypeScript assertion function that throws descriptive errors on validation failure.


Diagram: Message Validation Logic Flow

Function Signature


Defined at src/server.ts39-56

Validation Rules

  1. Array Check: Messages must be an array src/server.ts41-43
  2. Object Check: Each element must be a non-null object src/server.ts47-49
  3. Role Check: Each message must have a role field of type string src/server.ts50-52
  4. Content Check: Each message must have a content field of type string (not undefined, not null) src/server.ts53-55

The toolName parameter is included in error messages to identify which tool invocation failed validation.

Usage in Tool Handlers

All three chat-based tools invoke this function before calling performChatCompletion():

Sources: src/server.ts40-57


Utility Functions

stripThinkingTokens()

Removes `` blocks and their content from model output. Defined at src/server.ts59-61

  • Uses the regex /<think>[\s\S]*?<\/think>/g to match across newlines (non-greedy)
  • Calls .trim() on the result
  • Unclosed or orphaned tags are left unchanged (the regex requires both opening and closing tags to match)
  • Called inside performChatCompletion() when stripThinking === true src/server.ts235-237

Use case: Prevents chain-of-thought content from consuming the MCP client's context window when the reasoning steps are not needed.

formatSearchResults()

Transforms a SearchResponse into readable text. Defined at src/server.ts249-269

  • If data.results is not an array, returns "No search results found." src/server.ts250-252
  • Otherwise, builds a numbered list with title, URL, optional snippet, and optional date

Sources: src/server.ts59-61 src/server.ts249-269


Proxy-Aware Networking

The server implements a proxy resolution chain to support corporate networks and restricted environments.

Proxy resolution and request routing


getProxyUrl()

Implements the proxy resolution chain. Defined at src/server.ts17-22

Resolution priority:

  1. PERPLEXITY_PROXY (highest)
  2. HTTPS_PROXY
  3. HTTP_PROXY
  4. undefined → direct connection

proxyAwareFetch()

Conditionally routes requests through a proxy. Defined at src/server.ts24-38

For proxy configuration details, see page 5.2.

Sources: src/server.ts17-38


Environment Variable Usage

VariableRead AtPurposeDefault
PERPLEXITY_API_KEYsrc/server.ts14 src/server.ts68API authentication (required)
PERPLEXITY_BASE_URLsrc/server.ts15API endpoint base URLhttps://api.perplexity.ai
PERPLEXITY_TIMEOUT_MSsrc/server.ts73Request timeout (ms), read per call300000 (5 min)
PERPLEXITY_PROXYsrc/server.ts18Primary proxy URL
HTTPS_PROXYsrc/server.ts19Fallback HTTPS proxy
HTTP_PROXYsrc/server.ts20Fallback HTTP proxy

PERPLEXITY_TIMEOUT_MS is parsed inside makeApiRequest() on every call src/server.ts73 so it can be changed at runtime without restarting the server.

For the complete reference, see page 5.1.

Sources: src/server.ts14-15 src/server.ts17-22 src/server.ts73


Error Handling Strategy

The server implements comprehensive error handling with specific error types for different failure modes:

API Key Errors

Detected at src/server.ts68-70 and src/server.ts184-186:

"PERPLEXITY_API_KEY environment variable is required"

Timeout Errors

Detected via AbortController at src/server.ts102-104 and src/server.ts220-222:

"Request timeout: Perplexity API did not respond within Xms. Consider increasing PERPLEXITY_TIMEOUT_MS."

Network Errors

Caught in catch blocks at src/server.ts100-106 and src/server.ts218-224:

"Network error while calling Perplexity API: [error]"

HTTP Status Errors

Checked after fetch at src/server.ts108-118 and src/server.ts226-236:

"Perplexity API error: [status] [statusText]
[error response body]"

Response Validation Errors

Handled via Zod at src/server.ts120-135 and src/server.ts238-244 Zod errors are analyzed to provide specific messages:

  • "Invalid API response: missing message content"
  • "Invalid API response: missing or empty choices array"
  • "Failed to parse JSON response from Perplexity API: [error]"

All errors are thrown immediately, allowing the MCP SDK to handle error serialization and client communication.

Sources: src/server.ts68-244