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.
Files changed (42) hide show
  1. {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/PKG-INFO +27 -17
  2. {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/README.md +26 -16
  3. {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/pyproject.toml +1 -1
  4. {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/api/server.py +103 -56
  5. {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/cli/ai_doc.py +28 -25
  6. {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/cli/hack.py +1 -1
  7. {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/cli/main.py +1 -1
  8. {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/council.py +1 -1
  9. {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/data/SKILL.md +24 -22
  10. {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
  11. {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
  12. {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/data/references/models.md +19 -11
  13. {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/mcp/server.py +40 -24
  14. {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/models.py +16 -10
  15. {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/shared.py +23 -8
  16. {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/__init__.py +0 -0
  17. {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/api/__init__.py +0 -0
  18. {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/api/responses.py +0 -0
  19. {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/api/session_manager.py +0 -0
  20. {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/api/tool_calling.py +0 -0
  21. {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/cli/__init__.py +0 -0
  22. {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/cli/auth.py +0 -0
  23. {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/cli/doctor.py +0 -0
  24. {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/cli/setup.py +0 -0
  25. {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/cli/skill.py +0 -0
  26. {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/config.py +0 -0
  27. {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/constants.py +0 -0
  28. {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/core.py +0 -0
  29. {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/enums.py +0 -0
  30. {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/exceptions.py +0 -0
  31. {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/http.py +0 -0
  32. {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/limits.py +0 -0
  33. {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/logging.py +0 -0
  34. {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/mcp/__init__.py +0 -0
  35. {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/mcp/__main__.py +0 -0
  36. {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/py.typed +0 -0
  37. {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/rate_limits.py +0 -0
  38. {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/resilience.py +0 -0
  39. {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/router.py +0 -0
  40. {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/sessions.py +0 -0
  41. {perplexity_web_mcp_cli-0.14.0 → perplexity_web_mcp_cli-0.14.2}/src/perplexity_web_mcp/token_store.py +0 -0
  42. {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.0
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
  [![Total downloads](https://static.pepy.tech/badge/perplexity-web-mcp-cli)](https://pepy.tech/projects/perplexity-web-mcp-cli)
47
47
  [![Python](https://img.shields.io/pypi/pyversions/perplexity-web-mcp-cli)](https://pypi.org/project/perplexity-web-mcp-cli/)
48
48
  [![License](https://img.shields.io/pypi/l/perplexity-web-mcp-cli)](https://github.com/jacob-bd/perplexity-web-mcp/blob/main/LICENSE)
49
- [![Buy Me a Coffee](https://img.shields.io/badge/Buy%20Me%20a%20Coffee-FFDD00?style=flat-square&logo=buy-me-a-coffee&logoColor=black)](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.4, GPT-5.5, Claude Sonnet 5.0, Claude Opus 4.8, Gemini 3.1 Pro, GLM 5.2, Kimi K2.6, Nemotron 3 Ultra) from the terminal, through MCP tools, or as an API endpoint.
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
- - **9 Models**: Sonar 2, GPT-5.4, GPT-5.5, Claude Sonnet 5.0, Claude Opus 4.8, Gemini 3.1 Pro, GLM 5.2, Kimi K2.6, Nemotron 3 Ultra
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 gpt54
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.4, Claude Sonnet, Gemini Pro + Sonar 2 synthesis (4 Pro Searches)
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 gpt54,claude_sonnet
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 gpt54 # Launch Claude Code with a specific model
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
- | `gpt54` | OpenAI | Toggle | GPT-5.4 |
341
- | `claude_sonnet` | Anthropic | Toggle | Claude Sonnet 5.0 |
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
- | `pplx_gpt54` / `pplx_gpt54_thinking` | GPT-5.4 |
428
- | `pplx_gpt55` / `pplx_gpt55_thinking` | GPT-5.5 (Max tier) |
429
- | `pplx_claude_sonnet` / `pplx_claude_sonnet_think` | Claude Sonnet 5.0 |
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.4
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-0`) 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"`.
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.4` | GPT-5.4 | Toggle |
514
- | `claude-sonnet-5-0` | Claude Sonnet 5.0 | Toggle |
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
  [![Total downloads](https://static.pepy.tech/badge/perplexity-web-mcp-cli)](https://pepy.tech/projects/perplexity-web-mcp-cli)
10
10
  [![Python](https://img.shields.io/pypi/pyversions/perplexity-web-mcp-cli)](https://pypi.org/project/perplexity-web-mcp-cli/)
11
11
  [![License](https://img.shields.io/pypi/l/perplexity-web-mcp-cli)](https://github.com/jacob-bd/perplexity-web-mcp/blob/main/LICENSE)
12
- [![Buy Me a Coffee](https://img.shields.io/badge/Buy%20Me%20a%20Coffee-FFDD00?style=flat-square&logo=buy-me-a-coffee&logoColor=black)](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.4, GPT-5.5, Claude Sonnet 5.0, Claude Opus 4.8, Gemini 3.1 Pro, GLM 5.2, Kimi K2.6, Nemotron 3 Ultra) from the terminal, through MCP tools, or as an API endpoint.
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
- - **9 Models**: Sonar 2, GPT-5.4, GPT-5.5, Claude Sonnet 5.0, Claude Opus 4.8, Gemini 3.1 Pro, GLM 5.2, Kimi K2.6, Nemotron 3 Ultra
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 gpt54
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.4, Claude Sonnet, Gemini Pro + Sonar 2 synthesis (4 Pro Searches)
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 gpt54,claude_sonnet
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 gpt54 # Launch Claude Code with a specific model
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
- | `gpt54` | OpenAI | Toggle | GPT-5.4 |
304
- | `claude_sonnet` | Anthropic | Toggle | Claude Sonnet 5.0 |
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
- | `pplx_gpt54` / `pplx_gpt54_thinking` | GPT-5.4 |
391
- | `pplx_gpt55` / `pplx_gpt55_thinking` | GPT-5.5 (Max tier) |
392
- | `pplx_claude_sonnet` / `pplx_claude_sonnet_think` | Claude Sonnet 5.0 |
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.4
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-0`) 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"`.
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.4` | GPT-5.4 | Toggle |
477
- | `claude-sonnet-5-0` | Claude Sonnet 5.0 | Toggle |
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
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "perplexity-web-mcp-cli"
3
- version = "0.14.0"
3
+ version = "0.14.2"
4
4
  description = "CLI, MCP server, and Anthropic/OpenAI API-compatible interface for Perplexity AI."
5
5
  authors = [{ name = "Jacob BD" }]
6
6
  license = "MIT"
@@ -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.0 via Perplexity
24
- claude --model gpt-5.4 # Use GPT-5.4 via Perplexity
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.0
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.0 - supports thinking toggle
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.4": (Models.GPT_54, Models.GPT_54_THINKING),
163
- "gpt-5-4": (Models.GPT_54, Models.GPT_54_THINKING),
164
- "gpt-54": (Models.GPT_54, Models.GPT_54_THINKING),
165
- "gpt54": (Models.GPT_54, Models.GPT_54_THINKING),
166
- "gpt-5.5": (Models.GPT_55, Models.GPT_55_THINKING),
167
- "gpt-5-5": (Models.GPT_55, Models.GPT_55_THINKING),
168
- "gpt-55": (Models.GPT_55, Models.GPT_55_THINKING),
169
- "gpt55": (Models.GPT_55, Models.GPT_55_THINKING),
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-0", "description": "Claude Sonnet 5.0 - Fast, thinking toggle available"},
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
- Note: System messages are intentionally NOT included to avoid URL length
640
- limits with Perplexity.
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
- # Filter out system messages and get user/assistant messages only
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 conversation_msgs if m.role == "user"]
647
- if len(user_msgs) == 1 and len(conversation_msgs) == 1:
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
- parts = []
652
- for msg in conversation_msgs:
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 msg.role == "user":
655
- parts.append(f"User: {text}")
656
- elif msg.role == "assistant":
657
- parts.append(f"Assistant: {text}")
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
- input_tokens = estimate_tokens(query)
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, query, input_tokens, system_text),
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
- system_text: str | None = None,
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(full_query, stream=True):
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) :]