open-edison 0.1.10__tar.gz → 0.1.15__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 (40) hide show
  1. {open_edison-0.1.10 → open_edison-0.1.15}/PKG-INFO +5 -2
  2. {open_edison-0.1.10 → open_edison-0.1.15}/README.md +1 -1
  3. {open_edison-0.1.10 → open_edison-0.1.15}/config.json +36 -0
  4. open_edison-0.1.15/prompt_permissions.json +15 -0
  5. {open_edison-0.1.10 → open_edison-0.1.15}/pyproject.toml +4 -1
  6. open_edison-0.1.15/resource_permissions.json +15 -0
  7. {open_edison-0.1.10 → open_edison-0.1.15}/src/cli.py +2 -2
  8. {open_edison-0.1.10 → open_edison-0.1.15}/src/config.py +53 -1
  9. open_edison-0.1.15/src/frontend_dist/assets/index-_NTxjOfh.js +51 -0
  10. open_edison-0.1.15/src/frontend_dist/assets/index-h6k8aL6h.css +1 -0
  11. {open_edison-0.1.10 → open_edison-0.1.15}/src/frontend_dist/index.html +2 -2
  12. {open_edison-0.1.10 → open_edison-0.1.15}/src/middleware/data_access_tracker.py +224 -123
  13. {open_edison-0.1.10 → open_edison-0.1.15}/src/middleware/session_tracking.py +16 -0
  14. {open_edison-0.1.10 → open_edison-0.1.15}/src/server.py +195 -7
  15. open_edison-0.1.15/src/telemetry.py +336 -0
  16. open_edison-0.1.15/tool_permissions.json +260 -0
  17. open_edison-0.1.10/src/frontend_dist/assets/index-CKkid2y-.js +0 -51
  18. open_edison-0.1.10/src/frontend_dist/assets/index-CRxojymD.css +0 -1
  19. {open_edison-0.1.10 → open_edison-0.1.15}/.gitignore +0 -0
  20. {open_edison-0.1.10 → open_edison-0.1.15}/LICENSE +0 -0
  21. {open_edison-0.1.10 → open_edison-0.1.15}/desktop_ext/README.md +0 -0
  22. {open_edison-0.1.10 → open_edison-0.1.15}/docs/README.md +0 -0
  23. {open_edison-0.1.10 → open_edison-0.1.15}/docs/architecture/single_user_design.md +0 -0
  24. {open_edison-0.1.10 → open_edison-0.1.15}/docs/core/configuration.md +0 -0
  25. {open_edison-0.1.10 → open_edison-0.1.15}/docs/core/project_structure.md +0 -0
  26. {open_edison-0.1.10 → open_edison-0.1.15}/docs/core/proxy_usage.md +0 -0
  27. {open_edison-0.1.10 → open_edison-0.1.15}/docs/deployment/docker.md +0 -0
  28. {open_edison-0.1.10 → open_edison-0.1.15}/docs/deployment/local.md +0 -0
  29. {open_edison-0.1.10 → open_edison-0.1.15}/docs/development/contributing.md +0 -0
  30. {open_edison-0.1.10 → open_edison-0.1.15}/docs/development/development_guide.md +0 -0
  31. {open_edison-0.1.10 → open_edison-0.1.15}/docs/development/testing.md +0 -0
  32. {open_edison-0.1.10 → open_edison-0.1.15}/docs/quick-reference/api_reference.md +0 -0
  33. {open_edison-0.1.10 → open_edison-0.1.15}/docs/quick-reference/config_quick_start.md +0 -0
  34. {open_edison-0.1.10 → open_edison-0.1.15/frontend/configurations}/prompt_permissions.json +0 -0
  35. {open_edison-0.1.10 → open_edison-0.1.15/frontend/configurations}/resource_permissions.json +0 -0
  36. {open_edison-0.1.10 → open_edison-0.1.15/frontend/configurations}/tool_permissions.json +0 -0
  37. {open_edison-0.1.10 → open_edison-0.1.15}/src/__init__.py +0 -0
  38. {open_edison-0.1.10 → open_edison-0.1.15}/src/__main__.py +0 -0
  39. {open_edison-0.1.10 → open_edison-0.1.15}/src/mcp_manager.py +0 -0
  40. {open_edison-0.1.10 → open_edison-0.1.15}/src/single_user_mcp.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: open-edison
3
- Version: 0.1.10
3
+ Version: 0.1.15
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
@@ -11,6 +11,9 @@ Requires-Dist: fastapi>=0.116.1
11
11
  Requires-Dist: fastmcp>=2.10.5
12
12
  Requires-Dist: httpx>=0.28.1
13
13
  Requires-Dist: loguru>=0.7.3
14
+ Requires-Dist: opentelemetry-api>=1.36.0
15
+ Requires-Dist: opentelemetry-exporter-otlp>=1.36.0
16
+ Requires-Dist: opentelemetry-sdk>=1.36.0
14
17
  Requires-Dist: python-dotenv>=1.0.1
