open-edison 0.1.26__tar.gz → 0.1.30__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.26 → open_edison-0.1.30}/.gitignore +3 -1
  2. {open_edison-0.1.26 → open_edison-0.1.30}/PKG-INFO +19 -16
  3. {open_edison-0.1.26 → open_edison-0.1.30}/README.md +17 -15
  4. {open_edison-0.1.26 → open_edison-0.1.30}/docs/core/proxy_usage.md +1 -1
  5. {open_edison-0.1.26 → open_edison-0.1.30}/docs/deployment/local.md +4 -4
  6. {open_edison-0.1.26 → open_edison-0.1.30}/docs/development/testing.md +6 -6
  7. open_edison-0.1.30/hatch_build.py +42 -0
  8. {open_edison-0.1.26 → open_edison-0.1.30}/pyproject.toml +9 -6
  9. {open_edison-0.1.26 → open_edison-0.1.30}/src/cli.py +6 -0
  10. {open_edison-0.1.26 → open_edison-0.1.30}/src/config.py +16 -28
  11. open_edison-0.1.30/src/frontend_dist/assets/index-DOR5YaNc.js +51 -0
  12. open_edison-0.1.30/src/frontend_dist/assets/index-o6_8mdM8.css +1 -0
  13. open_edison-0.1.30/src/frontend_dist/index.html +21 -0
  14. open_edison-0.1.30/src/frontend_dist/sw.js +71 -0
  15. {open_edison-0.1.26 → open_edison-0.1.30}/src/middleware/session_tracking.py +40 -8
  16. {open_edison-0.1.26 → open_edison-0.1.30}/src/permissions.py +3 -14
  17. {open_edison-0.1.26 → open_edison-0.1.30}/src/server.py +27 -12
  18. {open_edison-0.1.26 → open_edison-0.1.30}/src/single_user_mcp.py +12 -2
  19. {open_edison-0.1.26 → open_edison-0.1.30}/LICENSE +0 -0
  20. {open_edison-0.1.26 → open_edison-0.1.30}/config.json +0 -0
  21. {open_edison-0.1.26 → open_edison-0.1.30}/desktop_ext/README.md +0 -0
  22. {open_edison-0.1.26 → open_edison-0.1.30}/docs/README.md +0 -0
  23. {open_edison-0.1.26 → open_edison-0.1.30}/docs/architecture/single_user_design.md +0 -0
  24. {open_edison-0.1.26 → open_edison-0.1.30}/docs/core/configuration.md +0 -0
  25. {open_edison-0.1.26 → open_edison-0.1.30}/docs/core/project_structure.md +0 -0
  26. {open_edison-0.1.26 → open_edison-0.1.30}/docs/deployment/docker.md +0 -0
  27. {open_edison-0.1.26 → open_edison-0.1.30}/docs/development/contributing.md +0 -0
  28. {open_edison-0.1.26 → open_edison-0.1.30}/docs/development/development_guide.md +0 -0
  29. {open_edison-0.1.26 → open_edison-0.1.30}/docs/quick-reference/api_reference.md +0 -0
  30. {open_edison-0.1.26 → open_edison-0.1.30}/docs/quick-reference/config_quick_start.md +0 -0
  31. {open_edison-0.1.26 → open_edison-0.1.30}/prompt_permissions.json +0 -0
  32. {open_edison-0.1.26 → open_edison-0.1.30}/resource_permissions.json +0 -0
  33. {open_edison-0.1.26 → open_edison-0.1.30}/src/__init__.py +0 -0
  34. {open_edison-0.1.26 → open_edison-0.1.30}/src/__main__.py +0 -0
  35. {open_edison-0.1.26 → open_edison-0.1.30}/src/events.py +0 -0
  36. {open_edison-0.1.26 → open_edison-0.1.30}/src/middleware/data_access_tracker.py +0 -0
  37. {open_edison-0.1.26 → open_edison-0.1.30}/src/oauth_manager.py +0 -0
  38. {open_edison-0.1.26 → open_edison-0.1.30}/src/telemetry.py +0 -0
  39. {open_edison-0.1.26 → open_edison-0.1.30}/tool_permissions.json +0 -0
