open-edison 0.1.29__tar.gz → 0.1.34__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 (39) hide show
  1. {open_edison-0.1.29 → open_edison-0.1.34}/PKG-INFO +4 -3
  2. {open_edison-0.1.29 → open_edison-0.1.34}/README.md +2 -2
  3. {open_edison-0.1.29 → open_edison-0.1.34}/docs/core/proxy_usage.md +1 -1
  4. {open_edison-0.1.29 → open_edison-0.1.34}/docs/deployment/local.md +4 -4
  5. {open_edison-0.1.29 → open_edison-0.1.34}/docs/development/testing.md +6 -6
  6. open_edison-0.1.34/hatch_build.py +51 -0
  7. {open_edison-0.1.29 → open_edison-0.1.34}/pyproject.toml +12 -6
  8. {open_edison-0.1.29 → open_edison-0.1.34}/src/cli.py +8 -2
  9. {open_edison-0.1.29 → open_edison-0.1.34}/src/config.py +14 -1
  10. open_edison-0.1.34/src/frontend_dist/assets/index-BUUcUfTt.js +51 -0
  11. open_edison-0.1.34/src/frontend_dist/assets/index-o6_8mdM8.css +1 -0
  12. open_edison-0.1.34/src/frontend_dist/index.html +21 -0
  13. open_edison-0.1.34/src/frontend_dist/sw.js +71 -0
  14. {open_edison-0.1.29 → open_edison-0.1.34}/src/server.py +29 -11
  15. {open_edison-0.1.29 → open_edison-0.1.34}/src/single_user_mcp.py +24 -0
  16. {open_edison-0.1.29 → open_edison-0.1.34}/.gitignore +0 -0
  17. {open_edison-0.1.29 → open_edison-0.1.34}/LICENSE +0 -0
  18. {open_edison-0.1.29 → open_edison-0.1.34}/config.json +0 -0
  19. {open_edison-0.1.29 → open_edison-0.1.34}/desktop_ext/README.md +0 -0
  20. {open_edison-0.1.29 → open_edison-0.1.34}/docs/README.md +0 -0
  21. {open_edison-0.1.29 → open_edison-0.1.34}/docs/architecture/single_user_design.md +0 -0
  22. {open_edison-0.1.29 → open_edison-0.1.34}/docs/core/configuration.md +0 -0
  23. {open_edison-0.1.29 → open_edison-0.1.34}/docs/core/project_structure.md +0 -0
  24. {open_edison-0.1.29 → open_edison-0.1.34}/docs/deployment/docker.md +0 -0
  25. {open_edison-0.1.29 → open_edison-0.1.34}/docs/development/contributing.md +0 -0
  26. {open_edison-0.1.29 → open_edison-0.1.34}/docs/development/development_guide.md +0 -0
  27. {open_edison-0.1.29 → open_edison-0.1.34}/docs/quick-reference/api_reference.md +0 -0
  28. {open_edison-0.1.29 → open_edison-0.1.34}/docs/quick-reference/config_quick_start.md +0 -0
  29. {open_edison-0.1.29 → open_edison-0.1.34}/prompt_permissions.json +0 -0
  30. {open_edison-0.1.29 → open_edison-0.1.34}/resource_permissions.json +0 -0
  31. {open_edison-0.1.29 → open_edison-0.1.34}/src/__init__.py +0 -0
  32. {open_edison-0.1.29 → open_edison-0.1.34}/src/__main__.py +0 -0
  33. {open_edison-0.1.29 → open_edison-0.1.34}/src/events.py +0 -0
  34. {open_edison-0.1.29 → open_edison-0.1.34}/src/middleware/data_access_tracker.py +0 -0
  35. {open_edison-0.1.29 → open_edison-0.1.34}/src/middleware/session_tracking.py +0 -0
  36. {open_edison-0.1.29 → open_edison-0.1.34}/src/oauth_manager.py +0 -0
  37. {open_edison-0.1.29 → open_edison-0.1.34}/src/permissions.py +0 -0
  38. {open_edison-0.1.29 → open_edison-0.1.34}/src/telemetry.py +0 -0
  39. {open_edison-0.1.29 → open_edison-0.1.34}/tool_permissions.json +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: open-edison
