@perplexity-ai/mcp-server 0.8.1 → 0.8.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,14 +6,14 @@
6
6
  },
7
7
  "metadata": {
8
8
  "description": "Official Perplexity AI plugin providing real-time web search, reasoning, and research capabilities",
9
- "version": "0.8.1"
9
+ "version": "0.8.3"
10
10
  },
11
11
  "plugins": [
12
12
  {
13
13
  "name": "perplexity",
14
14
  "source": "./",
15
15
  "description": "Real-time web search, reasoning, and research through Perplexity's API",
16
- "version": "0.8.1",
16
+ "version": "0.8.3",
17
17
  "author": {
18
18
  "name": "Perplexity AI",
19
19
  "email": "api@perplexity.ai"
package/dist/server.js CHANGED
@@ -43,6 +43,51 @@ export function validateMessages(messages, toolName) {
43
43
  export function stripThinkingTokens(content) {
44
44
  return content.replace(/<think>[\s\S]*?<\/think>/g, '').trim();
45
45
  }
46
+ async function makeApiRequest(endpoint, body, serviceOrigin) {
47
+ if (!PERPLEXITY_API_KEY) {
48
+ throw new Error("PERPLEXITY_API_KEY environment variable is required");
49
+ }
50
+ // Read timeout fresh each time to respect env var changes
51
+ const TIMEOUT_MS = parseInt(process.env.PERPLEXITY_TIMEOUT_MS || "300000", 10);
52
+ const url = new URL(`${PERPLEXITY_BASE_URL}/${endpoint}`);
53
+ const controller = new AbortController();
54
+ const timeoutId = setTimeout(() => controller.abort(), TIMEOUT_MS);
55
+ let response;
56
+ try {
57
+ const headers = {
58
+ "Content-Type": "application/json",
59
+ "Authorization": `Bearer ${PERPLEXITY_API_KEY}`,
60
+ };
61
+ if (serviceOrigin) {
62
+ headers["X-Service"] = serviceOrigin;
63
+ }
64
+ response = await proxyAwareFetch(url.toString(), {
65
+ method: "POST",
66
+ headers,
67
+ body: JSON.stringify(body),
68
+ signal: controller.signal,
69
+ });
70
+ }
71
+ catch (error) {
72
+ clearTimeout(timeoutId);
73
+ if (error instanceof Error && error.name === "AbortError") {
74
+ throw new Error(`Request timeout: Perplexity API did not respond within ${TIMEOUT_MS}ms. Consider increasing PERPLEXITY_TIMEOUT_MS.`);
75
+ }
76
+ throw new Error(`Network error while calling Perplexity API: ${error}`);
77
+ }
78
+ clearTimeout(timeoutId);
79
+ if (!response.ok) {
80
+ let errorText;
81
+ try {
82
+ errorText = await response.text();
83
+ }
84
+ catch (parseError) {
85
+ errorText = "Unable to parse error response";
86
+ }
87
+ throw new Error(`Perplexity API error: ${response.status} ${response.statusText}\n${errorText}`);
88
+ }
89
+ return response;
90
+ }
46
91
  export async function consumeSSEStream(response) {
47
92
  const body = response.body;
48
93
  if (!body) {
@@ -111,13 +156,7 @@ export async function consumeSSEStream(response) {
111
156
  return ChatCompletionResponseSchema.parse(assembled);
112
157
  }
113
158
  export async function performChatCompletion(messages, model = "sonar-pro", stripThinking = false, serviceOrigin, options) {
114
- if (!PERPLEXITY_API_KEY) {
115
- throw new Error("PERPLEXITY_API_KEY environment variable is required");
116
- }
117
- // Read timeout fresh each time to respect env var changes
118
- const TIMEOUT_MS = parseInt(process.env.PERPLEXITY_TIMEOUT_MS || "300000", 10);
119
159
  const useStreaming = model === "sonar-deep-research";
120
- const url = new URL(`${PERPLEXITY_BASE_URL}/chat/completions`);
121
160
  const body = {
122
161
  model: model,
123
162
  messages: messages,
@@ -127,42 +166,7 @@ export async function performChatCompletion(messages, model = "sonar-pro", strip
127
166
  ...(options?.search_context_size && { web_search_options: { search_context_size: options.search_context_size } }),
128
167
  ...(options?.reasoning_effort && { reasoning_effort: options.reasoning_effort }),
129
168
  };
130
- const controller = new AbortController();
131
- const timeoutId = setTimeout(() => controller.abort(), TIMEOUT_MS);
132
- let response;
133
- try {
134
- const headers = {
135
- "Content-Type": "application/json",
136
- "Authorization": `Bearer ${PERPLEXITY_API_KEY}`,
137
- };
138
- if (serviceOrigin) {
139
- headers["X-Service"] = serviceOrigin;
140
- }
141
- response = await proxyAwareFetch(url.toString(), {
142
- method: "POST",
143
- headers,
144
- body: JSON.stringify(body),
145
- signal: controller.signal,
146
- });
147
- clearTimeout(timeoutId);
148
- }
149
- catch (error) {
150
- clearTimeout(timeoutId);
151
- if (error instanceof Error && error.name === "AbortError") {
152
- throw new Error(`Request timeout: Perplexity API did not respond within ${TIMEOUT_MS}ms. Consider increasing PERPLEXITY_TIMEOUT_MS.`);
153
- }
154
- throw new Error(`Network error while calling Perplexity API: ${error}`);
155
- }
156
- if (!response.ok) {
157
- let errorText;
158
- try {
159
- errorText = await response.text();
160
- }
161
- catch (parseError) {
162
- errorText = "Unable to parse error response";
163
- }
164
- throw new Error(`Perplexity API error: ${response.status} ${response.statusText}\n${errorText}`);
165
- }
169
+ const response = await makeApiRequest("chat/completions", body, serviceOrigin);
166
170
  let data;
167
171
  try {
168
172
  if (useStreaming) {
@@ -217,54 +221,13 @@ export function formatSearchResults(data) {
217
221
  return formattedResults;
218
222
  }
219
223
  export async function performSearch(query, maxResults = 10, maxTokensPerPage = 1024, country, serviceOrigin) {
220
- if (!PERPLEXITY_API_KEY) {
221
- throw new Error("PERPLEXITY_API_KEY environment variable is required");
222
- }
223
- // Read timeout fresh each time to respect env var changes
224
- const TIMEOUT_MS = parseInt(process.env.PERPLEXITY_TIMEOUT_MS || "300000", 10);
225
- const url = new URL(`${PERPLEXITY_BASE_URL}/search`);
226
224
  const body = {
227
225
  query: query,
228
226
  max_results: maxResults,
229
227
  max_tokens_per_page: maxTokensPerPage,
230
228
  ...(country && { country }),
231
229
  };
232
- const controller = new AbortController();
233
- const timeoutId = setTimeout(() => controller.abort(), TIMEOUT_MS);
234
- let response;
235
- try {
236
- const headers = {
237
- "Content-Type": "application/json",
238
- "Authorization": `Bearer ${PERPLEXITY_API_KEY}`,
239
- };
240
- if (serviceOrigin) {
241
- headers["X-Service"] = serviceOrigin;
242
- }
243
- response = await proxyAwareFetch(url.toString(), {
244
- method: "POST",
245
- headers,
246
- body: JSON.stringify(body),
247
- signal: controller.signal,
248
- });
249
- clearTimeout(timeoutId);
250
- }
251
- catch (error) {
252
- clearTimeout(timeoutId);
253
- if (error instanceof Error && error.name === "AbortError") {
254
- throw new Error(`Request timeout: Perplexity Search API did not respond within ${TIMEOUT_MS}ms. Consider increasing PERPLEXITY_TIMEOUT_MS.`);
255
- }
256
- throw new Error(`Network error while calling Perplexity Search API: ${error}`);
257
- }
258
- if (!response.ok) {
259
- let errorText;
260
- try {
261
- errorText = await response.text();
262
- }
263
- catch (parseError) {
264
- errorText = "Unable to parse error response";
265
- }
266
- throw new Error(`Perplexity Search API error: ${response.status} ${response.statusText}\n${errorText}`);
267
- }
230
+ const response = await makeApiRequest("search", body, serviceOrigin);
268
231
  let data;
269
232
  try {
270
233
  const json = await response.json();
@@ -278,7 +241,7 @@ export async function performSearch(query, maxResults = 10, maxTokensPerPage = 1
278
241
  export function createPerplexityServer(serviceOrigin) {
279
242
  const server = new McpServer({
280
243
  name: "ai.perplexity/mcp-server",
281
- version: "0.8.1",
244
+ version: "0.8.3",
282
245
  }, {
283
246
  instructions: "Perplexity AI server for web-grounded search, research, and reasoning. " +
284
247
  "Use perplexity_search for finding URLs, facts, and recent news. " +
@@ -337,7 +300,8 @@ export function createPerplexityServer(serviceOrigin) {
337
300
  annotations: {
338
301
  readOnlyHint: true,
339
302
  openWorldHint: true,
340
- idempotentHint: true,
303
+ idempotentHint: false,
304
+ destructiveHint: false,
341
305
  },
342
306
  }, async (args) => {
343
307
  const { messages, search_recency_filter, search_domain_filter, search_context_size } = args;
@@ -366,7 +330,8 @@ export function createPerplexityServer(serviceOrigin) {
366
330
  annotations: {
367
331
  readOnlyHint: true,
368
332
  openWorldHint: true,
369
- idempotentHint: true,
333
+ idempotentHint: false,
334
+ destructiveHint: false,
370
335
  },
371
336
  }, async (args) => {
372
337
  const { messages, strip_thinking, reasoning_effort } = args;
@@ -394,7 +359,8 @@ export function createPerplexityServer(serviceOrigin) {
394
359
  annotations: {
395
360
  readOnlyHint: true,
396
361
  openWorldHint: true,
397
- idempotentHint: true,
362
+ idempotentHint: false,
363
+ destructiveHint: false,
398
364
  },
399
365
  }, async (args) => {
400
366
  const { messages, strip_thinking, search_recency_filter, search_domain_filter, search_context_size } = args;
@@ -434,7 +400,8 @@ export function createPerplexityServer(serviceOrigin) {
434
400
  annotations: {
435
401
  readOnlyHint: true,
436
402
  openWorldHint: true,
437
- idempotentHint: true,
403
+ idempotentHint: false,
404
+ destructiveHint: false,
438
405
  },
439
406
  }, async (args) => {
440
407
  const { query, max_results, max_tokens_per_page, country } = args;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@perplexity-ai/mcp-server",
3
- "version": "0.8.1",
3
+ "version": "0.8.3",
4
4
  "mcpName": "ai.perplexity/mcp-server",
5
5
  "description": "Real-time web search, reasoning, and research through Perplexity's API",
6
6
  "keywords": [