perplexity-web-mcp-cli 0.12.2__tar.gz → 0.12.4__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 (43) hide show
  1. {perplexity_web_mcp_cli-0.12.2 → perplexity_web_mcp_cli-0.12.4}/PKG-INFO +6 -6
  2. {perplexity_web_mcp_cli-0.12.2 → perplexity_web_mcp_cli-0.12.4}/README.md +5 -5
  3. {perplexity_web_mcp_cli-0.12.2 → perplexity_web_mcp_cli-0.12.4}/pyproject.toml +1 -1
  4. {perplexity_web_mcp_cli-0.12.2 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/api/server.py +6 -6
  5. {perplexity_web_mcp_cli-0.12.2 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/cli/ai_doc.py +5 -5
  6. perplexity_web_mcp_cli-0.12.4/src/perplexity_web_mcp/cli/doctor.py +208 -0
  7. {perplexity_web_mcp_cli-0.12.2 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/cli/main.py +1 -1
  8. {perplexity_web_mcp_cli-0.12.2 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/data/SKILL.md +4 -4
  9. {perplexity_web_mcp_cli-0.12.2 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/data/references/api-endpoints.md +1 -1
  10. {perplexity_web_mcp_cli-0.12.2 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/data/references/mcp-tools.md +3 -3
  11. {perplexity_web_mcp_cli-0.12.2 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/data/references/models.md +5 -5
  12. {perplexity_web_mcp_cli-0.12.2 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/mcp/server.py +6 -6
  13. {perplexity_web_mcp_cli-0.12.2 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/models.py +9 -0
  14. {perplexity_web_mcp_cli-0.12.2 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/shared.py +7 -7
  15. perplexity_web_mcp_cli-0.12.2/src/perplexity_web_mcp/cli/doctor.py +0 -152
  16. {perplexity_web_mcp_cli-0.12.2 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/__init__.py +0 -0
  17. {perplexity_web_mcp_cli-0.12.2 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/api/__init__.py +0 -0
  18. {perplexity_web_mcp_cli-0.12.2 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/api/responses.py +0 -0
  19. {perplexity_web_mcp_cli-0.12.2 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/api/session_manager.py +0 -0
  20. {perplexity_web_mcp_cli-0.12.2 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/api/tool_calling.py +0 -0
  21. {perplexity_web_mcp_cli-0.12.2 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/cli/__init__.py +0 -0
  22. {perplexity_web_mcp_cli-0.12.2 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/cli/auth.py +0 -0
  23. {perplexity_web_mcp_cli-0.12.2 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/cli/hack.py +0 -0
  24. {perplexity_web_mcp_cli-0.12.2 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/cli/setup.py +0 -0
  25. {perplexity_web_mcp_cli-0.12.2 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/cli/skill.py +0 -0
  26. {perplexity_web_mcp_cli-0.12.2 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/config.py +0 -0
  27. {perplexity_web_mcp_cli-0.12.2 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/constants.py +0 -0
  28. {perplexity_web_mcp_cli-0.12.2 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/core.py +0 -0
  29. {perplexity_web_mcp_cli-0.12.2 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/council.py +0 -0
  30. {perplexity_web_mcp_cli-0.12.2 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/enums.py +0 -0
  31. {perplexity_web_mcp_cli-0.12.2 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/exceptions.py +0 -0
  32. {perplexity_web_mcp_cli-0.12.2 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/http.py +0 -0
  33. {perplexity_web_mcp_cli-0.12.2 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/limits.py +0 -0
  34. {perplexity_web_mcp_cli-0.12.2 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/logging.py +0 -0
  35. {perplexity_web_mcp_cli-0.12.2 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/mcp/__init__.py +0 -0
  36. {perplexity_web_mcp_cli-0.12.2 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/mcp/__main__.py +0 -0
  37. {perplexity_web_mcp_cli-0.12.2 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/py.typed +0 -0
  38. {perplexity_web_mcp_cli-0.12.2 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/rate_limits.py +0 -0
  39. {perplexity_web_mcp_cli-0.12.2 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/resilience.py +0 -0
  40. {perplexity_web_mcp_cli-0.12.2 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/router.py +0 -0
  41. {perplexity_web_mcp_cli-0.12.2 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/sessions.py +0 -0
  42. {perplexity_web_mcp_cli-0.12.2 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/token_store.py +0 -0
  43. {perplexity_web_mcp_cli-0.12.2 → perplexity_web_mcp_cli-0.12.4}/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.12.2
3
+ Version: 0.12.4
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
@@ -62,14 +62,14 @@ Description-Content-Type: text/markdown
62
62
 
63
63
  MCP server, CLI, and API-compatible interface for Perplexity AI's web interface.
64
64
 
65
- Use your Perplexity Pro/Max subscription to access premium models (GPT-5.4, Claude 4.6 Opus, Claude 4.6 Sonnet, Gemini 3.1 Pro, Nemotron 3 Super) from the terminal, through MCP tools, or as an API endpoint.
65
+ Use your Perplexity Pro/Max subscription to access premium models (GPT-5.4, Claude 4.6 Opus, Claude 4.6 Sonnet, Gemini 3.1 Pro, Nemotron 3 Ultra) from the terminal, through MCP tools, or as an API endpoint.
66
66
 
67
67
  ## Features
68
68
 
69
69
  - **CLI**: Query Perplexity models directly from the terminal (`pwm ask`, `pwm council`, `pwm research`, `pwm chat`)
70
70
  - **MCP Server**: 17 MCP tools for AI agents with citations, rate limit checking, and multi-turn context
71
71
  - **API Server**: Drop-in Anthropic Messages API and OpenAI Chat Completions API
72
- - **6 Models**: GPT-5.4, Claude 4.6 Opus, Claude 4.6 Sonnet, Gemini 3.1 Pro, Nemotron 3 Super, Sonar 2
72
+ - **6 Models**: GPT-5.4, Claude 4.6 Opus, Claude 4.6 Sonnet, Gemini 3.1 Pro, Nemotron 3 Ultra, Sonar 2
73
73
  - **Thinking Mode**: Extended thinking support for all compatible models
74
74
  - **Deep Research**: Full support for Perplexity's Deep Research mode
75
75
  - **Multi-Turn Conversations**: State-preserved threaded conversations for both MCP and CLI REPL
@@ -337,7 +337,7 @@ pwm --ai # Print comprehensive AI-optimized reference
337
337
  | `claude_sonnet` | Anthropic | Toggle | Claude 4.6 Sonnet |
338
338
  | `claude_opus` | Anthropic | Toggle | Claude 4.6 Opus (Max tier required) |
339
339
  | `gemini_pro` | Google | Always | Gemini 3.1 Pro |
340
- | `nemotron` | NVIDIA | Always | Nemotron 3 Super 120B |
340
+ | `nemotron` | NVIDIA | Always | Nemotron 3 Ultra 550B |
341
341
 
342
342
  ### Source Focus
343
343
 
@@ -406,7 +406,7 @@ claude mcp add perplexity pwm-mcp
406
406
  | `pplx_claude_sonnet` / `pplx_claude_sonnet_think` | Claude 4.6 Sonnet |
407
407
  | `pplx_claude_opus` / `pplx_claude_opus_think` | Claude 4.6 Opus (Max tier) |
408
408
  | `pplx_gemini_pro_think` | Gemini 3.1 Pro (thinking always on) |
409
- | `pplx_nemotron_thinking` | Nemotron 3 Super (thinking always on) |
409
+ | `pplx_nemotron_thinking` | Nemotron 3 Ultra (thinking always on) |
410
410
 
411
411
  **Smart routing (1):**
412
412
 
@@ -488,7 +488,7 @@ Our server's `MODEL_MAP` will seamlessly intercept `sonar` (or any other mapped
488
488
  | `claude-sonnet-4-6` | Claude 4.6 Sonnet | Toggle |
489
489
  | `claude-opus-4-6` | Claude 4.6 Opus | Toggle |
490
490
  | `gemini-3.1-pro` | Gemini 3.1 Pro | Always |
491
- | `nemotron-3-super` / `nemotron` | Nemotron 3 Super | Always |
491
+ | `nemotron-3-ultra` / `nemotron` | Nemotron 3 Ultra | Always |
492
492
 
493
493
  Legacy aliases (`claude-3-5-sonnet`, `claude-3-opus`) are supported for compatibility.
494
494
 
@@ -25,14 +25,14 @@
25
25
 
26
26
  MCP server, CLI, and API-compatible interface for Perplexity AI's web interface.
27
27
 
28
- Use your Perplexity Pro/Max subscription to access premium models (GPT-5.4, Claude 4.6 Opus, Claude 4.6 Sonnet, Gemini 3.1 Pro, Nemotron 3 Super) from the terminal, through MCP tools, or as an API endpoint.
28
+ Use your Perplexity Pro/Max subscription to access premium models (GPT-5.4, Claude 4.6 Opus, Claude 4.6 Sonnet, Gemini 3.1 Pro, Nemotron 3 Ultra) from the terminal, through MCP tools, or as an API endpoint.
29
29
 
30
30
  ## Features
31
31
 
32
32
  - **CLI**: Query Perplexity models directly from the terminal (`pwm ask`, `pwm council`, `pwm research`, `pwm chat`)
33
33
  - **MCP Server**: 17 MCP tools for AI agents with citations, rate limit checking, and multi-turn context
34
34
  - **API Server**: Drop-in Anthropic Messages API and OpenAI Chat Completions API
35
- - **6 Models**: GPT-5.4, Claude 4.6 Opus, Claude 4.6 Sonnet, Gemini 3.1 Pro, Nemotron 3 Super, Sonar 2
35
+ - **6 Models**: GPT-5.4, Claude 4.6 Opus, Claude 4.6 Sonnet, Gemini 3.1 Pro, Nemotron 3 Ultra, Sonar 2
36
36
  - **Thinking Mode**: Extended thinking support for all compatible models
37
37
  - **Deep Research**: Full support for Perplexity's Deep Research mode
38
38
  - **Multi-Turn Conversations**: State-preserved threaded conversations for both MCP and CLI REPL
@@ -300,7 +300,7 @@ pwm --ai # Print comprehensive AI-optimized reference
300
300
  | `claude_sonnet` | Anthropic | Toggle | Claude 4.6 Sonnet |
301
301
  | `claude_opus` | Anthropic | Toggle | Claude 4.6 Opus (Max tier required) |
302
302
  | `gemini_pro` | Google | Always | Gemini 3.1 Pro |
303
- | `nemotron` | NVIDIA | Always | Nemotron 3 Super 120B |
303
+ | `nemotron` | NVIDIA | Always | Nemotron 3 Ultra 550B |
304
304
 
305
305
  ### Source Focus
306
306
 
@@ -369,7 +369,7 @@ claude mcp add perplexity pwm-mcp
369
369
  | `pplx_claude_sonnet` / `pplx_claude_sonnet_think` | Claude 4.6 Sonnet |
370
370
  | `pplx_claude_opus` / `pplx_claude_opus_think` | Claude 4.6 Opus (Max tier) |
371
371
  | `pplx_gemini_pro_think` | Gemini 3.1 Pro (thinking always on) |
372
- | `pplx_nemotron_thinking` | Nemotron 3 Super (thinking always on) |
372
+ | `pplx_nemotron_thinking` | Nemotron 3 Ultra (thinking always on) |
373
373
 
374
374
  **Smart routing (1):**
375
375
 
@@ -451,7 +451,7 @@ Our server's `MODEL_MAP` will seamlessly intercept `sonar` (or any other mapped
451
451
  | `claude-sonnet-4-6` | Claude 4.6 Sonnet | Toggle |
452
452
  | `claude-opus-4-6` | Claude 4.6 Opus | Toggle |
453
453
  | `gemini-3.1-pro` | Gemini 3.1 Pro | Always |
454
- | `nemotron-3-super` / `nemotron` | Nemotron 3 Super | Always |
454
+ | `nemotron-3-ultra` / `nemotron` | Nemotron 3 Ultra | Always |
455
455
 
456
456
  Legacy aliases (`claude-3-5-sonnet`, `claude-3-opus`) are supported for compatibility.
457
457
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "perplexity-web-mcp-cli"
3
- version = "0.12.2"
3
+ version = "0.12.4"
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"
@@ -169,12 +169,12 @@ MODEL_MAP: dict[str, tuple[Model, Model | None]] = {
169
169
  "gemini-3-pro": (Models.GEMINI_31_PRO_THINKING, Models.GEMINI_31_PRO_THINKING),
170
170
  "gemini-pro": (Models.GEMINI_31_PRO_THINKING, Models.GEMINI_31_PRO_THINKING),
171
171
  # ==========================================================================
172
- # NVIDIA Nemotron 3 Super (via Perplexity)
172
+ # NVIDIA Nemotron 3 Ultra (via Perplexity)
173
173
  # Thinking ALWAYS enabled (no toggle in UI) - reasoning only
174
174
  # ==========================================================================
175
- "nemotron-3-super": (Models.NEMOTRON_3_SUPER, Models.NEMOTRON_3_SUPER),
176
- "nemotron-3": (Models.NEMOTRON_3_SUPER, Models.NEMOTRON_3_SUPER),
177
- "nemotron": (Models.NEMOTRON_3_SUPER, Models.NEMOTRON_3_SUPER),
175
+ "nemotron-3-ultra": (Models.NEMOTRON_3_ULTRA, Models.NEMOTRON_3_ULTRA),
176
+ "nemotron-3": (Models.NEMOTRON_3_ULTRA, Models.NEMOTRON_3_ULTRA),
177
+ "nemotron": (Models.NEMOTRON_3_ULTRA, Models.NEMOTRON_3_ULTRA),
178
178
  # ==========================================================================
179
179
  # Moonshot Kimi Models (via Perplexity)
180
180
  # Kimi K2.6 - supports thinking toggle
@@ -198,9 +198,9 @@ AVAILABLE_MODELS = [
198
198
  {"id": "gpt-5.5", "description": "GPT-5.5 - OpenAI's latest, Max tier required, thinking toggle available"},
199
199
  # Anthropic Claude
200
200
  {"id": "claude-sonnet-4-6", "description": "Claude Sonnet 4.6 - Fast, thinking toggle available"},
201
- {"id": "claude-opus-4-7", "description": "Claude Opus 4.7 - Advanced reasoning, Max tier required"},
201
+ {"id": "claude-opus-4-8", "description": "Claude Opus 4.8 - Advanced reasoning, Max tier required"},
202
202
  # NVIDIA
203
- {"id": "nemotron-3-super", "description": "Nemotron 3 Super - NVIDIA 120B, thinking always on"},
203
+ {"id": "nemotron-3-ultra", "description": "Nemotron 3 Ultra - NVIDIA 120B, thinking always on"},
204
204
  # Moonshot
205
205
  {"id": "kimi-k2.6", "description": "Kimi K2.6 - Advanced, thinking toggle available"},
206
206
  ]
@@ -115,9 +115,9 @@ deep_research pplx_alpha No In-depth reports (monthly quo
115
115
  gpt54 gpt54 Yes OpenAI GPT-5.4 (versatile)
116
116
  gpt55 gpt55 Yes OpenAI GPT-5.5 (latest, Max tier)
117
117
  claude_sonnet claude46sonnet Yes Anthropic Claude 4.6 Sonnet
118
- claude_opus claude47opus Yes Anthropic Claude 4.7 Opus (Max tier)
118
+ claude_opus claude48opus Yes Anthropic Claude 4.8 Opus (Max tier)
119
119
  gemini_pro gemini31pro_high Always Google Gemini 3.1 Pro (thinking only)
120
- nemotron nv_nemotron_3_super Always NVIDIA Nemotron 3 Super 120B (thinking only)
120
+ nemotron nv_nemotron_3_ultra Always NVIDIA Nemotron 3 Ultra 550B (thinking only)
121
121
  kimi_k26 kimi_k26 Yes Moonshot Kimi K2.6
122
122
 
123
123
  "Thinking" = extended reasoning mode. Models marked "Always" have thinking
@@ -191,10 +191,10 @@ QUERY TOOLS (each call costs 1 Pro Search query unless noted):
191
191
  pplx_gpt55_thinking(query, source_focus="web") GPT-5.5 + thinking — 1 Pro (Max tier)
192
192
  pplx_claude_sonnet(query, source_focus="web") Claude 4.6 Sonnet — 1 Pro
193
193
  pplx_claude_sonnet_think(query, source_focus) Claude 4.6 Sonnet + thinking — 1 Pro
194
- pplx_claude_opus(query, source_focus="web") Claude 4.7 Opus — 1 Pro (Max tier)
195
- pplx_claude_opus_think(query, source_focus) Claude 4.7 Opus + thinking — 1 Pro (Max tier)
194
+ pplx_claude_opus(query, source_focus="web") Claude 4.8 Opus — 1 Pro (Max tier)
195
+ pplx_claude_opus_think(query, source_focus) Claude 4.8 Opus + thinking — 1 Pro (Max tier)
196
196
  pplx_gemini_pro_think(query, source_focus) Gemini 3.1 Pro (thinking) — 1 Pro
197
- pplx_nemotron_thinking(query, source_focus) Nemotron 3 Super (thinking) — 1 Pro
197
+ pplx_nemotron_thinking(query, source_focus) Nemotron 3 Ultra (thinking) — 1 Pro
198
198
  pplx_kimi_k26(query, source_focus="web") Kimi K2.6 — 1 Pro
199
199
  pplx_kimi_k26_thinking(query, source_focus) Kimi K2.6 + thinking — 1 Pro
200
200
 
@@ -0,0 +1,208 @@
1
+ """Diagnostic checks for perplexity-web-mcp installation.
2
+
3
+ Validates installation, authentication, configuration, rate limits,
4
+ and connectivity -- everything an AI agent or user needs to know
5
+ before using the tool.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from importlib import metadata
11
+ import shutil
12
+
13
+ from perplexity_web_mcp.token_store import TOKEN_FILE, load_token
14
+
15
+
16
+ def _check(label: str, ok: bool, detail: str, fix: str = "") -> bool:
17
+ """Print a check result line and return the status."""
18
+ icon = "✓" if ok else "✗"
19
+ line = f" {icon} {label}: {detail}"
20
+ if not ok and fix:
21
+ line += f" -> {fix}"
22
+ print(line)
23
+ return ok
24
+
25
+
26
+ def _check_installation() -> bool:
27
+ print("Installation")
28
+ all_ok = True
29
+
30
+ try:
31
+ version = metadata.version("perplexity-web-mcp-cli")
32
+ _check("perplexity-web-mcp-cli", True, version)
33
+ except metadata.PackageNotFoundError:
34
+ all_ok = (
35
+ _check("perplexity-web-mcp-cli", False, "not installed", "pip install perplexity-web-mcp-cli") and all_ok
36
+ )
37
+
38
+ pwm_path = shutil.which("pwm")
39
+ _check("pwm", pwm_path is not None, pwm_path or "not in PATH", "pip install -e '.[mcp]'")
40
+
41
+ pwm_mcp_path = shutil.which("pwm-mcp")
42
+ all_ok = (
43
+ _check("pwm-mcp", pwm_mcp_path is not None, pwm_mcp_path or "not in PATH", "pip install -e '.[mcp]'") and all_ok
44
+ )
45
+
46
+ try:
47
+ import perplexity_web_mcp.api.server # noqa: F401
48
+
49
+ _check("pwm api", True, "module available", "")
50
+ except ImportError:
51
+ _check("pwm api", False, "module not found", "pip install -e .")
52
+
53
+ return all_ok
54
+
55
+
56
+ def _check_authentication(token: str | None, token_exists: bool) -> bool:
57
+ print("\nAuthentication")
58
+
59
+ if not token_exists:
60
+ return _check("Token", False, "not found", "pwm login")
61
+
62
+ token_source = "file" if TOKEN_FILE.exists() else "env"
63
+ _check("Token", True, f"present ({token_source}, {len(token)} chars)") # type: ignore[arg-type]
64
+
65
+ from perplexity_web_mcp.cli.auth import get_user_info
66
+
67
+ user_info = get_user_info(token)
68
+ if user_info:
69
+ _check("Account", True, f"{user_info.email}")
70
+ _check("Subscription", True, user_info.tier_display)
71
+ return True
72
+
73
+ return _check("Account", False, "token invalid or expired", "pwm login")
74
+
75
+
76
+ def _check_connectivity(token: str | None, token_exists: bool) -> bool:
77
+ print("\nConnectivity")
78
+
79
+ if not token_exists:
80
+ _check("Search endpoint", False, "skipped (no token)", "pwm login first")
81
+ return True
82
+
83
+ try:
84
+ from curl_cffi.requests import Session as CurlSession
85
+
86
+ from perplexity_web_mcp.constants import API_BASE_URL, ENDPOINT_SEARCH_INIT, SESSION_COOKIE_NAME
87
+
88
+ with CurlSession(impersonate="chrome") as s:
89
+ s.cookies.set(SESSION_COOKIE_NAME, token) # type: ignore[arg-type]
90
+ resp = s.get(f"{API_BASE_URL}{ENDPOINT_SEARCH_INIT}", params={"q": "test"}, timeout=10)
91
+
92
+ if resp.status_code == 200:
93
+ return _check("Search endpoint", True, "reachable")
94
+ if resp.status_code == 403:
95
+ return _check(
96
+ "Search endpoint",
97
+ False,
98
+ "403 Forbidden",
99
+ 'Check for VPN/proxy; try: LOG_LEVEL=debug pwm ask "test"',
100
+ )
101
+ return _check(
102
+ "Search endpoint",
103
+ False,
104
+ f"unexpected status {resp.status_code}",
105
+ "check network connection",
106
+ )
107
+ except Exception as exc:
108
+ return _check("Search endpoint", False, f"error: {exc}", "check network connection")
109
+
110
+
111
+ def _check_rate_limits(token: str | None, token_exists: bool) -> bool:
112
+ print("\nRate Limits")
113
+
114
+ if not token_exists:
115
+ _check("Rate limits", False, "skipped (no token)", "pwm login first")
116
+ return True
117
+
118
+ from perplexity_web_mcp.rate_limits import fetch_rate_limits
119
+
120
+ limits = fetch_rate_limits(token)
121
+ if not limits:
122
+ return _check("Rate limits", False, "could not fetch", "check network connection")
123
+
124
+ pro_ok = limits.remaining_pro > 0
125
+ research_ok = limits.remaining_research > 0
126
+ all_ok = _check("Pro Search", pro_ok, f"{limits.remaining_pro} remaining", "wait for weekly reset")
127
+ _check("Deep Research", research_ok, f"{limits.remaining_research} remaining", "wait for monthly reset")
128
+ _check("Create Files & Apps", True, f"{limits.remaining_labs} remaining")
129
+ _check("Browser Agent", True, f"{limits.remaining_agentic_research} remaining")
130
+ return all_ok
131
+
132
+
133
+ def _check_mcp_config() -> bool:
134
+ print("\nMCP Configuration")
135
+
136
+ from perplexity_web_mcp.cli.setup import _get_tools, _is_configured_compat
137
+
138
+ tools = _get_tools()
139
+ any_configured = False
140
+ for tool in tools:
141
+ configured = _is_configured_compat(tool)
142
+ if configured:
143
+ any_configured = True
144
+ if configured:
145
+ _check(tool.name, True, "configured")
146
+ else:
147
+ _check(tool.name, False, "not configured", f"pwm setup add {tool.name}")
148
+
149
+ return any_configured
150
+
151
+
152
+ def _check_skills(verbose: bool) -> None:
153
+ print("\nSkill Installation")
154
+
155
+ from perplexity_web_mcp.cli.skill import SKILL_DIR_NAME, _get_current_version, _get_installed_version, _get_targets
156
+
157
+ skill_targets = _get_targets()
158
+ current_ver = _get_current_version()
159
+ any_skill = False
160
+ for t in skill_targets:
161
+ user_ver = _get_installed_version(t.user_dir / SKILL_DIR_NAME)
162
+ if user_ver:
163
+ any_skill = True
164
+ if user_ver == current_ver:
165
+ _check(t.name, True, f"v{user_ver}")
166
+ else:
167
+ _check(t.name, True, f"v{user_ver} (outdated, current: v{current_ver})")
168
+ elif verbose:
169
+ _check(t.name, False, "not installed", f"pwm skill install {t.name}")
170
+
171
+ if not any_skill:
172
+ _check("Skills", False, "no skills installed", "pwm skill install claude-code")
173
+
174
+
175
+ def _check_security(verbose: bool) -> bool:
176
+ if not verbose or not TOKEN_FILE.exists():
177
+ return True
178
+
179
+ print("\nSecurity")
180
+ mode = oct(TOKEN_FILE.stat().st_mode)[-3:]
181
+ secure = mode == "600"
182
+ return _check("Token permissions", secure, mode, "chmod 600 ~/.config/perplexity-web-mcp/token")
183
+
184
+
185
+ def cmd_doctor(args: list[str]) -> int:
186
+ """Handle: pwm doctor [--verbose]"""
187
+ verbose = "-v" in args or "--verbose" in args
188
+
189
+ print("\nPerplexity Web MCP Doctor\n")
190
+
191
+ token = load_token()
192
+ token_exists = token is not None and len(token) > 10
193
+
194
+ all_ok = _check_installation()
195
+ all_ok = _check_authentication(token, token_exists) and all_ok
196
+ all_ok = _check_connectivity(token, token_exists) and all_ok
197
+ all_ok = _check_rate_limits(token, token_exists) and all_ok
198
+ all_ok = _check_mcp_config() and all_ok
199
+ _check_skills(verbose)
200
+ all_ok = _check_security(verbose) and all_ok
201
+
202
+ print()
203
+ if all_ok:
204
+ print("✓ All checks passed!")
205
+ else:
206
+ print("Some checks failed. See suggestions above (->).")
207
+
208
+ return 0 if all_ok else 1
@@ -91,7 +91,7 @@ def cli(ctx):
91
91
  # ── Ask ────────────────────────────────────────────────────────────────────
92
92
 
93
93
 
94
- @cli.command()
94
+ @cli.command(name="ask")
95
95
  @click.argument("query")
96
96
  @click.option("-m", "--model", "model_name", default="auto", help=f"Model to use ({', '.join(MODEL_NAMES)}).")
97
97
  @click.option("-t", "--thinking", is_flag=True, help="Enable extended thinking mode.")
@@ -290,9 +290,9 @@ pwm usage --refresh # Force-refresh from server
290
290
  | `pplx_gpt54` / `_thinking` | 1 Pro | OpenAI GPT-5.4 (versatile) |
291
291
  | `pplx_gpt55` / `_thinking` | 1 Pro | OpenAI GPT-5.5 (latest, Max tier) |
292
292
  | `pplx_claude_sonnet` / `_think` | 1 Pro | Anthropic Claude 4.6 Sonnet |
293
- | `pplx_claude_opus` / `_think` | 1 Pro | Anthropic Claude 4.7 Opus |
293
+ | `pplx_claude_opus` / `_think` | 1 Pro | Anthropic Claude 4.8 Opus |
294
294
  | `pplx_gemini_pro_think` | 1 Pro | Google Gemini 3.1 Pro (thinking always on) |
295
- | `pplx_nemotron_thinking` | 1 Pro | NVIDIA Nemotron 3 Super (thinking always on) |
295
+ | `pplx_nemotron_thinking` | 1 Pro | NVIDIA Nemotron 3 Ultra (thinking always on) |
296
296
  | `pplx_kimi_k26` / `_thinking` | 1 Pro | Moonshot Kimi K2.6 |
297
297
  | `pplx_deep_research` | 1 Research | In-depth reports (**scarce monthly quota**) |
298
298
  | `pplx_usage` | FREE | Check remaining quotas |
@@ -317,9 +317,9 @@ For full MCP tool parameters: See [references/mcp-tools.md](references/mcp-tools
317
317
  | gpt54 | OpenAI | Toggle | GPT-5.4 (versatile) |
318
318
  | gpt55 | OpenAI | Toggle | GPT-5.5 (latest, Max tier) |
319
319
  | claude_sonnet | Anthropic | Toggle | Claude 4.6 Sonnet |
320
- | claude_opus | Anthropic | Toggle | Claude 4.7 Opus (Max tier) |
320
+ | claude_opus | Anthropic | Toggle | Claude 4.8 Opus (Max tier) |
321
321
  | gemini_pro | Google | Always | Gemini 3.1 Pro |
322
- | nemotron | NVIDIA | Always | Nemotron 3 Super 120B |
322
+ | nemotron | NVIDIA | Always | Nemotron 3 Ultra 550B |
323
323
  | kimi_k26 | Moonshot | Toggle | Kimi K2.6 |
324
324
 
325
325
  For full model details: See [references/models.md](references/models.md)
@@ -68,7 +68,7 @@ The API server accepts many model name variants:
68
68
  | `gpt-5.4`, `gpt-54`, `gpt54` | GPT-5.4 (versatile) |
69
69
  | `gpt-5.5`, `gpt-5-5`, `gpt-55`, `gpt55` | GPT-5.5 (latest, Max tier) |
70
70
  | `gemini-3.1-pro`, `gemini-3-pro`, `gemini-pro` | Gemini 3.1 Pro |
71
- | `nemotron-3-super`, `nemotron` | Nemotron 3 Super |
71
+ | `nemotron-3-ultra`, `nemotron` | Nemotron 3 Ultra |
72
72
 
73
73
  Unknown model names fall back to `perplexity-auto`.
74
74
 
@@ -96,10 +96,10 @@ pplx_<model>(
96
96
  | `pplx_gpt55_thinking` | GPT-5.5 (latest, Max tier) | Yes | 1 Pro |
97
97
  | `pplx_claude_sonnet` | Claude 4.6 Sonnet | No | 1 Pro |
98
98
  | `pplx_claude_sonnet_think` | Claude 4.6 Sonnet | Yes | 1 Pro |
99
- | `pplx_claude_opus` | Claude 4.7 Opus (Max tier) | No | 1 Pro |
100
- | `pplx_claude_opus_think` | Claude 4.7 Opus (Max tier) | Yes | 1 Pro |
99
+ | `pplx_claude_opus` | Claude 4.8 Opus (Max tier) | No | 1 Pro |
100
+ | `pplx_claude_opus_think` | Claude 4.8 Opus (Max tier) | Yes | 1 Pro |
101
101
  | `pplx_gemini_pro_think` | Gemini 3.1 Pro | Yes (always) | 1 Pro |
102
- | `pplx_nemotron_thinking` | Nemotron 3 Super | Yes (always) | 1 Pro |
102
+ | `pplx_nemotron_thinking` | Nemotron 3 Ultra | Yes (always) | 1 Pro |
103
103
  | `pplx_kimi_k26` | Kimi K2.6 | No | 1 Pro |
104
104
  | `pplx_kimi_k26_thinking` | Kimi K2.6 | Yes | 1 Pro |
105
105
 
@@ -45,8 +45,8 @@ Complete list of models available through Perplexity Web MCP.
45
45
  - **CLI:** `pwm ask "query" -m claude_sonnet` or `pwm ask "query" -m claude_sonnet -t`
46
46
  - **MCP:** `pplx_claude_sonnet(query)` or `pplx_claude_sonnet_think(query)`
47
47
 
48
- ### claude_opus (Anthropic Claude 4.7 Opus)
49
- - **Identifier:** `claude47opus` / `claude47opusthinking`
48
+ ### claude_opus (Anthropic Claude 4.8 Opus)
49
+ - **Identifier:** `claude48opus` / `claude48opusthinking`
50
50
  - **Thinking:** Toggle
51
51
  - **CLI:** `pwm ask "query" -m claude_opus` or `pwm ask "query" -m claude_opus -t`
52
52
  - **MCP:** `pplx_claude_opus(query)` or `pplx_claude_opus_think(query)`
@@ -59,12 +59,12 @@ Complete list of models available through Perplexity Web MCP.
59
59
  - **MCP:** `pplx_gemini_pro_think(query)` or `pplx_query(query, model="gemini_pro")`
60
60
  - **Notes:** Thinking is permanently enabled. The `-t` flag has no effect.
61
61
 
62
- ### nemotron (NVIDIA Nemotron 3 Super)
63
- - **Identifier:** `nv_nemotron_3_super`
62
+ ### nemotron (NVIDIA Nemotron 3 Ultra)
63
+ - **Identifier:** `nv_nemotron_3_ultra`
64
64
  - **Thinking:** Always on (no non-thinking variant)
65
65
  - **CLI:** `pwm ask "query" -m nemotron`
66
66
  - **MCP:** `pplx_nemotron_thinking(query)` or `pplx_query(query, model="nemotron")`
67
- - **Notes:** NVIDIA's Nemotron 3 Super 120B model. Thinking is permanently enabled.
67
+ - **Notes:** NVIDIA's Nemotron 3 Ultra 550B model. Thinking is permanently enabled.
68
68
 
69
69
  ### kimi_k26 (Moonshot Kimi K2.6)
70
70
  - **Identifier:** `kimik26instant` / `kimik26thinking`
@@ -213,16 +213,16 @@ def pplx_claude_sonnet_think(
213
213
 
214
214
  @mcp.tool
215
215
  def pplx_claude_opus(query: str, source_focus: SourceFocusName = "web", conversation_id: str | None = None) -> str:
216
- """Claude Opus 4.7 — Anthropic's most advanced reasoning model. COSTS 1 PRO SEARCH QUERY. Requires Max subscription."""
217
- return ask(query, Models.CLAUDE_47_OPUS, source_focus, conversation_id)
216
+ """Claude Opus 4.8 — Anthropic's most advanced reasoning model. COSTS 1 PRO SEARCH QUERY. Requires Max subscription."""
217
+ return ask(query, Models.CLAUDE_48_OPUS, source_focus, conversation_id)
218
218
 
219
219
 
220
220
  @mcp.tool
221
221
  def pplx_claude_opus_think(
222
222
  query: str, source_focus: SourceFocusName = "web", conversation_id: str | None = None
223
223
  ) -> str:
224
- """Claude Opus 4.7 Thinking — Anthropic's most advanced reasoning model with extended thinking. COSTS 1 PRO SEARCH QUERY. Requires Max subscription."""
225
- return ask(query, Models.CLAUDE_47_OPUS_THINKING, source_focus, conversation_id)
224
+ """Claude Opus 4.8 Thinking — Anthropic's most advanced reasoning model with extended thinking. COSTS 1 PRO SEARCH QUERY. Requires Max subscription."""
225
+ return ask(query, Models.CLAUDE_48_OPUS_THINKING, source_focus, conversation_id)
226
226
 
227
227
 
228
228
  @mcp.tool
@@ -235,8 +235,8 @@ def pplx_gemini_pro_think(query: str, source_focus: SourceFocusName = "web", con
235
235
  def pplx_nemotron_thinking(
236
236
  query: str, source_focus: SourceFocusName = "web", conversation_id: str | None = None
237
237
  ) -> str:
238
- """Nemotron 3 Super — NVIDIA's Nemotron 3 Super 120B model with extended thinking. COSTS 1 PRO SEARCH QUERY."""
239
- return ask(query, Models.NEMOTRON_3_SUPER, source_focus, conversation_id)
238
+ """Nemotron 3 Ultra — NVIDIA's Nemotron 3 Ultra 550B model with extended thinking. COSTS 1 PRO SEARCH QUERY."""
239
+ return ask(query, Models.NEMOTRON_3_ULTRA, source_focus, conversation_id)
240
240
 
241
241
 
242
242
  @mcp.tool
@@ -55,9 +55,18 @@ class Models:
55
55
  CLAUDE_47_OPUS_THINKING = Model(identifier="claude47opusthinking")
56
56
  """Claude Opus 4.7 Thinking - Anthropic's most advanced reasoning model (thinking)."""
57
57
 
58
+ CLAUDE_48_OPUS = Model(identifier="claude48opus")
59
+ """Claude Opus 4.8 - Anthropic's most advanced reasoning model."""
60
+
61
+ CLAUDE_48_OPUS_THINKING = Model(identifier="claude48opusthinking")
62
+ """Claude Opus 4.8 Thinking - Anthropic's most advanced reasoning model (thinking)."""
63
+
58
64
  NEMOTRON_3_SUPER = Model(identifier="nv_nemotron_3_super")
59
65
  """Nemotron 3 Super - NVIDIA's Nemotron 3 Super 120B model (thinking)."""
60
66
 
67
+ NEMOTRON_3_ULTRA = Model(identifier="nv_nemotron_3_ultra")
68
+ """Nemotron 3 Ultra - NVIDIA's Nemotron 3 Ultra 550B model (thinking)."""
69
+
61
70
  KIMI_K2_6 = Model(identifier="kimik26instant")
62
71
  """Kimi K2.6 - Moonshot AI's latest model."""
63
72
 
@@ -73,9 +73,9 @@ MODEL_METADATA: dict[str, ModelDefinition] = {
73
73
  "Anthropic",
74
74
  ),
75
75
  "claude_opus": ModelDefinition(
76
- Models.CLAUDE_47_OPUS,
77
- Models.CLAUDE_47_OPUS_THINKING,
78
- "Claude Opus 4.7",
76
+ Models.CLAUDE_48_OPUS,
77
+ Models.CLAUDE_48_OPUS_THINKING,
78
+ "Claude Opus 4.8",
79
79
  "Anthropic",
80
80
  minimum_tier="max",
81
81
  ),
@@ -86,9 +86,9 @@ MODEL_METADATA: dict[str, ModelDefinition] = {
86
86
  "Google",
87
87
  ),
88
88
  "nemotron": ModelDefinition(
89
- Models.NEMOTRON_3_SUPER,
90
- Models.NEMOTRON_3_SUPER,
91
- "Nemotron 3 Super",
89
+ Models.NEMOTRON_3_ULTRA,
90
+ Models.NEMOTRON_3_ULTRA,
91
+ "Nemotron 3 Ultra",
92
92
  "NVIDIA",
93
93
  ),
94
94
  "kimi_k26": ModelDefinition(Models.KIMI_K2_6, Models.KIMI_K2_6_THINKING, "Kimi K2.6", "Moonshot"),
@@ -535,7 +535,7 @@ def council_ask(
535
535
  Args:
536
536
  query: The question to ask all models.
537
537
  models: List of (display_name, Model) tuples. Defaults to
538
- GPT-5.4, Claude Opus 4.7, and Gemini 3.1 Pro.
538
+ GPT-5.4, Claude Opus 4.8, and Gemini 3.1 Pro.
539
539
  source_focus: Source focus for all queries.
540
540
  synthesize: Whether to run Sonar 2 synthesis (default chairman; still a web query).
541
541
  thinking: Use thinking model variants for default council members.
@@ -1,152 +0,0 @@
1
- """Diagnostic checks for perplexity-web-mcp installation.
2
-
3
- Validates installation, authentication, configuration, rate limits,
4
- and connectivity -- everything an AI agent or user needs to know
5
- before using the tool.
6
- """
7
-
8
- from __future__ import annotations
9
-
10
- from importlib import metadata
11
- import shutil
12
-
13
- from perplexity_web_mcp.token_store import TOKEN_FILE, load_token
14
-
15
-
16
- def _check(label: str, ok: bool, detail: str, fix: str = "") -> bool:
17
- """Print a check result line and return the status."""
18
- icon = "✓" if ok else "✗"
19
- line = f" {icon} {label}: {detail}"
20
- if not ok and fix:
21
- line += f" -> {fix}"
22
- print(line)
23
- return ok
24
-
25
-
26
- def cmd_doctor(args: list[str]) -> int:
27
- """Handle: pwm doctor [--verbose]"""
28
- verbose = "-v" in args or "--verbose" in args
29
- all_ok = True
30
-
31
- print("\nPerplexity Web MCP Doctor\n")
32
-
33
- # --- Installation ---
34
- print("Installation")
35
- try:
36
- version = metadata.version("perplexity-web-mcp-cli")
37
- _check("perplexity-web-mcp-cli", True, version)
38
- except metadata.PackageNotFoundError:
39
- all_ok = (
40
- _check("perplexity-web-mcp-cli", False, "not installed", "pip install perplexity-web-mcp-cli") and all_ok
41
- )
42
-
43
- pwm_path = shutil.which("pwm")
44
- _check("pwm", pwm_path is not None, pwm_path or "not in PATH", "pip install -e '.[mcp]'")
45
-
46
- pwm_mcp_path = shutil.which("pwm-mcp")
47
- all_ok = (
48
- _check("pwm-mcp", pwm_mcp_path is not None, pwm_mcp_path or "not in PATH", "pip install -e '.[mcp]'") and all_ok
49
- )
50
-
51
- try:
52
- import perplexity_web_mcp.api.server # noqa: F401
53
-
54
- _check("pwm api", True, "module available", "")
55
- except ImportError:
56
- _check("pwm api", False, "module not found", "pip install -e .")
57
-
58
- # --- Authentication ---
59
- print("\nAuthentication")
60
- token = load_token()
61
- token_exists = token is not None and len(token) > 10
62
-
63
- if token_exists:
64
- token_source = "file" if TOKEN_FILE.exists() else "env"
65
- _check("Token", True, f"present ({token_source}, {len(token)} chars)")
66
-
67
- from perplexity_web_mcp.cli.auth import get_user_info
68
-
69
- user_info = get_user_info(token)
70
- if user_info:
71
- _check("Account", True, f"{user_info.email}")
72
- _check("Subscription", True, user_info.tier_display)
73
- else:
74
- all_ok = _check("Account", False, "token invalid or expired", "pwm login") and all_ok
75
- else:
76
- all_ok = _check("Token", False, "not found", "pwm login") and all_ok
77
-
78
- # --- Rate Limits ---
79
- print("\nRate Limits")
80
- if token_exists:
81
- from perplexity_web_mcp.rate_limits import fetch_rate_limits
82
-
83
- limits = fetch_rate_limits(token)
84
- if limits:
85
- pro_ok = limits.remaining_pro > 0
86
- research_ok = limits.remaining_research > 0
87
- all_ok = (
88
- _check("Pro Search", pro_ok, f"{limits.remaining_pro} remaining", "wait for weekly reset") and all_ok
89
- )
90
- _check("Deep Research", research_ok, f"{limits.remaining_research} remaining", "wait for monthly reset")
91
- _check("Create Files & Apps", True, f"{limits.remaining_labs} remaining")
92
- _check("Browser Agent", True, f"{limits.remaining_agentic_research} remaining")
93
- else:
94
- all_ok = _check("Rate limits", False, "could not fetch", "check network connection") and all_ok
95
- else:
96
- _check("Rate limits", False, "skipped (no token)", "pwm login first")
97
-
98
- # --- MCP Configuration ---
99
- print("\nMCP Configuration")
100
- from perplexity_web_mcp.cli.setup import _get_tools, _is_configured_compat
101
-
102
- tools = _get_tools()
103
- any_configured = False
104
- for tool in tools:
105
- configured = _is_configured_compat(tool)
106
- if configured:
107
- any_configured = True
108
- label = tool.name
109
- if configured:
110
- _check(label, True, "configured")
111
- else:
112
- _check(label, False, "not configured", f"pwm setup add {tool.name}")
113
-
114
- if not any_configured:
115
- all_ok = False
116
-
117
- # --- Skill Installation ---
118
- print("\nSkill Installation")
119
- from perplexity_web_mcp.cli.skill import SKILL_DIR_NAME, _get_current_version, _get_installed_version, _get_targets
120
-
121
- skill_targets = _get_targets()
122
- current_ver = _get_current_version()
123
- any_skill = False
124
- for t in skill_targets:
125
- user_ver = _get_installed_version(t.user_dir / SKILL_DIR_NAME)
126
- if user_ver:
127
- any_skill = True
128
- if user_ver == current_ver:
129
- _check(t.name, True, f"v{user_ver}")
130
- else:
131
- _check(t.name, True, f"v{user_ver} (outdated, current: v{current_ver})")
132
- elif verbose:
133
- _check(t.name, False, "not installed", f"pwm skill install {t.name}")
134
-
135
- if not any_skill:
136
- _check("Skills", False, "no skills installed", "pwm skill install claude-code")
137
-
138
- # --- Token File Permissions ---
139
- if verbose and TOKEN_FILE.exists():
140
- print("\nSecurity")
141
- mode = oct(TOKEN_FILE.stat().st_mode)[-3:]
142
- secure = mode == "600"
143
- all_ok = _check("Token permissions", secure, mode, "chmod 600 ~/.config/perplexity-web-mcp/token") and all_ok
144
-
145
- # --- Summary ---
146
- print()
147
- if all_ok:
148
- print("✓ All checks passed!")
149
- else:
150
- print("Some checks failed. See suggestions above (->).")
151
-
152
- return 0 if all_ok else 1