Skip to content

Commit c0ba8d7

Browse files
authored
Merge pull request #66 from perplexityai/kesku/proxy
2 parents c82fcf0 + a93b354 commit c0ba8d7

File tree

5 files changed

+155
-4
lines changed

5 files changed

+155
-4
lines changed

README.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,12 +111,51 @@ For any MCP-compatible client, use:
111111
npx @perplexity-ai/mcp-server
112112
```
113113

114+
### Proxy Setup (For Corporate Networks)
115+
116+
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:
117+
118+
**1. Get your proxy details**
119+
120+
- Ask your IT department for your HTTP(S) proxy address and port.
121+
- You may also need a username and password.
122+
123+
**2. Set the proxy environment variable**
124+
125+
The easiest and most reliable way for Perplexity MCP is to use `PERPLEXITY_PROXY`. For example:
126+
127+
```bash
128+
export PERPLEXITY_PROXY=http://your-proxy-host:8080
129+
```
130+
131+
- If your proxy needs a username and password, use:
132+
```bash
133+
export PERPLEXITY_PROXY=http://username:password@your-proxy-host:8080
134+
```
135+
136+
**3. Alternate: Standard environment variables**
137+
138+
If you'd rather use the standard variables, we support `HTTPS_PROXY` and `HTTP_PROXY`.
139+
140+
> [!NOTE]
141+
>The server checks proxy settings in this order: `PERPLEXITY_PROXY``HTTPS_PROXY``HTTP_PROXY`. If none are set, it connects directly to the internet.
142+
114143
## Troubleshooting
115144

116145
- **API Key Issues**: Ensure `PERPLEXITY_API_KEY` is set correctly
117146
- **Connection Errors**: Check your internet connection and API key validity
118147
- **Tool Not Found**: Make sure the package is installed and the command path is correct
119148
- **Timeout Errors**: For very long research queries, set `PERPLEXITY_TIMEOUT_MS` to a higher value
149+
- **Proxy Issues**: If you're behind a corporate firewall and experience connection errors, you likely need to set up a proxy:
150+
- Obtain your proxy server address and port from your IT department.
151+
- Set the environment variable before running the server, e.g.:
152+
- `export PERPLEXITY_PROXY=http://proxy-address:port`
153+
- If authentication is needed: `export PERPLEXITY_PROXY=http://username:password@proxy-address:port`
154+
- Typical proxy ports include 8080, 3128, or 80.
155+
- The format for authenticated proxies is:
156+
`http://username:password@proxy-host:port`
157+
- Double-check the address, port, and credentials if connections fail or time out.
158+
- If you continue to have issues, your firewall may be blocking traffic; ask IT if traffic for `api.perplexity.ai` is being restricted.
120159

121160
For support, visit [community.perplexity.ai](https://community.perplexity.ai) or [file an issue](https://github.com/perplexityai/modelcontextprotocol/issues).
122161

index.test.ts

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -665,4 +665,65 @@ describe("Perplexity MCP Server", () => {
665665
expect(resultKept).toContain("The answer is 4.");
666666
});
667667
});
668+
669+
describe("Proxy Support", () => {
670+
const originalEnv = process.env;
671+
672+
beforeEach(() => {
673+
// Reset environment variables
674+
process.env = { ...originalEnv };
675+
delete process.env.PERPLEXITY_PROXY;
676+
delete process.env.HTTPS_PROXY;
677+
delete process.env.HTTP_PROXY;
678+
});
679+
680+
afterEach(() => {
681+
process.env = originalEnv;
682+
});
683+
684+
it("should use native fetch when no proxy is configured", async () => {
685+
const mockResponse = {
686+
choices: [{ message: { content: "Test response" } }],
687+
};
688+
689+
global.fetch = vi.fn().mockResolvedValue({
690+
ok: true,
691+
json: async () => mockResponse,
692+
} as Response);
693+
694+
const messages = [{ role: "user", content: "test" }];
695+
await performChatCompletion(messages);
696+
697+
// Verify native fetch was called (not undici)
698+
expect(global.fetch).toHaveBeenCalled();
699+
});
700+
701+
it("should read PERPLEXITY_PROXY environment variable", () => {
702+
process.env.PERPLEXITY_PROXY = "http://proxy.example.com:8080";
703+
expect(process.env.PERPLEXITY_PROXY).toBe("http://proxy.example.com:8080");
704+
});
705+
706+
it("should prioritize PERPLEXITY_PROXY over HTTPS_PROXY", () => {
707+
process.env.PERPLEXITY_PROXY = "http://perplexity-proxy.example.com:8080";
708+
process.env.HTTPS_PROXY = "http://https-proxy.example.com:8080";
709+
710+
// PERPLEXITY_PROXY should take precedence
711+
expect(process.env.PERPLEXITY_PROXY).toBe("http://perplexity-proxy.example.com:8080");
712+
});
713+
714+
it("should fall back to HTTPS_PROXY when PERPLEXITY_PROXY is not set", () => {
715+
delete process.env.PERPLEXITY_PROXY;
716+
process.env.HTTPS_PROXY = "http://https-proxy.example.com:8080";
717+
718+
expect(process.env.HTTPS_PROXY).toBe("http://https-proxy.example.com:8080");
719+
});
720+
721+
it("should fall back to HTTP_PROXY when others are not set", () => {
722+
delete process.env.PERPLEXITY_PROXY;
723+
delete process.env.HTTPS_PROXY;
724+
process.env.HTTP_PROXY = "http://http-proxy.example.com:8080";
725+
726+
expect(process.env.HTTP_PROXY).toBe("http://http-proxy.example.com:8080");
727+
});
728+
});
668729
});

