@perplexity-ai/mcp-server 0.3.1 → 0.4.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 +49 -0
- package/README.md +63 -0
- package/dist/index.js +67 -5
- package/dist/index.test.js +79 -0
- package/package.json +5 -3
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "perplexity-mcp-server",
|
|
3
|
+
"owner": {
|
|
4
|
+
"name": "Perplexity AI",
|
|
5
|
+
"email": "api@perplexity.ai"
|
|
6
|
+
},
|
|
7
|
+
"metadata": {
|
|
8
|
+
"description": "Official Perplexity AI plugin providing real-time web search, reasoning, and research capabilities",
|
|
9
|
+
"version": "0.4.0"
|
|
10
|
+
},
|
|
11
|
+
"plugins": [
|
|
12
|
+
{
|
|
13
|
+
"name": "perplexity",
|
|
14
|
+
"source": "./",
|
|
15
|
+
"description": "Real-time web search, reasoning, and research through Perplexity's API",
|
|
16
|
+
"version": "0.4.0",
|
|
17
|
+
"author": {
|
|
18
|
+
"name": "Perplexity AI",
|
|
19
|
+
"email": "api@perplexity.ai"
|
|
20
|
+
},
|
|
21
|
+
"homepage": "https://docs.perplexity.ai/guides/mcp-server",
|
|
22
|
+
"repository": "https://github.com/perplexityai/modelcontextprotocol",
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"keywords": [
|
|
25
|
+
"mcp",
|
|
26
|
+
"search",
|
|
27
|
+
"web-search",
|
|
28
|
+
"perplexity",
|
|
29
|
+
"research",
|
|
30
|
+
"reasoning",
|
|
31
|
+
"ai"
|
|
32
|
+
],
|
|
33
|
+
"category": "productivity",
|
|
34
|
+
"strict": false,
|
|
35
|
+
"mcpServers": {
|
|
36
|
+
"perplexity": {
|
|
37
|
+
"type": "stdio",
|
|
38
|
+
"command": "npx",
|
|
39
|
+
"args": ["-y", "@perplexity-ai/mcp-server"],
|
|
40
|
+
"env": {
|
|
41
|
+
"PERPLEXITY_API_KEY": "${PERPLEXITY_API_KEY}",
|
|
42
|
+
"PERPLEXITY_TIMEOUT_MS": "${PERPLEXITY_TIMEOUT_MS:-600000}"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
]
|
|
48
|
+
}
|
|
49
|
+
|
package/README.md
CHANGED
|
@@ -18,6 +18,11 @@ Deep, comprehensive research using the `sonar-deep-research` model. Ideal for th
|
|
|
18
18
|
### **perplexity_reason**
|
|
19
19
|
Advanced reasoning and problem-solving using the `sonar-reasoning-pro` model. Perfect for complex analytical tasks.
|
|
20
20
|
|
|
21
|
+
> [!TIP]
|
|
22
|
+
> Available as an optional parameter for **perplexity_reason** and **perplexity_research**: `strip_thinking`
|
|
23
|
+
>
|
|
24
|
+
> Set to `true` to remove `<think>...</think>` tags from the response, saving context tokens. Default: `false`
|
|
25
|
+
|
|
21
26
|
## Configuration
|
|
22
27
|
|
|
23
28
|
### Get Your API Key
|
|
@@ -27,6 +32,25 @@ Advanced reasoning and problem-solving using the `sonar-reasoning-pro` model. Pe
|
|
|
27
32
|
|
|
28
33
|
### Claude Code
|
|
29
34
|
|
|
35
|
+
#### Option 1: Install via Plugin (Recommended)
|
|
36
|
+
|
|
37
|
+
The easiest way to get started with Perplexity in Claude Code:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
# Add the Perplexity marketplace
|
|
41
|
+
/plugin marketplace add perplexityai/modelcontextprotocol
|
|
42
|
+
|
|
43
|
+
# Install the plugin
|
|
44
|
+
/plugin install perplexity
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Then set your API key:
|
|
48
|
+
```bash
|
|
49
|
+
export PERPLEXITY_API_KEY="your_key_here"
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
#### Option 2: Manual Configuration
|
|
53
|
+
|
|
30
54
|
Run in your terminal:
|
|
31
55
|
|
|
32
56
|
```bash
|
|
@@ -106,12 +130,51 @@ For any MCP-compatible client, use:
|
|
|
106
130
|
npx @perplexity-ai/mcp-server
|
|
107
131
|
```
|
|
108
132
|
|
|
133
|
+
### Proxy Setup (For Corporate Networks)
|
|
134
|
+
|
|
135
|
+
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:
|
|
136
|
+
|
|
137
|
+
**1. Get your proxy details**
|
|
138
|
+
|
|
139
|
+
- Ask your IT department for your HTTP(S) proxy address and port.
|
|
140
|
+
- You may also need a username and password.
|
|
141
|
+
|
|
142
|
+
**2. Set the proxy environment variable**
|
|
143
|
+
|
|
144
|
+
The easiest and most reliable way for Perplexity MCP is to use `PERPLEXITY_PROXY`. For example:
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
export PERPLEXITY_PROXY=http://your-proxy-host:8080
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
- If your proxy needs a username and password, use:
|
|
151
|
+
```bash
|
|
152
|
+
export PERPLEXITY_PROXY=http://username:password@your-proxy-host:8080
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
**3. Alternate: Standard environment variables**
|
|
156
|
+
|
|
157
|
+
If you'd rather use the standard variables, we support `HTTPS_PROXY` and `HTTP_PROXY`.
|
|
158
|
+
|
|
159
|
+
> [!NOTE]
|
|
160
|
+
>The server checks proxy settings in this order: `PERPLEXITY_PROXY` → `HTTPS_PROXY` → `HTTP_PROXY`. If none are set, it connects directly to the internet.
|
|
161
|
+
|
|
109
162
|
## Troubleshooting
|
|
110
163
|
|
|
111
164
|
- **API Key Issues**: Ensure `PERPLEXITY_API_KEY` is set correctly
|
|
112
165
|
- **Connection Errors**: Check your internet connection and API key validity
|
|
113
166
|
- **Tool Not Found**: Make sure the package is installed and the command path is correct
|
|
114
167
|
- **Timeout Errors**: For very long research queries, set `PERPLEXITY_TIMEOUT_MS` to a higher value
|
|
168
|
+
- **Proxy Issues**: If you're behind a corporate firewall and experience connection errors, you likely need to set up a proxy:
|
|
169
|
+
- Obtain your proxy server address and port from your IT department.
|
|
170
|
+
- Set the environment variable before running the server, e.g.:
|
|
171
|
+
- `export PERPLEXITY_PROXY=http://proxy-address:port`
|
|
172
|
+
- If authentication is needed: `export PERPLEXITY_PROXY=http://username:password@proxy-address:port`
|
|
173
|
+
- Typical proxy ports include 8080, 3128, or 80.
|
|
174
|
+
- The format for authenticated proxies is:
|
|
175
|
+
`http://username:password@proxy-host:port`
|
|
176
|
+
- Double-check the address, port, and credentials if connections fail or time out.
|
|
177
|
+
- If you continue to have issues, your firewall may be blocking traffic; ask IT if traffic for `api.perplexity.ai` is being restricted.
|
|
115
178
|
|
|
116
179
|
For support, visit [community.perplexity.ai](https://community.perplexity.ai) or [file an issue](https://github.com/perplexityai/modelcontextprotocol/issues).
|
|
117
180
|
|
package/dist/index.js
CHANGED
|
@@ -11,6 +11,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
11
11
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
12
12
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
13
13
|
import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
14
|
+
import { fetch as undiciFetch, ProxyAgent } from "undici";
|
|
14
15
|
/**
|
|
15
16
|
* Definition of the Perplexity Ask Tool.
|
|
16
17
|
* This tool accepts an array of messages and returns a chat completion response
|
|
@@ -76,6 +77,10 @@ const PERPLEXITY_RESEARCH_TOOL = {
|
|
|
76
77
|
},
|
|
77
78
|
description: "Array of conversation messages",
|
|
78
79
|
},
|
|
80
|
+
strip_thinking: {
|
|
81
|
+
type: "boolean",
|
|
82
|
+
description: "If true, removes <think>...</think> tags and their content from the response to save context tokens. Default is false.",
|
|
83
|
+
},
|
|
79
84
|
},
|
|
80
85
|
required: ["messages"],
|
|
81
86
|
},
|
|
@@ -110,6 +115,10 @@ const PERPLEXITY_REASON_TOOL = {
|
|
|
110
115
|
},
|
|
111
116
|
description: "Array of conversation messages",
|
|
112
117
|
},
|
|
118
|
+
strip_thinking: {
|
|
119
|
+
type: "boolean",
|
|
120
|
+
description: "If true, removes <think>...</think> tags and their content from the response to save context tokens. Default is false.",
|
|
121
|
+
},
|
|
113
122
|
},
|
|
114
123
|
required: ["messages"],
|
|
115
124
|
},
|
|
@@ -155,6 +164,42 @@ if (!PERPLEXITY_API_KEY) {
|
|
|
155
164
|
console.error("Error: PERPLEXITY_API_KEY environment variable is required");
|
|
156
165
|
process.exit(1);
|
|
157
166
|
}
|
|
167
|
+
/**
|
|
168
|
+
* Gets the proxy URL from environment variables.
|
|
169
|
+
* Checks PERPLEXITY_PROXY, HTTPS_PROXY, HTTP_PROXY in order.
|
|
170
|
+
*
|
|
171
|
+
* @returns {string | undefined} The proxy URL if configured, undefined otherwise
|
|
172
|
+
*/
|
|
173
|
+
function getProxyUrl() {
|
|
174
|
+
return process.env.PERPLEXITY_PROXY ||
|
|
175
|
+
process.env.HTTPS_PROXY ||
|
|
176
|
+
process.env.HTTP_PROXY ||
|
|
177
|
+
undefined;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Creates a proxy-aware fetch function.
|
|
181
|
+
* Uses undici with ProxyAgent when a proxy is configured, otherwise uses native fetch.
|
|
182
|
+
*
|
|
183
|
+
* @param {string} url - The URL to fetch
|
|
184
|
+
* @param {RequestInit} options - Fetch options
|
|
185
|
+
* @returns {Promise<Response>} The fetch response
|
|
186
|
+
*/
|
|
187
|
+
function proxyAwareFetch(url_1) {
|
|
188
|
+
return __awaiter(this, arguments, void 0, function* (url, options = {}) {
|
|
189
|
+
const proxyUrl = getProxyUrl();
|
|
190
|
+
if (proxyUrl) {
|
|
191
|
+
// Use undici with ProxyAgent when proxy is configured
|
|
192
|
+
const proxyAgent = new ProxyAgent(proxyUrl);
|
|
193
|
+
const response = yield undiciFetch(url, Object.assign(Object.assign({}, options), { dispatcher: proxyAgent }));
|
|
194
|
+
// Cast to native Response type for compatibility
|
|
195
|
+
return response;
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
// Use native fetch when no proxy is configured
|
|
199
|
+
return fetch(url, options);
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
}
|
|
158
203
|
/**
|
|
159
204
|
* Validates an array of message objects for chat completion tools.
|
|
160
205
|
* Ensures each message has a valid role and content field.
|
|
@@ -180,17 +225,28 @@ function validateMessages(messages, toolName) {
|
|
|
180
225
|
}
|
|
181
226
|
}
|
|
182
227
|
}
|
|
228
|
+
/**
|
|
229
|
+
* Strips thinking tokens (content within <think>...</think> tags) from the response.
|
|
230
|
+
* This helps reduce context usage when the thinking process is not needed.
|
|
231
|
+
*
|
|
232
|
+
* @param {string} content - The content to process
|
|
233
|
+
* @returns {string} The content with thinking tokens removed
|
|
234
|
+
*/
|
|
235
|
+
function stripThinkingTokens(content) {
|
|
236
|
+
return content.replace(/<think>[\s\S]*?<\/think>/g, '').trim();
|
|
237
|
+
}
|
|
183
238
|
/**
|
|
184
239
|
* Performs a chat completion by sending a request to the Perplexity API.
|
|
185
240
|
* Appends citations to the returned message content if they exist.
|
|
186
241
|
*
|
|
187
242
|
* @param {Array<{ role: string; content: string }>} messages - An array of message objects.
|
|
188
243
|
* @param {string} model - The model to use for the completion.
|
|
244
|
+
* @param {boolean} stripThinking - If true, removes <think>...</think> tags from the response.
|
|
189
245
|
* @returns {Promise<string>} The chat completion result with appended citations.
|
|
190
246
|
* @throws Will throw an error if the API request fails.
|
|
191
247
|
*/
|
|
192
248
|
export function performChatCompletion(messages_1) {
|
|
193
|
-
return __awaiter(this, arguments, void 0, function* (messages, model = "sonar-pro") {
|
|
249
|
+
return __awaiter(this, arguments, void 0, function* (messages, model = "sonar-pro", stripThinking = false) {
|
|
194
250
|
// Read timeout fresh each time to respect env var changes
|
|
195
251
|
const TIMEOUT_MS = parseInt(process.env.PERPLEXITY_TIMEOUT_MS || "300000", 10);
|
|
196
252
|
// Construct the API endpoint URL and request body
|
|
@@ -206,7 +262,7 @@ export function performChatCompletion(messages_1) {
|
|
|
206
262
|
const timeoutId = setTimeout(() => controller.abort(), TIMEOUT_MS);
|
|
207
263
|
let response;
|
|
208
264
|
try {
|
|
209
|
-
response = yield
|
|
265
|
+
response = yield proxyAwareFetch(url.toString(), {
|
|
210
266
|
method: "POST",
|
|
211
267
|
headers: {
|
|
212
268
|
"Content-Type": "application/json",
|
|
@@ -253,6 +309,10 @@ export function performChatCompletion(messages_1) {
|
|
|
253
309
|
}
|
|
254
310
|
// Directly retrieve the main message content from the response
|
|
255
311
|
let messageContent = firstChoice.message.content;
|
|
312
|
+
// Strip thinking tokens if requested
|
|
313
|
+
if (stripThinking) {
|
|
314
|
+
messageContent = stripThinkingTokens(messageContent);
|
|
315
|
+
}
|
|
256
316
|
// If citations are provided, append them to the message content
|
|
257
317
|
if (data.citations && Array.isArray(data.citations) && data.citations.length > 0) {
|
|
258
318
|
messageContent += "\n\nCitations:\n";
|
|
@@ -314,7 +374,7 @@ export function performSearch(query_1) {
|
|
|
314
374
|
const timeoutId = setTimeout(() => controller.abort(), TIMEOUT_MS);
|
|
315
375
|
let response;
|
|
316
376
|
try {
|
|
317
|
-
response = yield
|
|
377
|
+
response = yield proxyAwareFetch(url.toString(), {
|
|
318
378
|
method: "POST",
|
|
319
379
|
headers: {
|
|
320
380
|
"Content-Type": "application/json",
|
|
@@ -397,7 +457,8 @@ server.setRequestHandler(CallToolRequestSchema, (request) => __awaiter(void 0, v
|
|
|
397
457
|
case "perplexity_research": {
|
|
398
458
|
validateMessages(args.messages, "perplexity_research");
|
|
399
459
|
const messages = args.messages;
|
|
400
|
-
const
|
|
460
|
+
const stripThinking = typeof args.strip_thinking === "boolean" ? args.strip_thinking : false;
|
|
461
|
+
const result = yield performChatCompletion(messages, "sonar-deep-research", stripThinking);
|
|
401
462
|
return {
|
|
402
463
|
content: [{ type: "text", text: result }],
|
|
403
464
|
isError: false,
|
|
@@ -406,7 +467,8 @@ server.setRequestHandler(CallToolRequestSchema, (request) => __awaiter(void 0, v
|
|
|
406
467
|
case "perplexity_reason": {
|
|
407
468
|
validateMessages(args.messages, "perplexity_reason");
|
|
408
469
|
const messages = args.messages;
|
|
409
|
-
const
|
|
470
|
+
const stripThinking = typeof args.strip_thinking === "boolean" ? args.strip_thinking : false;
|
|
471
|
+
const result = yield performChatCompletion(messages, "sonar-reasoning-pro", stripThinking);
|
|
410
472
|
return {
|
|
411
473
|
content: [{ type: "text", text: result }],
|
|
412
474
|
isError: false,
|
package/dist/index.test.js
CHANGED
|
@@ -484,4 +484,83 @@ describe("Perplexity MCP Server", () => {
|
|
|
484
484
|
expect(formatted).not.toContain("12345");
|
|
485
485
|
});
|
|
486
486
|
});
|
|
487
|
+
describe("strip_thinking parameter", () => {
|
|
488
|
+
it("should strip thinking tokens when true and keep them when false", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
489
|
+
const mockResponse = {
|
|
490
|
+
choices: [
|
|
491
|
+
{
|
|
492
|
+
message: {
|
|
493
|
+
content: "<think>This is my reasoning process</think>\n\nThe answer is 4.",
|
|
494
|
+
},
|
|
495
|
+
},
|
|
496
|
+
],
|
|
497
|
+
};
|
|
498
|
+
// Test with stripThinking = true
|
|
499
|
+
global.fetch = vi.fn().mockResolvedValue({
|
|
500
|
+
ok: true,
|
|
501
|
+
json: () => __awaiter(void 0, void 0, void 0, function* () { return mockResponse; }),
|
|
502
|
+
});
|
|
503
|
+
const messages = [{ role: "user", content: "What is 2+2?" }];
|
|
504
|
+
const resultStripped = yield performChatCompletion(messages, "sonar-reasoning-pro", true);
|
|
505
|
+
expect(resultStripped).not.toContain("<think>");
|
|
506
|
+
expect(resultStripped).not.toContain("</think>");
|
|
507
|
+
expect(resultStripped).not.toContain("This is my reasoning process");
|
|
508
|
+
expect(resultStripped).toContain("The answer is 4.");
|
|
509
|
+
// Test with stripThinking = false
|
|
510
|
+
global.fetch = vi.fn().mockResolvedValue({
|
|
511
|
+
ok: true,
|
|
512
|
+
json: () => __awaiter(void 0, void 0, void 0, function* () { return mockResponse; }),
|
|
513
|
+
});
|
|
514
|
+
const resultKept = yield performChatCompletion(messages, "sonar-reasoning-pro", false);
|
|
515
|
+
expect(resultKept).toContain("<think>This is my reasoning process</think>");
|
|
516
|
+
expect(resultKept).toContain("The answer is 4.");
|
|
517
|
+
}));
|
|
518
|
+
});
|
|
519
|
+
describe("Proxy Support", () => {
|
|
520
|
+
const originalEnv = process.env;
|
|
521
|
+
beforeEach(() => {
|
|
522
|
+
// Reset environment variables
|
|
523
|
+
process.env = Object.assign({}, originalEnv);
|
|
524
|
+
delete process.env.PERPLEXITY_PROXY;
|
|
525
|
+
delete process.env.HTTPS_PROXY;
|
|
526
|
+
delete process.env.HTTP_PROXY;
|
|
527
|
+
});
|
|
528
|
+
afterEach(() => {
|
|
529
|
+
process.env = originalEnv;
|
|
530
|
+
});
|
|
531
|
+
it("should use native fetch when no proxy is configured", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
532
|
+
const mockResponse = {
|
|
533
|
+
choices: [{ message: { content: "Test response" } }],
|
|
534
|
+
};
|
|
535
|
+
global.fetch = vi.fn().mockResolvedValue({
|
|
536
|
+
ok: true,
|
|
537
|
+
json: () => __awaiter(void 0, void 0, void 0, function* () { return mockResponse; }),
|
|
538
|
+
});
|
|
539
|
+
const messages = [{ role: "user", content: "test" }];
|
|
540
|
+
yield performChatCompletion(messages);
|
|
541
|
+
// Verify native fetch was called (not undici)
|
|
542
|
+
expect(global.fetch).toHaveBeenCalled();
|
|
543
|
+
}));
|
|
544
|
+
it("should read PERPLEXITY_PROXY environment variable", () => {
|
|
545
|
+
process.env.PERPLEXITY_PROXY = "http://proxy.example.com:8080";
|
|
546
|
+
expect(process.env.PERPLEXITY_PROXY).toBe("http://proxy.example.com:8080");
|
|
547
|
+
});
|
|
548
|
+
it("should prioritize PERPLEXITY_PROXY over HTTPS_PROXY", () => {
|
|
549
|
+
process.env.PERPLEXITY_PROXY = "http://perplexity-proxy.example.com:8080";
|
|
550
|
+
process.env.HTTPS_PROXY = "http://https-proxy.example.com:8080";
|
|
551
|
+
// PERPLEXITY_PROXY should take precedence
|
|
552
|
+
expect(process.env.PERPLEXITY_PROXY).toBe("http://perplexity-proxy.example.com:8080");
|
|
553
|
+
});
|
|
554
|
+
it("should fall back to HTTPS_PROXY when PERPLEXITY_PROXY is not set", () => {
|
|
555
|
+
delete process.env.PERPLEXITY_PROXY;
|
|
556
|
+
process.env.HTTPS_PROXY = "http://https-proxy.example.com:8080";
|
|
557
|
+
expect(process.env.HTTPS_PROXY).toBe("http://https-proxy.example.com:8080");
|
|
558
|
+
});
|
|
559
|
+
it("should fall back to HTTP_PROXY when others are not set", () => {
|
|
560
|
+
delete process.env.PERPLEXITY_PROXY;
|
|
561
|
+
delete process.env.HTTPS_PROXY;
|
|
562
|
+
process.env.HTTP_PROXY = "http://http-proxy.example.com:8080";
|
|
563
|
+
expect(process.env.HTTP_PROXY).toBe("http://http-proxy.example.com:8080");
|
|
564
|
+
});
|
|
565
|
+
});
|
|
487
566
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@perplexity-ai/mcp-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"mcpName": "io.github.perplexityai/mcp-server",
|
|
5
5
|
"description": "Real-time web search, reasoning, and research through Perplexity's API",
|
|
6
6
|
"keywords": [
|
|
@@ -29,7 +29,8 @@
|
|
|
29
29
|
},
|
|
30
30
|
"files": [
|
|
31
31
|
"dist",
|
|
32
|
-
"README.md"
|
|
32
|
+
"README.md",
|
|
33
|
+
".claude-plugin"
|
|
33
34
|
],
|
|
34
35
|
"scripts": {
|
|
35
36
|
"build": "tsc && shx chmod +x dist/*.js",
|
|
@@ -41,7 +42,8 @@
|
|
|
41
42
|
},
|
|
42
43
|
"dependencies": {
|
|
43
44
|
"@modelcontextprotocol/sdk": "^1.21.1",
|
|
44
|
-
"dotenv": "^16.6.1"
|
|
45
|
+
"dotenv": "^16.6.1",
|
|
46
|
+
"undici": "^6.20.0"
|
|
45
47
|
},
|
|
46
48
|
"devDependencies": {
|
|
47
49
|
"@types/node": "^20",
|