@@ -217,4 +217,6 @@ frontend_dist/
217
217
  frontend/node_modules/
218
218
  frontend/package-lock.json
219
219
  .vscode
220
- install_id
220
+ install_id
221
+ dev_config_dir/
222
+ sessions.db
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: open-edison
3
- Version: 0.1.26
3
+ Version: 0.1.30
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,7 +28,11 @@ Description-Content-Type: text/markdown
27
28
 
28
29
  # OpenEdison 🔒⚡️
29
30
 
30
- MCP security gateway that prevents data exfiltration—via direct access or tool chaining—with full monitoring for local single‑user deployments. Provides core functionality of <https://edison.watch> for local use.
31
+ > The secure MCP proxy gateway
32
+
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. No more "approve fatigue" with the MCP tool-call approvals.
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.
31
36
 
32
37
  <p align="center">
33
38
  <img src="media/trifecta520p.gif" alt="Trifecta Security Risk Animation" width="520">
@@ -42,22 +47,23 @@ MCP security gateway that prevents data exfiltration—via direct access or tool
42
47
  <img alt="Python Version" src="https://img.shields.io/badge/python-3.12-blue?logo=python">
43
48
  <img src="https://img.shields.io/badge/License-GPLv3-blue" alt="License">
44
49
 
45
-
46
50
  </p>
47
51
 
48
- ---
49
-
52
+ ---
50
53
 
51
54
  ## Features ✨
52
55
 
53
- - 🛑 **Prevent Data Leaks** - Edison automatically blocks any data leaks, even if your AI gets jailbroken
54
- - 👤 **Single-user MCP proxy** - No multi-user complexity, just a simple proxy for your MCP servers
55
- - 🗂️ **JSON configuration** - Easy to configure and manage your MCP servers
56
- - 🖥️ **Simple local frontend** - Track and monitor your MCP interactions, servers, and sessions.
57
- - 📊 **Session tracking** - Track and monitor your MCP interactions
56
+ - 🛑 **Data leak blocker** - Edison automatically blocks any data leaks, even if your AI gets jailbroken
57
+ - 🕰️ **Deterministic execution** - Deterministic execution. Guaranteed data exfiltration blocker.
58
+ - 🗂️ **Easily configurable** - Easy to configure and manage your MCP servers
59
+ - 📊 **Visibility into agent interactions** - Track and monitor your agents and their interactions with connected software/data via MCP calls
58
60
  - 🔗 **Simple API** - REST API for managing MCP servers and proxying requests
59
61
  - 🐳 **Docker support** - Run in a container for easy deployment
60
62
 
63
+ ## About Edison.watch 🏢
64
+
65
+ Edison helps you gain observability, control, and policy enforcement for all AI interactions with systems of records, existing company software and data. Prevent AI from causing data leakage, lightning-fast setup for cross-system governance.
66
+
61
67
  ## Quick Start 🚀
62
68
 
63
69
  The fastest way to get started:
@@ -68,7 +74,7 @@ The fastest way to get started:
68
74
  curl -fsSL https://raw.githubusercontent.com/Edison-Watch/open-edison/main/curl_pipe_bash.sh | bash
69
75
  ```
70
76
 
71
- Run locally with uvx: `uvx open-edison --config-dir ~/edison-config`
77
+ Run locally with uvx: `uvx open-edison`
72
78
 
73
79
  <details>
74
80
  <summary>⬇️ Install Node.js/npm (optional for MCP tools)</summary>
@@ -102,11 +108,11 @@ After installation, ensure that `npx` is available on PATH.
102
108
 
103
109
  ```bash
104
110
  # Using uvx
