signalpilot-ai-internal 0.10.0__py3-none-any.whl → 0.11.24__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.
- signalpilot_ai_internal/__init__.py +1 -0
- signalpilot_ai_internal/_version.py +1 -1
- signalpilot_ai_internal/cache_service.py +22 -21
- signalpilot_ai_internal/composio_handlers.py +224 -0
- signalpilot_ai_internal/composio_service.py +511 -0
- signalpilot_ai_internal/database_config_handlers.py +182 -0
- signalpilot_ai_internal/database_config_service.py +166 -0
- signalpilot_ai_internal/databricks_schema_service.py +907 -0
- signalpilot_ai_internal/file_scanner_service.py +5 -146
- signalpilot_ai_internal/handlers.py +388 -9
- signalpilot_ai_internal/integrations_config.py +256 -0
- signalpilot_ai_internal/log_utils.py +31 -0
- signalpilot_ai_internal/mcp_handlers.py +532 -0
- signalpilot_ai_internal/mcp_server_manager.py +298 -0
- signalpilot_ai_internal/mcp_service.py +1255 -0
- signalpilot_ai_internal/oauth_token_store.py +141 -0
- signalpilot_ai_internal/schema_search_config.yml +17 -11
- signalpilot_ai_internal/schema_search_service.py +85 -4
- signalpilot_ai_internal/signalpilot_home.py +961 -0
- signalpilot_ai_internal/snowflake_schema_service.py +2 -0
- signalpilot_ai_internal/test_dbt_mcp_server.py +180 -0
- signalpilot_ai_internal/unified_database_schema_service.py +2 -0
- signalpilot_ai_internal-0.10.0.data/data/share/jupyter/labextensions/signalpilot-ai-internal/schemas/signalpilot-ai-internal/package.json.orig → signalpilot_ai_internal-0.11.24.data/data/share/jupyter/labextensions/signalpilot-ai-internal/package.json +15 -48
- signalpilot_ai_internal-0.10.0.data/data/share/jupyter/labextensions/signalpilot-ai-internal/package.json → signalpilot_ai_internal-0.11.24.data/data/share/jupyter/labextensions/signalpilot-ai-internal/schemas/signalpilot-ai-internal/package.json.orig +9 -52
- {signalpilot_ai_internal-0.10.0.data → signalpilot_ai_internal-0.11.24.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/schemas/signalpilot-ai-internal/plugin.json +7 -1
- signalpilot_ai_internal-0.11.24.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/122.bab318d6caadb055e29c.js +1 -0
- signalpilot_ai_internal-0.11.24.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/129.868ca665e6fc225c20a0.js +1 -0
- signalpilot_ai_internal-0.11.24.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/179.fd45a2e75d471d0aa3b9.js +7 -0
- signalpilot_ai_internal-0.11.24.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/220.81105a94aa873fc51a94.js +1 -0
- signalpilot_ai_internal-0.11.24.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/262.a002dd4630d3b6404a90.js +1 -0
- signalpilot_ai_internal-0.11.24.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/353.cc6f6ecacd703bcdb468.js +1 -0
- signalpilot_ai_internal-0.11.24.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/364.817a883549d55a0e0576.js +1 -0
- signalpilot_ai_internal-0.11.24.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/384.a4daecd44f1e9364e44a.js +1 -0
- signalpilot_ai_internal-0.11.24.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/439.667225aab294fb5ed161.js +1 -0
- signalpilot_ai_internal-0.11.24.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/447.8138af2522716e5a926f.js +1 -0
- signalpilot_ai_internal-0.11.24.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/476.925c73e32f3c07448da0.js +1 -0
- signalpilot_ai_internal-0.11.24.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/477.aaa4cc9e87801fb45f5b.js +1 -0
- signalpilot_ai_internal-0.11.24.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/481.370056149a59022b700c.js +1 -0
- signalpilot_ai_internal-0.11.24.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/510.868ca665e6fc225c20a0.js +1 -0
- signalpilot_ai_internal-0.11.24.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/512.835f97f7ccfc70ff5c93.js +1 -0
- signalpilot_ai_internal-0.11.24.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/57.6c13335f73de089d6b1e.js +1 -0
- signalpilot_ai_internal-0.11.24.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/574.ad2709e91ebcac5bbe68.js +1 -0
- signalpilot_ai_internal-0.11.24.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/635.bddbab8e464fe31f0393.js +1 -0
- signalpilot_ai_internal-0.11.24.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/713.fda1bcdb10497b0a6ade.js +1 -0
- signalpilot_ai_internal-0.11.24.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/741.d046701f475fcbf6697d.js +1 -0
- signalpilot_ai_internal-0.11.24.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/785.c306dffd4cfe8a613d13.js +1 -0
- signalpilot_ai_internal-0.11.24.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/801.e39898b6f336539f228c.js +1 -0
- signalpilot_ai_internal-0.11.24.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/880.77cc0ca10a1860df1b52.js +1 -0
- signalpilot_ai_internal-0.11.24.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/936.4e2850b2af985ed0d378.js +1 -0
- signalpilot_ai_internal-0.11.24.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/956.eeffe67d7781fd63ef4b.js +2 -0
- signalpilot_ai_internal-0.11.24.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/remoteEntry.055f50d20a31f3068c72.js +1 -0
- {signalpilot_ai_internal-0.10.0.data → signalpilot_ai_internal-0.11.24.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/third-party-licenses.json +47 -29
- {signalpilot_ai_internal-0.10.0.dist-info → signalpilot_ai_internal-0.11.24.dist-info}/METADATA +14 -31
- signalpilot_ai_internal-0.11.24.dist-info/RECORD +66 -0
- signalpilot_ai_internal-0.11.24.dist-info/licenses/LICENSE +7 -0
- signalpilot_ai_internal-0.10.0.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/122.e2dadf63dc64d7b5f1ee.js +0 -1
- signalpilot_ai_internal-0.10.0.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/220.328403b5545f268b95c6.js +0 -1
- signalpilot_ai_internal-0.10.0.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/262.726e1da31a50868cb297.js +0 -1
- signalpilot_ai_internal-0.10.0.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/330.af2e9cb5def5ae2b84d5.js +0 -1
- signalpilot_ai_internal-0.10.0.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/353.972abe1d2d66f083f9cc.js +0 -1
- signalpilot_ai_internal-0.10.0.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/364.dbec4c2dc12e7b050dcc.js +0 -1
- signalpilot_ai_internal-0.10.0.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/384.fa432bdb7fb6b1c95ad6.js +0 -1
- signalpilot_ai_internal-0.10.0.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/439.37e271d7a80336daabe2.js +0 -1
- signalpilot_ai_internal-0.10.0.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/476.ad22ccddd74ee306fb56.js +0 -1
- signalpilot_ai_internal-0.10.0.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/481.73c7a9290b7d35a8b9c1.js +0 -1
- signalpilot_ai_internal-0.10.0.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/512.b58fc0093d080b8ee61c.js +0 -1
- signalpilot_ai_internal-0.10.0.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/553.b4042a795c91d9ff71ef.js +0 -2
- signalpilot_ai_internal-0.10.0.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/57.e9acd2e1f9739037f1ab.js +0 -1
- signalpilot_ai_internal-0.10.0.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/635.9720593ee20b768da3ca.js +0 -1
- signalpilot_ai_internal-0.10.0.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/713.8e6edc9a965bdd578ca7.js +0 -1
- signalpilot_ai_internal-0.10.0.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/741.dc49867fafb03ea2ba4d.js +0 -1
- signalpilot_ai_internal-0.10.0.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/742.91e7b516c8699eea3373.js +0 -1
- signalpilot_ai_internal-0.10.0.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/785.2d75de1a8d2c3131a8db.js +0 -1
- signalpilot_ai_internal-0.10.0.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/786.770dc7bcab77e14cc135.js +0 -7
- signalpilot_ai_internal-0.10.0.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/801.ca9e114a30896b669a3c.js +0 -1
- signalpilot_ai_internal-0.10.0.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/880.25ddd15aca09421d3765.js +0 -1
- signalpilot_ai_internal-0.10.0.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/888.34054db17bcf6e87ec95.js +0 -1
- signalpilot_ai_internal-0.10.0.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/remoteEntry.b05b2f0c9617ba28370d.js +0 -1
- signalpilot_ai_internal-0.10.0.dist-info/RECORD +0 -50
- signalpilot_ai_internal-0.10.0.dist-info/licenses/LICENSE +0 -29
- {signalpilot_ai_internal-0.10.0.data → signalpilot_ai_internal-0.11.24.data}/data/etc/jupyter/jupyter_server_config.d/signalpilot_ai.json +0 -0
- {signalpilot_ai_internal-0.10.0.data → signalpilot_ai_internal-0.11.24.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/install.json +0 -0
- /signalpilot_ai_internal-0.10.0.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/553.b4042a795c91d9ff71ef.js.LICENSE.txt → /signalpilot_ai_internal-0.11.24.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/956.eeffe67d7781fd63ef4b.js.LICENSE.txt +0 -0
- {signalpilot_ai_internal-0.10.0.data → signalpilot_ai_internal-0.11.24.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/style.js +0 -0
- {signalpilot_ai_internal-0.10.0.dist-info → signalpilot_ai_internal-0.11.24.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
"""
|
|
2
|
+
MCP Server Manager
|
|
3
|
+
|
|
4
|
+
Handles automatic startup and management of MCP servers (like dbt-mcp) when SignalPilot AI starts.
|
|
5
|
+
"""
|
|
6
|
+
import subprocess
|
|
7
|
+
import sys
|
|
8
|
+
import os
|
|
9
|
+
import logging
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from typing import Optional, Dict, List
|
|
12
|
+
import atexit
|
|
13
|
+
|
|
14
|
+
logger = logging.getLogger(__name__)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class MCPServerManager:
|
|
18
|
+
"""Manages MCP server processes"""
|
|
19
|
+
|
|
20
|
+
def __init__(self):
|
|
21
|
+
self._processes: Dict[str, subprocess.Popen] = {}
|
|
22
|
+
self._server_configs: List[Dict] = []
|
|
23
|
+
|
|
24
|
+
# Register cleanup on exit
|
|
25
|
+
atexit.register(self.stop_all_servers)
|
|
26
|
+
|
|
27
|
+
def add_server_config(self, name: str, command: List[str], cwd: Optional[str] = None,
|
|
28
|
+
env: Optional[Dict[str, str]] = None, transport: str = "stdio"):
|
|
29
|
+
"""
|
|
30
|
+
Add an MCP server configuration
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
name: Server identifier
|
|
34
|
+
command: Command to start the server (as list)
|
|
35
|
+
cwd: Working directory for the server process
|
|
36
|
+
env: Environment variables for the server
|
|
37
|
+
transport: MCP transport type (stdio, sse, etc.)
|
|
38
|
+
"""
|
|
39
|
+
config = {
|
|
40
|
+
'name': name,
|
|
41
|
+
'command': command,
|
|
42
|
+
'cwd': cwd,
|
|
43
|
+
'env': env or {},
|
|
44
|
+
'transport': transport
|
|
45
|
+
}
|
|
46
|
+
self._server_configs.append(config)
|
|
47
|
+
logger.info(f"Added MCP server config: {name}")
|
|
48
|
+
|
|
49
|
+
def start_server(self, name: str) -> bool:
|
|
50
|
+
"""
|
|
51
|
+
Start a specific MCP server
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
name: Server identifier
|
|
55
|
+
|
|
56
|
+
Returns:
|
|
57
|
+
True if server started successfully, False otherwise
|
|
58
|
+
"""
|
|
59
|
+
# Find the server config
|
|
60
|
+
config = None
|
|
61
|
+
for cfg in self._server_configs:
|
|
62
|
+
if cfg['name'] == name:
|
|
63
|
+
config = cfg
|
|
64
|
+
break
|
|
65
|
+
|
|
66
|
+
if not config:
|
|
67
|
+
logger.error(f"No configuration found for server: {name}")
|
|
68
|
+
return False
|
|
69
|
+
|
|
70
|
+
# Check if already running
|
|
71
|
+
if name in self._processes:
|
|
72
|
+
if self._processes[name].poll() is None:
|
|
73
|
+
logger.info(f"MCP server '{name}' is already running")
|
|
74
|
+
return True
|
|
75
|
+
else:
|
|
76
|
+
# Process ended, remove it
|
|
77
|
+
del self._processes[name]
|
|
78
|
+
|
|
79
|
+
try:
|
|
80
|
+
# Prepare environment
|
|
81
|
+
env = os.environ.copy()
|
|
82
|
+
env.update(config['env'])
|
|
83
|
+
env['MCP_TRANSPORT'] = config['transport']
|
|
84
|
+
|
|
85
|
+
# Start the process
|
|
86
|
+
logger.info(f"Starting MCP server '{name}' with command: {' '.join(config['command'])}")
|
|
87
|
+
process = subprocess.Popen(
|
|
88
|
+
config['command'],
|
|
89
|
+
cwd=config['cwd'],
|
|
90
|
+
env=env,
|
|
91
|
+
stdout=subprocess.PIPE,
|
|
92
|
+
stderr=subprocess.PIPE,
|
|
93
|
+
stdin=subprocess.PIPE,
|
|
94
|
+
bufsize=0 # Unbuffered for stdio transport
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
self._processes[name] = process
|
|
98
|
+
logger.info(f"MCP server '{name}' started with PID: {process.pid}")
|
|
99
|
+
return True
|
|
100
|
+
|
|
101
|
+
except Exception as e:
|
|
102
|
+
logger.error(f"Failed to start MCP server '{name}': {e}")
|
|
103
|
+
return False
|
|
104
|
+
|
|
105
|
+
def start_all_servers(self) -> Dict[str, bool]:
|
|
106
|
+
"""
|
|
107
|
+
Start all configured MCP servers
|
|
108
|
+
|
|
109
|
+
Returns:
|
|
110
|
+
Dictionary mapping server names to start success status
|
|
111
|
+
"""
|
|
112
|
+
results = {}
|
|
113
|
+
for config in self._server_configs:
|
|
114
|
+
name = config['name']
|
|
115
|
+
results[name] = self.start_server(name)
|
|
116
|
+
return results
|
|
117
|
+
|
|
118
|
+
def stop_server(self, name: str) -> bool:
|
|
119
|
+
"""
|
|
120
|
+
Stop a specific MCP server
|
|
121
|
+
|
|
122
|
+
Args:
|
|
123
|
+
name: Server identifier
|
|
124
|
+
|
|
125
|
+
Returns:
|
|
126
|
+
True if server stopped successfully, False otherwise
|
|
127
|
+
"""
|
|
128
|
+
if name not in self._processes:
|
|
129
|
+
logger.warning(f"MCP server '{name}' is not running")
|
|
130
|
+
return False
|
|
131
|
+
|
|
132
|
+
try:
|
|
133
|
+
process = self._processes[name]
|
|
134
|
+
|
|
135
|
+
# Try graceful termination first
|
|
136
|
+
process.terminate()
|
|
137
|
+
|
|
138
|
+
try:
|
|
139
|
+
process.wait(timeout=5)
|
|
140
|
+
logger.info(f"MCP server '{name}' terminated gracefully")
|
|
141
|
+
except subprocess.TimeoutExpired:
|
|
142
|
+
# Force kill if it doesn't terminate
|
|
143
|
+
process.kill()
|
|
144
|
+
process.wait()
|
|
145
|
+
logger.warning(f"MCP server '{name}' was force killed")
|
|
146
|
+
|
|
147
|
+
del self._processes[name]
|
|
148
|
+
return True
|
|
149
|
+
|
|
150
|
+
except Exception as e:
|
|
151
|
+
logger.error(f"Failed to stop MCP server '{name}': {e}")
|
|
152
|
+
return False
|
|
153
|
+
|
|
154
|
+
def stop_all_servers(self):
|
|
155
|
+
"""Stop all running MCP servers"""
|
|
156
|
+
server_names = list(self._processes.keys())
|
|
157
|
+
for name in server_names:
|
|
158
|
+
self.stop_server(name)
|
|
159
|
+
|
|
160
|
+
def get_server_status(self, name: str) -> Optional[str]:
|
|
161
|
+
"""
|
|
162
|
+
Get the status of a specific server
|
|
163
|
+
|
|
164
|
+
Args:
|
|
165
|
+
name: Server identifier
|
|
166
|
+
|
|
167
|
+
Returns:
|
|
168
|
+
'running', 'stopped', or None if not configured
|
|
169
|
+
"""
|
|
170
|
+
# Check if configured
|
|
171
|
+
if not any(cfg['name'] == name for cfg in self._server_configs):
|
|
172
|
+
return None
|
|
173
|
+
|
|
174
|
+
if name not in self._processes:
|
|
175
|
+
return 'stopped'
|
|
176
|
+
|
|
177
|
+
if self._processes[name].poll() is None:
|
|
178
|
+
return 'running'
|
|
179
|
+
else:
|
|
180
|
+
return 'stopped'
|
|
181
|
+
|
|
182
|
+
def get_all_server_status(self) -> Dict[str, str]:
|
|
183
|
+
"""
|
|
184
|
+
Get status of all configured servers
|
|
185
|
+
|
|
186
|
+
Returns:
|
|
187
|
+
Dictionary mapping server names to their status
|
|
188
|
+
"""
|
|
189
|
+
status = {}
|
|
190
|
+
for config in self._server_configs:
|
|
191
|
+
name = config['name']
|
|
192
|
+
status[name] = self.get_server_status(name)
|
|
193
|
+
return status
|
|
194
|
+
|
|
195
|
+
def get_server_logs(self, name: str, num_lines: int = 50) -> Dict[str, str]:
|
|
196
|
+
"""
|
|
197
|
+
Get recent stdout/stderr logs from a server
|
|
198
|
+
|
|
199
|
+
Args:
|
|
200
|
+
name: Server identifier
|
|
201
|
+
num_lines: Number of recent lines to retrieve (approximate)
|
|
202
|
+
|
|
203
|
+
Returns:
|
|
204
|
+
Dictionary with 'stdout' and 'stderr' keys containing log output
|
|
205
|
+
"""
|
|
206
|
+
if name not in self._processes:
|
|
207
|
+
return {"stdout": "", "stderr": "", "error": "Server not running"}
|
|
208
|
+
|
|
209
|
+
process = self._processes[name]
|
|
210
|
+
logs = {"stdout": "", "stderr": ""}
|
|
211
|
+
|
|
212
|
+
try:
|
|
213
|
+
# Try to read from stdout (non-blocking)
|
|
214
|
+
import select
|
|
215
|
+
import sys
|
|
216
|
+
|
|
217
|
+
if process.stdout and hasattr(select, 'select'):
|
|
218
|
+
# Unix-like systems
|
|
219
|
+
if select.select([process.stdout], [], [], 0)[0]:
|
|
220
|
+
logs["stdout"] = process.stdout.read(4096).decode('utf-8', errors='ignore')
|
|
221
|
+
elif process.stdout:
|
|
222
|
+
# Windows fallback - attempt read
|
|
223
|
+
try:
|
|
224
|
+
logs["stdout"] = process.stdout.read(4096).decode('utf-8', errors='ignore')
|
|
225
|
+
except:
|
|
226
|
+
logs["stdout"] = "(Unable to read stdout on Windows - pipe may be blocking)"
|
|
227
|
+
|
|
228
|
+
if process.stderr and hasattr(select, 'select'):
|
|
229
|
+
if select.select([process.stderr], [], [], 0)[0]:
|
|
230
|
+
logs["stderr"] = process.stderr.read(4096).decode('utf-8', errors='ignore')
|
|
231
|
+
elif process.stderr:
|
|
232
|
+
try:
|
|
233
|
+
logs["stderr"] = process.stderr.read(4096).decode('utf-8', errors='ignore')
|
|
234
|
+
except:
|
|
235
|
+
logs["stderr"] = "(Unable to read stderr on Windows - pipe may be blocking)"
|
|
236
|
+
|
|
237
|
+
except Exception as e:
|
|
238
|
+
logs["error"] = f"Error reading logs: {e}"
|
|
239
|
+
|
|
240
|
+
return logs
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
# Global instance
|
|
244
|
+
_mcp_server_manager: Optional[MCPServerManager] = None
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
def get_mcp_server_manager() -> MCPServerManager:
|
|
248
|
+
"""Get the global MCP server manager instance"""
|
|
249
|
+
global _mcp_server_manager
|
|
250
|
+
if _mcp_server_manager is None:
|
|
251
|
+
_mcp_server_manager = MCPServerManager()
|
|
252
|
+
return _mcp_server_manager
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
def configure_default_servers():
|
|
256
|
+
"""Configure default MCP servers for SignalPilot AI"""
|
|
257
|
+
manager = get_mcp_server_manager()
|
|
258
|
+
|
|
259
|
+
# Configure dbt-mcp server
|
|
260
|
+
signalpilot_ai_internal_dir = Path(__file__).parent
|
|
261
|
+
dbt_mcp_dir = signalpilot_ai_internal_dir / "dbt-mcp"
|
|
262
|
+
|
|
263
|
+
if dbt_mcp_dir.exists():
|
|
264
|
+
# Use the Python executable that's running this process
|
|
265
|
+
python_executable = sys.executable
|
|
266
|
+
|
|
267
|
+
# Command to run dbt-mcp using the main module
|
|
268
|
+
dbt_mcp_command = [
|
|
269
|
+
python_executable,
|
|
270
|
+
"-m",
|
|
271
|
+
"dbt_mcp.main"
|
|
272
|
+
]
|
|
273
|
+
|
|
274
|
+
manager.add_server_config(
|
|
275
|
+
name="dbt-mcp",
|
|
276
|
+
command=dbt_mcp_command,
|
|
277
|
+
cwd=str(dbt_mcp_dir),
|
|
278
|
+
env={},
|
|
279
|
+
transport="stdio"
|
|
280
|
+
)
|
|
281
|
+
logger.info(f"Configured dbt-mcp server at {dbt_mcp_dir}")
|
|
282
|
+
else:
|
|
283
|
+
logger.warning(f"dbt-mcp directory not found at {dbt_mcp_dir}")
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
def autostart_mcp_servers():
|
|
287
|
+
"""Automatically start all configured MCP servers"""
|
|
288
|
+
configure_default_servers()
|
|
289
|
+
manager = get_mcp_server_manager()
|
|
290
|
+
results = manager.start_all_servers()
|
|
291
|
+
|
|
292
|
+
for name, success in results.items():
|
|
293
|
+
if success:
|
|
294
|
+
logger.info(f"✓ MCP server '{name}' started successfully")
|
|
295
|
+
else:
|
|
296
|
+
logger.error(f"✗ MCP server '{name}' failed to start")
|
|
297
|
+
|
|
298
|
+
return results
|