open-edison 0.1.38__py3-none-any.whl → 0.1.40__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.
Files changed (37) hide show
  1. {open_edison-0.1.38.dist-info → open_edison-0.1.40.dist-info}/METADATA +10 -10
  2. open_edison-0.1.40.dist-info/RECORD +39 -0
  3. open_edison-0.1.40.dist-info/entry_points.txt +5 -0
  4. src/frontend_dist/assets/index-BUUcUfTt.js +51 -0
  5. src/frontend_dist/assets/index-o6_8mdM8.css +1 -0
  6. src/frontend_dist/index.html +21 -0
  7. src/frontend_dist/sw.js +71 -0
  8. src/mcp_importer/__init__.py +15 -0
  9. src/mcp_importer/__main__.py +19 -0
  10. src/mcp_importer/api.py +196 -0
  11. src/mcp_importer/cli.py +113 -0
  12. src/mcp_importer/export_cli.py +201 -0
  13. src/mcp_importer/exporters.py +393 -0
  14. src/mcp_importer/import_api.py +3 -0
  15. src/mcp_importer/importers.py +63 -0
  16. src/mcp_importer/merge.py +47 -0
  17. src/mcp_importer/parsers.py +148 -0
  18. src/mcp_importer/paths.py +92 -0
  19. src/mcp_importer/quick_cli.py +62 -0
  20. src/mcp_importer/types.py +5 -0
  21. oauth_manager.py → src/oauth_manager.py +1 -1
  22. open_edison-0.1.38.dist-info/RECORD +0 -22
  23. open_edison-0.1.38.dist-info/entry_points.txt +0 -5
  24. {open_edison-0.1.38.dist-info → open_edison-0.1.40.dist-info}/WHEEL +0 -0
  25. {open_edison-0.1.38.dist-info → open_edison-0.1.40.dist-info}/licenses/LICENSE +0 -0
  26. /__init__.py → /src/__init__.py +0 -0
  27. /__main__.py → /src/__main__.py +0 -0
  28. /cli.py → /src/cli.py +0 -0
  29. /config.py → /src/config.py +0 -0
  30. /config.pyi → /src/config.pyi +0 -0
  31. /events.py → /src/events.py +0 -0
  32. {middleware → src/middleware}/data_access_tracker.py +0 -0
  33. {middleware → src/middleware}/session_tracking.py +0 -0
  34. /permissions.py → /src/permissions.py +0 -0
  35. /server.py → /src/server.py +0 -0
  36. /single_user_mcp.py → /src/single_user_mcp.py +0 -0
  37. /telemetry.py → /src/telemetry.py +0 -0