3
- Version: 0.1.29
3
+ Version: 0.1.34
4
4
  Summary: Open-source MCP security, aggregation, and monitoring. Single-user, self-hosted MCP proxy.
5
5
  Author-email: Hugo Berg <hugo@edison.watch>
6
6
  License-File: LICENSE
@@ -9,6 +9,7 @@ Requires-Dist: aiohttp>=3.12.14
9
9
  Requires-Dist: aiosqlite>=0.20.0
10
10
  Requires-Dist: fastapi>=0.116.1
11
11
  Requires-Dist: fastmcp>=2.10.5
12
+ Requires-Dist: hatchling>=1.27.0
12
13
  Requires-Dist: httpx>=0.28.1
13
14
  Requires-Dist: loguru>=0.7.3
14
15
  Requires-Dist: opentelemetry-api>=1.36.0
@@ -27,9 +28,9 @@ Description-Content-Type: text/markdown
27
28
 
28
29
  # OpenEdison 🔒⚡️
29
30
 
30
- > The secure MCP proxy gateway
31
+ > The Secure MCP Control Panel
31
32
 
32
- Connect AI to your data/software securely without risk of data exfiltration. Gain visibility, block threats, and get alerts on the data your agent is reading/writing. No more "approve fatigue" with the MCP tool-call approvals.
33
+ Connect AI to your data/software securely without risk of data exfiltration. Gain visibility, block threats, and get alerts on the data your agent is reading/writing.
33
34
 
