open-edison 0.1.16__py3-none-any.whl → 0.1.19__py3-none-any.whl
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.
- {open_edison-0.1.16.dist-info → open_edison-0.1.19.dist-info}/METADATA +92 -22
- open_edison-0.1.19.dist-info/RECORD +14 -0
- src/middleware/data_access_tracker.py +31 -2
- src/middleware/session_tracking.py +1 -1
- src/server.py +115 -144
- src/single_user_mcp.py +95 -112
- src/telemetry.py +17 -1
- open_edison-0.1.16.dist-info/RECORD +0 -18
- src/frontend_dist/assets/index-_NTxjOfh.js +0 -51
- src/frontend_dist/assets/index-h6k8aL6h.css +0 -1
- src/frontend_dist/index.html +0 -21
- src/mcp_manager.py +0 -137
- {open_edison-0.1.16.dist-info → open_edison-0.1.19.dist-info}/WHEEL +0 -0
- {open_edison-0.1.16.dist-info → open_edison-0.1.19.dist-info}/entry_points.txt +0 -0
- {open_edison-0.1.16.dist-info → open_edison-0.1.19.dist-info}/licenses/LICENSE +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: open-edison
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.19
|
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
|
@@ -27,15 +27,7 @@ Description-Content-Type: text/markdown
|
|
27
27
|
|
28
28
|
# OpenEdison
|
29
29
|
|
30
|
-
Open-source 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
|
31
|
-
|
32
|
-
Just want to run it?
|
33
|
-
|
34
|
-
```bash
|
35
|
-
curl -fsSL https://raw.githubusercontent.com/Edison-Watch/open-edison/main/curl_pipe_bash.sh | bash
|
36
|
-
```
|
37
|
-
|
38
|
-
Run locally with uvx: `uvx open-edison --config-dir ~/edison-config`
|
30
|
+
Open-source single-user 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.
|
39
31
|
|
40
32
|
<div align="center">
|
41
33
|
<h2>📧 Interested in connecting AI to your business software with proper access controls? <a href="mailto:hello@edison.watch">Contact us</a> to discuss.</h2>
|
@@ -52,7 +44,40 @@ Run locally with uvx: `uvx open-edison --config-dir ~/edison-config`
|
|
52
44
|
|
53
45
|
## Quick Start
|
54
46
|
|
55
|
-
|
47
|
+
The fastest way to get started:
|
48
|
+
|
49
|
+
```bash
|
50
|
+
# Installs uv (via Astral installer) and launches open-edison with uvx.
|
51
|
+
# Note: This does NOT install Node/npx. Install Node if you plan to use npx-based tools like mcp-remote.
|
52
|
+
curl -fsSL https://raw.githubusercontent.com/Edison-Watch/open-edison/main/curl_pipe_bash.sh | bash
|
53
|
+
```
|
54
|
+
|
55
|
+
Run locally with uvx: `uvx open-edison --config-dir ~/edison-config`
|
56
|
+
|
57
|
+
<details>
|
58
|
+
<summary>Install Node.js/npm (optional for MCP tools)</summary>
|
59
|
+
|
60
|
+
If you need `npx` (for Node-based MCP tools like `mcp-remote`), install Node.js as well:
|
61
|
+
|
62
|
+

|
63
|
+
|
64
|
+
- uv: `curl -fsSL https://astral.sh/uv/install.sh | sh`
|
65
|
+
- Node/npx: `brew install node`
|
66
|
+
|
67
|
+

|
68
|
+
|
69
|
+
- uv: `curl -fsSL https://astral.sh/uv/install.sh | sh`
|
70
|
+
- Node/npx: `sudo apt-get update && sudo apt-get install -y nodejs npm`
|
71
|
+
|
72
|
+

