|
1
|
""" |
|
2
|
Editor integrations — generate MCP config snippets for AI coding editors. |
|
3
|
|
|
4
|
Supported editors: |
|
5
|
claude-code — .claude/mcp.json |
|
6
|
cursor — .cursor/mcp.json |
|
7
|
codex — .codex/config.json |
|
8
|
windsurf — .windsurf/mcp.json |
|
9
|
""" |
|
10
|
|
|
11
|
from __future__ import annotations |
|
12
|
|
|
13
|
import json |
|
14
|
from pathlib import Path |
|
15
|
|
|
16
|
SUPPORTED_EDITORS = ["claude-code", "cursor", "codex", "windsurf"] |
|
17
|
|
|
18
|
# Config file path relative to the project root for each editor |
|
19
|
_CONFIG_PATHS: dict[str, str] = { |
|
20
|
"claude-code": ".claude/mcp.json", |
|
21
|
"cursor": ".cursor/mcp.json", |
|
22
|
"codex": ".codex/config.json", |
|
23
|
"windsurf": ".windsurf/mcp.json", |
|
24
|
} |
|
25
|
|
|
26
|
|
|
27
|
def _mcp_block(db: str) -> dict: |
|
28
|
"""Return the shared mcpServers block used by all editors.""" |
|
29
|
return { |
|
30
|
"mcpServers": { |
|
31
|
"navegador": { |
|
32
|
"command": "navegador", |
|
33
|
"args": ["mcp", "--db", db], |
|
34
|
} |
|
35
|
} |
|
36
|
} |
|
37
|
|
|
38
|
|
|
39
|
class EditorIntegration: |
|
40
|
"""Generate MCP config snippets for AI coding editors.""" |
|
41
|
|
|
42
|
def __init__(self, db: str = ".navegador/graph.db") -> None: |
|
43
|
self.db = db |
|
44
|
|
|
45
|
# ── public API ──────────────────────────────────────────────────────────── |
|
46
|
|
|
47
|
def config_for(self, editor: str) -> dict: |
|
48
|
"""Return the config dict for *editor*. |
|
49
|
|
|
50
|
Raises ValueError for unsupported editors. |
|
51
|
""" |
|
52
|
if editor not in SUPPORTED_EDITORS: |
|
53
|
raise ValueError( |
|
54
|
f"Unsupported editor {editor!r}. Choose from: {', '.join(SUPPORTED_EDITORS)}" |
|
55
|
) |
|
56
|
return _mcp_block(self.db) |
|
57
|
|
|
58
|
def config_json(self, editor: str) -> str: |
|
59
|
"""Return the JSON string for *editor*'s config file.""" |
|
60
|
return json.dumps(self.config_for(editor), indent=2) |
|
61
|
|
|
62
|
def config_path(self, editor: str) -> str: |
|
63
|
"""Return the relative config file path for *editor*.""" |
|
64
|
if editor not in SUPPORTED_EDITORS: |
|
65
|
raise ValueError( |
|
66
|
f"Unsupported editor {editor!r}. Choose from: {', '.join(SUPPORTED_EDITORS)}" |
|
67
|
) |
|
68
|
return _CONFIG_PATHS[editor] |
|
69
|
|
|
70
|
def write_config(self, editor: str, base_dir: str = ".") -> Path: |
|
71
|
"""Write the config file to the expected path under *base_dir*. |
|
72
|
|
|
73
|
Creates parent directories as needed. Returns the written Path. |
|
74
|
""" |
|
75
|
rel = self.config_path(editor) |
|
76
|
dest = Path(base_dir) / rel |
|
77
|
dest.parent.mkdir(parents=True, exist_ok=True) |
|
78
|
dest.write_text(self.config_json(editor)) |
|
79
|
return dest |
|
80
|
|