34
35
  OpenEdison solves the [lethal trifecta problem](https://simonwillison.net/2025/Jun/16/the-lethal-trifecta/), which can cause agent hijacking & data exfiltration by malicious actors.
35
36
 
@@ -1,8 +1,8 @@
1
1
  # OpenEdison 🔒⚡️
2
2
 
3
- > The secure MCP proxy gateway
3
+ > The Secure MCP Control Panel
4
4
 
5
- Connect AI to your data/software securely without risk of data exfiltration. Gain visibility, block threats, and get alerts on the data your agent is reading/writing. No more "approve fatigue" with the MCP tool-call approvals.
5
+ Connect AI to your data/software securely without risk of data exfiltration. Gain visibility, block threats, and get alerts on the data your agent is reading/writing.
6
6
 
7
7
  OpenEdison solves the [lethal trifecta problem](https://simonwillison.net/2025/Jun/16/the-lethal-trifecta/), which can cause agent hijacking & data exfiltration by malicious actors.
8
8
 
@@ -13,7 +13,7 @@ Open Edison provides a simple MCP proxy that manages multiple MCP servers as sub
13
13
  make run
14
14
 
15
15
  # Or run directly
16
- rye run python main.py
16
+ uv run python main.py
17
17
  ```
18
18
 
19
19
  The server starts on `localhost:3001` with:
@@ -30,14 +30,14 @@ cd open-edison
30
30
 
31
31
  ### 2. Install Dependencies
32
32
 
33
- #### Using Rye (Recommended)
33
+ #### Using UV (Recommended)
34
34
 
35
35
  ```bash
36
- # Install Rye if not already installed
37
- curl -sSf https://rye.astral.sh/get | bash
36
+ # Install UV if not already installed
37
+ curl -LsSf https://astral.sh/uv/install.sh | sh
38
38
 
39
39
  # Install dependencies
40
- rye sync
40
+ uv sync
41
41
  ```
42
42
 
43
43
  #### Using pip/venv
@@ -618,18 +618,18 @@ jobs:
618
618
  with:
619
619
  python-version: ${{ matrix.python-version }}
620
620
 
621
- - name: Install Rye
621
+ - name: Install UV
622
622
  run: |
623
- curl -sSf https://rye.astral.sh/get | bash
624
- echo "$HOME/.rye/shims" >> $GITHUB_PATH
623
+ curl -LsSf https://astral.sh/uv/install.sh | sh
624
+ echo "$HOME/.cargo/bin" >> $GITHUB_PATH
625
625
 
626
626
  - name: Install dependencies
627
- run: rye sync
627
+ run: uv sync
628
628
 
629
629
  - name: Run tests
630
630
  run: |
631
- rye run pytest --cov=src tests/
632
- rye run pytest --cov-report=xml
631
+ uv run pytest --cov=src tests/
632
+ uv run pytest --cov-report=xml
633
633
 
634
634
  - name: Upload coverage
635
635
  uses: codecov/codecov-action@v3
@@ -0,0 +1,51 @@
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ import shutil
5
+ from pathlib import Path
6
+
7
+ from hatchling.builders.hooks.plugin.interface import BuildHookInterface
8
+
9
+
10
+ class BuildHook(BuildHookInterface): # type: ignore
11
+ """Ensure packaged frontend assets exist in src/frontend_dist before build.
12
+
13
+ Behavior:
14
+ - If src/frontend_dist/index.html exists, do nothing.
15
+ - Else if frontend/dist/index.html exists, copy it to src/frontend_dist/.
16
+ - Else raise a clear error instructing to run `make build_package` first.
17
+ We intentionally DO NOT run npm during packaging to avoid assuming it
18
+ on build/install environments.
19
+ """
20
+
21
+ def initialize(self, version: str, build_data: dict) -> None: # noqa: D401 # type: ignore
22
+ project_root = Path(self.root)
23
+ src_frontend_dist = project_root / "src" / "frontend_dist"
24
+ repo_frontend_dist = project_root / "frontend" / "dist"
25
+
26
+ # Opt-in enforcement: only enforce when OPEN_EDISON_REQUIRE_FRONTEND=1/true/yes
27
+ enforce = os.environ.get("OPEN_EDISON_REQUIRE_FRONTEND", "").lower() in {"1", "true", "yes"}
28
+ if not enforce:
29
+ self.app.display_info(
30
+ "Skipping frontend_dist enforcement (set OPEN_EDISON_REQUIRE_FRONTEND=1 to enforce)"
31
+ )
32
+ return
33
+
34
+ # Fast path: already present in src/
35
+ if (src_frontend_dist / "index.html").exists():
36
+ self.app.display_info("frontend_dist already present; skipping build/copy")
37
+ return
38
+
39
+ # Copy from repo frontend/dist if present
40
+ if (repo_frontend_dist / "index.html").exists():
41
+ if src_frontend_dist.exists():
42
+ shutil.rmtree(src_frontend_dist)
43
+ shutil.copytree(repo_frontend_dist, src_frontend_dist)
44
+ self.app.display_info("Copied frontend/dist -> src/frontend_dist for packaging")
45
+ return
46
+
47
+ # No assets available; fail fast with guidance
48
+ raise RuntimeError(
49
+ "Packaged dashboard (src/frontend_dist) missing and frontend/dist not found. "
50
+ "Run 'make build_package' to generate assets before packaging/uvx."
51
+ )
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "open-edison"
3
- version = "0.1.29"
3
+ version = "0.1.34"
4
4
  description = "Open-source MCP security, aggregation, and monitoring. Single-user, self-hosted MCP proxy."
5
5
  readme = "README.md"
6
6
  authors = [
@@ -21,6 +21,7 @@ dependencies = [
21
21
  "opentelemetry-api>=1.36.0",
22
22
  "opentelemetry-sdk>=1.36.0",
23
23
  "opentelemetry-exporter-otlp>=1.36.0",
24
+ "hatchling>=1.27.0",
24
25
  ]
25
26
  requires-python = ">= 3.12"
26
27
 
@@ -32,9 +33,8 @@ open_edison = "src.cli:main"
32
33
  requires = ["hatchling"]
33
34
  build-backend = "hatchling.build"
34
35
 
35
- [tool.rye]
36
+ [tool.uv]
36
37
  managed = true
37
- python = "3.12"
38
38
  dev-dependencies = [
39
39
  "basedpyright>=1.21.0",
40
40
  "ruff>=0.12.3",
@@ -67,6 +67,9 @@ include = [
67
67
  "src/frontend_dist/**",
68
68
  ]
69
69
 
70
+ [tool.hatch.build.targets.wheel.hooks.custom]
71
+ path = "hatch_build.py"
72
+
70
73
 
71
74
  [tool.hatch.build.targets.sdist]
72
75
  include = [
@@ -77,10 +80,13 @@ include = [
77
80
  "resource_permissions.json",
78
81
  "prompt_permissions.json",
79
82
  "src/**",
80
- "docs/**",
81
- # Ensure packaged dashboard assets are present when building from sdist
82
83
  "src/frontend_dist/**",
84
+ "docs/**",
83
85
  ]
86
+ force-include = { "src/frontend_dist" = "src/frontend_dist" }
87
+
88
+ [tool.hatch.build.targets.sdist.hooks.custom]
89
+ path = "hatch_build.py"
84
90
 
85
91
  [tool.ruff]
86
92
  line-length = 100
@@ -114,4 +120,4 @@ venvPath = ".venv"
114
120
  extraPaths = ["src"]
115
121
 
116
122
  [tool.vulture]
117
- exclude = ["tests", "src/frontend_dist"]
123
+ exclude = ["tests", "src/frontend_dist"]
@@ -17,7 +17,7 @@ from typing import Any, NoReturn, cast
17
17
 
18
18
  from loguru import logger as _log # type: ignore[reportMissingImports]
19
19
 
20
- from .config import Config, get_config_dir
20
+ from .config import Config, get_config_dir, get_config_json_path
21
21
  from .server import OpenEdisonProxy
22
22
 
23
23
  log: Any = _log
@@ -125,6 +125,12 @@ def _spawn_frontend_dev( # noqa: C901 - pragmatic complexity for env probing
125
125
  )
126
126
  # No separate website process needed. Return sentinel port (-1) so caller knows not to warn.
127
127
  return (-1, None)
128
+
129
+ if static_dir is None:
130
+ raise RuntimeError(
131
+ "No packaged dashboard detected. The website will be served from the frontend directory."
132
+ )
133
+
128
134
  pkg_frontend_candidates = [
129
135
  Path(__file__).parent / "frontend", # inside package dir
130
136
  Path(__file__).parent.parent / "frontend", # site-packages root
@@ -185,7 +191,7 @@ async def _run_server(args: Any) -> None:
185
191
  config_dir = get_config_dir()
186
192
 
187
193
  # Load config after setting env override
188
- cfg = Config(config_dir)
194
+ cfg = Config(get_config_json_path())
189
195
 
190
196
  host = getattr(args, "host", None) or cfg.server.host
191
197
  port = getattr(args, "port", None) or cfg.server.port
@@ -252,7 +252,20 @@ class Config:
252
252
  }
253
253
 
254
254
  # Ensure directory exists
255
- config_path.parent.mkdir(parents=True, exist_ok=True)
255
+ try:
256
+ config_path.parent.mkdir(parents=True, exist_ok=True)
257
+ except FileExistsError as e:
258
+ # If the parent path exists as a file, not a directory, this will fail
259
+ if config_path.parent.is_file():
260
+ log.error(
261
+ f"Config directory path {config_path.parent} exists as a file, not a directory"
262
+ )
263
+ log.error("Please remove the file or specify a different config directory")
264
+ raise FileExistsError(
265
+ f"Config directory path {config_path.parent} exists as a file, not a directory"
266
+ ) from e
267
+ log.error(f"Failed to create config directory {config_path.parent}: {e}")
268
+ raise
256
269
  with open(config_path, "w") as f:
257
270
  json.dump(data, f, indent=2)
258
271