remote-debug-mcp 0.2.0__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.
@@ -0,0 +1,3 @@
1
+ from remote_debug_mcp.server import main
2
+
3
+ __all__ = ["main"]
@@ -0,0 +1,5 @@
1
+ import asyncio
2
+ from remote_debug_mcp.server import main
3
+
4
+ if __name__ == "__main__":
5
+ asyncio.run(main())
@@ -0,0 +1,30 @@
1
+ # 远程调试连接配置文件(示例)
2
+ # 复制为 config.yaml 并填入真实参数
3
+ #
4
+ # save_config 工具是配置唯一入库入口:
5
+ # - 无参调用:保存当前内存配置到文件
6
+ # - 带 connections 参数:合并条目后写入文件
7
+ # - 无配置文件时:LLM 询问用户参数,调用 save_config 创建
8
+ # - setup_com2tcp 完成后:LLM 调用 save_config 持久化 com2tcp 配置
9
+
10
+ connections:
11
+ - name: "my-pc"
12
+ type: ssh
13
+ host: "192.168.1.100"
14
+ port: 22
15
+ username: "your-username"
16
+ password: "your-password"
17
+ # key_file: "/path/to/key" # 可选,密钥认证
18
+
19
+ - name: "com2tcp_COM4_5200"
20
+ type: com2tcp
21
+ ssh: "my-pc" # 关联的 SSH 配置名(用于解析 host)
22
+ com_port: "COM4"
23
+ telnet_port: 5200
24
+ baud: 115200
25
+ # 以下为可选参数(均有默认值)
26
+ # username: "" # Telnet 登录用户名
27
+ # password: "" # Telnet 登录密码
28
+ # connect_timeout: 15 # 连接超时(秒)
29
+ # buffer_max_size: 65536 # 缓冲区大小(字节,默认 64KB)
30
+ # max_retries: 3 # 自动重连次数
@@ -0,0 +1,216 @@
1
+ """
2
+ 配置文件加载器,读取 config.yaml 中的连接参数。
3
+ 支持 SSH 连接和 com2tcp 串口映射配置。
4
+ """
5
+ import os
6
+ from dataclasses import dataclass, field
7
+ from typing import Optional
8
+
9
+
10
+ @dataclass
11
+ class SSHConfig:
12
+ name: str
13
+ host: str
14
+ port: int = 22
15
+ username: str = ""
16
+ password: str = ""
17
+ key_file: str = ""
18
+
19
+
20
+ @dataclass
21
+ class Com2TcpConfig:
22
+ name: str
23
+ ssh: str
24
+ com_port: str
25
+ telnet_port: int = 5200
26
+ baud: int = 115200
27
+ username: str = ""
28
+ password: str = ""
29
+ connect_timeout: int = 15
30
+ buffer_max_size: int = 65536
31
+ max_retries: int = 3
32
+
33
+
34
+ @dataclass
35
+ class AppConfig:
36
+ ssh_connections: list[SSHConfig] = field(default_factory=list)
37
+ com2tcp_connections: list[Com2TcpConfig] = field(default_factory=list)
38
+
39
+ def get_ssh(self, name: str) -> Optional[SSHConfig]:
40
+ for c in self.ssh_connections:
41
+ if c.name == name:
42
+ return c
43
+ return None
44
+
45
+ def get_com2tcp(self, name: str) -> Optional[Com2TcpConfig]:
46
+ for c in self.com2tcp_connections:
47
+ if c.name == name:
48
+ return c
49
+ return None
50
+
51
+
52
+ def _parse_yaml_simple(content: str) -> AppConfig:
53
+ """简版 YAML 解析器,无需 PyYAML 依赖。"""
54
+ config = AppConfig()
55
+ current_section = None
56
+ current_entry = {}
57
+ in_connections = False
58
+
59
+ for raw_line in content.split("\n"):
60
+ line = raw_line.rstrip()
61
+ if not line or line.strip().startswith("#"):
62
+ continue
63
+
64
+ stripped = line.strip()
65
+
66
+ if stripped == "connections:":
67
+ in_connections = True
68
+ continue
69
+
70
+ if not in_connections:
71
+ continue
72
+
73
+ if stripped.startswith("- name:"):
74
+ if current_entry:
75
+ _add_entry(config, current_entry)
76
+ current_entry = {}
77
+ name_part = stripped.split(":", 1)[1].strip()
78
+ if "#" in name_part:
79
+ name_part = name_part[:name_part.index("#")].strip()
80
+ current_entry["name"] = name_part.strip().strip('"')
81
+
82
+ elif ":" in stripped and not stripped.startswith("-"):
83
+ key, _, val = stripped.partition(":")
84
+ key = key.strip()
85
+ val = val.strip()
86
+ if "#" in val:
87
+ val = val[:val.index("#")].strip()
88
+ val = val.strip('"').strip("'")
89
+ if key in ("port", "telnet_port", "baud", "connect_timeout", "buffer_max_size", "max_retries"):
90
+ current_entry[key] = int(val) if val else 0
91
+ else:
92
+ current_entry[key] = val
93
+
94
+ if current_entry:
95
+ _add_entry(config, current_entry)
96
+
97
+ return config
98
+
99
+
100
+ def _add_entry(config: AppConfig, entry: dict):
101
+ name = entry.get("name", "")
102
+ etype = entry.get("type", "ssh")
103
+ if etype == "ssh":
104
+ config.ssh_connections.append(SSHConfig(
105
+ name=name,
106
+ host=entry.get("host", ""),
107
+ port=entry.get("port", 22),
108
+ username=entry.get("username", ""),
109
+ password=entry.get("password", ""),
110
+ key_file=entry.get("key_file", ""),
111
+ ))
112
+ elif etype == "com2tcp":
113
+ config.com2tcp_connections.append(Com2TcpConfig(
114
+ name=name,
115
+ ssh=entry.get("ssh", ""),
116
+ com_port=entry.get("com_port", ""),
117
+ telnet_port=entry.get("telnet_port", 5200),
118
+ baud=entry.get("baud", 115200),
119
+ username=entry.get("username", ""),
120
+ password=entry.get("password", ""),
121
+ connect_timeout=entry.get("connect_timeout", 15),
122
+ buffer_max_size=entry.get("buffer_max_size", 65536),
123
+ max_retries=entry.get("max_retries", 3),
124
+ ))
125
+
126
+
127
+ def _find_config_path(path: str) -> str:
128
+ """搜索配置文件路径,返回第一个存在的文件路径。"""
129
+ source_dir = os.path.dirname(os.path.abspath(__file__))
130
+ repo_root = os.path.join(source_dir, "..", "..", "..")
131
+ search_paths = [
132
+ path,
133
+ os.path.join(source_dir, path),
134
+ os.path.join(source_dir, "..", path),
135
+ os.path.join(repo_root, path),
136
+ os.path.join(repo_root, "src", "remote_debug_mcp", path),
137
+ os.path.join(os.path.expanduser("~"), ".config", "remote-debug-mcp", path),
138
+ ]
139
+ for p in search_paths:
140
+ if os.path.exists(p):
141
+ return p
142
+ return search_paths[0] # default to cwd
143
+
144
+
145
+ def load_config(path: str = "config.yaml") -> AppConfig:
146
+ """加载配置文件,自动搜索多个路径。"""
147
+ found = _find_config_path(path)
148
+ if os.path.exists(found):
149
+ with open(found, "r", encoding="utf-8") as f:
150
+ return _parse_yaml_simple(f.read())
151
+ raise FileNotFoundError(f"Config file not found: {path}")
152
+
153
+
154
+ def _build_yaml(config: AppConfig) -> str:
155
+ """将 AppConfig 序列化为 YAML 字符串。"""
156
+ lines = ["# 远程调试连接配置文件",
157
+ "# 支持 SSH 连接和 com2tcp 串口映射配置",
158
+ "",
159
+ "connections:"]
160
+ for c in config.ssh_connections:
161
+ lines.append(f" - name: {c.name}")
162
+ lines.append(" type: ssh")
163
+ lines.append(f" host: \"{c.host}\"")
164
+ lines.append(f" port: {c.port}")
165
+ lines.append(f" username: \"{c.username}\"")
166
+ lines.append(f" password: \"{c.password}\"")
167
+ if c.key_file:
168
+ lines.append(f" key_file: \"{c.key_file}\"")
169
+ lines.append("")
170
+ for c in config.com2tcp_connections:
171
+ lines.append(f" - name: {c.name}")
172
+ lines.append(" type: com2tcp")
173
+ lines.append(f" ssh: \"{c.ssh}\"")
174
+ lines.append(f" com_port: \"{c.com_port}\"")
175
+ lines.append(f" telnet_port: {c.telnet_port}")
176
+ lines.append(f" baud: {c.baud}")
177
+ if c.username:
178
+ lines.append(f" username: \"{c.username}\"")
179
+ if c.password:
180
+ lines.append(f" password: \"{c.password}\"")
181
+ if c.connect_timeout != 15:
182
+ lines.append(f" connect_timeout: {c.connect_timeout}")
183
+ if c.buffer_max_size != 65536:
184
+ lines.append(f" buffer_max_size: {c.buffer_max_size}")
185
+ if c.max_retries != 3:
186
+ lines.append(f" max_retries: {c.max_retries}")
187
+ lines.append("")
188
+ return "\n".join(lines) + "\n"
189
+
190
+
191
+ def save_config(config: AppConfig, path: str = "config.yaml") -> str:
192
+ """保存当前配置到 YAML 文件。"""
193
+ output_path = os.path.join(os.getcwd(), path)
194
+ with open(output_path, "w", encoding="utf-8") as f:
195
+ f.write(_build_yaml(config))
196
+ ssh_count = len(config.ssh_connections)
197
+ c2t_count = len(config.com2tcp_connections)
198
+ return (f"Config saved: {output_path}\n"
199
+ f" SSH connections: {ssh_count}\n"
200
+ f" com2tcp entries: {c2t_count}")
201
+
202
+
203
+ _config: Optional[AppConfig] = None
204
+
205
+
206
+ def get_config(path: str = "config.yaml") -> AppConfig:
207
+ global _config
208
+ if _config is None:
209
+ _config = load_config(path)
210
+ return _config
211
+
212
+
213
+ def reload_config(path: str = "config.yaml") -> AppConfig:
214
+ global _config
215
+ _config = load_config(path)
216
+ return _config