105
- uvx open-edison --help
111
+ uvx open-edison
106
112
 
107
113
  # Using pipx
108
114
  pipx install open-edison
109
- open-edison --help
115
+ open-edison
110
116
  ```
111
117
 
112
118
  Run with a custom config directory:
@@ -349,8 +355,6 @@ Use the `get_security_status` tool to monitor your session's current risk level
349
355
 
350
356
  </details>
351
357
 
352
-
353
-
354
358
  ## Documentation 📚
355
359
 
356
360
  📚 **Complete documentation available in [`docs/`](docs/)**
@@ -360,7 +364,6 @@ Use the `get_security_status` tool to monitor your session's current risk level
360
364
  - 📡 **[API Reference](docs/quick-reference/api_reference.md)** - REST API documentation
361
365
  - 🧑‍💻 **[Development Guide](docs/development/development_guide.md)** - Contributing and development
362
366
 
363
-
364
367
  <details>
365
368
  <summary>📄 License</summary>
366
369
 
@@ -1,6 +1,10 @@
1
1
  # OpenEdison 🔒⚡️
2
2
 
3
- MCP security gateway that prevents data exfiltration—via direct access or tool chaining—with full monitoring for local single‑user deployments. Provides core functionality of <https://edison.watch> for local use.
3
+ > The secure MCP proxy gateway
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.
6
+
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.
4
8
 
5
9
  <p align="center">
6
10
  <img src="media/trifecta520p.gif" alt="Trifecta Security Risk Animation" width="520">
@@ -15,22 +19,23 @@ MCP security gateway that prevents data exfiltration—via direct access or tool
15
19
  <img alt="Python Version" src="https://img.shields.io/badge/python-3.12-blue?logo=python">
16
20
  <img src="https://img.shields.io/badge/License-GPLv3-blue" alt="License">
17
21
 
18
-
19
22
  </p>
20
23
 
21
- ---
22
-
24
+ ---
23
25
 
24
26
  ## Features ✨
25
27
 
26
- - 🛑 **Prevent Data Leaks** - Edison automatically blocks any data leaks, even if your AI gets jailbroken
27
- - 👤 **Single-user MCP proxy** - No multi-user complexity, just a simple proxy for your MCP servers
28
- - 🗂️ **JSON configuration** - Easy to configure and manage your MCP servers
29
- - 🖥️ **Simple local frontend** - Track and monitor your MCP interactions, servers, and sessions.
30
- - 📊 **Session tracking** - Track and monitor your MCP interactions
28
+ - 🛑 **Data leak blocker** - Edison automatically blocks any data leaks, even if your AI gets jailbroken
29
+ - 🕰️ **Deterministic execution** - Deterministic execution. Guaranteed data exfiltration blocker.
30
+ - 🗂️ **Easily configurable** - Easy to configure and manage your MCP servers
31
+ - 📊 **Visibility into agent interactions** - Track and monitor your agents and their interactions with connected software/data via MCP calls
31
32
  - 🔗 **Simple API** - REST API for managing MCP servers and proxying requests
32
33
  - 🐳 **Docker support** - Run in a container for easy deployment
33
34
 
35
+ ## About Edison.watch 🏢
36
+
37
+ Edison helps you gain observability, control, and policy enforcement for all AI interactions with systems of records, existing company software and data. Prevent AI from causing data leakage, lightning-fast setup for cross-system governance.
38
+
34
39
  ## Quick Start 🚀
35
40
 
36
41
  The fastest way to get started:
@@ -41,7 +46,7 @@ The fastest way to get started:
41
46
  curl -fsSL https://raw.githubusercontent.com/Edison-Watch/open-edison/main/curl_pipe_bash.sh | bash
42
47
  ```
43
48
 
44
- Run locally with uvx: `uvx open-edison --config-dir ~/edison-config`
49
+ Run locally with uvx: `uvx open-edison`
45
50
 