15
18
  Requires-Dist: pyyaml>=6.0.2
16
19
  Requires-Dist: sqlalchemy>=2.0.41
@@ -111,7 +114,7 @@ The server will be available at `http://localhost:3000`.
111
114
 
112
115
  ```bash
113
116
  # After cloning the repo
114
- make run_docker
117
+ make docker_run
115
118
  ```
116
119
 
117
120
  The MCP server will be available at `http://localhost:3000` and the api + frontend at `http://localhost:3001`.
@@ -87,7 +87,7 @@ The server will be available at `http://localhost:3000`.
87
87
 
88
88
  ```bash
89
89
  # After cloning the repo
90
- make run_docker
90
+ make docker_run
91
91
  ```
92
92
 
93
93
  The MCP server will be available at `http://localhost:3000` and the api + frontend at `http://localhost:3001`.
@@ -54,6 +54,42 @@
54
54
  "env": {},
55
55
  "enabled": false,
56
56
  "roots": []
57
+ },
58
+ {
59
+ "name": "supabase",
60
+ "command": "",
61
+ "args": [],
62
+ "env": {
63
+ "SUPABASE_URL": "https://your-supabase-url.supabase.co",
64
+ "SUPABASE_API_KEY": "your-supabase-api-key",
65
+ "SUPABASE_DATABASE": "your-database-name"
66
+ },
67
+ "enabled": false
68
+ },
69
+ {
70
+ "name": "google_drive",
71
+ "command": "npx",
72
+ "args": [
73
+ "-y",
74
+ "@modelcontextprotocol/server-gdrive"
75
+ ],
76
+ "env": {
77
+ "GOOGLE_CLIENT_ID": "your-client-id",
78
+ "GOOGLE_CLIENT_SECRET": "your-client-secret",
79
+ "GOOGLE_REFRESH_TOKEN": "your-refresh-token"
80
+ },
81
+ "enabled": false
82
+ },
83
+ {
84
+ "name": "atlassian",
85
+ "command": "npx",
86
+ "args": [
87
+ "-y",
88
+ "mcp-remote",
89
+ "https://mcp.atlassian.com/v1/sse"
90
+ ],
91
+ "env": {},
92
+ "enabled": false
57
93
  }
58
94
  ]
59
95
  }
@@ -0,0 +1,15 @@
1
+ {
2
+ "_metadata": {
3
+ "description": "Prompt security classifications for Open Edison data access tracker",
4
+ "last_updated": "2025-08-07"
5
+ },
6
+ "builtin": {
7
+ "summarize_text": {
8
+ "enabled": true,
9
+ "write_operation": false,
10
+ "read_private_data": false,
11
+ "read_untrusted_public_data": false
12
+ }
13
+ },
14
+ "sqlite": {}
15
+ }
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "open-edison"
3
- version = "0.1.10"
3
+ version = "0.1.15"
4
4
  description = "Open-source MCP security, aggregation, and monitoring. Single-user, self-hosted MCP proxy."
5
5
  readme = "README.md"
