@perplexity-ai/mcp-server 0.5.2 → 0.6.0
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.
- package/.claude-plugin/marketplace.json +2 -2
- package/README.md +42 -100
- package/dist/http.js +2 -16
- package/dist/index.js +1 -7
- package/dist/server.js +24 -91
- package/dist/types.js +0 -3
- package/package.json +1 -1
|
@@ -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.
|
|
9
|
+
"version": "0.6.0"
|
|
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.
|
|
16
|
+
"version": "0.6.0",
|
|
17
17
|
"author": {
|
|
18
18
|
"name": "Perplexity AI",
|
|
19
19
|
"email": "api@perplexity.ai"
|
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@ The official MCP server implementation for the Perplexity API Platform, providin
|
|
|
13
13
|
### **perplexity_search**
|
|
14
14
|
Direct web search using the Perplexity Search API. Returns ranked search results with metadata, perfect for finding current information.
|
|
15
15
|
|
|
16
|
-
### **perplexity_ask**
|
|
16
|
+
### **perplexity_ask**
|
|
17
17
|
General-purpose conversational AI with real-time web search using the `sonar-pro` model. Great for quick questions and everyday searches.
|
|
18
18
|
|
|
19
19
|
### **perplexity_research**
|
|
@@ -30,61 +30,37 @@ Advanced reasoning and problem-solving using the `sonar-reasoning-pro` model. Pe
|
|
|
30
30
|
## Configuration
|
|
31
31
|
|
|
32
32
|
### Get Your API Key
|
|
33
|
+
|
|
33
34
|
1. Get your Perplexity API Key from the [API Portal](https://www.perplexity.ai/account/api/group)
|
|
34
|
-
2.
|
|
35
|
-
3. (Optional) Set
|
|
36
|
-
4. (Optional) Set log level
|
|
35
|
+
2. Replace `your_key_here` in the configurations below with your API key
|
|
36
|
+
3. (Optional) Set timeout: `PERPLEXITY_TIMEOUT_MS=600000` (default: 5 minutes)
|
|
37
|
+
4. (Optional) Set log level: `PERPLEXITY_LOG_LEVEL=DEBUG|INFO|WARN|ERROR` (default: ERROR)
|
|
37
38
|
|
|
38
39
|
### Claude Code
|
|
39
40
|
|
|
40
|
-
#### Option 1: Install via Plugin (Recommended)
|
|
41
|
-
|
|
42
|
-
The easiest way to get started with Perplexity in Claude Code, set your API key:
|
|
43
41
|
```bash
|
|
44
|
-
|
|
42
|
+
claude mcp add perplexity --env PERPLEXITY_API_KEY="your_key_here" -- npx -y @perplexity-ai/mcp-server
|
|
45
43
|
```
|
|
46
|
-
|
|
44
|
+
|
|
45
|
+
Or install via plugin:
|
|
47
46
|
```bash
|
|
48
|
-
|
|
47
|
+
export PERPLEXITY_API_KEY="your_key_here"
|
|
49
48
|
claude
|
|
50
|
-
|
|
51
|
-
#
|
|
52
|
-
/plugin marketplace add perplexityai/modelcontextprotocol
|
|
53
|
-
|
|
54
|
-
# Install the plugin
|
|
55
|
-
/plugin install perplexity
|
|
49
|
+
# Then run: /plugin marketplace add perplexityai/modelcontextprotocol
|
|
50
|
+
# Then run: /plugin install perplexity
|
|
56
51
|
```
|
|
57
52
|
|
|
58
|
-
|
|
53
|
+
### Cursor, Claude Desktop & Windsurf
|
|
59
54
|
|
|
60
|
-
|
|
55
|
+
We recommend using the one-click install badge at the top of this README for Cursor.
|
|
61
56
|
|
|
62
|
-
|
|
63
|
-
claude mcp add perplexity --transport stdio --env PERPLEXITY_API_KEY=your_key_here -- npx -y perplexity-mcp
|
|
64
|
-
```
|
|
57
|
+
For manual setup, all these clients use the same `mcpServers` format:
|
|
65
58
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
"type": "stdio",
|
|
72
|
-
"command": "npx",
|
|
73
|
-
"args": [
|
|
74
|
-
"-y",
|
|
75
|
-
"perplexity-mcp"
|
|
76
|
-
],
|
|
77
|
-
"env": {
|
|
78
|
-
"PERPLEXITY_API_KEY": "your_key_here",
|
|
79
|
-
"PERPLEXITY_TIMEOUT_MS": "600000"
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
### Cursor
|
|
86
|
-
|
|
87
|
-
Add to your `mcp.json` (Cursor):
|
|
59
|
+
| Client | Config File |
|
|
60
|
+
|--------|-------------|
|
|
61
|
+
| Cursor | `~/.cursor/mcp.json` |
|
|
62
|
+
| Claude Desktop | `claude_desktop_config.json` |
|
|
63
|
+
| Windsurf | `~/.codeium/windsurf/mcp_config.json` |
|
|
88
64
|
|
|
89
65
|
```json
|
|
90
66
|
{
|
|
@@ -102,63 +78,33 @@ Add to your `mcp.json` (Cursor):
|
|
|
102
78
|
|
|
103
79
|
### VS Code
|
|
104
80
|
|
|
105
|
-
|
|
81
|
+
We recommend using the one-click install badge at the top of this README for VS Code, or for manual setup, add to `.vscode/mcp.json`:
|
|
106
82
|
|
|
107
83
|
```json
|
|
108
84
|
{
|
|
109
|
-
|
|
110
|
-
"perplexity": {
|
|
111
|
-
"type": "stdio",
|
|
112
|
-
"command": "npx",
|
|
113
|
-
"args": [
|
|
114
|
-
"-y",
|
|
115
|
-
"@perplexity-ai/mcp-server"
|
|
116
|
-
],
|
|
117
|
-
"env": {
|
|
118
|
-
"PERPLEXITY_API_KEY": "your_key_here"
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
Or use the one-click install badges at the top of this README.
|
|
126
|
-
|
|
127
|
-
### Codex
|
|
128
|
-
|
|
129
|
-
Run in your terminal:
|
|
130
|
-
|
|
131
|
-
```bash
|
|
132
|
-
codex mcp add perplexity --env PERPLEXITY_API_KEY=your_key_here -- npx -y @perplexity-ai/mcp-server
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
### Claude Desktop
|
|
136
|
-
|
|
137
|
-
Add to your `claude_desktop_config.json`:
|
|
138
|
-
|
|
139
|
-
```json
|
|
140
|
-
{
|
|
141
|
-
"mcpServers": {
|
|
85
|
+
"servers": {
|
|
142
86
|
"perplexity": {
|
|
87
|
+
"type": "stdio",
|
|
143
88
|
"command": "npx",
|
|
144
89
|
"args": ["-y", "@perplexity-ai/mcp-server"],
|
|
145
90
|
"env": {
|
|
146
|
-
"PERPLEXITY_API_KEY": "your_key_here"
|
|
147
|
-
"PERPLEXITY_TIMEOUT_MS": "600000"
|
|
91
|
+
"PERPLEXITY_API_KEY": "your_key_here"
|
|
148
92
|
}
|
|
149
93
|
}
|
|
150
94
|
}
|
|
151
95
|
}
|
|
152
96
|
```
|
|
153
97
|
|
|
154
|
-
###
|
|
155
|
-
|
|
156
|
-
For any MCP-compatible client, use:
|
|
98
|
+
### Codex
|
|
157
99
|
|
|
158
100
|
```bash
|
|
159
|
-
npx @perplexity-ai/mcp-server
|
|
101
|
+
codex mcp add perplexity --env PERPLEXITY_API_KEY="your_key_here" -- npx -y @perplexity-ai/mcp-server
|
|
160
102
|
```
|
|
161
103
|
|
|
104
|
+
### Other MCP Clients
|
|
105
|
+
|
|
106
|
+
Most clients can be manually configured to use the `mcpServers` wrapper in their configuration file (like Cursor). If your client doesn't work, check its documentation for the correct wrapper format.
|
|
107
|
+
|
|
162
108
|
### Proxy Setup (For Corporate Networks)
|
|
163
109
|
|
|
164
110
|
If you are running this server at work—especially behind a company firewall or proxy—you may need to tell the program how to send its internet traffic through your network's proxy. Follow these steps:
|
|
@@ -190,39 +136,34 @@ If you'd rather use the standard variables, we support `HTTPS_PROXY` and `HTTP_P
|
|
|
190
136
|
> The server checks proxy settings in this order: `PERPLEXITY_PROXY` → `HTTPS_PROXY` → `HTTP_PROXY`. If none are set, it connects directly to the internet.
|
|
191
137
|
> URLs must include `https://`. Typical ports are `8080`, `3128`, and `80`.
|
|
192
138
|
|
|
193
|
-
|
|
194
139
|
### HTTP Server Deployment
|
|
195
140
|
|
|
196
|
-
For cloud or shared deployments,
|
|
141
|
+
For cloud or shared deployments, run the server in HTTP mode.
|
|
197
142
|
|
|
198
143
|
#### Environment Variables
|
|
199
144
|
|
|
200
|
-
|
|
145
|
+
| Variable | Description | Default |
|
|
146
|
+
|----------|-------------|---------|
|
|
147
|
+
| `PERPLEXITY_API_KEY` | Your Perplexity API key | *Required* |
|
|
148
|
+
| `PORT` | HTTP server port | `8080` |
|
|
149
|
+
| `BIND_ADDRESS` | Network interface to bind to | `0.0.0.0` |
|
|
150
|
+
| `ALLOWED_ORIGINS` | CORS origins (comma-separated) | `*` |
|
|
201
151
|
|
|
202
|
-
|
|
203
|
-
- **`BIND_ADDRESS`** - Network interface to bind to (default: `127.0.0.1` for local, use `0.0.0.0` for hosted)
|
|
204
|
-
- **`ALLOWED_ORIGINS`** - Comma-separated list of allowed CORS origins (default: `http://localhost:3000,http://127.0.0.1:3000`, use `*` for public service)
|
|
205
|
-
- **`PERPLEXITY_API_KEY`** - Your Perplexity API key (required)
|
|
206
|
-
|
|
207
|
-
#### Using Docker
|
|
152
|
+
#### Docker
|
|
208
153
|
|
|
209
154
|
```bash
|
|
210
155
|
docker build -t perplexity-mcp-server .
|
|
211
156
|
docker run -p 8080:8080 -e PERPLEXITY_API_KEY=your_key_here perplexity-mcp-server
|
|
212
157
|
```
|
|
213
158
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
#### Using Node.js Directly
|
|
159
|
+
#### Node.js
|
|
217
160
|
|
|
218
161
|
```bash
|
|
219
|
-
|
|
220
|
-
npm run build
|
|
221
|
-
npm run start:http
|
|
162
|
+
export PERPLEXITY_API_KEY=your_key_here
|
|
163
|
+
npm install && npm run build && npm run start:http
|
|
222
164
|
```
|
|
223
165
|
|
|
224
|
-
|
|
225
|
-
|
|
166
|
+
The server will be accessible at `http://localhost:8080/mcp`
|
|
226
167
|
|
|
227
168
|
## Troubleshooting
|
|
228
169
|
|
|
@@ -231,6 +172,7 @@ Connect your MCP client to: `http://localhost:8080/mcp`
|
|
|
231
172
|
- **Tool Not Found**: Make sure the package is installed and the command path is correct
|
|
232
173
|
- **Timeout Errors**: For very long research queries, set `PERPLEXITY_TIMEOUT_MS` to a higher value
|
|
233
174
|
- **Proxy Issues**: Verify your `PERPLEXITY_PROXY` or `HTTPS_PROXY` setup and ensure `api.perplexity.ai` isn't blocked by your firewall.
|
|
175
|
+
- **EOF / Initialize Errors**: Some strict MCP clients fail because `npx` writes installation messages to stdout. Use `npx -yq` instead of `npx -y` to suppress this output.
|
|
234
176
|
|
|
235
177
|
For support, visit [community.perplexity.ai](https://community.perplexity.ai) or [file an issue](https://github.com/perplexityai/modelcontextprotocol/issues).
|
|
236
178
|
|
package/dist/http.js
CHANGED
|
@@ -4,7 +4,6 @@ import cors from "cors";
|
|
|
4
4
|
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
5
5
|
import { createPerplexityServer } from "./server.js";
|
|
6
6
|
import { logger } from "./logger.js";
|
|
7
|
-
// Check for required API key
|
|
8
7
|
const PERPLEXITY_API_KEY = process.env.PERPLEXITY_API_KEY;
|
|
9
8
|
if (!PERPLEXITY_API_KEY) {
|
|
10
9
|
logger.error("PERPLEXITY_API_KEY environment variable is required");
|
|
@@ -12,11 +11,8 @@ if (!PERPLEXITY_API_KEY) {
|
|
|
12
11
|
}
|
|
13
12
|
const app = express();
|
|
14
13
|
const PORT = parseInt(process.env.PORT || "8080", 10);
|
|
15
|
-
const BIND_ADDRESS = process.env.BIND_ADDRESS || "
|
|
16
|
-
const ALLOWED_ORIGINS = process.env.ALLOWED_ORIGINS?.split(",") || [
|
|
17
|
-
"http://localhost:3000",
|
|
18
|
-
"http://127.0.0.1:3000",
|
|
19
|
-
];
|
|
14
|
+
const BIND_ADDRESS = process.env.BIND_ADDRESS || "0.0.0.0";
|
|
15
|
+
const ALLOWED_ORIGINS = process.env.ALLOWED_ORIGINS?.split(",") || ["*"];
|
|
20
16
|
// CORS configuration for browser-based MCP clients
|
|
21
17
|
app.use(cors({
|
|
22
18
|
origin: (origin, callback) => {
|
|
@@ -37,10 +33,6 @@ app.use(cors({
|
|
|
37
33
|
}));
|
|
38
34
|
app.use(express.json());
|
|
39
35
|
const mcpServer = createPerplexityServer();
|
|
40
|
-
/**
|
|
41
|
-
* POST: client-to-server messages (requests, responses, notifications)
|
|
42
|
-
* GET: SSE stream for server-to-client messages (notifications, requests)
|
|
43
|
-
*/
|
|
44
36
|
app.all("/mcp", async (req, res) => {
|
|
45
37
|
try {
|
|
46
38
|
const transport = new StreamableHTTPServerTransport({
|
|
@@ -64,15 +56,9 @@ app.all("/mcp", async (req, res) => {
|
|
|
64
56
|
}
|
|
65
57
|
}
|
|
66
58
|
});
|
|
67
|
-
/**
|
|
68
|
-
* Health check endpoint
|
|
69
|
-
*/
|
|
70
59
|
app.get("/health", (req, res) => {
|
|
71
60
|
res.json({ status: "ok", service: "perplexity-mcp-server" });
|
|
72
61
|
});
|
|
73
|
-
/**
|
|
74
|
-
* Start the HTTP server
|
|
75
|
-
*/
|
|
76
62
|
app.listen(PORT, BIND_ADDRESS, () => {
|
|
77
63
|
logger.info(`Perplexity MCP Server listening on http://${BIND_ADDRESS}:${PORT}/mcp`);
|
|
78
64
|
logger.info(`Allowed origins: ${ALLOWED_ORIGINS.join(", ")}`);
|
package/dist/index.js
CHANGED
|
@@ -1,19 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
3
|
import { createPerplexityServer } from "./server.js";
|
|
4
|
-
// Check for required API key
|
|
5
4
|
const PERPLEXITY_API_KEY = process.env.PERPLEXITY_API_KEY;
|
|
6
5
|
if (!PERPLEXITY_API_KEY) {
|
|
7
6
|
console.error("Error: PERPLEXITY_API_KEY environment variable is required");
|
|
8
7
|
process.exit(1);
|
|
9
8
|
}
|
|
10
|
-
/**
|
|
11
|
-
* Initializes and runs the server using standard I/O for communication.
|
|
12
|
-
* Logs an error and exits if the server fails to start.
|
|
13
|
-
*/
|
|
14
9
|
async function main() {
|
|
15
10
|
try {
|
|
16
|
-
const server = createPerplexityServer();
|
|
11
|
+
const server = createPerplexityServer("local-mcp");
|
|
17
12
|
const transport = new StdioServerTransport();
|
|
18
13
|
await server.connect(transport);
|
|
19
14
|
}
|
|
@@ -22,7 +17,6 @@ async function main() {
|
|
|
22
17
|
process.exit(1);
|
|
23
18
|
}
|
|
24
19
|
}
|
|
25
|
-
// Start the server and catch any startup errors
|
|
26
20
|
main().catch((error) => {
|
|
27
21
|
console.error("Fatal error running server:", error);
|
|
28
22
|
process.exit(1);
|
package/dist/server.js
CHANGED
|
@@ -2,52 +2,26 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { fetch as undiciFetch, ProxyAgent } from "undici";
|
|
4
4
|
import { ChatCompletionResponseSchema, SearchResponseSchema } from "./validation.js";
|
|
5
|
-
// Retrieve the Perplexity API key from environment variables
|
|
6
5
|
const PERPLEXITY_API_KEY = process.env.PERPLEXITY_API_KEY;
|
|
7
|
-
/**
|
|
8
|
-
* Gets the proxy URL from environment variables.
|
|
9
|
-
* Checks PERPLEXITY_PROXY, HTTPS_PROXY, HTTP_PROXY in order.
|
|
10
|
-
*
|
|
11
|
-
* @returns {string | undefined} The proxy URL if configured, undefined otherwise
|
|
12
|
-
*/
|
|
13
6
|
export function getProxyUrl() {
|
|
14
7
|
return process.env.PERPLEXITY_PROXY ||
|
|
15
8
|
process.env.HTTPS_PROXY ||
|
|
16
9
|
process.env.HTTP_PROXY ||
|
|
17
10
|
undefined;
|
|
18
11
|
}
|
|
19
|
-
/**
|
|
20
|
-
* Creates a proxy-aware fetch function.
|
|
21
|
-
* Uses undici with ProxyAgent when a proxy is configured, otherwise uses native fetch.
|
|
22
|
-
*
|
|
23
|
-
* @param {string} url - The URL to fetch
|
|
24
|
-
* @param {RequestInit} options - Fetch options
|
|
25
|
-
* @returns {Promise<Response>} The fetch response
|
|
26
|
-
*/
|
|
27
12
|
export async function proxyAwareFetch(url, options = {}) {
|
|
28
13
|
const proxyUrl = getProxyUrl();
|
|
29
14
|
if (proxyUrl) {
|
|
30
|
-
// Use undici with ProxyAgent when proxy is configured
|
|
31
15
|
const proxyAgent = new ProxyAgent(proxyUrl);
|
|
32
16
|
const undiciOptions = {
|
|
33
17
|
...options,
|
|
34
18
|
dispatcher: proxyAgent,
|
|
35
19
|
};
|
|
36
20
|
const response = await undiciFetch(url, undiciOptions);
|
|
37
|
-
// Cast to native Response type for compatibility
|
|
38
21
|
return response;
|
|
39
22
|
}
|
|
40
|
-
// Use native fetch when no proxy is configured
|
|
41
23
|
return fetch(url, options);
|
|
42
24
|
}
|
|
43
|
-
/**
|
|
44
|
-
* Validates an array of message objects for chat completion tools.
|
|
45
|
-
* Ensures each message has a valid role and content field.
|
|
46
|
-
*
|
|
47
|
-
* @param {unknown} messages - The messages to validate
|
|
48
|
-
* @param {string} toolName - The name of the tool calling this validation (for error messages)
|
|
49
|
-
* @throws {Error} If messages is not an array or if any message is invalid
|
|
50
|
-
*/
|
|
51
25
|
export function validateMessages(messages, toolName) {
|
|
52
26
|
if (!Array.isArray(messages)) {
|
|
53
27
|
throw new Error(`Invalid arguments for ${toolName}: 'messages' must be an array`);
|
|
@@ -65,33 +39,15 @@ export function validateMessages(messages, toolName) {
|
|
|
65
39
|
}
|
|
66
40
|
}
|
|
67
41
|
}
|
|
68
|
-
/**
|
|
69
|
-
* Strips thinking tokens (content within <think>...</think> tags) from the response.
|
|
70
|
-
* This helps reduce context usage when the thinking process is not needed.
|
|
71
|
-
*
|
|
72
|
-
* @param {string} content - The content to process
|
|
73
|
-
* @returns {string} The content with thinking tokens removed
|
|
74
|
-
*/
|
|
75
42
|
export function stripThinkingTokens(content) {
|
|
76
43
|
return content.replace(/<think>[\s\S]*?<\/think>/g, '').trim();
|
|
77
44
|
}
|
|
78
|
-
|
|
79
|
-
* Performs a chat completion by sending a request to the Perplexity API.
|
|
80
|
-
* Appends citations to the returned message content if they exist.
|
|
81
|
-
*
|
|
82
|
-
* @param {Message[]} messages - An array of message objects.
|
|
83
|
-
* @param {string} model - The model to use for the completion.
|
|
84
|
-
* @param {boolean} stripThinking - If true, removes <think>...</think> tags from the response.
|
|
85
|
-
* @returns {Promise<string>} The chat completion result with appended citations.
|
|
86
|
-
* @throws Will throw an error if the API request fails.
|
|
87
|
-
*/
|
|
88
|
-
export async function performChatCompletion(messages, model = "sonar-pro", stripThinking = false) {
|
|
45
|
+
export async function performChatCompletion(messages, model = "sonar-pro", stripThinking = false, serviceOrigin) {
|
|
89
46
|
if (!PERPLEXITY_API_KEY) {
|
|
90
47
|
throw new Error("PERPLEXITY_API_KEY environment variable is required");
|
|
91
48
|
}
|
|
92
49
|
// Read timeout fresh each time to respect env var changes
|
|
93
50
|
const TIMEOUT_MS = parseInt(process.env.PERPLEXITY_TIMEOUT_MS || "300000", 10);
|
|
94
|
-
// Construct the API endpoint URL and request body
|
|
95
51
|
const url = new URL("https://api.perplexity.ai/chat/completions");
|
|
96
52
|
const body = {
|
|
97
53
|
model: model,
|
|
@@ -101,12 +57,16 @@ export async function performChatCompletion(messages, model = "sonar-pro", strip
|
|
|
101
57
|
const timeoutId = setTimeout(() => controller.abort(), TIMEOUT_MS);
|
|
102
58
|
let response;
|
|
103
59
|
try {
|
|
60
|
+
const headers = {
|
|
61
|
+
"Content-Type": "application/json",
|
|
62
|
+
"Authorization": `Bearer ${PERPLEXITY_API_KEY}`,
|
|
63
|
+
};
|
|
64
|
+
if (serviceOrigin) {
|
|
65
|
+
headers["X-Service"] = serviceOrigin;
|
|
66
|
+
}
|
|
104
67
|
response = await proxyAwareFetch(url.toString(), {
|
|
105
68
|
method: "POST",
|
|
106
|
-
headers
|
|
107
|
-
"Content-Type": "application/json",
|
|
108
|
-
"Authorization": `Bearer ${PERPLEXITY_API_KEY}`,
|
|
109
|
-
},
|
|
69
|
+
headers,
|
|
110
70
|
body: JSON.stringify(body),
|
|
111
71
|
signal: controller.signal,
|
|
112
72
|
});
|
|
@@ -119,7 +79,6 @@ export async function performChatCompletion(messages, model = "sonar-pro", strip
|
|
|
119
79
|
}
|
|
120
80
|
throw new Error(`Network error while calling Perplexity API: ${error}`);
|
|
121
81
|
}
|
|
122
|
-
// Check for non-successful HTTP status
|
|
123
82
|
if (!response.ok) {
|
|
124
83
|
let errorText;
|
|
125
84
|
try {
|
|
@@ -148,13 +107,10 @@ export async function performChatCompletion(messages, model = "sonar-pro", strip
|
|
|
148
107
|
throw new Error(`Failed to parse JSON response from Perplexity API: ${error}`);
|
|
149
108
|
}
|
|
150
109
|
const firstChoice = data.choices[0];
|
|
151
|
-
// Directly retrieve the main message content from the response
|
|
152
110
|
let messageContent = firstChoice.message.content;
|
|
153
|
-
// Strip thinking tokens if requested
|
|
154
111
|
if (stripThinking) {
|
|
155
112
|
messageContent = stripThinkingTokens(messageContent);
|
|
156
113
|
}
|
|
157
|
-
// If citations are provided, append them to the message content
|
|
158
114
|
if (data.citations && Array.isArray(data.citations) && data.citations.length > 0) {
|
|
159
115
|
messageContent += "\n\nCitations:\n";
|
|
160
116
|
data.citations.forEach((citation, index) => {
|
|
@@ -163,12 +119,6 @@ export async function performChatCompletion(messages, model = "sonar-pro", strip
|
|
|
163
119
|
}
|
|
164
120
|
return messageContent;
|
|
165
121
|
}
|
|
166
|
-
/**
|
|
167
|
-
* Formats search results from the Perplexity Search API into a readable string.
|
|
168
|
-
*
|
|
169
|
-
* @param {SearchResponse} data - The search response data from the API.
|
|
170
|
-
* @returns {string} Formatted search results.
|
|
171
|
-
*/
|
|
172
122
|
export function formatSearchResults(data) {
|
|
173
123
|
if (!data.results || !Array.isArray(data.results)) {
|
|
174
124
|
return "No search results found.";
|
|
@@ -187,17 +137,7 @@ export function formatSearchResults(data) {
|
|
|
187
137
|
});
|
|
188
138
|
return formattedResults;
|
|
189
139
|
}
|
|
190
|
-
|
|
191
|
-
* Performs a web search using the Perplexity Search API.
|
|
192
|
-
*
|
|
193
|
-
* @param {string} query - The search query string.
|
|
194
|
-
* @param {number} maxResults - Maximum number of results to return (1-20).
|
|
195
|
-
* @param {number} maxTokensPerPage - Maximum tokens to extract per webpage.
|
|
196
|
-
* @param {string} country - Optional ISO country code for regional results.
|
|
197
|
-
* @returns {Promise<string>} The formatted search results.
|
|
198
|
-
* @throws Will throw an error if the API request fails.
|
|
199
|
-
*/
|
|
200
|
-
export async function performSearch(query, maxResults = 10, maxTokensPerPage = 1024, country) {
|
|
140
|
+
export async function performSearch(query, maxResults = 10, maxTokensPerPage = 1024, country, serviceOrigin) {
|
|
201
141
|
if (!PERPLEXITY_API_KEY) {
|
|
202
142
|
throw new Error("PERPLEXITY_API_KEY environment variable is required");
|
|
203
143
|
}
|
|
@@ -214,12 +154,16 @@ export async function performSearch(query, maxResults = 10, maxTokensPerPage = 1
|
|
|
214
154
|
const timeoutId = setTimeout(() => controller.abort(), TIMEOUT_MS);
|
|
215
155
|
let response;
|
|
216
156
|
try {
|
|
157
|
+
const headers = {
|
|
158
|
+
"Content-Type": "application/json",
|
|
159
|
+
"Authorization": `Bearer ${PERPLEXITY_API_KEY}`,
|
|
160
|
+
};
|
|
161
|
+
if (serviceOrigin) {
|
|
162
|
+
headers["X-Service"] = serviceOrigin;
|
|
163
|
+
}
|
|
217
164
|
response = await proxyAwareFetch(url.toString(), {
|
|
218
165
|
method: "POST",
|
|
219
|
-
headers
|
|
220
|
-
"Content-Type": "application/json",
|
|
221
|
-
"Authorization": `Bearer ${PERPLEXITY_API_KEY}`,
|
|
222
|
-
},
|
|
166
|
+
headers,
|
|
223
167
|
body: JSON.stringify(body),
|
|
224
168
|
signal: controller.signal,
|
|
225
169
|
});
|
|
@@ -232,7 +176,6 @@ export async function performSearch(query, maxResults = 10, maxTokensPerPage = 1
|
|
|
232
176
|
}
|
|
233
177
|
throw new Error(`Network error while calling Perplexity Search API: ${error}`);
|
|
234
178
|
}
|
|
235
|
-
// Check for non-successful HTTP status
|
|
236
179
|
if (!response.ok) {
|
|
237
180
|
let errorText;
|
|
238
181
|
try {
|
|
@@ -253,18 +196,11 @@ export async function performSearch(query, maxResults = 10, maxTokensPerPage = 1
|
|
|
253
196
|
}
|
|
254
197
|
return formatSearchResults(data);
|
|
255
198
|
}
|
|
256
|
-
|
|
257
|
-
* Creates and configures the Perplexity MCP server with all tools.
|
|
258
|
-
* This factory function is transport-agnostic and returns a configured server instance.
|
|
259
|
-
*
|
|
260
|
-
* @returns The configured MCP server instance
|
|
261
|
-
*/
|
|
262
|
-
export function createPerplexityServer() {
|
|
199
|
+
export function createPerplexityServer(serviceOrigin) {
|
|
263
200
|
const server = new McpServer({
|
|
264
201
|
name: "io.github.perplexityai/mcp-server",
|
|
265
|
-
version: "0.
|
|
202
|
+
version: "0.6.0",
|
|
266
203
|
});
|
|
267
|
-
// Register perplexity_ask tool
|
|
268
204
|
server.registerTool("perplexity_ask", {
|
|
269
205
|
title: "Ask Perplexity",
|
|
270
206
|
description: "Engages in a conversation using the Sonar API. " +
|
|
@@ -285,13 +221,12 @@ export function createPerplexityServer() {
|
|
|
285
221
|
},
|
|
286
222
|
}, async ({ messages }) => {
|
|
287
223
|
validateMessages(messages, "perplexity_ask");
|
|
288
|
-
const result = await performChatCompletion(messages, "sonar-pro");
|
|
224
|
+
const result = await performChatCompletion(messages, "sonar-pro", false, serviceOrigin);
|
|
289
225
|
return {
|
|
290
226
|
content: [{ type: "text", text: result }],
|
|
291
227
|
structuredContent: { response: result },
|
|
292
228
|
};
|
|
293
229
|
});
|
|
294
|
-
// Register perplexity_research tool
|
|
295
230
|
server.registerTool("perplexity_research", {
|
|
296
231
|
title: "Deep Research",
|
|
297
232
|
description: "Performs deep research using the Perplexity API. " +
|
|
@@ -315,13 +250,12 @@ export function createPerplexityServer() {
|
|
|
315
250
|
}, async ({ messages, strip_thinking }) => {
|
|
316
251
|
validateMessages(messages, "perplexity_research");
|
|
317
252
|
const stripThinking = typeof strip_thinking === "boolean" ? strip_thinking : false;
|
|
318
|
-
const result = await performChatCompletion(messages, "sonar-deep-research", stripThinking);
|
|
253
|
+
const result = await performChatCompletion(messages, "sonar-deep-research", stripThinking, serviceOrigin);
|
|
319
254
|
return {
|
|
320
255
|
content: [{ type: "text", text: result }],
|
|
321
256
|
structuredContent: { response: result },
|
|
322
257
|
};
|
|
323
258
|
});
|
|
324
|
-
// Register perplexity_reason tool
|
|
325
259
|
server.registerTool("perplexity_reason", {
|
|
326
260
|
title: "Advanced Reasoning",
|
|
327
261
|
description: "Performs reasoning tasks using the Perplexity API. " +
|
|
@@ -345,13 +279,12 @@ export function createPerplexityServer() {
|
|
|
345
279
|
}, async ({ messages, strip_thinking }) => {
|
|
346
280
|
validateMessages(messages, "perplexity_reason");
|
|
347
281
|
const stripThinking = typeof strip_thinking === "boolean" ? strip_thinking : false;
|
|
348
|
-
const result = await performChatCompletion(messages, "sonar-reasoning-pro", stripThinking);
|
|
282
|
+
const result = await performChatCompletion(messages, "sonar-reasoning-pro", stripThinking, serviceOrigin);
|
|
349
283
|
return {
|
|
350
284
|
content: [{ type: "text", text: result }],
|
|
351
285
|
structuredContent: { response: result },
|
|
352
286
|
};
|
|
353
287
|
});
|
|
354
|
-
// Register perplexity_search tool
|
|
355
288
|
server.registerTool("perplexity_search", {
|
|
356
289
|
title: "Search the Web",
|
|
357
290
|
description: "Performs web search using the Perplexity Search API. " +
|
|
@@ -377,7 +310,7 @@ export function createPerplexityServer() {
|
|
|
377
310
|
const maxResults = typeof max_results === "number" ? max_results : 10;
|
|
378
311
|
const maxTokensPerPage = typeof max_tokens_per_page === "number" ? max_tokens_per_page : 1024;
|
|
379
312
|
const countryCode = typeof country === "string" ? country : undefined;
|
|
380
|
-
const result = await performSearch(query, maxResults, maxTokensPerPage, countryCode);
|
|
313
|
+
const result = await performSearch(query, maxResults, maxTokensPerPage, countryCode, serviceOrigin);
|
|
381
314
|
return {
|
|
382
315
|
content: [{ type: "text", text: result }],
|
|
383
316
|
structuredContent: { results: result },
|
package/dist/types.js
CHANGED
package/package.json
CHANGED