46
51
  <details>
47
52
  <summary>⬇️ Install Node.js/npm (optional for MCP tools)</summary>
@@ -75,11 +80,11 @@ After installation, ensure that `npx` is available on PATH.
75
80
 
76
81
  ```bash
77
82
  # Using uvx
78
- uvx open-edison --help
83
+ uvx open-edison
79
84
 
80
85
  # Using pipx
81
86
  pipx install open-edison
82
- open-edison --help
87
+ open-edison
83
88
  ```
84
89
 
85
90
  Run with a custom config directory:
@@ -322,8 +327,6 @@ Use the `get_security_status` tool to monitor your session's current risk level
322
327
 
323
328
  </details>
324
329
 
325
-
326
-
327
330
  ## Documentation 📚
328
331
 
329
332
  📚 **Complete documentation available in [`docs/`](docs/)**
@@ -333,7 +336,6 @@ Use the `get_security_status` tool to monitor your session's current risk level
333
336
  - 📡 **[API Reference](docs/quick-reference/api_reference.md)** - REST API documentation
334
337
  - 🧑‍💻 **[Development Guide](docs/development/development_guide.md)** - Contributing and development
335
338
 
336
-
337
339
  <details>
338
340
  <summary>📄 License</summary>
339
341
 
@@ -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,42 @@
1
+ from __future__ import annotations
2
+
3
+ import shutil
4
+ from pathlib import Path
5
+
6
+ from hatchling.builders.hooks.plugin.interface import BuildHookInterface
7
+
8
+
9
+ class BuildHook(BuildHookInterface): # type: ignore
10
+ """Ensure packaged frontend assets exist in src/frontend_dist before build.
11
+
12
+ Behavior:
13
+ - If src/frontend_dist/index.html exists, do nothing.
14
+ - Else if frontend/dist/index.html exists, copy it to src/frontend_dist/.
15
+ - Else raise a clear error instructing to run `make build_package` first.
16
+ We intentionally DO NOT run npm during packaging to avoid assuming it
17
+ on build/install environments.
18
+ """
19
+
20
+ def initialize(self, version: str, build_data: dict) -> None: # noqa: D401 # type: ignore
21
+ project_root = Path(self.root)
22
+ src_frontend_dist = project_root / "src" / "frontend_dist"
23
+ repo_frontend_dist = project_root / "frontend" / "dist"
24
+
25
+ # Fast path: already present in src/
26
+ if (src_frontend_dist / "index.html").exists():
27
+ self.app.display_info("frontend_dist already present; skipping build/copy")
28
+ return
29
+
30
+ # Copy from repo frontend/dist if present
31
+ if (repo_frontend_dist / "index.html").exists():
32
+ if src_frontend_dist.exists():
33
+ shutil.rmtree(src_frontend_dist)
34
+ shutil.copytree(repo_frontend_dist, src_frontend_dist)
35
+ self.app.display_info("Copied frontend/dist -> src/frontend_dist for packaging")
36
+ return
37
+
38
+ # No assets available; fail fast with guidance
39
+ raise RuntimeError(
40
+ "Packaged dashboard (src/frontend_dist) missing and frontend/dist not found. "
41
+ "Run 'make build_package' to generate assets before packaging/uvx."
42
+ )
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "open-edison"
3
- version = "0.1.26"
3
+ version = "0.1.30"
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.hooks.custom]
71
+ path = "hatch_build.py"
72
+
70
73
 
71
74
  [tool.hatch.build.targets.sdist]