@@ -0,0 +1,92 @@
1
+ import os
2
+ import sys
3
+ from pathlib import Path
4
+
5
+
6
+ def is_windows() -> bool:
7
+ return os.name == "nt"
8
+
9
+
10
+ def is_macos() -> bool:
11
+ return sys.platform == "darwin"
12
+
13
+
14
+ def find_cursor_user_file() -> list[Path]:
15
+ """Find user-level Cursor MCP config (~/.cursor/mcp.json)."""
16
+ p = (Path.home() / ".cursor" / "mcp.json").resolve()
17
+ return [p] if p.exists() else []
18
+
19
+
20
+ def find_vscode_user_mcp_file() -> list[Path]:
21
+ """Find VSCode user-level MCP config (User/mcp.json) on macOS or Linux."""
22
+ if is_macos():
23
+ p = Path.home() / "Library" / "Application Support" / "Code" / "User" / "mcp.json"
24
+ else:
25
+ p = Path.home() / ".config" / "Code" / "User" / "mcp.json"
26
+ p = p.resolve()
27
+ return [p] if p.exists() else []
28
+
29
+
30
+ def find_claude_code_user_settings_file() -> list[Path]:
31
+ """Find Claude Code user-level settings (~/.claude/settings.json)."""
32
+ p = (Path.home() / ".claude" / "settings.json").resolve()
33
+ return [p] if p.exists() else []
34
+
35
+
36
+ def find_claude_code_user_all_candidates() -> list[Path]:
37
+ """Return ordered list of Claude Code user-level MCP config candidates.
38
+
39
+ Based on docs, check in priority order:
40
+ - ~/.claude.json (primary user-level)
41
+ - ~/.claude/settings.json
42
+ - ~/.claude/settings.local.json
43
+ - ~/.claude/mcp_servers.json
44
+ """
45
+ home = Path.home()
46
+ candidates: list[Path] = [
47
+ home / ".claude.json",
48
+ home / ".claude" / "settings.json",
49
+ home / ".claude" / "settings.local.json",
50
+ home / ".claude" / "mcp_servers.json",
51
+ ]
52
+ existing: list[Path] = []
53
+ for p in candidates:
54
+ rp = p.resolve()
55
+ if rp.exists():
56
+ existing.append(rp)
57
+ return existing
58
+
59
+
60
+ # Shared utils for CLI import/export
61
+
62
+
63
+ def detect_cursor_config_path() -> Path | None:
64
+ files = find_cursor_user_file()
65
+ return files[0] if files else None
66
+
67
+
68
+ def detect_vscode_config_path() -> Path | None:
69
+ files = find_vscode_user_mcp_file()
70
+ return files[0] if files else None
71
+
72
+
73
+ def get_default_vscode_config_path() -> Path:
74
+ if is_macos():
75
+ return (
76
+ Path.home() / "Library" / "Application Support" / "Code" / "User" / "mcp.json"
77
+ ).resolve()
78
+ return (Path.home() / ".config" / "Code" / "User" / "mcp.json").resolve()
79
+
80
+
81
+ def get_default_cursor_config_path() -> Path:
82
+ return (Path.home() / ".cursor" / "mcp.json").resolve()
83
+
84
+
85
+ def detect_claude_code_config_path() -> Path | None:
86
+ candidates = find_claude_code_user_all_candidates()
87
+ return candidates[0] if candidates else None
88
+
89
+
90
+ def get_default_claude_code_config_path() -> Path:
91
+ # Prefer top-level ~/.claude.json as default create target
92
+ return (Path.home() / ".claude.json").resolve()
@@ -0,0 +1,62 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ from collections.abc import Iterable
5
+
6
+ from src.mcp_importer.api import (
7
+ CLIENT,
8
+ detect_clients,
9
+ export_edison_to,
10
+ import_from,
11
+ save_imported_servers,
12
+ )
13
+
14
+
15
+ def _pick_first(iterable: Iterable[CLIENT]) -> CLIENT | None:
16
+ for item in iterable:
17
+ return item
18
+ return None
19
+
20
+
21
+ def run_cli(argv: list[str] | None = None) -> int:
22
+ parser = argparse.ArgumentParser(
23
+ description=(
24
+ "Detect a client, import its servers into Open Edison, and export Open Edison back to it."
25
+ )
26
+ )
27
+ parser.add_argument("--dry-run", action="store_true", help="Preview actions without writing")
28
+ parser.add_argument("--yes", action="store_true", help="Skip confirmations (no effect here)")
29
+ parser.add_argument(
30
+ "--source-client", type=CLIENT, help="Client to import from", required=False, default=None
31
+ )
32
+ args = parser.parse_args(argv)
33
+
34
+ detected = detect_clients()
35
+ print(f"Detected clients: {detected}")
36
+ if args.source_client:
37
+ client = args.source_client
38
+ assert client in detected, f"Client {client} not detected"
39
+ else:
40
+ client = _pick_first(detected)
41
+ print(f"Going to import from client: {client}")
42
+ if client is None:
43
+ print("No supported clients detected.")
44
+ return 2
45
+
46
+ servers = import_from(client)
47
+ if not servers:
48
+ print(f"No servers found to import from '{client.value}'.")
49
+ return 0
50
+
51
+ save_imported_servers(servers, dry_run=args.dry_run)
52
+ export_edison_to(client, dry_run=args.dry_run, force=True, create_if_missing=True)
53
+ print(f"Completed quick import/export for {client.value}.")
54
+ return 0
55
+
56
+
57
+ def main(argv: list[str] | None = None) -> int:
58
+ return run_cli(argv)
59
+
60
+
61
+ if __name__ == "__main__":
62
+ raise SystemExit(main())
@@ -0,0 +1,5 @@
1
+ """Type helpers for MCP importer."""
2
+
3
+ from __future__ import annotations
4
+
5
+ # This module intentionally minimal to avoid unused code flags.
@@ -7,6 +7,7 @@ Provides detection, token management, and authentication flow coordination.
7
7
 