|
73
|
+
|
74
|
+
- uv: `powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"`
|
75
|
+
- Node/npx: `winget install -e --id OpenJS.NodeJS`
|
76
|
+
|
77
|
+
After installation, ensure that `npx` is available on PATH.
|
78
|
+
|
79
|
+
<details>
|
80
|
+
<summary><img src="https://img.shields.io/badge/pypi-3775A9?style=for-the-badge&logo=pypi&logoColor=white" alt="PyPI"> Install from PyPI</summary>
|
56
81
|
|
57
82
|
#### Prerequisites
|
58
83
|
|
@@ -75,7 +100,10 @@ open-edison run --config-dir ~/edison-config
|
|
75
100
|
OPEN_EDISON_CONFIG_DIR=~/edison-config open-edison run
|
76
101
|
```
|
77
102
|
|
78
|
-
|
103
|
+
</details>
|
104
|
+
|
105
|
+
<details>
|
106
|
+
<summary><img src="https://img.shields.io/badge/Docker-2CA5E0?style=for-the-badge&logo=docker&logoColor=white" alt="Docker"> Run with Docker</summary>
|
79
107
|
|
80
108
|
There is a dockerfile for simple local setup.
|
81
109
|
|
@@ -94,7 +122,10 @@ make docker_run
|
|
94
122
|
|
95
123
|
The MCP server will be available at `http://localhost:3000` and the api + frontend at `http://localhost:3001`.
|
96
124
|
|
97
|
-
|
125
|
+
</details>
|
126
|
+
|
127
|
+
<details>
|
128
|
+
<summary>⚙️ Run from source</summary>
|
98
129
|
|
99
130
|
1. Clone the repository:
|
100
131
|
|
@@ -116,7 +147,7 @@ make setup
|
|
116
147
|
"server": { "host": "0.0.0.0", "port": 3000, "api_key": "..." },
|
117
148
|
"logging": { "level": "INFO", "database_path": "sessions.db" },
|
118
149
|
"mcp_servers": [
|
119
|
-
{ "name": "filesystem", "command": "
|
150
|
+
{ "name": "filesystem", "command": "uvx", "args": ["mcp-server-filesystem", "/tmp"], "enabled": true },
|
120
151
|
{ "name": "github", "enabled": false, "env": { "GITHUB_PERSONAL_ACCESS_TOKEN": "..." } }
|
121
152
|
]
|
122
153
|
}
|
@@ -132,9 +163,12 @@ open-edison run
|
|
132
163
|
|
133
164
|
The server will be available at `http://localhost:3000`.
|
134
165
|
|
135
|
-
|
166
|
+
</details>
|
136
167
|
|
137
|
-
|
168
|
+
<details>
|
169
|
+
<summary>MCP Connection</summary>
|
170
|
+
|
171
|
+
Connect any MCP client to Open Edison (requires Node.js/npm for `npx`):
|
138
172
|
|
139
173
|
```bash
|
140
174
|
npx -y mcp-remote http://localhost:3000/mcp/ --http-only --header "Authorization: Bearer your-api-key"
|
@@ -153,13 +187,17 @@ Or add to your MCP client config:
|
|
153
187
|
}
|
154
188
|
```
|
155
189
|
|
156
|
-
|
190
|
+
</details>
|
191
|
+
|
192
|
+
<details>
|
193
|
+
<summary>Usage</summary>
|
157
194
|
|
158
195
|
### API Endpoints
|
159
196
|
|
160
197
|
See [API Reference](docs/quick-reference/api_reference.md) for full API documentation.
|
161
198
|
|
162
|
-
|
199
|
+
<details>
|
200
|
+
<summary>Development</summary>
|
163
201
|
|
164
202
|
### Setup
|
165
203
|
|
@@ -181,6 +219,11 @@ We expect `make ci` to return cleanly.
|
|
181
219
|
make ci
|
182
220
|
```
|
183
221
|
|
222
|
+
</details>
|
223
|
+
|
224
|
+
<details>
|
225
|
+
<summary>⚙️ Configuration (config.json)</summary>
|
226
|
+
|
184
227
|
## Configuration
|
185
228
|
|
186
229
|
The `config.json` file contains all configuration:
|
@@ -199,14 +242,23 @@ Each MCP server configuration includes:
|
|
199
242
|
- `env` - Environment variables (optional)
|
200
243
|
- `enabled` - Whether to auto-start this server
|
201
244
|
|
202
|
-
|
245
|
+
</details>
|
246
|
+
|
247
|
+
</details>
|
203
248
|
|
204
|
-
|
249
|
+
<details>
|
250
|
+
<summary>Security & Permissions System</summary>
|
251
|
+
|
252
|
+
Open Edison includes a comprehensive security monitoring system that tracks the "lethal trifecta" of AI agent risks, as described in [Simon Willison's blog post](https://simonwillison.net/2025/Jun/16/the-lethal-trifecta/):
|
253
|
+
|
254
|
+
<img src="media/lethal-trifecta.png" alt="The lethal trifecta diagram showing the three key AI agent security risks" width="30%">
|
205
255
|
|
206
256
|
1. **Private data access** - Access to sensitive local files/data
|
207
257
|
2. **Untrusted content exposure** - Exposure to external/web content
|
208
258
|
3. **External communication** - Ability to write/send data externally
|
209
259
|
|
260
|
+
<img src="media/pam-diagram.png" alt="Privileged Access Management (PAM) example showing the lethal trifecta in action" width="60%">
|
261
|
+
|
210
262
|
The configuration allows you to classify these risks across **tools**, **resources**, and **prompts** using separate configuration files.
|
211
263
|
|
212
264
|
In addition to trifecta, we track Access Control Level (ACL) for each tool call,
|
@@ -230,6 +282,9 @@ Defines security classifications for MCP tools. See full file: [tool_permissions
|
|
230
282
|
}
|
231
283
|
```
|
232
284
|
|
285
|
+
<details>
|
286
|
+
<summary>Resource Permissions (`resource_permissions.json`)</summary>
|
287
|
+
|
233
288
|
### Resource Permissions (`resource_permissions.json`)
|
234
289
|
|
235
290
|
Defines security classifications for resource access patterns. See full file: [resource_permissions.json](resource_permissions.json), it looks like:
|
@@ -241,6 +296,11 @@ Defines security classifications for resource access patterns. See full file: [r
|
|
241
296
|
}
|
242
297
|
```
|
243
298
|
|
299
|
+
</details>
|
300
|
+
|
301
|
+
<details>
|
302
|
+
<summary>Prompt Permissions (`prompt_permissions.json`)</summary>
|
303
|
+
|
244
304
|
### Prompt Permissions (`prompt_permissions.json`)
|
245
305
|
|
246
306
|
Defines security classifications for prompt types. See full file: [prompt_permissions.json](prompt_permissions.json), it looks like:
|
@@ -252,6 +312,8 @@ Defines security classifications for prompt types. See full file: [prompt_permis
|
|
252
312
|
}
|
253
313
|
```
|
254
314
|
|
315
|
+
</details>
|
316
|
+
|
255
317
|
### Wildcard Patterns
|
256
318
|
|
257
319
|
All permission types support wildcard patterns:
|
@@ -266,7 +328,10 @@ All permission types support wildcard patterns:
|
|
266
328
|
|
267
329
|
Use the `get_security_status` tool to monitor your session's current risk level and see which capabilities have been accessed. When the lethal trifecta is achieved (all three risk flags set), further potentially dangerous operations are blocked.
|
268
330
|
|
269
|
-
|
331
|
+
</details>
|
332
|
+
|
333
|
+
<details>
|
334
|
+
<summary>Documentation</summary>
|
270
335
|
|
271
336
|
📚 **Complete documentation available in [`docs/`](docs/)**
|
272
337
|
|
@@ -275,6 +340,11 @@ Use the `get_security_status` tool to monitor your session's current risk level
|
|
275
340
|
- **[API Reference](docs/quick-reference/api_reference.md)** - REST API documentation
|
276
341
|
- **[Development Guide](docs/development/development_guide.md)** - Contributing and development
|
277
342
|
|
278
|
-
|
343
|
+
</details>
|
344
|
+
|
345
|
+
<details>
|
346
|
+
<summary>License</summary>
|
279
347
|
|
280
348
|
GPL-3.0 License - see [LICENSE](LICENSE) for details.
|
349
|
+
|
350
|
+
</details>
|
@@ -0,0 +1,14 @@
|
|
1
|
+
src/__init__.py,sha256=QWeZdjAm2D2B0eWhd8m2-DPpWvIP26KcNJxwEoU1oEQ,254
|
2
|
+
src/__main__.py,sha256=kQsaVyzRa_ESC57JpKDSQJAHExuXme0rM5beJsYxFeA,161
|
3
|
+
src/cli.py,sha256=9cJN6mRvjbCcpTyTdUVl47J7OB7bxzSy0h8tfVbHuQU,9982
|
4
|
+
src/config.py,sha256=2a5rdImQmNGggL690PQprqZVsRUAJcdo8KS2Foj9N-U,9345
|
5
|
+
src/server.py,sha256=cXW16m6UMUofQFbtM6E2EasxClhWAS-955BuasNupmM,29557
|
6
|
+
src/single_user_mcp.py,sha256=3pDBMant1DNlNPeW_NWD-uFyLrA-qNrx6sDHgDKsDfM,14457
|
7
|
+
src/telemetry.py,sha256=M8iZ7nTPA6BhbPna_xsEoTOOa7A81YyvZ0CkVYa_pPg,12619
|
8
|
+
src/middleware/data_access_tracker.py,sha256=N4g_T-JF9W7yzRIFRasY-JA7ha-Zt_Ov4nSn-TCq-Ps,27026
|
9
|
+
src/middleware/session_tracking.py,sha256=O-n8RvEVCUGAFGYny_gA7-MMQYSlvND-lj3oBZLCT3U,20046
|
10
|
+
open_edison-0.1.19.dist-info/METADATA,sha256=88QHl-ngXl0uFZwYUO2dVMtxmQ0T3eyVUE7NyP6jXAY,10905
|
11
|
+
open_edison-0.1.19.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
12
|
+
open_edison-0.1.19.dist-info/entry_points.txt,sha256=qNAkJcnoTXRhj8J--3PDmXz_TQKdB8H_0C9wiCtDIyA,72
|
13
|
+
open_edison-0.1.19.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
14
|
+
open_edison-0.1.19.dist-info/RECORD,,
|
@@ -171,6 +171,12 @@ def _load_tool_permissions_cached() -> dict[str, dict[str, Any]]:
|
|
171
171
|
return {}
|
172
172
|
|
173
173
|
|
174
|
+
def clear_tool_permissions_cache() -> None:
|
175
|
+
"""Clear the tool permissions cache to force reload from file."""
|
176
|
+
_load_tool_permissions_cached.cache_clear()
|
177
|
+
log.info("Tool permissions cache cleared")
|
178
|
+
|
179
|
+
|
174
180
|
@cache
|
175
181
|
def _load_resource_permissions_cached() -> dict[str, dict[str, Any]]:
|
176
182
|
"""Load resource permissions from JSON configuration file with LRU caching."""
|
@@ -186,6 +192,12 @@ def _load_resource_permissions_cached() -> dict[str, dict[str, Any]]:
|
|
186
192
|
return {}
|
187
193
|
|
188
194
|
|
195
|
+
def clear_resource_permissions_cache() -> None:
|
196
|
+
"""Clear the resource permissions cache to force reload from file."""
|
197
|
+
_load_resource_permissions_cached.cache_clear()
|
198
|
+
log.info("Resource permissions cache cleared")
|
199
|
+
|
200
|
+
|
189
201
|
@cache
|
190
202
|
def _load_prompt_permissions_cached() -> dict[str, dict[str, Any]]:
|
191
203
|
"""Load prompt permissions from JSON configuration file with LRU caching."""
|
@@ -201,6 +213,20 @@ def _load_prompt_permissions_cached() -> dict[str, dict[str, Any]]:
|
|
201
213
|
return {}
|
202
214
|
|
203
215
|
|
216
|
+
def clear_prompt_permissions_cache() -> None:
|
217
|
+
"""Clear the prompt permissions cache to force reload from file."""
|
218
|
+
_load_prompt_permissions_cached.cache_clear()
|
219
|
+
log.info("Prompt permissions cache cleared")
|
220
|
+
|
221
|
+
|
222
|
+
def clear_all_permissions_caches() -> None:
|
223
|
+
"""Clear all permission caches to force reload from files."""
|
224
|
+
clear_tool_permissions_cache()
|
225
|
+
clear_resource_permissions_cache()
|
226
|
+
clear_prompt_permissions_cache()
|
227
|
+
log.info("All permission caches cleared")
|
228
|
+
|
229
|
+
|
204
230
|
@cache
|
205
231
|
def _classify_tool_permissions_cached(tool_name: str) -> dict[str, Any]:
|
206
232
|
"""Classify tool permissions with LRU caching."""
|
@@ -351,6 +377,10 @@ class DataAccessTracker:
|
|
351
377
|
"""Load prompt permissions from JSON configuration file with caching."""
|
352
378
|
return _load_prompt_permissions_cached()
|
353
379
|
|
380
|
+
def clear_caches(self) -> None:
|
381
|
+
"""Clear all permission caches to force reload from configuration files."""
|
382
|
+
clear_all_permissions_caches()
|
383
|
+
|
354
384
|
def _classify_by_tool_name(self, tool_name: str) -> dict[str, Any]:
|
355
385
|
"""Classify permissions based on external JSON configuration only."""
|
356
386
|
return _classify_tool_permissions_cached(tool_name)
|
@@ -606,6 +636,5 @@ class SecurityError(Exception):
|
|
606
636
|
████ ████ ████ ████ ████ ████
|
607
637
|
██ ████ ████ ████ ████ ████ █
|
608
638
|
████ ████ ████ ████ ████ ████
|
609
|
-
|
610
|
-
"""
|
639
|
+
"""
|
611
640
|
super().__init__(message)
|
@@ -102,7 +102,7 @@ def create_db_session() -> Generator[Session, None, None]:
|
|
102
102
|
|
103
103
|
# Ensure changes are flushed to the main database file (avoid WAL for sql.js compatibility)
|
104
104
|
@event.listens_for(engine, "connect")
|
105
|
-
def _set_sqlite_pragmas(dbapi_connection, connection_record): # type: ignore[no-untyped-def]
|
105
|
+
def _set_sqlite_pragmas(dbapi_connection, connection_record): # type: ignore[no-untyped-def] # noqa
|
106
106
|
cur = dbapi_connection.cursor() # type: ignore[attr-defined]
|
107
107
|
try:
|
108
108
|
cur.execute("PRAGMA journal_mode=DELETE") # type: ignore[attr-defined]
|