VOOZH about

URL: https://deepwiki.com/ppl-ai/modelcontextprotocol/3.4-api-client-and-network-layer

⇱ API Client and Network Layer | ppl-ai/modelcontextprotocol | DeepWiki


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

API Client and Network Layer

This page documents the internal HTTP client functions in src/server.ts that handle all outbound communication with the Perplexity API. It covers request construction, response streaming, timeout management, error classification, and proxy support.

For the types used in requests and responses, see Data Types and Validation. For proxy configuration options and environment variables, see Proxy Configuration and Environment Variables Reference. For how tools invoke these functions, see Server Implementation (src/server.ts).


Overview

The network layer exposes three exported functions from src/server.ts alongside two supporting utilities:

FunctionPurpose
performChatCompletionCalls /chat/completions; handles both JSON and SSE streaming responses
performSearchCalls /search; always returns a JSON response
proxyAwareFetchWrapper that routes through a proxy if configured, otherwise uses native fetch
getProxyUrlResolves the active proxy URL from environment variables
stripThinkingTokensRemoves `` blocks from response content

All outbound HTTP requests flow through proxyAwareFetch, which delegates to either global.fetch or undici's ProxyAgent-backed fetch depending on environment configuration.

Sources: src/index.test.ts2 src/server.test.ts2


Function Call Graph

Diagram: Network Layer Call Flow


Sources: src/index.test.ts57-176 src/server.test.ts116-192


Request Construction

Chat Completions (performChatCompletion)

performChatCompletion builds a POST request to ${PERPLEXITY_BASE_URL}/chat/completions (defaulting to https://api.perplexity.ai/chat/completions).

Request headers:

HeaderValue
Content-Typeapplication/json
AuthorizationBearer ${PERPLEXITY_API_KEY}

Request body fields:

FieldSourceNotes
modelSecond argument to performChatCompletionDefaults to sonar-pro
messagesFirst argumentArray of Message objects (role, content)
search_recency_filterChatCompletionOptionsOptional
search_domain_filterChatCompletionOptionsOptional
search_context_sizeChatCompletionOptionsOptional
reasoning_effortChatCompletionOptionsUsed by sonar-deep-research
streamInternalSet to true when model is sonar-deep-research

The ChatCompletionOptions interface is defined in src/types.ts59-64

Sources: src/index.test.ts69-91 src/types.ts59-64

Search (performSearch)

performSearch builds a POST request to ${PERPLEXITY_BASE_URL}/search (defaulting to https://api.perplexity.ai/search).

Request body fields:

FieldTypeNotes
querystringRequired
max_resultsnumberDefault: 10
max_tokens_per_pagenumberDefault: 1024
countrystringOptional; omitted from body when not provided

This maps directly to the SearchRequestBody interface in src/types.ts52-57

The country field is only included in the serialized body when explicitly passed:

Sources: src/index.test.ts179-237 src/types.ts52-57


SSE Streaming (sonar-deep-research)

When the model is sonar-deep-research, performChatCompletion requests a streaming response by setting stream: true in the request body. The response is consumed as a ReadableStream from response.body rather than parsed with response.json().

Streaming protocol:

  • Each chunk arrives as a UTF-8 encoded line prefixed with data: .
  • Chunks contain a JSON object with choices[0].delta.content holding the incremental text.
  • The stream terminates when a chunk contains data: [DONE].
  • Accumulated delta.content strings are concatenated to produce the final response.

Diagram: SSE Frame Processing


Sources: src/index.test.ts473-516


Timeout Handling

Both performChatCompletion and performSearch create an AbortController per request. The controller is wired into the fetch call via options.signal.

  • Timeout duration is read from process.env.PERPLEXITY_TIMEOUT_MS, parsed as an integer.
  • Default value is 300000 ms (5 minutes).
  • setTimeout calls controller.abort() after the configured duration.
  • If the signal fires, the fetch rejects with a DOMException of name AbortError.
  • The catch block inspects the error name: AbortError → throws "Request timeout".
PERPLEXITY_TIMEOUT_MS=100 → AbortController fires at 100ms → fetch rejects with AbortError → throws "Request timeout"

Sources: src/index.test.ts138-165 src/index.test.ts252-277


Error Classification

Both functions share the same three-tier error classification in their catch blocks:

Diagram: Error Classification Decision Tree


Summary table:

ConditionError Message
response.ok === falsePerplexity API error: {status} {statusText}
Error body cannot be readUnable to parse error response
response.json() throwsFailed to parse JSON response
choices is null, missing, or empty arraymissing or empty choices array
message.content is absent or not a stringmissing message content
citations is present but not an arrayFailed to parse JSON response
Fetch rejected with AbortErrorRequest timeout
Fetch rejected with any other errorNetwork error while calling Perplexity API

Sources: src/index.test.ts123-136 src/index.test.ts162-174 src/index.test.ts288-401 src/index.test.ts405-435


Proxy-Aware Fetch

getProxyUrl()

Resolves the proxy URL by checking environment variables in priority order:

PERPLEXITY_PROXY → HTTPS_PROXY → HTTP_PROXY → undefined

Returns undefined when none are set.

Sources: src/server.test.ts60-113

proxyAwareFetch(url, options?)

Acts as a drop-in replacement for fetch. Its behavior differs based on whether a proxy is configured:

Diagram: proxyAwareFetch Dispatch


  • Without a proxy, global.fetch is called directly with the url and options object passed through unchanged.
  • With a proxy, undici's fetch is used with a ProxyAgent set as the dispatcher field. The UndiciRequestOptions interface in src/types.ts66-69 types this extended options object.
  • The AbortSignal from the calling function's AbortController is forwarded through options.signal in both paths.

Sources: src/server.test.ts116-192 src/types.ts66-69


Citation Appending

After a successful chat completion response is parsed, performChatCompletion checks the citations field of ChatCompletionResponse (src/types.ts25-32). If it is a non-empty array of strings, a formatted block is appended to the response text:

{response content}

Citations:
[1] https://...
[2] https://...

An empty citations array produces no citation block. A non-array value causes a "Failed to parse JSON response" error via the Zod validation path.

Sources: src/index.test.ts94-121 src/index.test.ts367-401 src/types.ts25-32


stripThinkingTokens

A post-processing utility applied when strip_thinking is true. It removes all content between `` tags using a regex, then trims the result.

Behavior notes:

  • Handles multiple `` blocks in a single response.
  • Handles multiline content within tags.
  • Passes through unclosed `` closing tags unchanged.

Sources: src/server.test.ts5-58


Type Reference for Network Layer

The network layer is typed entirely through interfaces in src/types.ts:

InterfaceUsed ByPurpose
MessageperformChatCompletion inputSingle {role, content} message
ChatCompletionOptionsperformChatCompletionOptional API parameters forwarded to the request body
ChatCompletionResponseperformChatCompletion output parsingTyped shape of the JSON response
ChatChoiceChatCompletionResponse.choices[]Individual choice with message
ChatMessageChatChoice.messageHolds the content string
SearchRequestBodyperformSearchTyped request body for /search
SearchResponseperformSearch output parsingTyped shape of search JSON response
SearchResultSearchResponse.results[]Individual search result
UndiciRequestOptionsproxyAwareFetchExtends RequestInit with dispatcher?: ProxyAgent

Sources: src/types.ts1-70