perplexity-web-mcp-cli 0.14.0__tar.gz → 0.14.2__tar.gz
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.
- {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/PKG-INFO +27 -17
- {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/README.md +26 -16
- {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/pyproject.toml +1 -1
- {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/api/server.py +103 -56
- {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/cli/ai_doc.py +28 -25
- {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/cli/hack.py +1 -1
- {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/cli/main.py +1 -1
- {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/council.py +1 -1
- {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/data/SKILL.md +24 -22
- {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/data/references/api-endpoints.md +7 -6
- {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/data/references/mcp-tools.md +9 -7
- {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/data/references/models.md +19 -11
- {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/mcp/server.py +40 -24
- {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/models.py +16 -10
- {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/shared.py +23 -8
- {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/__init__.py +0 -0
- {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/api/__init__.py +0 -0
- {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/api/responses.py +0 -0
- {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/api/session_manager.py +0 -0
- {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/api/tool_calling.py +0 -0
- {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/cli/__init__.py +0 -0
- {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/cli/auth.py +0 -0
- {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/cli/doctor.py +0 -0
- {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/cli/setup.py +0 -0
- {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/cli/skill.py +0 -0
- {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/config.py +0 -0
- {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/constants.py +0 -0
- {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/core.py +0 -0
- {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/enums.py +0 -0
- {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/exceptions.py +0 -0
- {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/http.py +0 -0
- {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/limits.py +0 -0
- {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/logging.py +0 -0
- {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/mcp/__init__.py +0 -0
- {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/mcp/__main__.py +0 -0
- {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/py.typed +0 -0
- {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/rate_limits.py +0 -0
- {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/resilience.py +0 -0
- {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/router.py +0 -0
- {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/sessions.py +0 -0
- {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/token_store.py +0 -0
- {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/types.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: perplexity-web-mcp-cli
|
|
3
|
-
Version: 0.14.
|
|
3
|
+
Version: 0.14.2
|
|
4
4
|
Summary: CLI, MCP server, and Anthropic/OpenAI API-compatible interface for Perplexity AI.
|
|
5
5
|
Keywords: perplexity,ai,mcp,anthropic,api,client
|
|
6
6
|
Author: Jacob BD
|
|
@@ -46,7 +46,6 @@ Description-Content-Type: text/markdown
|
|
|
46
46
|
[](https://pepy.tech/projects/perplexity-web-mcp-cli)
|
|
47
47
|
[](https://pypi.org/project/perplexity-web-mcp-cli/)
|
|
48
48
|
[](https://github.com/jacob-bd/perplexity-web-mcp/blob/main/LICENSE)
|
|
49
|
-
[](https://buymeacoffee.com/jacobbd)
|
|
50
49
|
|
|
51
50
|
<p align="center">
|
|
52
51
|
<a href="https://youtu.be/9xyClDvmoZ0">
|
|
@@ -62,14 +61,14 @@ Description-Content-Type: text/markdown
|
|
|
62
61
|
|
|
63
62
|
MCP server, CLI, and API-compatible interface for Perplexity AI's web interface.
|
|
64
63
|
|
|
65
|
-
Use your Perplexity Pro/Max subscription to access premium models (Sonar 2, GPT-5.
|
|
64
|
+
Use your Perplexity Pro/Max subscription to access premium models (Sonar 2, GPT-5.6 Terra, GPT-5.6 Sol, Gemini 3.1 Pro, Claude Sonnet 5, Claude Opus 4.8, GLM 5.2, Kimi K2.6, Grok 4.5, and Nemotron 3 Ultra) from the terminal, through MCP tools, or as an API endpoint.
|
|
66
65
|
|
|
67
66
|
## Features
|
|
68
67
|
|
|
69
68
|
- **CLI**: Query Perplexity models directly from the terminal (`pwm ask`, `pwm council`, `pwm research`, `pwm chat`)
|
|
70
69
|
- **MCP Server**: MCP tools for AI agents with citations, rate limit checking, and multi-turn context
|
|
71
70
|
- **API Server**: Drop-in Anthropic Messages API and OpenAI Chat Completions API
|
|
72
|
-
- **
|
|
71
|
+
- **10 Models**: Sonar 2, GPT-5.6 Terra, GPT-5.6 Sol, Gemini 3.1 Pro, Claude Sonnet 5, Claude Opus 4.8, GLM 5.2, Kimi K2.6, Grok 4.5, and Nemotron 3 Ultra
|
|
73
72
|
- **Thinking Mode**: Extended thinking support for all compatible models
|
|
74
73
|
- **Deep Research**: Full support for Perplexity's Deep Research mode
|
|
75
74
|
- **Multi-Turn Conversations**: State-preserved threaded conversations for both MCP and CLI REPL
|
|
@@ -174,7 +173,7 @@ pwm ask "What is quantum computing?"
|
|
|
174
173
|
**Choose a specific model** with `-m` (see [Models](#models) for the full list):
|
|
175
174
|
|
|
176
175
|
```bash
|
|
177
|
-
pwm ask "Compare React and Vue" -m
|
|
176
|
+
pwm ask "Compare React and Vue" -m gpt56_terra
|
|
178
177
|
```
|
|
179
178
|
|
|
180
179
|
```bash
|
|
@@ -244,13 +243,13 @@ pwm research "NVIDIA competitive landscape" -s finance --json
|
|
|
244
243
|
Query multiple models in parallel and get a synthesized consensus. Each model costs 1 Pro Search. Default synthesis uses Sonar 2 (also 1 Pro Search).
|
|
245
244
|
|
|
246
245
|
```bash
|
|
247
|
-
# Default: GPT-5.
|
|
246
|
+
# Default: GPT-5.6 Terra, Claude Sonnet, Gemini Pro + Sonar 2 synthesis (4 Pro Searches)
|
|
248
247
|
pwm council "What are best practices for microservices?"
|
|
249
248
|
```
|
|
250
249
|
|
|
251
250
|
```bash
|
|
252
251
|
# Custom model selection
|
|
253
|
-
pwm council "Compare Rust and Go" -m
|
|
252
|
+
pwm council "Compare Rust and Go" -m gpt56_terra,claude_sonnet
|
|
254
253
|
```
|
|
255
254
|
|
|
256
255
|
```bash
|
|
@@ -285,7 +284,7 @@ Seamlessly launch external AI tools connected to the Perplexity API server. This
|
|
|
285
284
|
|
|
286
285
|
```bash
|
|
287
286
|
pwm hack claude # Launch Claude Code
|
|
288
|
-
pwm hack claude -m
|
|
287
|
+
pwm hack claude -m gpt56_terra # Launch Claude Code with a specific model
|
|
289
288
|
```
|
|
290
289
|
|
|
291
290
|
### MCP Setup
|
|
@@ -337,8 +336,10 @@ pwm --ai # Print comprehensive AI-optimized reference
|
|
|
337
336
|
| `auto` | Perplexity | No | Auto-selects best model |
|
|
338
337
|
| `sonar` | Perplexity | No | Sonar 2 (latest in-house; API id `experimental`) |
|
|
339
338
|
| `deep_research` | Perplexity | No | Monthly quota, in-depth reports |
|
|
340
|
-
| `
|
|
341
|
-
| `
|
|
339
|
+
| `gpt56_terra` | OpenAI | Toggle | GPT-5.6 Terra |
|
|
340
|
+
| `gpt56_sol` | OpenAI | Toggle | GPT-5.6 Sol (Max tier required) |
|
|
341
|
+
| `grok45` | xAI | Toggle | Grok 4.5 |
|
|
342
|
+
| `claude_sonnet` | Anthropic | Toggle | Claude Sonnet 5 |
|
|
342
343
|
| `claude_opus` | Anthropic | Toggle | Claude Opus 4.8 (Max tier required) |
|
|
343
344
|
| `gemini_pro` | Google | Always | Gemini 3.1 Pro |
|
|
344
345
|
| `nemotron` | NVIDIA | Always | Nemotron 3 Ultra 550B |
|
|
@@ -424,9 +425,10 @@ claude mcp add perplexity pwm-mcp
|
|
|
424
425
|
| `pplx_ask` | Quick Q&A (auto-selects best model) |
|
|
425
426
|
| `pplx_deep_research` | In-depth reports with sources |
|
|
426
427
|
| `pplx_sonar` | Perplexity Sonar 2 (1 Pro Search) |
|
|
427
|
-
| `
|
|
428
|
-
| `
|
|
429
|
-
| `
|
|
428
|
+
| `pplx_gpt56_terra` / `pplx_gpt56_terra_thinking` | GPT-5.6 Terra |
|
|
429
|
+
| `pplx_gpt56_sol` / `pplx_gpt56_sol_thinking` | GPT-5.6 Sol (Max tier) |
|
|
430
|
+
| `pplx_grok45` / `pplx_grok45_thinking` | Grok 4.5 |
|
|
431
|
+
| `pplx_claude_sonnet` / `pplx_claude_sonnet_think` | Claude Sonnet 5 |
|
|
430
432
|
| `pplx_claude_opus` / `pplx_claude_opus_think` | Claude Opus 4.8 (Max tier) |
|
|
431
433
|
| `pplx_gemini_pro_think` | Gemini 3.1 Pro (thinking always on) |
|
|
432
434
|
| `pplx_nemotron_thinking` | Nemotron 3 Ultra (thinking always on) |
|
|
@@ -474,7 +476,7 @@ pwm api
|
|
|
474
476
|
```bash
|
|
475
477
|
export ANTHROPIC_BASE_URL=http://localhost:8080
|
|
476
478
|
export ANTHROPIC_API_KEY=perplexity
|
|
477
|
-
claude --model gpt-5.
|
|
479
|
+
claude --model gpt-5.6-terra
|
|
478
480
|
```
|
|
479
481
|
|
|
480
482
|
Alternatively, launch Claude Code seamlessly using the `hack` command, which automatically starts the API server and configures the environment for you:
|
|
@@ -503,15 +505,17 @@ export OPENAI_API_KEY=dummy
|
|
|
503
505
|
codex -m sonar --local-provider lmstudio
|
|
504
506
|
```
|
|
505
507
|
|
|
506
|
-
Our server's `MODEL_MAP` will seamlessly intercept `sonar` (or any other mapped names like `gemini-pro`, `nemotron`, `glm-5.2`, `claude-sonnet-5
|
|
508
|
+
Our server's `MODEL_MAP` will seamlessly intercept `sonar` (or any other mapped names like `gemini-pro`, `nemotron`, `glm-5.2`, `claude-sonnet-5`) and correctly route it to Perplexity's API. You can also create an alias in your shell to make this easier: `alias codex-pplx="codex --local-provider lmstudio"`.
|
|
507
509
|
|
|
508
510
|
### API Model Names
|
|
509
511
|
|
|
510
512
|
| API Name | Perplexity Model | Thinking |
|
|
511
513
|
| ------------------------------- | ------------------ | -------- |
|
|
512
514
|
| `perplexity-auto` | Best (auto-select) | No |
|
|
513
|
-
| `gpt-5.
|
|
514
|
-
| `
|
|
515
|
+
| `gpt-5.6-terra` | GPT-5.6 Terra | Toggle |
|
|
516
|
+
| `gpt-5.6-sol` | GPT-5.6 Sol | Toggle |
|
|
517
|
+
| `grok-4.5` | Grok 4.5 | Toggle |
|
|
518
|
+
| `claude-sonnet-5` | Claude Sonnet 5 | Toggle |
|
|
515
519
|
| `claude-opus-4-8` | Claude Opus 4.8 | Toggle |
|
|
516
520
|
| `gemini-3.1-pro` | Gemini 3.1 Pro | Always |
|
|
517
521
|
| `glm-5.2` / `glm52` | GLM 5.2 | Always |
|
|
@@ -622,6 +626,12 @@ The skill follows Anthropic's Agent Skills open standard and works across any co
|
|
|
622
626
|
|
|
623
627
|
Originally forked from [perplexity-webui-scraper](https://github.com/henrique-coder/perplexity-webui-scraper) by [henrique-coder](https://github.com/henrique-coder).
|
|
624
628
|
|
|
629
|
+
## Support
|
|
630
|
+
|
|
631
|
+
If Perplexity Web MCP saves you time or money, you can help cover the AI bills that go into building and testing it. Any support is hugely appreciated. 🙏
|
|
632
|
+
|
|
633
|
+
<a href="https://buymeacoffee.com/jacobbd"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" height="42"></a>
|
|
634
|
+
|
|
625
635
|
## License
|
|
626
636
|
|
|
627
637
|
MIT
|
|
@@ -9,7 +9,6 @@
|
|
|
9
9
|
[](https://pepy.tech/projects/perplexity-web-mcp-cli)
|
|
10
10
|
[](https://pypi.org/project/perplexity-web-mcp-cli/)
|
|
11
11
|
[](https://github.com/jacob-bd/perplexity-web-mcp/blob/main/LICENSE)
|
|
12
|
-
[](https://buymeacoffee.com/jacobbd)
|
|
13
12
|
|
|
14
13
|
<p align="center">
|
|
15
14
|
<a href="https://youtu.be/9xyClDvmoZ0">
|
|
@@ -25,14 +24,14 @@
|
|
|
25
24
|
|
|
26
25
|
MCP server, CLI, and API-compatible interface for Perplexity AI's web interface.
|
|
27
26
|
|
|
28
|
-
Use your Perplexity Pro/Max subscription to access premium models (Sonar 2, GPT-5.
|
|
27
|
+
Use your Perplexity Pro/Max subscription to access premium models (Sonar 2, GPT-5.6 Terra, GPT-5.6 Sol, Gemini 3.1 Pro, Claude Sonnet 5, Claude Opus 4.8, GLM 5.2, Kimi K2.6, Grok 4.5, and Nemotron 3 Ultra) from the terminal, through MCP tools, or as an API endpoint.
|
|
29
28
|
|
|
30
29
|
## Features
|
|
31
30
|
|
|
32
31
|
- **CLI**: Query Perplexity models directly from the terminal (`pwm ask`, `pwm council`, `pwm research`, `pwm chat`)
|
|
33
32
|
- **MCP Server**: MCP tools for AI agents with citations, rate limit checking, and multi-turn context
|
|
34
33
|
- **API Server**: Drop-in Anthropic Messages API and OpenAI Chat Completions API
|
|
35
|
-
- **
|
|
34
|
+
- **10 Models**: Sonar 2, GPT-5.6 Terra, GPT-5.6 Sol, Gemini 3.1 Pro, Claude Sonnet 5, Claude Opus 4.8, GLM 5.2, Kimi K2.6, Grok 4.5, and Nemotron 3 Ultra
|
|
36
35
|
- **Thinking Mode**: Extended thinking support for all compatible models
|
|
37
36
|
- **Deep Research**: Full support for Perplexity's Deep Research mode
|
|
38
37
|
- **Multi-Turn Conversations**: State-preserved threaded conversations for both MCP and CLI REPL
|
|
@@ -137,7 +136,7 @@ pwm ask "What is quantum computing?"
|
|
|
137
136
|
**Choose a specific model** with `-m` (see [Models](#models) for the full list):
|
|
138
137
|
|
|
139
138
|
```bash
|
|
140
|
-
pwm ask "Compare React and Vue" -m
|
|
139
|
+
pwm ask "Compare React and Vue" -m gpt56_terra
|
|
141
140
|
```
|
|
142
141
|
|
|
143
142
|
```bash
|
|
@@ -207,13 +206,13 @@ pwm research "NVIDIA competitive landscape" -s finance --json
|
|
|
207
206
|
Query multiple models in parallel and get a synthesized consensus. Each model costs 1 Pro Search. Default synthesis uses Sonar 2 (also 1 Pro Search).
|
|
208
207
|
|
|
209
208
|
```bash
|
|
210
|
-
# Default: GPT-5.
|
|
209
|
+
# Default: GPT-5.6 Terra, Claude Sonnet, Gemini Pro + Sonar 2 synthesis (4 Pro Searches)
|
|
211
210
|
pwm council "What are best practices for microservices?"
|
|
212
211
|
```
|
|
213
212
|
|
|
214
213
|
```bash
|
|
215
214
|
# Custom model selection
|
|
216
|
-
pwm council "Compare Rust and Go" -m
|
|
215
|
+
pwm council "Compare Rust and Go" -m gpt56_terra,claude_sonnet
|
|
217
216
|
```
|
|
218
217
|
|
|
219
218
|
```bash
|
|
@@ -248,7 +247,7 @@ Seamlessly launch external AI tools connected to the Perplexity API server. This
|
|
|
248
247
|
|
|
249
248
|
```bash
|
|
250
249
|
pwm hack claude # Launch Claude Code
|
|
251
|
-
pwm hack claude -m
|
|
250
|
+
pwm hack claude -m gpt56_terra # Launch Claude Code with a specific model
|
|
252
251
|
```
|
|
253
252
|
|
|
254
253
|
### MCP Setup
|
|
@@ -300,8 +299,10 @@ pwm --ai # Print comprehensive AI-optimized reference
|
|
|
300
299
|
| `auto` | Perplexity | No | Auto-selects best model |
|
|
301
300
|
| `sonar` | Perplexity | No | Sonar 2 (latest in-house; API id `experimental`) |
|
|
302
301
|
| `deep_research` | Perplexity | No | Monthly quota, in-depth reports |
|
|
303
|
-
| `
|
|
304
|
-
| `
|
|
302
|
+
| `gpt56_terra` | OpenAI | Toggle | GPT-5.6 Terra |
|
|
303
|
+
| `gpt56_sol` | OpenAI | Toggle | GPT-5.6 Sol (Max tier required) |
|
|
304
|
+
| `grok45` | xAI | Toggle | Grok 4.5 |
|
|
305
|
+
| `claude_sonnet` | Anthropic | Toggle | Claude Sonnet 5 |
|
|
305
306
|
| `claude_opus` | Anthropic | Toggle | Claude Opus 4.8 (Max tier required) |
|
|
306
307
|
| `gemini_pro` | Google | Always | Gemini 3.1 Pro |
|
|
307
308
|
| `nemotron` | NVIDIA | Always | Nemotron 3 Ultra 550B |
|
|
@@ -387,9 +388,10 @@ claude mcp add perplexity pwm-mcp
|
|
|
387
388
|
| `pplx_ask` | Quick Q&A (auto-selects best model) |
|
|
388
389
|
| `pplx_deep_research` | In-depth reports with sources |
|
|
389
390
|
| `pplx_sonar` | Perplexity Sonar 2 (1 Pro Search) |
|
|
390
|
-
| `
|
|
391
|
-
| `
|
|
392
|
-
| `
|
|
391
|
+
| `pplx_gpt56_terra` / `pplx_gpt56_terra_thinking` | GPT-5.6 Terra |
|
|
392
|
+
| `pplx_gpt56_sol` / `pplx_gpt56_sol_thinking` | GPT-5.6 Sol (Max tier) |
|
|
393
|
+
| `pplx_grok45` / `pplx_grok45_thinking` | Grok 4.5 |
|
|
394
|
+
| `pplx_claude_sonnet` / `pplx_claude_sonnet_think` | Claude Sonnet 5 |
|
|
393
395
|
| `pplx_claude_opus` / `pplx_claude_opus_think` | Claude Opus 4.8 (Max tier) |
|
|
394
396
|
| `pplx_gemini_pro_think` | Gemini 3.1 Pro (thinking always on) |
|
|
395
397
|
| `pplx_nemotron_thinking` | Nemotron 3 Ultra (thinking always on) |
|
|
@@ -437,7 +439,7 @@ pwm api
|
|
|
437
439
|
```bash
|
|
438
440
|
export ANTHROPIC_BASE_URL=http://localhost:8080
|
|
439
441
|
export ANTHROPIC_API_KEY=perplexity
|
|
440
|
-
claude --model gpt-5.
|
|
442
|
+
claude --model gpt-5.6-terra
|
|
441
443
|
```
|
|
442
444
|
|
|
443
445
|
Alternatively, launch Claude Code seamlessly using the `hack` command, which automatically starts the API server and configures the environment for you:
|
|
@@ -466,15 +468,17 @@ export OPENAI_API_KEY=dummy
|
|
|
466
468
|
codex -m sonar --local-provider lmstudio
|
|
467
469
|
```
|
|
468
470
|
|
|
469
|
-
Our server's `MODEL_MAP` will seamlessly intercept `sonar` (or any other mapped names like `gemini-pro`, `nemotron`, `glm-5.2`, `claude-sonnet-5
|
|
471
|
+
Our server's `MODEL_MAP` will seamlessly intercept `sonar` (or any other mapped names like `gemini-pro`, `nemotron`, `glm-5.2`, `claude-sonnet-5`) and correctly route it to Perplexity's API. You can also create an alias in your shell to make this easier: `alias codex-pplx="codex --local-provider lmstudio"`.
|
|
470
472
|
|
|
471
473
|
### API Model Names
|
|
472
474
|
|
|
473
475
|
| API Name | Perplexity Model | Thinking |
|
|
474
476
|
| ------------------------------- | ------------------ | -------- |
|
|
475
477
|
| `perplexity-auto` | Best (auto-select) | No |
|
|
476
|
-
| `gpt-5.
|
|
477
|
-
| `
|
|
478
|
+
| `gpt-5.6-terra` | GPT-5.6 Terra | Toggle |
|
|
479
|
+
| `gpt-5.6-sol` | GPT-5.6 Sol | Toggle |
|
|
480
|
+
| `grok-4.5` | Grok 4.5 | Toggle |
|
|
481
|
+
| `claude-sonnet-5` | Claude Sonnet 5 | Toggle |
|
|
478
482
|
| `claude-opus-4-8` | Claude Opus 4.8 | Toggle |
|
|
479
483
|
| `gemini-3.1-pro` | Gemini 3.1 Pro | Always |
|
|
480
484
|
| `glm-5.2` / `glm52` | GLM 5.2 | Always |
|
|
@@ -585,6 +589,12 @@ The skill follows Anthropic's Agent Skills open standard and works across any co
|
|
|
585
589
|
|
|
586
590
|
Originally forked from [perplexity-webui-scraper](https://github.com/henrique-coder/perplexity-webui-scraper) by [henrique-coder](https://github.com/henrique-coder).
|
|
587
591
|
|
|
592
|
+
## Support
|
|
593
|
+
|
|
594
|
+
If Perplexity Web MCP saves you time or money, you can help cover the AI bills that go into building and testing it. Any support is hugely appreciated. 🙏
|
|
595
|
+
|
|
596
|
+
<a href="https://buymeacoffee.com/jacobbd"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" height="42"></a>
|
|
597
|
+
|
|
588
598
|
## License
|
|
589
599
|
|
|
590
600
|
MIT
|
{perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/api/server.py
RENAMED
|
@@ -20,10 +20,10 @@ Claude Code Integration:
|
|
|
20
20
|
export ANTHROPIC_API_KEY=""
|
|
21
21
|
|
|
22
22
|
Then run Claude Code with any supported model:
|
|
23
|
-
claude --model claude-sonnet-5-0 # Use Claude Sonnet 5
|
|
24
|
-
claude --model gpt-5.
|
|
23
|
+
claude --model claude-sonnet-5-0 # Use Claude Sonnet 5 via Perplexity
|
|
24
|
+
claude --model gpt-5.6-terra # Use GPT-5.6 Terra via Perplexity
|
|
25
25
|
claude --model perplexity-auto # Use Perplexity's auto model selection
|
|
26
|
-
claude --model claude-3-5-sonnet # Legacy name, maps to Claude Sonnet 5
|
|
26
|
+
claude --model claude-3-5-sonnet # Legacy name, maps to Claude Sonnet 5
|
|
27
27
|
"""
|
|
28
28
|
|
|
29
29
|
from __future__ import annotations
|
|
@@ -50,10 +50,7 @@ from perplexity_web_mcp import ConversationConfig, Models, Perplexity
|
|
|
50
50
|
|
|
51
51
|
# Tool calling disabled for now - models don't reliably follow format instructions
|
|
52
52
|
# from perplexity_web_mcp.api.tool_calling import (...)
|
|
53
|
-
from perplexity_web_mcp.api.session_manager import
|
|
54
|
-
ConversationManager,
|
|
55
|
-
distill_system_prompt,
|
|
56
|
-
)
|
|
53
|
+
from perplexity_web_mcp.api.session_manager import ConversationManager
|
|
57
54
|
from perplexity_web_mcp.enums import CitationMode
|
|
58
55
|
from perplexity_web_mcp.models import Model
|
|
59
56
|
from perplexity_web_mcp.token_store import load_token
|
|
@@ -117,7 +114,7 @@ MODEL_MAP: dict[str, tuple[Model, Model | None]] = {
|
|
|
117
114
|
"deep-research": (Models.DEEP_RESEARCH, None),
|
|
118
115
|
# ==========================================================================
|
|
119
116
|
# Anthropic Claude Models (via Perplexity)
|
|
120
|
-
# Claude Sonnet 5
|
|
117
|
+
# Claude Sonnet 5 - supports thinking toggle
|
|
121
118
|
# Claude Opus 4.8 - supports thinking (requires Max subscription)
|
|
122
119
|
# ==========================================================================
|
|
123
120
|
# Current model names
|
|
@@ -157,16 +154,17 @@ MODEL_MAP: dict[str, tuple[Model, Model | None]] = {
|
|
|
157
154
|
"sonnet": (Models.CLAUDE_50_SONNET, Models.CLAUDE_50_SONNET_THINKING),
|
|
158
155
|
"opus": (Models.CLAUDE_48_OPUS, Models.CLAUDE_48_OPUS_THINKING),
|
|
159
156
|
# ==========================================================================
|
|
160
|
-
# OpenAI GPT Models (via Perplexity) - support thinking toggle
|
|
157
|
+
# OpenAI GPT and xAI Grok Models (via Perplexity) - support thinking toggle
|
|
161
158
|
# ==========================================================================
|
|
162
|
-
"gpt-5.
|
|
163
|
-
"gpt-5-
|
|
164
|
-
"
|
|
165
|
-
"
|
|
166
|
-
"gpt-5
|
|
167
|
-
"
|
|
168
|
-
"
|
|
169
|
-
"
|
|
159
|
+
"gpt-5.6-terra": (Models.GPT_56_TERRA, Models.GPT_56_TERRA_THINKING),
|
|
160
|
+
"gpt-5-6-terra": (Models.GPT_56_TERRA, Models.GPT_56_TERRA_THINKING),
|
|
161
|
+
"gpt56_terra": (Models.GPT_56_TERRA, Models.GPT_56_TERRA_THINKING),
|
|
162
|
+
"gpt-5.6-sol": (Models.GPT_56_SOL, Models.GPT_56_SOL_THINKING),
|
|
163
|
+
"gpt-5-6-sol": (Models.GPT_56_SOL, Models.GPT_56_SOL_THINKING),
|
|
164
|
+
"gpt56_sol": (Models.GPT_56_SOL, Models.GPT_56_SOL_THINKING),
|
|
165
|
+
"grok-4.5": (Models.GROK_45, Models.GROK_45_THINKING),
|
|
166
|
+
"grok-4-5": (Models.GROK_45, Models.GROK_45_THINKING),
|
|
167
|
+
"grok45": (Models.GROK_45, Models.GROK_45_THINKING),
|
|
170
168
|
# ==========================================================================
|
|
171
169
|
# Google Gemini Models (via Perplexity)
|
|
172
170
|
# Gemini 3.1 Pro: thinking ALWAYS enabled (no toggle in UI)
|
|
@@ -205,20 +203,22 @@ AVAILABLE_MODELS = [
|
|
|
205
203
|
{"id": "perplexity-auto", "description": "Best - Automatically selects optimal model"},
|
|
206
204
|
{"id": "perplexity-sonar", "description": "Sonar 2 - Perplexity's latest in-house model"},
|
|
207
205
|
{"id": "perplexity-research", "description": "Deep Research - In-depth reports with sources"},
|
|
206
|
+
# OpenAI
|
|
207
|
+
{"id": "gpt-5.6-terra", "description": "GPT-5.6 Terra - OpenAI's versatile model, thinking toggle available"},
|
|
208
|
+
{"id": "gpt-5.6-sol", "description": "GPT-5.6 Sol - OpenAI's most powerful model, Max tier required"},
|
|
208
209
|
# Google Gemini
|
|
209
210
|
{"id": "gemini-3.1-pro", "description": "Gemini 3.1 Pro - Advanced, thinking always on"},
|
|
210
|
-
# OpenAI
|
|
211
|
-
{"id": "gpt-5.4", "description": "GPT-5.4 - OpenAI's versatile model, thinking toggle available"},
|
|
212
|
-
{"id": "gpt-5.5", "description": "GPT-5.5 - OpenAI's latest, Max tier required, thinking toggle available"},
|
|
213
211
|
# Anthropic Claude
|
|
214
|
-
{"id": "claude-sonnet-5
|
|
212
|
+
{"id": "claude-sonnet-5", "description": "Claude Sonnet 5 - Fast, thinking toggle available"},
|
|
215
213
|
{"id": "claude-opus-4-8", "description": "Claude Opus 4.8 - Advanced reasoning, Max tier required"},
|
|
216
214
|
# Z.ai
|
|
217
215
|
{"id": "glm-5.2", "description": "GLM 5.2 - Z.ai advanced model, thinking always on"},
|
|
218
|
-
# NVIDIA
|
|
219
|
-
{"id": "nemotron-3-ultra", "description": "Nemotron 3 Ultra - NVIDIA 120B, thinking always on"},
|
|
220
216
|
# Moonshot
|
|
221
217
|
{"id": "kimi-k2.6", "description": "Kimi K2.6 - Advanced, thinking toggle available"},
|
|
218
|
+
# xAI
|
|
219
|
+
{"id": "grok-4.5", "description": "Grok 4.5 - xAI's most advanced model, thinking toggle available"},
|
|
220
|
+
# NVIDIA
|
|
221
|
+
{"id": "nemotron-3-ultra", "description": "Nemotron 3 Ultra - NVIDIA 550B, thinking always on"},
|
|
222
222
|
]
|
|
223
223
|
|
|
224
224
|
|
|
@@ -528,6 +528,7 @@ perplexity_semaphore: asyncio.Semaphore
|
|
|
528
528
|
# Track last request time for rate limiting
|
|
529
529
|
last_request_time: float = 0.0
|
|
530
530
|
MIN_REQUEST_INTERVAL: float = 5.0 # Minimum seconds between Perplexity requests (Perplexity rate limits)
|
|
531
|
+
API_CONTEXT_MAX_CHARS: int = int(os.getenv("PWM_API_CONTEXT_MAX_CHARS", "60000"))
|
|
531
532
|
|
|
532
533
|
|
|
533
534
|
# =============================================================================
|
|
@@ -633,29 +634,85 @@ def messages_to_query(messages: list[MessageParam]) -> str:
|
|
|
633
634
|
return "\n\n".join(parts)
|
|
634
635
|
|
|
635
636
|
|
|
637
|
+
def bound_context_text(text: str | None, max_chars: int = API_CONTEXT_MAX_CHARS) -> str:
|
|
638
|
+
"""Preserve prompt context within a bounded character budget."""
|
|
639
|
+
if not text:
|
|
640
|
+
return ""
|
|
641
|
+
|
|
642
|
+
stripped = text.strip()
|
|
643
|
+
if len(stripped) <= max_chars:
|
|
644
|
+
return stripped
|
|
645
|
+
if max_chars <= 0:
|
|
646
|
+
return ""
|
|
647
|
+
|
|
648
|
+
marker = f"\n\n[... {len(stripped)} characters of API context truncated to fit budget ...]\n\n"
|
|
649
|
+
available = max_chars - len(marker)
|
|
650
|
+
if available <= 0:
|
|
651
|
+
return stripped[:max_chars]
|
|
652
|
+
|
|
653
|
+
head_chars = available // 2
|
|
654
|
+
tail_chars = available - head_chars
|
|
655
|
+
return f"{stripped[:head_chars].rstrip()}{marker}{stripped[-tail_chars:].lstrip()}"
|
|
656
|
+
|
|
657
|
+
|
|
658
|
+
def build_query_with_system_context(query: str, system_text: str | None) -> str:
|
|
659
|
+
"""Prefix a user/conversation query with preserved system/workspace context."""
|
|
660
|
+
context = bound_context_text(system_text)
|
|
661
|
+
if not context:
|
|
662
|
+
return query
|
|
663
|
+
|
|
664
|
+
return f"[System instructions and workspace context]\n{context}\n\n[Conversation]\n{query}"
|
|
665
|
+
|
|
666
|
+
|
|
667
|
+
def openai_messages_to_search_query(messages: list[OpenAIChatMessage]) -> str:
|
|
668
|
+
"""Return the latest user text for Perplexity search initialization."""
|
|
669
|
+
for msg in reversed(messages):
|
|
670
|
+
if msg.role == "user":
|
|
671
|
+
text = msg.get_text().strip()
|
|
672
|
+
if text:
|
|
673
|
+
return text
|
|
674
|
+
|
|
675
|
+
return openai_messages_to_query(messages)[:500]
|
|
676
|
+
|
|
677
|
+
|
|
636
678
|
def openai_messages_to_query(messages: list[OpenAIChatMessage]) -> str:
|
|
637
679
|
"""Convert OpenAI chat messages to Perplexity query.
|
|
638
680
|
|
|
639
|
-
|
|
640
|
-
|
|
681
|
+
System and developer messages are preserved because agent runtimes use them
|
|
682
|
+
for workspace bootstrap context. URL length is handled separately by passing
|
|
683
|
+
a short init_query to Perplexity's search initialization endpoint.
|
|
641
684
|
"""
|
|
642
|
-
|
|
643
|
-
conversation_msgs = [m for m in messages if m.role in ("user", "assistant")]
|
|
685
|
+
supported_msgs = [m for m in messages if m.role in ("system", "developer", "user", "assistant", "tool")]
|
|
644
686
|
|
|
645
687
|
# For single user message, just return it directly
|
|
646
|
-
user_msgs = [m for m in
|
|
647
|
-
if len(user_msgs) == 1 and len(
|
|
688
|
+
user_msgs = [m for m in supported_msgs if m.role == "user"]
|
|
689
|
+
if len(user_msgs) == 1 and len(supported_msgs) == 1:
|
|
648
690
|
return user_msgs[0].get_text()
|
|
649
691
|
|
|
650
692
|
# Multi-turn: format as conversation
|
|
651
|
-
|
|
652
|
-
|
|
693
|
+
context_parts = []
|
|
694
|
+
conversation_parts = []
|
|
695
|
+
role_labels = {
|
|
696
|
+
"system": "System",
|
|
697
|
+
"developer": "Developer",
|
|
698
|
+
"user": "User",
|
|
699
|
+
"assistant": "Assistant",
|
|
700
|
+
"tool": "Tool",
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
for msg in supported_msgs:
|
|
653
704
|
text = msg.get_text()
|
|
654
|
-
if
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
705
|
+
if not text:
|
|
706
|
+
continue
|
|
707
|
+
label = role_labels[msg.role]
|
|
708
|
+
formatted = f"{label}: {text}"
|
|
709
|
+
if msg.role in ("system", "developer"):
|
|
710
|
+
context_parts.append(formatted)
|
|
711
|
+
else:
|
|
712
|
+
conversation_parts.append(formatted)
|
|
658
713
|
|
|
714
|
+
context = bound_context_text("\n\n".join(context_parts))
|
|
715
|
+
parts = [part for part in (context, "\n\n".join(conversation_parts)) if part]
|
|
659
716
|
return "\n\n".join(parts)
|
|
660
717
|
|
|
661
718
|
|
|
@@ -813,7 +870,8 @@ async def create_message(request: Request, body: MessagesRequest):
|
|
|
813
870
|
|
|
814
871
|
# Convert messages to query (tool calling not supported via web UI)
|
|
815
872
|
query = messages_to_query(body.messages)
|
|
816
|
-
|
|
873
|
+
full_query = build_query_with_system_context(query, system_text)
|
|
874
|
+
input_tokens = estimate_tokens(full_query)
|
|
817
875
|
|
|
818
876
|
# Generate response ID
|
|
819
877
|
response_id = f"msg_{uuid.uuid4().hex[:24]}"
|
|
@@ -822,7 +880,7 @@ async def create_message(request: Request, body: MessagesRequest):
|
|
|
822
880
|
|
|
823
881
|
if body.stream:
|
|
824
882
|
return StreamingResponse(
|
|
825
|
-
stream_response(response_id, body.model, model,
|
|
883
|
+
stream_response(response_id, body.model, model, full_query, input_tokens, init_query=query),
|
|
826
884
|
media_type="text/event-stream",
|
|
827
885
|
headers={
|
|
828
886
|
"Cache-Control": "no-cache",
|
|
@@ -846,18 +904,12 @@ async def create_message(request: Request, body: MessagesRequest):
|
|
|
846
904
|
await asyncio.sleep(wait_needed)
|
|
847
905
|
last_request_time = time_module.time()
|
|
848
906
|
|
|
849
|
-
# Prepend distilled system prompt to query (single ask)
|
|
850
|
-
full_query = query
|
|
851
|
-
if system_text:
|
|
852
|
-
distilled = distill_system_prompt(system_text)
|
|
853
|
-
full_query = f"[Instructions: {distilled}]\n\n{query}"
|
|
854
|
-
|
|
855
907
|
fresh_client = Perplexity(session_token=config.session_token)
|
|
856
908
|
conversation = fresh_client.create_conversation(
|
|
857
909
|
ConversationConfig(model=model, citation_mode=CitationMode.DEFAULT)
|
|
858
910
|
)
|
|
859
911
|
# Single ask with prepended system context
|
|
860
|
-
await asyncio.to_thread(conversation.ask, full_query)
|
|
912
|
+
await asyncio.to_thread(conversation.ask, full_query, init_query=query)
|
|
861
913
|
fresh_client.close()
|
|
862
914
|
answer = conversation.answer or ""
|
|
863
915
|
|
|
@@ -890,7 +942,7 @@ async def stream_response(
|
|
|
890
942
|
model: Model,
|
|
891
943
|
query: str,
|
|
892
944
|
input_tokens: int,
|
|
893
|
-
|
|
945
|
+
init_query: str | None = None,
|
|
894
946
|
) -> AsyncGenerator[str, None]:
|
|
895
947
|
"""Stream Anthropic-format SSE response.
|
|
896
948
|
|
|
@@ -960,13 +1012,6 @@ async def stream_response(
|
|
|
960
1012
|
last = ""
|
|
961
1013
|
max_retries = 3
|
|
962
1014
|
|
|
963
|
-
# Prepend distilled system prompt to query (single ask instead of priming)
|
|
964
|
-
full_query = query
|
|
965
|
-
if system_text:
|
|
966
|
-
distilled = distill_system_prompt(system_text)
|
|
967
|
-
full_query = f"[Instructions: {distilled}]\n\n{query}"
|
|
968
|
-
logging.debug(f"Query with system context ({len(distilled)} chars)")
|
|
969
|
-
|
|
970
1015
|
for attempt in range(max_retries):
|
|
971
1016
|
try:
|
|
972
1017
|
# Create fresh client for each request to avoid curl_cffi Session issues
|
|
@@ -976,7 +1021,7 @@ async def stream_response(
|
|
|
976
1021
|
)
|
|
977
1022
|
|
|
978
1023
|
# Single ask with prepended system context
|
|
979
|
-
for resp in conversation.ask(
|
|
1024
|
+
for resp in conversation.ask(query, stream=True, init_query=init_query):
|
|
980
1025
|
current = resp.answer or ""
|
|
981
1026
|
if len(current) > len(last):
|
|
982
1027
|
delta = current[len(last) :]
|
|
@@ -1112,6 +1157,7 @@ async def create_chat_completion(request: Request, body: OpenAIChatRequest):
|
|
|
1112
1157
|
|
|
1113
1158
|
# Convert messages to query
|
|
1114
1159
|
query = openai_messages_to_query(body.messages)
|
|
1160
|
+
init_query = openai_messages_to_search_query(body.messages)
|
|
1115
1161
|
input_tokens = estimate_tokens(query)
|
|
1116
1162
|
|
|
1117
1163
|
# Generate response ID
|
|
@@ -1122,7 +1168,7 @@ async def create_chat_completion(request: Request, body: OpenAIChatRequest):
|
|
|
1122
1168
|
|
|
1123
1169
|
if body.stream:
|
|
1124
1170
|
return StreamingResponse(
|
|
1125
|
-
stream_openai_response(response_id, body.model, model, query, created),
|
|
1171
|
+
stream_openai_response(response_id, body.model, model, query, created, init_query),
|
|
1126
1172
|
media_type="text/event-stream",
|
|
1127
1173
|
headers={
|
|
1128
1174
|
"Cache-Control": "no-cache",
|
|
@@ -1141,7 +1187,7 @@ async def create_chat_completion(request: Request, body: OpenAIChatRequest):
|
|
|
1141
1187
|
)
|
|
1142
1188
|
|
|
1143
1189
|
# Run in thread to not block
|
|
1144
|
-
await asyncio.to_thread(conversation.ask, query)
|
|
1190
|
+
await asyncio.to_thread(conversation.ask, query, init_query=init_query)
|
|
1145
1191
|
answer = conversation.answer or ""
|
|
1146
1192
|
|
|
1147
1193
|
# Append citations if available
|
|
@@ -1178,6 +1224,7 @@ async def stream_openai_response(
|
|
|
1178
1224
|
model: Model,
|
|
1179
1225
|
query: str,
|
|
1180
1226
|
created: int,
|
|
1227
|
+
init_query: str | None = None,
|
|
1181
1228
|
) -> AsyncGenerator[str, None]:
|
|
1182
1229
|
"""Stream OpenAI-format SSE response.
|
|
1183
1230
|
|
|
@@ -1217,7 +1264,7 @@ async def stream_openai_response(
|
|
|
1217
1264
|
conversation = client.create_conversation(
|
|
1218
1265
|
ConversationConfig(model=model, citation_mode=CitationMode.DEFAULT)
|
|
1219
1266
|
)
|
|
1220
|
-
for resp in conversation.ask(query, stream=True):
|
|
1267
|
+
for resp in conversation.ask(query, stream=True, init_query=init_query):
|
|
1221
1268
|
current = resp.answer or ""
|
|
1222
1269
|
if len(current) > len(last):
|
|
1223
1270
|
delta = current[len(last) :]
|