72
75
  include = [
@@ -77,10 +80,10 @@ 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" }
84
87
 
85
88
  [tool.ruff]
86
89
  line-length = 100
@@ -114,4 +117,4 @@ venvPath = ".venv"
114
117
  extraPaths = ["src"]
115
118
 
116
119
  [tool.vulture]
117
- exclude = ["tests", "src/frontend_dist"]
120
+ exclude = ["tests", "src/frontend_dist"]
@@ -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
@@ -10,6 +10,7 @@ import os
10
10
  import sys
11
11
  import tomllib
12
12
  from dataclasses import asdict, dataclass
13
+ from functools import cache
13
14
  from pathlib import Path
14
15
  from typing import Any, cast
15
16
 
@@ -37,8 +38,7 @@ def get_config_dir() -> Path:
37
38
  try:
38
39
  return Path(env_dir).expanduser().resolve()
39
40
  except Exception:
40
- # Fall through to defaults
41
- pass
41
+ log.warning(f"Failed to resolve OPEN_EDISON_CONFIG_DIR: {env_dir}")
42
42
 
43
43
  # Platform-specific defaults
44
44
  try:
@@ -58,26 +58,8 @@ def get_config_dir() -> Path:
58
58
  return (Path.home() / ".open-edison").resolve()
59
59
 
60
60
 
61
- def _default_config_path() -> Path:
62
- """Determine default config.json path.
63
-
64
- In development (editable or source checkout), prefer repository root
65
- `config.json` when present. In an installed package (site-packages),
66
- use the resolved user config dir.
67
- """
68
- repo_pyproject = root_dir / "pyproject.toml"
69
- repo_config = root_dir / "config.json"
70
-
71
- # If pyproject.toml exists next to src/, we are likely in a repo checkout
72
- # Prefer the user config directory if a config already exists there (runtime source of truth),
73
- # otherwise fall back to the repo copy.
74
- if repo_pyproject.exists():
75
- user_cfg = get_config_dir() / "config.json"
76
- if user_cfg.exists():
77
- return user_cfg
78
- return repo_config
79
-
80
- # Installed package: prefer user config directory
61
+ def get_config_json_path() -> Path:
62
+ """Get the path to the config.json file"""
81
63
  return get_config_dir() / "config.json"
82
64
 
83
65
 
@@ -156,6 +138,15 @@ class TelemetryConfig:
156
138
  export_interval_ms: int = 60000
157
139
 
158
140
 
141
+ @cache
142
+ def load_json_file(path: Path) -> dict[str, Any]:
143
+ """Load a JSON file from the given path.
144
+ Kept as a separate function because we want to manually clear cache sometimes (update in config)"""
145
+ log.info(f"Loading configuration from {path}")
146
+ with open(path) as f:
147
+ return json.load(f)
148
+
149
+
159
150
  @dataclass
160
151
  class Config:
161
152
  """Main configuration class"""
@@ -188,21 +179,18 @@ class Config:
188
179
  If no path is provided, uses OPEN_EDISON_CONFIG_DIR or project root.
189
180
  """
190
181
  if config_path is None:
191
- config_path = _default_config_path()
182
+ config_path = get_config_json_path()
192
183
  else:
193
184
  # If a directory was passed, use config.json inside it
194
185
  if config_path.is_dir():
195
186
  config_path = config_path / "config.json"
196
187
 
197
- log.info(f"Loading configuration from {config_path}")
198
-
199
188
  if not config_path.exists():
200
189
  log.warning(f"Config file not found at {config_path}, creating default config")
201
190
  self.create_default()
202
191
  self.save(config_path)
203
192
 
204
- with open(config_path) as f:
205
- data: dict[str, Any] = json.load(f)
193
+ data = load_json_file(config_path)
206
194
 
207
195
  mcp_servers_data = data.get("mcp_servers", []) # type: ignore
208
196
  server_data = data.get("server", {}) # type: ignore
@@ -248,7 +236,7 @@ class Config:
248
236
  def save(self, config_path: Path | None = None) -> None:
249
237
  """Save configuration to JSON file"""
250
238
  if config_path is None:
251
- config_path = _default_config_path()
239
+ config_path = get_config_json_path()
252
240
  else:
253
241
  # If a directory was passed, save to config.json inside it
254
242
  if config_path.is_dir():