proxy-doctor 0.1.0__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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Jiansen He
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,195 @@
1
+ Metadata-Version: 2.2
2
+ Name: proxy-doctor
3
+ Version: 0.1.0
4
+ Summary: Diagnose proxy misconfigurations that break AI coding tools (Cursor, VS Code, Windsurf)
5
+ Author: Jiansen He
6
+ License: MIT
7
+ Keywords: proxy,cursor,vscode,windsurf,network,diagnostic,mcp
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Environment :: Console
10
+ Classifier: Environment :: MacOS X
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Operating System :: MacOS
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Topic :: Software Development :: Quality Assurance
15
+ Classifier: Topic :: System :: Networking
16
+ Requires-Python: >=3.9
17
+ Description-Content-Type: text/markdown
18
+ License-File: LICENSE
19
+ Provides-Extra: mcp
20
+ Requires-Dist: fastmcp>=2.0.0; extra == "mcp"
21
+ Provides-Extra: dev
22
+ Requires-Dist: ruff; extra == "dev"
23
+ Requires-Dist: pytest; extra == "dev"
24
+
25
+ # proxy-doctor
26
+
27
+ **Diagnose proxy misconfigurations that break AI coding tools.**
28
+
29
+ When your browser works fine but Cursor / VS Code / Windsurf AI features don't — proxy-doctor tells you exactly why and how to fix it.
30
+
31
+ ## The Problem
32
+
33
+ AI coding tools (Cursor, VS Code with Copilot, Windsurf) rely on long-lived streaming connections (SSE/HTTP2) that break when:
34
+
35
+ - Your system proxy points to a localhost port where nothing is listening
36
+ - A VPN/proxy app was closed but its settings linger in macOS system preferences
37
+ - Your editor inherited stale proxy environment variables from `launchctl`
38
+ - The proxy is running but buffers streaming responses, breaking AI completions
39
+
40
+ The result: **"browser works, AI editor doesn't"** — the most common and frustrating developer experience.
41
+
42
+ ## What It Checks
43
+
44
+ proxy-doctor inspects 5 layers of your macOS proxy configuration:
45
+
46
+ | Layer | What | How |
47
+ |-------|------|-----|
48
+ | 1. System Proxy | Web/HTTPS/SOCKS proxy across all network services | `networksetup` |
49
+ | 2. Residual Values | Disabled proxies with stale localhost addresses | Parse disabled-but-set entries |
50
+ | 3. Port Health | Whether referenced proxy ports are actually listening | `socket.connect()` |
51
+ | 4. Editor Config | `settings.json`, `argv.json`, recent error logs | File read + pattern match |
52
+ | 5. GUI Environment | `http_proxy`/`https_proxy` in GUI app context | `launchctl getenv` |
53
+
54
+ ## Quick Start
55
+
56
+ ### CLI
57
+
58
+ ```bash
59
+ # Install
60
+ pip install proxy-doctor
61
+
62
+ # Run diagnosis (JSON output — default, optimized for AI agents)
63
+ proxy-doctor check
64
+
65
+ # Run diagnosis (human-readable output)
66
+ proxy-doctor check --human
67
+
68
+ # Show recommended fixes
69
+ proxy-doctor fix
70
+
71
+ # Check a different editor
72
+ proxy-doctor check --editor vscode
73
+ ```
74
+
75
+ ### As an MCP Tool (for AI agents)
76
+
77
+ proxy-doctor ships as an MCP server that AI agents can call directly:
78
+
79
+ ```bash
80
+ # Install with MCP support
81
+ pip install proxy-doctor[mcp]
82
+
83
+ # Run MCP server
84
+ python -m proxy_doctor.mcp_server
85
+ ```
86
+
87
+ Add to your MCP configuration (e.g., Cursor `~/.cursor/mcp.json`):
88
+
89
+ ```json
90
+ {
91
+ "mcpServers": {
92
+ "proxy-doctor": {
93
+ "command": "python",
94
+ "args": ["-m", "proxy_doctor.mcp_server"]
95
+ }
96
+ }
97
+ }
98
+ ```
99
+
100
+ Your AI agent can then call:
101
+ - `diagnose_proxy(editor="cursor")` — full 5-layer diagnosis
102
+ - `list_fixes(editor="cursor")` — just the recommended fixes
103
+ - `supported_editors()` — list available editors
104
+
105
+ ### Menu Bar (SwiftBar)
106
+
107
+ ```bash
108
+ # If SwiftBar is installed
109
+ cp plugins/swiftbar/proxy-doctor.5m.sh ~/Library/Application\ Support/SwiftBar/Plugins/
110
+ chmod +x ~/Library/Application\ Support/SwiftBar/Plugins/proxy-doctor.5m.sh
111
+ ```
112
+
113
+ Shows a green/red/orange indicator in your menu bar with one-click diagnosis.
114
+
115
+ ## Example Output
116
+
117
+ ### Unhealthy (Case A: dead proxy port)
118
+
119
+ ```json
120
+ {
121
+ "status": "unhealthy",
122
+ "diagnosis": {
123
+ "case": "A",
124
+ "root_cause": "Editor is configured to use proxy at 127.0.0.1:10903, but no process is listening on that port.",
125
+ "confidence": "high",
126
+ "source": "system proxy (Wi-Fi (http))",
127
+ "browser_explanation": "Browser may use a different proxy path (e.g. browser-only mode) or fall back to a direct connection."
128
+ },
129
+ "fixes": [
130
+ {
131
+ "fix_id": "clear-system-http-wi-fi",
132
+ "description": "Disable http proxy on Wi-Fi",
133
+ "command": "networksetup -setwebproxystate \"Wi-Fi\" off",
134
+ "risk": "low"
135
+ }
136
+ ]
137
+ }
138
+ ```
139
+
140
+ ### Healthy
141
+
142
+ ```
143
+ proxy-doctor v0.1.0
144
+ Editor: cursor | Platform: Darwin
145
+
146
+ Status: HEALTHY
147
+
148
+ No proxy contamination detected.
149
+ ```
150
+
151
+ ## Supported Editors
152
+
153
+ | Editor | Config Detection | Log Scanning | Status |
154
+ |--------|-----------------|-------------|--------|
155
+ | Cursor | yes | yes | **supported** |
156
+ | VS Code | yes | yes | supported |
157
+ | Windsurf | yes | yes | supported |
158
+ | Claude Desktop | planned | — | future |
159
+ | Zed | planned | planned | future |
160
+
161
+ ## How It Works
162
+
163
+ proxy-doctor identifies three failure patterns:
164
+
165
+ **Case A — Dead proxy port (high confidence):** Your system or editor points to `127.0.0.1:port` but nothing is listening. This happens when a VPN/proxy app is closed but its settings remain.
166
+
167
+ **Case B — Streaming broken (medium confidence):** A proxy is running, but it buffers SSE/streaming connections that AI editors depend on. Common with browser-only proxy modes.
168
+
169
+ **Case C — Path mismatch (medium confidence):** Browser and editor use different proxy paths. Browser works via a dedicated proxy route; editor inherits a stale or incompatible one.
170
+
171
+ ## Platform Support
172
+
173
+ - **macOS**: Full support (system proxy, launchctl, networksetup)
174
+ - **Linux**: Partial (editor config + environment variables; no networksetup)
175
+ - **Windows**: Not yet supported
176
+
177
+ ## Development
178
+
179
+ ```bash
180
+ git clone https://github.com/Jiansen/proxy-doctor.git
181
+ cd proxy-doctor
182
+
183
+ # Install in development mode
184
+ pip install -e ".[dev,mcp]"
185
+
186
+ # Run tests
187
+ make test
188
+
189
+ # Run linter
190
+ make lint
191
+ ```
192
+
193
+ ## License
194
+
195
+ MIT
@@ -0,0 +1,171 @@
1
+ # proxy-doctor
2
+
3
+ **Diagnose proxy misconfigurations that break AI coding tools.**
4
+
5
+ When your browser works fine but Cursor / VS Code / Windsurf AI features don't — proxy-doctor tells you exactly why and how to fix it.
6
+
7
+ ## The Problem
8
+
9
+ AI coding tools (Cursor, VS Code with Copilot, Windsurf) rely on long-lived streaming connections (SSE/HTTP2) that break when:
10
+
11
+ - Your system proxy points to a localhost port where nothing is listening
12
+ - A VPN/proxy app was closed but its settings linger in macOS system preferences
13
+ - Your editor inherited stale proxy environment variables from `launchctl`
14
+ - The proxy is running but buffers streaming responses, breaking AI completions
15
+
16
+ The result: **"browser works, AI editor doesn't"** — the most common and frustrating developer experience.
17
+
18
+ ## What It Checks
19
+
20
+ proxy-doctor inspects 5 layers of your macOS proxy configuration:
21
+
22
+ | Layer | What | How |
23
+ |-------|------|-----|
24
+ | 1. System Proxy | Web/HTTPS/SOCKS proxy across all network services | `networksetup` |
25
+ | 2. Residual Values | Disabled proxies with stale localhost addresses | Parse disabled-but-set entries |
26
+ | 3. Port Health | Whether referenced proxy ports are actually listening | `socket.connect()` |
27
+ | 4. Editor Config | `settings.json`, `argv.json`, recent error logs | File read + pattern match |
28
+ | 5. GUI Environment | `http_proxy`/`https_proxy` in GUI app context | `launchctl getenv` |
29
+
30
+ ## Quick Start
31
+
32
+ ### CLI
33
+
34
+ ```bash
35
+ # Install
36
+ pip install proxy-doctor
37
+
38
+ # Run diagnosis (JSON output — default, optimized for AI agents)
39
+ proxy-doctor check
40
+
41
+ # Run diagnosis (human-readable output)
42
+ proxy-doctor check --human
43
+
44
+ # Show recommended fixes
45
+ proxy-doctor fix
46
+
47
+ # Check a different editor
48
+ proxy-doctor check --editor vscode
49
+ ```
50
+
51
+ ### As an MCP Tool (for AI agents)
52
+
53
+ proxy-doctor ships as an MCP server that AI agents can call directly:
54
+
55
+ ```bash
56
+ # Install with MCP support
57
+ pip install proxy-doctor[mcp]
58
+
59
+ # Run MCP server
60
+ python -m proxy_doctor.mcp_server
61
+ ```
62
+
63
+ Add to your MCP configuration (e.g., Cursor `~/.cursor/mcp.json`):
64
+
65
+ ```json
66
+ {
67
+ "mcpServers": {
68
+ "proxy-doctor": {
69
+ "command": "python",
70
+ "args": ["-m", "proxy_doctor.mcp_server"]
71
+ }
72
+ }
73
+ }
74
+ ```
75
+
76
+ Your AI agent can then call:
77
+ - `diagnose_proxy(editor="cursor")` — full 5-layer diagnosis
78
+ - `list_fixes(editor="cursor")` — just the recommended fixes
79
+ - `supported_editors()` — list available editors
80
+
81
+ ### Menu Bar (SwiftBar)
82
+
83
+ ```bash
84
+ # If SwiftBar is installed
85
+ cp plugins/swiftbar/proxy-doctor.5m.sh ~/Library/Application\ Support/SwiftBar/Plugins/
86
+ chmod +x ~/Library/Application\ Support/SwiftBar/Plugins/proxy-doctor.5m.sh
87
+ ```
88
+
89
+ Shows a green/red/orange indicator in your menu bar with one-click diagnosis.
90
+
91
+ ## Example Output
92
+
93
+ ### Unhealthy (Case A: dead proxy port)
94
+
95
+ ```json
96
+ {
97
+ "status": "unhealthy",
98
+ "diagnosis": {
99
+ "case": "A",
100
+ "root_cause": "Editor is configured to use proxy at 127.0.0.1:10903, but no process is listening on that port.",
101
+ "confidence": "high",
102
+ "source": "system proxy (Wi-Fi (http))",
103
+ "browser_explanation": "Browser may use a different proxy path (e.g. browser-only mode) or fall back to a direct connection."
104
+ },
105
+ "fixes": [
106
+ {
107
+ "fix_id": "clear-system-http-wi-fi",
108
+ "description": "Disable http proxy on Wi-Fi",
109
+ "command": "networksetup -setwebproxystate \"Wi-Fi\" off",
110
+ "risk": "low"
111
+ }
112
+ ]
113
+ }
114
+ ```
115
+
116
+ ### Healthy
117
+
118
+ ```
119
+ proxy-doctor v0.1.0
120
+ Editor: cursor | Platform: Darwin
121
+
122
+ Status: HEALTHY
123
+
124
+ No proxy contamination detected.
125
+ ```
126
+
127
+ ## Supported Editors
128
+
129
+ | Editor | Config Detection | Log Scanning | Status |
130
+ |--------|-----------------|-------------|--------|
131
+ | Cursor | yes | yes | **supported** |
132
+ | VS Code | yes | yes | supported |
133
+ | Windsurf | yes | yes | supported |
134
+ | Claude Desktop | planned | — | future |
135
+ | Zed | planned | planned | future |
136
+
137
+ ## How It Works
138
+
139
+ proxy-doctor identifies three failure patterns:
140
+
141
+ **Case A — Dead proxy port (high confidence):** Your system or editor points to `127.0.0.1:port` but nothing is listening. This happens when a VPN/proxy app is closed but its settings remain.
142
+
143
+ **Case B — Streaming broken (medium confidence):** A proxy is running, but it buffers SSE/streaming connections that AI editors depend on. Common with browser-only proxy modes.
144
+
145
+ **Case C — Path mismatch (medium confidence):** Browser and editor use different proxy paths. Browser works via a dedicated proxy route; editor inherits a stale or incompatible one.
146
+
147
+ ## Platform Support
148
+
149
+ - **macOS**: Full support (system proxy, launchctl, networksetup)
150
+ - **Linux**: Partial (editor config + environment variables; no networksetup)
151
+ - **Windows**: Not yet supported
152
+
153
+ ## Development
154
+
155
+ ```bash
156
+ git clone https://github.com/Jiansen/proxy-doctor.git
157
+ cd proxy-doctor
158
+
159
+ # Install in development mode
160
+ pip install -e ".[dev,mcp]"
161
+
162
+ # Run tests
163
+ make test
164
+
165
+ # Run linter
166
+ make lint
167
+ ```
168
+
169
+ ## License
170
+
171
+ MIT
@@ -0,0 +1,46 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68.0,<77.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "proxy-doctor"
7
+ version = "0.1.0"
8
+ description = "Diagnose proxy misconfigurations that break AI coding tools (Cursor, VS Code, Windsurf)"
9
+ readme = "README.md"
10
+ license = {text = "MIT"}
11
+ requires-python = ">=3.9"
12
+ authors = [{name = "Jiansen He"}]
13
+ keywords = ["proxy", "cursor", "vscode", "windsurf", "network", "diagnostic", "mcp"]
14
+ classifiers = [
15
+ "Development Status :: 3 - Alpha",
16
+ "Environment :: Console",
17
+ "Environment :: MacOS X",
18
+ "Intended Audience :: Developers",
19
+ "Operating System :: MacOS",
20
+ "Programming Language :: Python :: 3",
21
+ "Topic :: Software Development :: Quality Assurance",
22
+ "Topic :: System :: Networking",
23
+ ]
24
+
25
+ [project.optional-dependencies]
26
+ mcp = ["fastmcp>=2.0.0"]
27
+ dev = ["ruff", "pytest"]
28
+
29
+ [project.scripts]
30
+ proxy-doctor = "proxy_doctor.cli:main"
31
+
32
+ [project.entry-points."mcp.servers"]
33
+ proxy-doctor = "proxy_doctor.mcp_server:mcp"
34
+
35
+ [tool.setuptools.packages.find]
36
+ where = ["src"]
37
+
38
+ [tool.ruff]
39
+ target-version = "py39"
40
+ line-length = 100
41
+
42
+ [tool.ruff.lint]
43
+ select = ["E", "F", "W", "I"]
44
+
45
+ [tool.pytest.ini_options]
46
+ testpaths = ["tests"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,3 @@
1
+ """proxy-doctor: Diagnose proxy misconfigurations that break AI coding tools."""
2
+
3
+ __version__ = "0.1.0"
@@ -0,0 +1,7 @@
1
+ """Allow running as: python3 -m proxy_doctor"""
2
+
3
+ import sys
4
+
5
+ from proxy_doctor.cli import main
6
+
7
+ sys.exit(main())
@@ -0,0 +1,126 @@
1
+ """CLI entry point for proxy-doctor.
2
+
3
+ Usage:
4
+ proxy-doctor check [--json | --human] [--editor NAME]
5
+ proxy-doctor fix [--editor NAME]
6
+ proxy-doctor editors
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import argparse
12
+ import json
13
+ import sys
14
+
15
+ from proxy_doctor import __version__
16
+ from proxy_doctor.core import run_diagnosis
17
+ from proxy_doctor.editors import list_editors
18
+
19
+
20
+ def build_parser() -> argparse.ArgumentParser:
21
+ parser = argparse.ArgumentParser(
22
+ prog="proxy-doctor",
23
+ description="Diagnose proxy misconfigurations that break AI coding tools.",
24
+ )
25
+ parser.add_argument(
26
+ "--version", action="version", version=f"proxy-doctor {__version__}",
27
+ )
28
+
29
+ sub = parser.add_subparsers(dest="command")
30
+
31
+ # check
32
+ p_check = sub.add_parser("check", help="Run proxy diagnosis")
33
+ fmt = p_check.add_mutually_exclusive_group()
34
+ fmt.add_argument("--json", dest="output_json", action="store_true", default=True,
35
+ help="Output JSON (default)")
36
+ fmt.add_argument("--human", dest="output_json", action="store_false",
37
+ help="Output human-readable text")
38
+ p_check.add_argument("--editor", default="cursor",
39
+ help="Editor to check (default: cursor)")
40
+ p_check.add_argument("--markdown", metavar="FILE",
41
+ help="Also write markdown report to FILE")
42
+
43
+ # fix
44
+ p_fix = sub.add_parser("fix", help="Show recommended fixes")
45
+ p_fix.add_argument("--editor", default="cursor",
46
+ help="Editor to check (default: cursor)")
47
+
48
+ # editors
49
+ sub.add_parser("editors", help="List supported editors")
50
+
51
+ return parser
52
+
53
+
54
+ def cmd_check(args: argparse.Namespace) -> int:
55
+ report = run_diagnosis(args.editor)
56
+
57
+ if args.output_json:
58
+ print(report.to_json())
59
+ else:
60
+ print(report.to_human())
61
+
62
+ if args.markdown:
63
+ try:
64
+ with open(args.markdown, "w", encoding="utf-8") as f:
65
+ f.write(f"# proxy-doctor report\n\n```\n{report.to_human()}\n```\n\n")
66
+ f.write(f"## Evidence (JSON)\n\n```json\n{report.to_json()}\n```\n")
67
+ print(f"\nReport written to {args.markdown}", file=sys.stderr)
68
+ except OSError as e:
69
+ print(f"Failed to write report: {e}", file=sys.stderr)
70
+
71
+ return 0 if report.diagnosis.status == "healthy" else 1
72
+
73
+
74
+ def cmd_fix(args: argparse.Namespace) -> int:
75
+ report = run_diagnosis(args.editor)
76
+
77
+ if not report.diagnosis.fixes:
78
+ print(json.dumps({"status": "healthy", "fixes": []}, indent=2))
79
+ return 0
80
+
81
+ fixes_out = {
82
+ "status": report.diagnosis.status,
83
+ "case": report.diagnosis.case,
84
+ "fixes": [
85
+ {
86
+ "fix_id": f.fix_id,
87
+ "description": f.description,
88
+ "command": f.command,
89
+ "risk": f.risk,
90
+ "layer": f.layer,
91
+ }
92
+ for f in report.diagnosis.fixes
93
+ ],
94
+ }
95
+ print(json.dumps(fixes_out, indent=2))
96
+ return 0 if report.diagnosis.status == "healthy" else 1
97
+
98
+
99
+ def cmd_editors(_args: argparse.Namespace) -> int:
100
+ editors = list_editors()
101
+ print(json.dumps({"supported_editors": editors}, indent=2))
102
+ return 0
103
+
104
+
105
+ def main() -> int:
106
+ parser = build_parser()
107
+ args = parser.parse_args()
108
+
109
+ if args.command is None:
110
+ parser.print_help()
111
+ return 0
112
+
113
+ dispatch = {
114
+ "check": cmd_check,
115
+ "fix": cmd_fix,
116
+ "editors": cmd_editors,
117
+ }
118
+ handler = dispatch.get(args.command)
119
+ if handler is None:
120
+ parser.print_help()
121
+ return 2
122
+ return handler(args)
123
+
124
+
125
+ if __name__ == "__main__":
126
+ sys.exit(main())