6
6
  authors = [
@@ -18,6 +18,9 @@ dependencies = [
18
18
  "starlette>=0.47.1",
19
19
  "sqlalchemy>=2.0.41",
20
20
  "aiosqlite>=0.20.0",
21
+ "opentelemetry-api>=1.36.0",
22
+ "opentelemetry-sdk>=1.36.0",
23
+ "opentelemetry-exporter-otlp>=1.36.0",
21
24
  ]
22
25
  requires-python = ">= 3.12"
23
26
 
@@ -0,0 +1,15 @@
1
+ {
2
+ "_metadata": {
3
+ "description": "Resource security classifications for Open Edison data access tracker",
4
+ "last_updated": "2025-08-07"
5
+ },
6
+ "builtin": {
7
+ "config://app": {
8
+ "enabled": true,
9
+ "write_operation": false,
10
+ "read_private_data": false,
11
+ "read_untrusted_public_data": false
12
+ }
13
+ },
14
+ "sqlite": {}
15
+ }
@@ -10,10 +10,10 @@ import argparse
10
10
  import asyncio
11
11
  import os
12
12
  import subprocess as _subprocess
13
+ import sys
13
14
  from contextlib import suppress
14
15
  from pathlib import Path
15
16
  from typing import Any, NoReturn, cast
16
- import sys
17
17
 
18
18
  from loguru import logger as _log # type: ignore[reportMissingImports]
19
19
 
@@ -218,7 +218,7 @@ def _run_website(port: int, website_dir: Path | None = None) -> int:
218
218
  return 0 if proc is not None else 1
219
219
 
220
220
 
221
- def main(argv: list[str] | None = None) -> NoReturn:
221
+ def main(argv: list[str] | None = None) -> NoReturn: # noqa: C901
222
222
  args = _parse_args(argv)
223
223
 
224
224
  if getattr(args, "command", None) == "website":
@@ -11,10 +11,13 @@ import sys
11
11
  import tomllib
12
12
  from dataclasses import asdict, dataclass
13
13
  from pathlib import Path
14
- from typing import Any
14
+ from typing import Any, cast
15
15
 
16
16
  from loguru import logger as log
17
17
 
18
+ # Default OTLP metrics endpoint for central dev collector.
19
+ DEFAULT_OTLP_METRICS_ENDPOINT = "https://otel-collector-production-e7a6.up.railway.app/v1/metrics"
20
+
18
21
  # Get the path to the repository/package root directory (module src/ parent)
19
22
  root_dir = Path(__file__).parent.parent
20
23
 
@@ -121,6 +124,17 @@ class MCPServerConfig:
121
124
  self.env = {}
122
125
 
123
126
 
127
+ @dataclass
128
+ class TelemetryConfig:
129
+ """Telemetry configuration"""
130
+
131
+ enabled: bool = True
132
+ # If not provided, exporter may use environment variables or defaults
133
+ otlp_endpoint: str | None = None
134
+ headers: dict[str, str] | None = None
135
+ export_interval_ms: int = 60000
136
+
137
+
124
138
  @dataclass
125
139
  class Config:
126
140
  """Main configuration class"""
@@ -128,6 +142,7 @@ class Config:
128
142
  server: ServerConfig
129
143
  logging: LoggingConfig
130
144
  mcp_servers: list[MCPServerConfig]
145
+ telemetry: TelemetryConfig | None = None
131
146
 
132
147
  @property
133
148
  def version(self) -> str:
@@ -171,6 +186,35 @@ class Config:
171
186
  mcp_servers_data = data.get("mcp_servers", []) # type: ignore
172
187
  server_data = data.get("server", {}) # type: ignore
173
188
  logging_data = data.get("logging", {}) # type: ignore
189
+ telemetry_data_obj: object = data.get("telemetry", {})
190
+
191
+ # Parse telemetry config with explicit typing to satisfy strict type checker
192
+ td: dict[str, object] = {}
193
+ if isinstance(telemetry_data_obj, dict):
194
+ for k_any, v_any in cast(dict[Any, Any], telemetry_data_obj).items():
195
+ td[str(k_any)] = v_any
196
+ tel_enabled: bool = bool(td.get("enabled", True))
197
+ otlp_raw: object = td.get("otlp_endpoint")
198
+ otlp_endpoint: str | None = (
199
+ str(otlp_raw) if isinstance(otlp_raw, str) and otlp_raw else None
200
+ )
201
+ # If not provided in config, use our central dev collector by default
202
+ if not otlp_endpoint:
203
+ otlp_endpoint = DEFAULT_OTLP_METRICS_ENDPOINT
204
+ headers_val: object = td.get("headers")
205
+ headers_dict: dict[str, str] | None = None
206
+ if isinstance(headers_val, dict):
207
+ headers_dict = {}
208
+ for k_any, v_any in cast(dict[Any, Any], headers_val).items():
209
+ headers_dict[str(k_any)] = str(v_any)
210
+ interval_raw: object = td.get("export_interval_ms")
211
+ export_interval_ms: int = interval_raw if isinstance(interval_raw, int) else 60000
212
+ telemetry_cfg = TelemetryConfig(
213
+ enabled=tel_enabled,
214
+ otlp_endpoint=otlp_endpoint,
215
+ headers=headers_dict,
216
+ export_interval_ms=export_interval_ms,
217
+ )
174
218
 
175
219
  return cls(
176
220
  server=ServerConfig(**server_data), # type: ignore
@@ -179,6 +223,7 @@ class Config:
179
223
  MCPServerConfig(**server_item) # type: ignore
180
224
  for server_item in mcp_servers_data # type: ignore
181
225
  ],
226
+ telemetry=telemetry_cfg,
182
227
  )
183
228
 
184
229
  def save(self, config_path: Path | None = None) -> None:
@@ -194,6 +239,9 @@ class Config:
194
239
  "server": asdict(self.server),
195
240
  "logging": asdict(self.logging),
196
241
  "mcp_servers": [asdict(server) for server in self.mcp_servers],
242
+ "telemetry": asdict(
243
+ self.telemetry if self.telemetry is not None else TelemetryConfig()
244
+ ),
197
245
  }
198
246
 
199
247
  # Ensure directory exists
@@ -217,6 +265,10 @@ class Config:
217
265
  enabled=False,
218
266
  )
219
267
  ],
268
+ telemetry=TelemetryConfig(
269
+ enabled=True,
270
+ otlp_endpoint=DEFAULT_OTLP_METRICS_ENDPOINT,
271
+ ),
220
272
  )
221
273
 
222
274