mirror of
https://github.com/anthropics/claude-code-action.git
synced 2026-01-23 15:04:13 +08:00
* feat: make MCP servers conditional in agent mode In agent mode, MCP servers (github_comment, github_ci) are now only included when explicitly requested via allowedTools, rather than being auto-provisioned. This change gives agent mode workflows complete control over which MCP servers are included, preventing unwanted automatic provisioning of GitHub integration tools. Changes: - Add agent mode detection in prepareMcpConfig - Make github_comment server conditional based on allowedTools in agent mode - Make github_ci server conditional based on allowedTools in agent mode - Tag mode behavior remains unchanged (auto-inclusion) 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * test: update agent mode test for conditional MCP behavior Updated test expectation to match the new conditional MCP server behavior where agent mode only includes MCP config when servers are actually needed. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Kashyap Murali <13315300+katchu11@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com>
226 lines
6.6 KiB
TypeScript
226 lines
6.6 KiB
TypeScript
import * as core from "@actions/core";
|
|
import { GITHUB_API_URL, GITHUB_SERVER_URL } from "../github/api/config";
|
|
import type { GitHubContext } from "../github/context";
|
|
import { isEntityContext } from "../github/context";
|
|
import { Octokit } from "@octokit/rest";
|
|
|
|
type PrepareConfigParams = {
|
|
githubToken: string;
|
|
owner: string;
|
|
repo: string;
|
|
branch: string;
|
|
baseBranch: string;
|
|
claudeCommentId?: string;
|
|
allowedTools: string[];
|
|
context: GitHubContext;
|
|
};
|
|
|
|
async function checkActionsReadPermission(
|
|
token: string,
|
|
owner: string,
|
|
repo: string,
|
|
): Promise<boolean> {
|
|
try {
|
|
const client = new Octokit({ auth: token, baseUrl: GITHUB_API_URL });
|
|
|
|
// Try to list workflow runs - this requires actions:read
|
|
// We use per_page=1 to minimize the response size
|
|
await client.actions.listWorkflowRunsForRepo({
|
|
owner,
|
|
repo,
|
|
per_page: 1,
|
|
});
|
|
|
|
return true;
|
|
} catch (error: any) {
|
|
// Check if it's a permission error
|
|
if (
|
|
error.status === 403 &&
|
|
error.message?.includes("Resource not accessible")
|
|
) {
|
|
return false;
|
|
}
|
|
|
|
// For other errors (network issues, etc), log but don't fail
|
|
core.debug(`Failed to check actions permission: ${error.message}`);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
export async function prepareMcpConfig(
|
|
params: PrepareConfigParams,
|
|
): Promise<string> {
|
|
const {
|
|
githubToken,
|
|
owner,
|
|
repo,
|
|
branch,
|
|
baseBranch,
|
|
claudeCommentId,
|
|
allowedTools,
|
|
context,
|
|
} = params;
|
|
try {
|
|
const allowedToolsList = allowedTools || [];
|
|
|
|
// Detect if we're in agent mode (explicit prompt provided)
|
|
const isAgentMode = !!context.inputs?.prompt;
|
|
|
|
const hasGitHubMcpTools = allowedToolsList.some((tool) =>
|
|
tool.startsWith("mcp__github__"),
|
|
);
|
|
|
|
const hasInlineCommentTools = allowedToolsList.some((tool) =>
|
|
tool.startsWith("mcp__github_inline_comment__"),
|
|
);
|
|
|
|
const hasGitHubCommentTools = allowedToolsList.some((tool) =>
|
|
tool.startsWith("mcp__github_comment__"),
|
|
);
|
|
|
|
const hasGitHubCITools = allowedToolsList.some((tool) =>
|
|
tool.startsWith("mcp__github_ci__"),
|
|
);
|
|
|
|
const baseMcpConfig: { mcpServers: Record<string, unknown> } = {
|
|
mcpServers: {},
|
|
};
|
|
|
|
// Include comment server:
|
|
// - Always in tag mode (for updating Claude comments)
|
|
// - Only with explicit tools in agent mode
|
|
const shouldIncludeCommentServer = !isAgentMode || hasGitHubCommentTools;
|
|
|
|
if (shouldIncludeCommentServer) {
|
|
baseMcpConfig.mcpServers.github_comment = {
|
|
command: "bun",
|
|
args: [
|
|
"run",
|
|
`${process.env.GITHUB_ACTION_PATH}/src/mcp/github-comment-server.ts`,
|
|
],
|
|
env: {
|
|
GITHUB_TOKEN: githubToken,
|
|
REPO_OWNER: owner,
|
|
REPO_NAME: repo,
|
|
...(claudeCommentId && { CLAUDE_COMMENT_ID: claudeCommentId }),
|
|
GITHUB_EVENT_NAME: process.env.GITHUB_EVENT_NAME || "",
|
|
GITHUB_API_URL: GITHUB_API_URL,
|
|
},
|
|
};
|
|
}
|
|
|
|
// Include file ops server when commit signing is enabled
|
|
if (context.inputs.useCommitSigning) {
|
|
baseMcpConfig.mcpServers.github_file_ops = {
|
|
command: "bun",
|
|
args: [
|
|
"run",
|
|
`${process.env.GITHUB_ACTION_PATH}/src/mcp/github-file-ops-server.ts`,
|
|
],
|
|
env: {
|
|
GITHUB_TOKEN: githubToken,
|
|
REPO_OWNER: owner,
|
|
REPO_NAME: repo,
|
|
BRANCH_NAME: branch,
|
|
BASE_BRANCH: baseBranch,
|
|
REPO_DIR: process.env.GITHUB_WORKSPACE || process.cwd(),
|
|
GITHUB_EVENT_NAME: process.env.GITHUB_EVENT_NAME || "",
|
|
IS_PR: process.env.IS_PR || "false",
|
|
GITHUB_API_URL: GITHUB_API_URL,
|
|
},
|
|
};
|
|
}
|
|
|
|
// Include inline comment server for PRs when requested via allowed tools
|
|
if (
|
|
isEntityContext(context) &&
|
|
context.isPR &&
|
|
(hasGitHubMcpTools || hasInlineCommentTools)
|
|
) {
|
|
baseMcpConfig.mcpServers.github_inline_comment = {
|
|
command: "bun",
|
|
args: [
|
|
"run",
|
|
`${process.env.GITHUB_ACTION_PATH}/src/mcp/github-inline-comment-server.ts`,
|
|
],
|
|
env: {
|
|
GITHUB_TOKEN: githubToken,
|
|
REPO_OWNER: owner,
|
|
REPO_NAME: repo,
|
|
PR_NUMBER: context.entityNumber?.toString() || "",
|
|
GITHUB_API_URL: GITHUB_API_URL,
|
|
},
|
|
};
|
|
}
|
|
|
|
// CI server is included when:
|
|
// - In tag mode: when we have a workflow token and context is a PR
|
|
// - In agent mode: same conditions PLUS explicit CI tools in allowedTools
|
|
const hasWorkflowToken = !!process.env.DEFAULT_WORKFLOW_TOKEN;
|
|
const shouldIncludeCIServer =
|
|
(!isAgentMode || hasGitHubCITools) &&
|
|
isEntityContext(context) &&
|
|
context.isPR &&
|
|
hasWorkflowToken;
|
|
|
|
if (shouldIncludeCIServer) {
|
|
// Verify the token actually has actions:read permission
|
|
const actuallyHasPermission = await checkActionsReadPermission(
|
|
process.env.DEFAULT_WORKFLOW_TOKEN || "",
|
|
owner,
|
|
repo,
|
|
);
|
|
|
|
if (!actuallyHasPermission) {
|
|
core.warning(
|
|
"The github_ci MCP server requires 'actions: read' permission. " +
|
|
"Please ensure your GitHub token has this permission. " +
|
|
"See: https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token",
|
|
);
|
|
}
|
|
baseMcpConfig.mcpServers.github_ci = {
|
|
command: "bun",
|
|
args: [
|
|
"run",
|
|
`${process.env.GITHUB_ACTION_PATH}/src/mcp/github-actions-server.ts`,
|
|
],
|
|
env: {
|
|
// Use workflow github token, not app token
|
|
GITHUB_TOKEN: process.env.DEFAULT_WORKFLOW_TOKEN,
|
|
REPO_OWNER: owner,
|
|
REPO_NAME: repo,
|
|
PR_NUMBER: context.entityNumber?.toString() || "",
|
|
RUNNER_TEMP: process.env.RUNNER_TEMP || "/tmp",
|
|
},
|
|
};
|
|
}
|
|
|
|
if (hasGitHubMcpTools) {
|
|
baseMcpConfig.mcpServers.github = {
|
|
command: "docker",
|
|
args: [
|
|
"run",
|
|
"-i",
|
|
"--rm",
|
|
"-e",
|
|
"GITHUB_PERSONAL_ACCESS_TOKEN",
|
|
"-e",
|
|
"GITHUB_HOST",
|
|
"ghcr.io/github/github-mcp-server:sha-efef8ae", // https://github.com/github/github-mcp-server/releases/tag/v0.9.0
|
|
],
|
|
env: {
|
|
GITHUB_PERSONAL_ACCESS_TOKEN: githubToken,
|
|
GITHUB_HOST: GITHUB_SERVER_URL,
|
|
},
|
|
};
|
|
}
|
|
|
|
// Return only our GitHub servers config
|
|
// User's config will be passed as separate --mcp-config flags
|
|
return JSON.stringify(baseMcpConfig, null, 2);
|
|
} catch (error) {
|
|
core.setFailed(`Install MCP server failed with error: ${error}`);
|
|
process.exit(1);
|
|
}
|
|
}
|