index.ts

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
ListToolsRequestSchema,
88
Tool,
99
} from "@modelcontextprotocol/sdk/types.js";
10+
import { fetch as undiciFetch, ProxyAgent } from "undici";
1011

1112
/**
1213
* Definition of the Perplexity Ask Tool.
@@ -169,6 +170,45 @@ if (!PERPLEXITY_API_KEY) {
169170
process.exit(1);
170171
}
171172

173+
/**
174+
* Gets the proxy URL from environment variables.
175+
* Checks PERPLEXITY_PROXY, HTTPS_PROXY, HTTP_PROXY in order.
176+
*
177+
* @returns {string | undefined} The proxy URL if configured, undefined otherwise
178+
*/
179+
function getProxyUrl(): string | undefined {
180+
return process.env.PERPLEXITY_PROXY ||
181+
process.env.HTTPS_PROXY ||
182+
process.env.HTTP_PROXY ||
183+
undefined;
184+
}
185+
186+
/**
187+
* Creates a proxy-aware fetch function.
188+
* Uses undici with ProxyAgent when a proxy is configured, otherwise uses native fetch.
189+
*
190+
* @param {string} url - The URL to fetch
191+
* @param {RequestInit} options - Fetch options
192+
* @returns {Promise<Response>} The fetch response
193+
*/
194+
async function proxyAwareFetch(url: string, options: RequestInit = {}): Promise<Response> {
195+
const proxyUrl = getProxyUrl();
196+
197+
if (proxyUrl) {
198+
// Use undici with ProxyAgent when proxy is configured
199+
const proxyAgent = new ProxyAgent(proxyUrl);
200+
const response = await undiciFetch(url, {
201+
...options,
202+
dispatcher: proxyAgent,
203+
} as any);
204+
// Cast to native Response type for compatibility
205+
return response as unknown as Response;
206+
} else {
207+
// Use native fetch when no proxy is configured
208+
return fetch(url, options);
209+
}
210+
}
211+
172212
/**
173213
* Validates an array of message objects for chat completion tools.
174214
* Ensures each message has a valid role and content field.
@@ -240,7 +280,7 @@ export async function performChatCompletion(
240280

241281
let response;
242282
try {
243-
response = await fetch(url.toString(), {
283+
response = await proxyAwareFetch(url.toString(), {
244284
method: "POST",
245285
headers: {
246286
"Content-Type": "application/json",
@@ -371,7 +411,7 @@ export async function performSearch(
371411

372412
let response;
373413
try {
374-
response = await fetch(url.toString(), {
414+
response = await proxyAwareFetch(url.toString(), {
375415
method: "POST",
376416
headers: {
377417
"Content-Type": "application/json",

package-lock.json

Lines changed: 11 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@
4141
},
4242
"dependencies": {
4343
"@modelcontextprotocol/sdk": "^1.21.1",
44-
"dotenv": "^16.6.1"
44+
"dotenv": "^16.6.1",
45+
"undici": "^6.20.0"
4546
},
4647
"devDependencies": {
4748
"@types/node": "^20",

0 commit comments

Comments
 (0)