Add GitHub MCP support to agent mode

- Parse --allowedTools from claude_args to detect when user wants GitHub MCPs
- Wire up github_inline_comment server in prepareMcpConfig for PR contexts
- Update agent mode to use prepareMcpConfig instead of manual config
- Add comprehensive tests for parseAllowedTools edge cases
- Fix TypeScript types to support both entity and automation contexts
This commit is contained in:
km-anthropic
2025-08-13 09:26:04 -07:00
parent eb146ef8b8
commit e3b5697276
4 changed files with 149 additions and 33 deletions

View File

@@ -2,6 +2,8 @@ import * as core from "@actions/core";
import { mkdir, writeFile } from "fs/promises";
import type { Mode, ModeOptions, ModeResult } from "../types";
import type { PreparedContext } from "../../create-prompt/types";
import { prepareMcpConfig } from "../../mcp/install-mcp-server";
import { parseAllowedTools } from "./parse-tools";
/**
* Agent mode implementation.
@@ -39,7 +41,7 @@ export const agentMode: Mode = {
return false;
},
async prepare({ context, githubToken, octokit }: ModeOptions): Promise<ModeResult> {
async prepare({ context, githubToken }: ModeOptions): Promise<ModeResult> {
// Create prompt directory
await mkdir(`${process.env.RUNNER_TEMP}/claude-prompts`, {
recursive: true,
@@ -54,43 +56,43 @@ export const agentMode: Mode = {
promptContent,
);
const mcpConfig: any = {
mcpServers: {},
};
// Add user-provided additional MCP config if any
const additionalMcpConfig = process.env.MCP_CONFIG || "";
if (additionalMcpConfig.trim()) {
try {
const additional = JSON.parse(additionalMcpConfig);
if (additional && typeof additional === "object") {
// Merge mcpServers if both have them
if (additional.mcpServers && mcpConfig.mcpServers) {
Object.assign(mcpConfig.mcpServers, additional.mcpServers);
} else {
Object.assign(mcpConfig, additional);
}
}
} catch (error) {
core.warning(`Failed to parse additional MCP config: ${error}`);
}
}
// Agent mode: pass through user's claude_args with MCP config
// Parse allowed tools from user's claude_args
const userClaudeArgs = process.env.CLAUDE_ARGS || "";
const escapedMcpConfig = JSON.stringify(mcpConfig).replace(/'/g, "'\\''");
const claudeArgs =
`--mcp-config '${escapedMcpConfig}' ${userClaudeArgs}`.trim();
const allowedTools = parseAllowedTools(userClaudeArgs);
// Detect current branch from GitHub environment
const currentBranch = process.env.GITHUB_HEAD_REF ||
process.env.GITHUB_REF_NAME ||
"main";
// Get MCP configuration with GitHub servers when requested
const additionalMcpConfig = process.env.MCP_CONFIG || "";
const mcpConfig = await prepareMcpConfig({
githubToken,
owner: context.repository.owner,
repo: context.repository.repo,
branch: currentBranch,
baseBranch: context.inputs.baseBranch || "main",
additionalMcpConfig,
claudeCommentId: undefined, // No tracking comment in agent mode
allowedTools,
context,
});
// Build final claude_args
const escapedMcpConfig = mcpConfig.replace(/'/g, "'\\''");
const claudeArgs = `--mcp-config '${escapedMcpConfig}' ${userClaudeArgs}`.trim();
core.setOutput("claude_args", claudeArgs);
return {
commentId: undefined,
branchInfo: {
baseBranch: "",
currentBranch: "",
baseBranch: context.inputs.baseBranch || "main",
currentBranch,
claudeBranch: undefined,
},
mcpConfig: JSON.stringify(mcpConfig),
mcpConfig,
};
},

View File

@@ -0,0 +1,22 @@
export function parseAllowedTools(claudeArgs: string): string[] {
// Match --allowedTools followed by the value
// Handle both quoted and unquoted values
const patterns = [
/--allowedTools\s+"([^"]+)"/, // Double quoted
/--allowedTools\s+'([^']+)'/, // Single quoted
/--allowedTools\s+([^\s]+)/, // Unquoted
];
for (const pattern of patterns) {
const match = claudeArgs.match(pattern);
if (match && match[1]) {
// Don't return if the value starts with -- (another flag)
if (match[1].startsWith('--')) {
return [];
}
return match[1].split(',').map(t => t.trim());
}
}
return [];
}