8
8
  import asyncio
9
9
  from dataclasses import dataclass
10
+ from datetime import datetime, timedelta
10
11
  from enum import Enum
11
12
  from pathlib import Path
12
13
 
@@ -137,7 +138,6 @@ class OAuthManager:
137
138
  expires_in = getattr(existing_tokens, "expires_in", None)
138
139
  if expires_in:
139
140
  # If expires_in is available, we can calculate expiration
140
- from datetime import datetime, timedelta
141
141
 
142
142
  expiry = datetime.now() + timedelta(seconds=expires_in)
143
143
  token_expires_at = expiry.isoformat()
@@ -1,22 +0,0 @@
1
- __init__.py,sha256=bEYMwBiuW9jzF07iWhas4Vb30EcpnqfpNfz_Q6yO1jU,209
2
- __main__.py,sha256=kQsaVyzRa_ESC57JpKDSQJAHExuXme0rM5beJsYxFeA,161
3
- cli.py,sha256=P38IWER41S5oAfbd_7p89hBpnjClsNHpmE5pSsJc6uU,9733
4
- config.py,sha256=RSsAYzl8cj6eaDN1RORMcfKKWBcp4bKTQp2BdhAL9mg,10258
5
- config.pyi,sha256=FgehEGli8ZXSjGlANBgMGv5497q4XskQciOc1fUcxqM,2033
6
- events.py,sha256=aFQrVXDIZwt55Dz6OtyoXu2yi9evqo-8jZzo3CR2Tto,4965
7
- oauth_manager.py,sha256=qcQa5BDRZr4bjqiXNflCnrXOh9mo9JVjvP2Caseg2Uc,9943
8
- permissions.py,sha256=NGAnlG_z59HEiVA-k3cYvwmmiuHzxuNb5Tbd5umbL00,10483
9
- server.py,sha256=cnO5bgxT-lrfuwk9AIvB_HBV8SWOtFClfGUn5_zFWyo,45652
10
- single_user_mcp.py,sha256=rJrlqHcIubGkos_24ux5rb3OoKYDzvagCHghhfDeXTI,18535
11
- telemetry.py,sha256=-RZPIjpI53zbsKmp-63REeZ1JirWHV5WvpSRa2nqZEk,11321
12
- frontend_dist/index.html,sha256=s95FMkH8VLisvawLH7bZxbLzRUFvMhHkH6ZMzpVBngs,673
13
- frontend_dist/sw.js,sha256=rihX1es-vWwjmtnXyaksJjs2dio6MVAOTAWwQPeJUYw,2164
14
- frontend_dist/assets/index-BUUcUfTt.js,sha256=awoyPI6u0v6ao2iarZdSkrSDUvyU8aNkMLqHMvgVgyY,257666
15
- frontend_dist/assets/index-o6_8mdM8.css,sha256=nwmX_6q55mB9463XN2JM8BdeihjkALpQK83Fc3_iGvE,15936
16
- middleware/data_access_tracker.py,sha256=bArBffWgYmvxOx9z_pgXQhogvnWQcc1m6WvEblDD4gw,15039
17
- middleware/session_tracking.py,sha256=5W1VH9HNqIZeX0HNxDEm41U4GY6SqKSXtApDEeZK2qo,23084
18
- open_edison-0.1.38.dist-info/METADATA,sha256=FAscw046zzz6mf51VTVrkvC8ulR_8GAaO-WVB9M1zRg,13152
19
- open_edison-0.1.38.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
20
- open_edison-0.1.38.dist-info/entry_points.txt,sha256=qUjYGPEfqSQyra9dTe1aRvHVAAzLzoNvZqNDk1t75IA,163
21
- open_edison-0.1.38.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
22
- open_edison-0.1.38.dist-info/RECORD,,
@@ -1,5 +0,0 @@
1
- [console_scripts]
2
- mcp-importer = mcp_importer.__main__:main
3
- mcp-importer-quick = mcp_importer.quick_cli:main
4
- open-edison = src.cli:main
5
- open_edison = src.cli:main
File without changes
File without changes
/cli.py → /src/cli.py RENAMED
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes