sallyport 0.3.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,43 @@
1
+ # OS / editors
2
+ .DS_Store
3
+ *.swp
4
+
5
+ # Python
6
+ __pycache__/
7
+ *.pyc
8
+ *.egg-info/
9
+ build/
10
+ .venv/
11
+ .mypy_cache/
12
+ .ruff_cache/
13
+ .pytest_cache/
14
+
15
+ # Node / extension
16
+ node_modules/
17
+ dist/
18
+ *.log
19
+ coverage/
20
+ .coverage
21
+ .coverage.*
22
+ htmlcov/
23
+ *.tsbuildinfo
24
+ *.zip
25
+ *.crx
26
+ *.pem
27
+
28
+ # Secrets (just in case anyone runs from-repo)
29
+ secret
30
+ .config/
31
+ .env
32
+ .env.*
33
+
34
+ # Local editor / tooling files
35
+ CLAUDE.md
36
+ .claude/
37
+ .mcp.json
38
+ .vscode/
39
+ .idea/
40
+
41
+ # Local-only reference material (not for redistribution)
42
+ kimi-reference/
43
+ ANALYSIS.md
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ginkida
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,83 @@
1
+ Metadata-Version: 2.4
2
+ Name: sallyport
3
+ Version: 0.3.0
4
+ Summary: MCP server bridging Claude Code to a browser extension over WS+HMAC
5
+ Project-URL: Homepage, https://github.com/ginkida/sallyport
6
+ Project-URL: Repository, https://github.com/ginkida/sallyport
7
+ Project-URL: Issues, https://github.com/ginkida/sallyport/issues
8
+ Project-URL: Changelog, https://github.com/ginkida/sallyport/blob/main/CHANGELOG.md
9
+ Author: ginkida
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: ai-agents,anthropic,browser-automation,chrome,claude,claude-code,hmac,mcp,model-context-protocol,security
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Environment :: Console
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Topic :: Internet :: WWW/HTTP :: Browsers
22
+ Classifier: Topic :: Security
23
+ Classifier: Topic :: Software Development
24
+ Requires-Python: >=3.10
25
+ Requires-Dist: mcp<2.0.0,>=1.0.0
26
+ Requires-Dist: websockets<17.0,>=13.0
27
+ Provides-Extra: dev
28
+ Requires-Dist: mypy>=1.10; extra == 'dev'
29
+ Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
30
+ Requires-Dist: pytest-cov>=5.0; extra == 'dev'
31
+ Requires-Dist: pytest>=8.0; extra == 'dev'
32
+ Requires-Dist: ruff>=0.6; extra == 'dev'
33
+ Description-Content-Type: text/markdown
34
+
35
+ # sallyport
36
+
37
+ The Python MCP-server half of **[Sallyport](https://github.com/ginkida/sallyport)** —
38
+ a security-first bridge between Claude Code (or any MCP client) and your Chrome,
39
+ with explicit trust boundaries instead of implicit ones.
40
+
41
+ ```
42
+ Claude Code ── MCP/stdio ──▶ daemon (this package) ── WS+HMAC ──▶ extension (MV3) ── CDP ──▶ Chrome
43
+ ```
44
+
45
+ The daemon speaks MCP on stdio and hosts an HMAC-authenticated WebSocket server
46
+ on `127.0.0.1:10086` that the companion Chrome extension connects into. Every
47
+ frame is signed (HMAC-SHA256 + timestamp + nonce); the extension enforces a
48
+ per-domain allowlist and a per-domain opt-in for arbitrary JS.
49
+
50
+ ## Install
51
+
52
+ ```sh
53
+ pip install sallyport
54
+ ```
55
+
56
+ The package installs the `sallyport-daemon` console command.
57
+
58
+ ## Quickstart
59
+
60
+ ```sh
61
+ sallyport-daemon doctor # check Python, secret file + perms, port; print the pairing block
62
+ claude mcp add sallyport sallyport-daemon # register with Claude Code
63
+ ```
64
+
65
+ Then load the unpacked extension (or the release zip) from the
66
+ [main repository](https://github.com/ginkida/sallyport) and paste the pairing
67
+ block into its popup.
68
+
69
+ - `sallyport-daemon list-tools` — print the tool catalogue (no daemon start)
70
+ - `sallyport-daemon serve` — WS-only mode (no MCP) for wire testing
71
+ - `sallyport-daemon exec <tool> k=v …` — fire one tool from the shell
72
+
73
+ ## Security
74
+
75
+ The full threat model, the load-bearing invariants, and known limitations live
76
+ in [SECURITY.md](https://github.com/ginkida/sallyport/blob/main/SECURITY.md).
77
+ In short: loopback-only bind, HMAC on every frame, a domain allowlist enforced
78
+ in the extension, per-domain `evaluate` opt-in, password-field gates, and
79
+ daemon-side filesystem sandboxes for `upload`/`save_to_file`.
80
+
81
+ ## License
82
+
83
+ MIT — see [LICENSE](https://github.com/ginkida/sallyport/blob/main/LICENSE).
@@ -0,0 +1,49 @@
1
+ # sallyport
2
+
3
+ The Python MCP-server half of **[Sallyport](https://github.com/ginkida/sallyport)** —
4
+ a security-first bridge between Claude Code (or any MCP client) and your Chrome,
5
+ with explicit trust boundaries instead of implicit ones.
6
+
7
+ ```
8
+ Claude Code ── MCP/stdio ──▶ daemon (this package) ── WS+HMAC ──▶ extension (MV3) ── CDP ──▶ Chrome
9
+ ```
10
+
11
+ The daemon speaks MCP on stdio and hosts an HMAC-authenticated WebSocket server
12
+ on `127.0.0.1:10086` that the companion Chrome extension connects into. Every
13
+ frame is signed (HMAC-SHA256 + timestamp + nonce); the extension enforces a
14
+ per-domain allowlist and a per-domain opt-in for arbitrary JS.
15
+
16
+ ## Install
17
+
18
+ ```sh
19
+ pip install sallyport
20
+ ```
21
+
22
+ The package installs the `sallyport-daemon` console command.
23
+
24
+ ## Quickstart
25
+
26
+ ```sh
27
+ sallyport-daemon doctor # check Python, secret file + perms, port; print the pairing block
28
+ claude mcp add sallyport sallyport-daemon # register with Claude Code
29
+ ```
30
+
31
+ Then load the unpacked extension (or the release zip) from the
32
+ [main repository](https://github.com/ginkida/sallyport) and paste the pairing
33
+ block into its popup.
34
+
35
+ - `sallyport-daemon list-tools` — print the tool catalogue (no daemon start)
36
+ - `sallyport-daemon serve` — WS-only mode (no MCP) for wire testing
37
+ - `sallyport-daemon exec <tool> k=v …` — fire one tool from the shell
38
+
39
+ ## Security
40
+
41
+ The full threat model, the load-bearing invariants, and known limitations live
42
+ in [SECURITY.md](https://github.com/ginkida/sallyport/blob/main/SECURITY.md).
43
+ In short: loopback-only bind, HMAC on every frame, a domain allowlist enforced
44
+ in the extension, per-domain `evaluate` opt-in, password-field gates, and
45
+ daemon-side filesystem sandboxes for `upload`/`save_to_file`.
46
+
47
+ ## License
48
+
49
+ MIT — see [LICENSE](https://github.com/ginkida/sallyport/blob/main/LICENSE).
@@ -0,0 +1,118 @@
1
+ [project]
2
+ name = "sallyport"
3
+ version = "0.3.0"
4
+ description = "MCP server bridging Claude Code to a browser extension over WS+HMAC"
5
+ readme = "README.md"
6
+ license = "MIT"
7
+ license-files = ["LICENSE"]
8
+ requires-python = ">=3.10"
9
+ authors = [{ name = "ginkida" }]
10
+ keywords = [
11
+ "mcp",
12
+ "model-context-protocol",
13
+ "claude",
14
+ "claude-code",
15
+ "anthropic",
16
+ "browser-automation",
17
+ "chrome",
18
+ "security",
19
+ "hmac",
20
+ "ai-agents",
21
+ ]
22
+ classifiers = [
23
+ "Development Status :: 4 - Beta",
24
+ "Intended Audience :: Developers",
25
+ "Environment :: Console",
26
+ "Operating System :: OS Independent",
27
+ "Programming Language :: Python :: 3",
28
+ "Programming Language :: Python :: 3.10",
29
+ "Programming Language :: Python :: 3.11",
30
+ "Programming Language :: Python :: 3.12",
31
+ "Topic :: Software Development",
32
+ "Topic :: Internet :: WWW/HTTP :: Browsers",
33
+ "Topic :: Security",
34
+ ]
35
+ dependencies = [
36
+ # Upper-bounded at the next major: the MCP SDK churns its API across the
37
+ # 1.x line, so an unbounded floor would let a fresh install pull a future
38
+ # release that breaks startup. Tested against mcp 1.26.0 / websockets 16.0.
39
+ "mcp>=1.0.0,<2.0.0",
40
+ "websockets>=13.0,<17.0",
41
+ ]
42
+
43
+ [project.optional-dependencies]
44
+ dev = [
45
+ "pytest>=8.0",
46
+ "pytest-asyncio>=0.23",
47
+ "pytest-cov>=5.0",
48
+ "ruff>=0.6",
49
+ "mypy>=1.10",
50
+ ]
51
+
52
+ [project.scripts]
53
+ sallyport-daemon = "sallyport_daemon.__main__:main"
54
+
55
+ [project.urls]
56
+ Homepage = "https://github.com/ginkida/sallyport"
57
+ Repository = "https://github.com/ginkida/sallyport"
58
+ Issues = "https://github.com/ginkida/sallyport/issues"
59
+ Changelog = "https://github.com/ginkida/sallyport/blob/main/CHANGELOG.md"
60
+
61
+ [tool.pytest.ini_options]
62
+ asyncio_mode = "auto"
63
+ testpaths = ["tests"]
64
+ addopts = [
65
+ "--cov=sallyport_daemon",
66
+ "--cov-report=term-missing:skip-covered",
67
+ "--cov-fail-under=80",
68
+ ]
69
+
70
+ [tool.coverage.run]
71
+ branch = true
72
+ source = ["sallyport_daemon"]
73
+
74
+ [tool.coverage.report]
75
+ exclude_lines = [
76
+ "pragma: no cover",
77
+ "if __name__ == .__main__.:",
78
+ "raise NotImplementedError",
79
+ ]
80
+
81
+ [tool.ruff]
82
+ target-version = "py310"
83
+ line-length = 100
84
+
85
+ [tool.ruff.lint]
86
+ select = ["E", "F", "W", "I", "B", "UP", "ASYNC", "S", "PT"]
87
+ ignore = ["S101"] # allow asserts in tests
88
+
89
+ [tool.ruff.lint.per-file-ignores]
90
+ # Tests legitimately: use hardcoded secrets (S105/S106), seed PRNG (S311),
91
+ # run blocking I/O in async contexts (ASYNC230/240), and spawn subprocesses
92
+ # with controlled arg lists (S603).
93
+ "tests/**" = ["S105", "S106", "S311", "S603", "ASYNC230", "ASYNC240"]
94
+
95
+ [tool.mypy]
96
+ python_version = "3.10"
97
+ strict = true
98
+ warn_return_any = true
99
+ warn_unused_ignores = true
100
+ mypy_path = "src"
101
+ packages = ["sallyport_daemon"]
102
+ explicit_package_bases = true
103
+
104
+ [[tool.mypy.overrides]]
105
+ # The mcp SDK's decorators are untyped — silence the noise from server.list_tools / call_tool.
106
+ module = "mcp.*"
107
+ ignore_missing_imports = true
108
+
109
+ [[tool.mypy.overrides]]
110
+ module = "sallyport_daemon.mcp_server"
111
+ disallow_untyped_decorators = false
112
+
113
+ [build-system]
114
+ requires = ["hatchling"]
115
+ build-backend = "hatchling.build"
116
+
117
+ [tool.hatch.build.targets.wheel]
118
+ packages = ["src/sallyport_daemon"]