perplexity-web-mcp-cli 0.12.3__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.3 → perplexity_web_mcp_cli-0.12.4}/PKG-INFO +1 -1
  2. {perplexity_web_mcp_cli-0.12.3 → perplexity_web_mcp_cli-0.12.4}/pyproject.toml +1 -1
  3. perplexity_web_mcp_cli-0.12.4/src/perplexity_web_mcp/cli/doctor.py +208 -0
  4. perplexity_web_mcp_cli-0.12.3/src/perplexity_web_mcp/cli/doctor.py +0 -152
  5. {perplexity_web_mcp_cli-0.12.3 → perplexity_web_mcp_cli-0.12.4}/README.md +0 -0
  6. {perplexity_web_mcp_cli-0.12.3 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/__init__.py +0 -0
  7. {perplexity_web_mcp_cli-0.12.3 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/api/__init__.py +0 -0
  8. {perplexity_web_mcp_cli-0.12.3 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/api/responses.py +0 -0
  9. {perplexity_web_mcp_cli-0.12.3 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/api/server.py +0 -0
  10. {perplexity_web_mcp_cli-0.12.3 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/api/session_manager.py +0 -0
  11. {perplexity_web_mcp_cli-0.12.3 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/api/tool_calling.py +0 -0
  12. {perplexity_web_mcp_cli-0.12.3 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/cli/__init__.py +0 -0
  13. {perplexity_web_mcp_cli-0.12.3 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/cli/ai_doc.py +0 -0
  14. {perplexity_web_mcp_cli-0.12.3 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/cli/auth.py +0 -0
  15. {perplexity_web_mcp_cli-0.12.3 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/cli/hack.py +0 -0
  16. {perplexity_web_mcp_cli-0.12.3 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/cli/main.py +0 -0
  17. {perplexity_web_mcp_cli-0.12.3 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/cli/setup.py +0 -0
  18. {perplexity_web_mcp_cli-0.12.3 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/cli/skill.py +0 -0
  19. {perplexity_web_mcp_cli-0.12.3 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/config.py +0 -0
  20. {perplexity_web_mcp_cli-0.12.3 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/constants.py +0 -0
  21. {perplexity_web_mcp_cli-0.12.3 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/core.py +0 -0
  22. {perplexity_web_mcp_cli-0.12.3 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/council.py +0 -0
  23. {perplexity_web_mcp_cli-0.12.3 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/data/SKILL.md +0 -0
  24. {perplexity_web_mcp_cli-0.12.3 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/data/references/api-endpoints.md +0 -0
  25. {perplexity_web_mcp_cli-0.12.3 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/data/references/mcp-tools.md +0 -0
  26. {perplexity_web_mcp_cli-0.12.3 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/data/references/models.md +0 -0
  27. {perplexity_web_mcp_cli-0.12.3 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/enums.py +0 -0
  28. {perplexity_web_mcp_cli-0.12.3 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/exceptions.py +0 -0
  29. {perplexity_web_mcp_cli-0.12.3 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/http.py +0 -0
  30. {perplexity_web_mcp_cli-0.12.3 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/limits.py +0 -0
  31. {perplexity_web_mcp_cli-0.12.3 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/logging.py +0 -0
  32. {perplexity_web_mcp_cli-0.12.3 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/mcp/__init__.py +0 -0
  33. {perplexity_web_mcp_cli-0.12.3 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/mcp/__main__.py +0 -0
  34. {perplexity_web_mcp_cli-0.12.3 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/mcp/server.py +0 -0
  35. {perplexity_web_mcp_cli-0.12.3 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/models.py +0 -0
  36. {perplexity_web_mcp_cli-0.12.3 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/py.typed +0 -0
  37. {perplexity_web_mcp_cli-0.12.3 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/rate_limits.py +0 -0
  38. {perplexity_web_mcp_cli-0.12.3 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/resilience.py +0 -0
  39. {perplexity_web_mcp_cli-0.12.3 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/router.py +0 -0
  40. {perplexity_web_mcp_cli-0.12.3 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/sessions.py +0 -0
  41. {perplexity_web_mcp_cli-0.12.3 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/shared.py +0 -0
  42. {perplexity_web_mcp_cli-0.12.3 → perplexity_web_mcp_cli-0.12.4}/src/perplexity_web_mcp/token_store.py +0 -0
  43. {perplexity_web_mcp_cli-0.12.3 → 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.3
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
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "perplexity-web-mcp-cli"
3
- version = "0.12.3"
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"
@@ -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
@@ -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