Skip to content

Commit ad9fb12

Browse files
add .mcp.json parser to runner (#196)
Signed-off-by: Michael Clifford <mcliffor@redhat.com> Co-authored-by: Ryan Cook <rcook@redhat.com>
1 parent 8456a14 commit ad9fb12

File tree

1 file changed

+76
-3
lines changed

1 file changed

+76
-3
lines changed

components/runners/claude-code-runner/wrapper.py

Lines changed: 76 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -189,14 +189,27 @@ async def _run_claude_agent_sdk(self, prompt: str):
189189
# Log working directory and additional directories for debugging
190190
logging.info(f"Claude SDK CWD: {cwd_path}")
191191
logging.info(f"Claude SDK additional directories: {add_dirs}")
192-
192+
193+
# Load MCP server configuration from .mcp.json if present
194+
mcp_servers = self._load_mcp_config(cwd_path)
195+
# Build allowed_tools list with MCP server
196+
allowed_tools = ["Read","Write","Bash","Glob","Grep","Edit","MultiEdit","WebSearch","WebFetch"]
197+
if mcp_servers:
198+
# Add permissions for all tools from each MCP server
199+
for server_name in mcp_servers.keys():
200+
allowed_tools.append(f"mcp__{server_name}")
201+
logging.info(f"MCP tool permissions granted for servers: {list(mcp_servers.keys())}")
202+
193203
options = ClaudeAgentOptions(
194-
cwd=cwd_path, permission_mode="acceptEdits",
195-
allowed_tools=["Read","Write","Bash","Glob","Grep","Edit","MultiEdit","WebSearch","WebFetch"],
204+
cwd=cwd_path,
205+
permission_mode="acceptEdits",
206+
allowed_tools= allowed_tools,
207+
mcp_servers=mcp_servers,
196208
setting_sources=["project"],
197209
system_prompt={"type":"preset",
198210
"preset":"claude_code"}
199211
)
212+
200213
# Best-effort set add_dirs if supported by SDK version
201214
try:
202215
if add_dirs:
@@ -1085,6 +1098,66 @@ def _get_repos_config(self) -> list[dict]:
10851098
return []
10861099
return []
10871100

1101+
def _load_mcp_config(self, cwd_path: str) -> dict | None:
1102+
"""Load MCP server configuration from .mcp.json file in the workspace.
1103+
1104+
Searches for .mcp.json in the following locations:
1105+
1. MCP_CONFIG_PATH environment variable (if set)
1106+
2. cwd_path/.mcp.json (main working directory)
1107+
3. workspace root/.mcp.json (for multi-repo setups)
1108+
1109+
Returns the parsed MCP servers configuration dict, or None if not found.
1110+
"""
1111+
try:
1112+
# Check if MCP discovery is disabled
1113+
if os.getenv('MCP_CONFIG_SEARCH', '').strip().lower() in ('0', 'false', 'no'):
1114+
logging.info("MCP config search disabled by MCP_CONFIG_SEARCH env var")
1115+
return None
1116+
1117+
# Option 1: Explicit path from environment
1118+
explicit_path = os.getenv('MCP_CONFIG_PATH', '').strip()
1119+
if explicit_path:
1120+
mcp_file = Path(explicit_path)
1121+
if mcp_file.exists() and mcp_file.is_file():
1122+
logging.info(f"Loading MCP config from MCP_CONFIG_PATH: {mcp_file}")
1123+
with open(mcp_file, 'r') as f:
1124+
config = _json.load(f)
1125+
logging.info(f"MCP servers loaded: {list(config.get('mcpServers', {}).keys())}")
1126+
return config.get('mcpServers')
1127+
else:
1128+
logging.warning(f"MCP_CONFIG_PATH specified but file not found: {explicit_path}")
1129+
1130+
# Option 2: Look in cwd_path (main working directory)
1131+
mcp_file = Path(cwd_path) / ".mcp.json"
1132+
if mcp_file.exists() and mcp_file.is_file():
1133+
logging.info(f"Found .mcp.json in working directory: {mcp_file}")
1134+
with open(mcp_file, 'r') as f:
1135+
config = _json.load(f)
1136+
server_names = list(config.get('mcpServers', {}).keys())
1137+
logging.info(f"MCP servers loaded from {mcp_file}: {server_names}")
1138+
return config.get('mcpServers')
1139+
1140+
# Option 3: Look in workspace root (for multi-repo setups)
1141+
if self.context and self.context.workspace_path != cwd_path:
1142+
workspace_mcp_file = Path(self.context.workspace_path) / ".mcp.json"
1143+
if workspace_mcp_file.exists() and workspace_mcp_file.is_file():
1144+
logging.info(f"Found .mcp.json in workspace root: {workspace_mcp_file}")
1145+
with open(workspace_mcp_file, 'r') as f:
1146+
config = _json.load(f)
1147+
server_names = list(config.get('mcpServers', {}).keys())
1148+
logging.info(f"MCP servers loaded from {workspace_mcp_file}: {server_names}")
1149+
return config.get('mcpServers')
1150+
1151+
logging.info("No .mcp.json file found in any search location")
1152+
return None
1153+
1154+
except _json.JSONDecodeError as e:
1155+
logging.error(f"Failed to parse .mcp.json: {e}")
1156+
return None
1157+
except Exception as e:
1158+
logging.error(f"Error loading MCP config: {e}")
1159+
return None
1160+
10881161

10891162
async def main():
10901163
"""Main entry point for the Claude Code runner wrapper."""

0 commit comments

Comments
 (0)