@@ -74,7 +74,6 @@ def build_mcp_servers(
7474 load_rubric_content ,
7575 )
7676 from ambient_runner .bridges .claude .corrections import create_correction_mcp_tool
77- from ambient_runner .bridges .claude .backend_tools import create_backend_mcp_tools
7877
7978 mcp_servers = load_mcp_config (context , cwd_path ) or {}
8079
@@ -130,18 +129,12 @@ def build_mcp_servers(
130129 mcp_servers ["corrections" ] = correction_server
131130 logger .info ("Added corrections feedback MCP tool (log_correction)" )
132131
133- # Backend API tools (session management)
134- backend_tools = create_backend_mcp_tools (sdk_tool_decorator = sdk_tool )
135- if backend_tools :
136- backend_server = create_sdk_mcp_server (
137- name = "acp" , version = "1.0.0" , tools = backend_tools
138- )
139- mcp_servers ["acp" ] = backend_server
132+ # Credential-aware MCP servers (dynamically configured per bound credentials)
133+ credential_mcp_servers = build_credential_mcp_servers ()
134+ mcp_servers .update (credential_mcp_servers )
135+ if credential_mcp_servers :
140136 logger .info (
141- f"Added backend API MCP tools ({ len (backend_tools )} ): "
142- "acp_list_sessions, acp_get_session, acp_create_session, "
143- "acp_stop_session, acp_send_message, acp_get_session_status, "
144- "acp_restart_session, acp_list_workflows, acp_get_api_reference"
137+ "Added credential MCP servers: %s" , list (credential_mcp_servers .keys ())
145138 )
146139
147140 # Gerrit MCP server (only if credentials are configured)
@@ -160,6 +153,97 @@ def build_mcp_servers(
160153 return mcp_servers
161154
162155
156+ _CREDENTIAL_MCP_REGISTRY : dict [str , dict ] = {
157+ "jira" : {
158+ "command" : "uvx" ,
159+ "args" : ["mcp-atlassian" ],
160+ "env" : {
161+ "JIRA_URL" : "${JIRA_URL}" ,
162+ "JIRA_USERNAME" : "${JIRA_EMAIL}" ,
163+ "JIRA_API_TOKEN" : "${JIRA_API_TOKEN}" ,
164+ "JIRA_SSL_VERIFY" : "true" ,
165+ "READ_ONLY_MODE" : "${JIRA_READ_ONLY_MODE:-true}" ,
166+ },
167+ "server_name" : "mcp-atlassian" ,
168+ },
169+ "kubeconfig" : {
170+ "command" : "uvx" ,
171+ "args" : [
172+ "kubernetes-mcp-server@latest" ,
173+ "--kubeconfig" ,
174+ "/tmp/.ambient_kubeconfig" ,
175+ "--disable-multi-cluster" ,
176+ ],
177+ "server_name" : "openshift" ,
178+ },
179+ "google" : {
180+ "command" : "uvx" ,
181+ "args" : ["workspace-mcp@1.17.1" , "--permissions" , "gmail:send" , "drive:full" ],
182+ "env" : {
183+ "GOOGLE_MCP_CREDENTIALS_DIR" : "${GOOGLE_MCP_CREDENTIALS_DIR}" ,
184+ "MCP_SINGLE_USER_MODE" : "1" ,
185+ "GOOGLE_OAUTH_CLIENT_ID" : "${GOOGLE_OAUTH_CLIENT_ID}" ,
186+ "GOOGLE_OAUTH_CLIENT_SECRET" : "${GOOGLE_OAUTH_CLIENT_SECRET}" ,
187+ "GOOGLE_OAUTH_REDIRECT_URI" : "${GOOGLE_OAUTH_REDIRECT_URI}" ,
188+ "USER_GOOGLE_EMAIL" : "${USER_GOOGLE_EMAIL:-user@example.com}" ,
189+ },
190+ "server_name" : "google-workspace" ,
191+ },
192+ }
193+
194+
195+ def _expand_env_vars (value : str ) -> str :
196+ import re as _re
197+
198+ def _replace (match : _re .Match ) -> str :
199+ expr = match .group (1 )
200+ if ":-" in expr :
201+ var , default = expr .split (":-" , 1 )
202+ return os .environ .get (var , default )
203+ return os .environ .get (expr , match .group (0 ))
204+
205+ return _re .sub (r"\$\{([^}]+)}" , _replace , value )
206+
207+
208+ def build_credential_mcp_servers () -> dict :
209+ credential_ids_raw = os .getenv ("CREDENTIAL_IDS" , "" ).strip ()
210+ if not credential_ids_raw :
211+ return {}
212+
213+ try :
214+ credential_ids = json .loads (credential_ids_raw )
215+ except (json .JSONDecodeError , TypeError ):
216+ logger .warning ("Failed to parse CREDENTIAL_IDS — skipping credential MCP servers" )
217+ return {}
218+
219+ servers : dict = {}
220+ for provider , _cred_id in credential_ids .items ():
221+ registry_entry = _CREDENTIAL_MCP_REGISTRY .get (provider )
222+ if not registry_entry :
223+ continue
224+
225+ server_name = registry_entry ["server_name" ]
226+ server_config : dict = {
227+ "command" : registry_entry ["command" ],
228+ "args" : list (registry_entry ["args" ]),
229+ }
230+
231+ if "env" in registry_entry :
232+ server_config ["env" ] = {
233+ k : _expand_env_vars (v ) for k , v in registry_entry ["env" ].items ()
234+ }
235+
236+ servers [server_name ] = server_config
237+ logger .info (
238+ "Configured %s MCP server for bound credential %s (provider: %s)" ,
239+ server_name ,
240+ _cred_id ,
241+ provider ,
242+ )
243+
244+ return servers
245+
246+
163247def build_allowed_tools (mcp_servers : dict ) -> list [str ]:
164248 """Build the list of allowed tool names from default tools + MCP servers."""
165249 allowed = list (DEFAULT_ALLOWED_TOOLS )
0 commit comments