Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions src/modes/tag/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,12 @@ export async function prepareTagMode({
...userAllowedMCPTools,
];

// Enable inline PR comments for PR contexts so Claude can post
// review feedback directly on diff lines alongside the tracking comment
if (context.isPR) {
tagModeTools.push("mcp__github_inline_comment__create_inline_comment");
Comment thread
sunnypatell marked this conversation as resolved.
}
Comment thread
sunnypatell marked this conversation as resolved.

// Add git commands when using git CLI (no API commit signing, or SSH signing)
// SSH signing still uses git CLI, just with signing enabled
if (!useApiCommitSigning) {
Expand All @@ -149,6 +155,10 @@ export async function prepareTagMode({
);
}

// Dedupe once so both the MCP config and the --allowedTools CLI flag
// see the same set (user-supplied CLAUDE_ARGS may include tools we also push)
const dedupedTools = Array.from(new Set(tagModeTools));

// Get our GitHub MCP servers configuration
const ourMcpConfig = await prepareMcpConfig({
githubToken,
Expand All @@ -157,7 +167,7 @@ export async function prepareTagMode({
branch: branchInfo.claudeBranch || branchInfo.currentBranch,
baseBranch: branchInfo.baseBranch,
claudeCommentId: commentId.toString(),
allowedTools: Array.from(new Set(tagModeTools)),
allowedTools: dedupedTools,
mode: "tag",
context,
});
Expand All @@ -172,7 +182,7 @@ export async function prepareTagMode({
// Add required tools for tag mode.
// acceptEdits: file edits auto-allowed inside cwd ($GITHUB_WORKSPACE), denied outside.
// Headless SDK has no prompt handler, so anything that falls through to "ask" is denied.
claudeArgs += ` --permission-mode acceptEdits --allowedTools "${tagModeTools.join(",")}"`;
claudeArgs += ` --permission-mode acceptEdits --allowedTools "${dedupedTools.join(",")}"`;

// Append user's claude_args (which may have more --mcp-config flags)
if (userClaudeArgs) {
Expand Down
43 changes: 43 additions & 0 deletions test/install-mcp-server.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -314,4 +314,47 @@ describe("prepareMcpConfig", () => {
const parsed = JSON.parse(result);
expect(parsed.mcpServers.github_ci).not.toBeDefined();
});

test("should not include inline comment server for non-PR contexts", async () => {
const result = await prepareMcpConfig({
githubToken: "test-token",
owner: "test-owner",
repo: "test-repo",
branch: "test-branch",
baseBranch: "main",
allowedTools: ["mcp__github_inline_comment__create_inline_comment"],
mode: "tag",
context: mockContext, // isPR: false
});

const parsed = JSON.parse(result);
expect(parsed.mcpServers.github_inline_comment).not.toBeDefined();
});

test("should include both comment and inline comment servers for PR contexts", async () => {
const mockPRContextWithSticky: ParsedGitHubContext = {
...mockPRContext,
inputs: {
...mockPRContext.inputs,
useStickyComment: true,
},
};

const result = await prepareMcpConfig({
githubToken: "test-token",
owner: "test-owner",
repo: "test-repo",
branch: "test-branch",
baseBranch: "main",
allowedTools: ["mcp__github_inline_comment__create_inline_comment"],
mode: "tag",
context: mockPRContextWithSticky,
});

const parsed = JSON.parse(result);
// Both comment server (for sticky tracking comment) and inline comment server should coexist
expect(parsed.mcpServers.github_comment).toBeDefined();
expect(parsed.mcpServers.github_inline_comment).toBeDefined();
expect(parsed.mcpServers.github_inline_comment.env.PR_NUMBER).toBe("456");
});
});