diff --git a/src/create-prompt/index.ts b/src/create-prompt/index.ts
index 93bca54..79ad7e3 100644
--- a/src/create-prompt/index.ts
+++ b/src/create-prompt/index.ts
@@ -31,6 +31,7 @@ const BASE_ALLOWED_TOOLS = [
"Write",
"mcp__github_file_ops__commit_files",
"mcp__github_file_ops__delete_files",
+ "mcp__github_file_ops__update_claude_comment",
];
const DISALLOWED_TOOLS = ["WebSearch", "WebFetch"];
@@ -40,15 +41,6 @@ export function buildAllowedToolsString(
): string {
let baseTools = [...BASE_ALLOWED_TOOLS];
- // Add the appropriate comment tool based on event type
- if (eventData.eventName === "pull_request_review_comment") {
- // For inline PR review comments, only use PR comment tool
- baseTools.push("mcp__github__update_pull_request_comment");
- } else {
- // For all other events (issue comments, PR reviews, issues), use issue comment tool
- baseTools.push("mcp__github__update_issue_comment");
- }
-
let allAllowedTools = baseTools.join(",");
if (customAllowedTools) {
allAllowedTools = `${allAllowedTools},${customAllowedTools}`;
@@ -447,33 +439,15 @@ ${sanitizeContent(context.directPrompt)}
`
: ""
}
-${
- eventData.eventName === "pull_request_review_comment"
- ? `
-IMPORTANT: For this inline PR review comment, you have been provided with ONLY the mcp__github__update_pull_request_comment tool to update this specific review comment.
+${`
+IMPORTANT: You have been provided with the mcp__github_file_ops__update_claude_comment tool to update your comment. This tool automatically handles both issue and PR comments.
-Tool usage example for mcp__github__update_pull_request_comment:
+Tool usage example for mcp__github_file_ops__update_claude_comment:
{
- "owner": "${context.repository.split("/")[0]}",
- "repo": "${context.repository.split("/")[1]}",
- "commentId": ${eventData.commentId || context.claudeCommentId},
"body": "Your comment text here"
}
-All four parameters (owner, repo, commentId, body) are required.
-`
- : `
-IMPORTANT: For this event type, you have been provided with ONLY the mcp__github__update_issue_comment tool to update comments.
-
-Tool usage example for mcp__github__update_issue_comment:
-{
- "owner": "${context.repository.split("/")[0]}",
- "repo": "${context.repository.split("/")[1]}",
- "commentId": ${context.claudeCommentId},
- "body": "Your comment text here"
-}
-All four parameters (owner, repo, commentId, body) are required.
-`
-}
+Only the body parameter is required - the tool automatically knows which comment to update.
+`}
Your task is to analyze the context, understand the request, and provide helpful responses and/or implement code changes as needed.
@@ -487,7 +461,7 @@ Follow these steps:
1. Create a Todo List:
- Use your GitHub comment to maintain a detailed task list based on the request.
- Format todos as a checklist (- [ ] for incomplete, - [x] for complete).
- - Update the comment using ${eventData.eventName === "pull_request_review_comment" ? "mcp__github__update_pull_request_comment" : "mcp__github__update_issue_comment"} with each task completion.
+ - Update the comment using mcp__github_file_ops__update_claude_comment with each task completion.
2. Gather Context:
- Analyze the pre-fetched data provided above.
@@ -517,11 +491,11 @@ ${context.directPrompt ? ` - DIRECT INSTRUCTION: A direct instruction was prov
- Look for bugs, security issues, performance problems, and other issues
- Suggest improvements for readability and maintainability
- Check for best practices and coding standards
- - Reference specific code sections with file paths and line numbers${eventData.isPR ? "\n - AFTER reading files and analyzing code, you MUST call mcp__github__update_issue_comment to post your review" : ""}
+ - Reference specific code sections with file paths and line numbers${eventData.isPR ? "\n - AFTER reading files and analyzing code, you MUST call mcp__github_file_ops__update_claude_comment to post your review" : ""}
- Formulate a concise, technical, and helpful response based on the context.
- Reference specific code with inline formatting or code blocks.
- Include relevant file paths and line numbers when applicable.
- - ${eventData.isPR ? "IMPORTANT: Submit your review feedback by updating the Claude comment. This will be displayed as your PR review." : "Remember that this feedback must be posted to the GitHub comment."}
+ - ${eventData.isPR ? "IMPORTANT: Submit your review feedback by updating the Claude comment using mcp__github_file_ops__update_claude_comment. This will be displayed as your PR review." : "Remember that this feedback must be posted to the GitHub comment using mcp__github_file_ops__update_claude_comment."}
B. For Straightforward Changes:
- Use file system tools to make the change locally.
@@ -576,8 +550,8 @@ ${context.directPrompt ? ` - DIRECT INSTRUCTION: A direct instruction was prov
Important Notes:
- All communication must happen through GitHub PR comments.
-- Never create new comments. Only update the existing comment using ${eventData.eventName === "pull_request_review_comment" ? "mcp__github__update_pull_request_comment" : "mcp__github__update_issue_comment"} with comment_id: ${context.claudeCommentId}.
-- This includes ALL responses: code reviews, answers to questions, progress updates, and final results.${eventData.isPR ? "\n- PR CRITICAL: After reading files and forming your response, you MUST post it by calling mcp__github__update_issue_comment. Do NOT just respond with a normal response, the user will not see it." : ""}
+- Never create new comments. Only update the existing comment using mcp__github_file_ops__update_claude_comment.
+- This includes ALL responses: code reviews, answers to questions, progress updates, and final results.${eventData.isPR ? "\n- PR CRITICAL: After reading files and forming your response, you MUST post it by calling mcp__github_file_ops__update_claude_comment. Do NOT just respond with a normal response, the user will not see it." : ""}
- You communicate exclusively by editing your single comment - not through any other means.
- Use this spinner HTML when work is in progress:
${eventData.isPR && !eventData.claudeBranch ? `- Always push to the existing branch when triggered on a PR.` : `- IMPORTANT: You are already on the correct branch (${eventData.claudeBranch || "the created branch"}). Never create new branches when triggered on issues or closed/merged PRs.`}
diff --git a/src/entrypoints/prepare.ts b/src/entrypoints/prepare.ts
index c3e0b38..c69f08b 100644
--- a/src/entrypoints/prepare.ts
+++ b/src/entrypoints/prepare.ts
@@ -89,6 +89,7 @@ async function run() {
context.repository.owner,
context.repository.repo,
branchInfo.currentBranch,
+ commentId.toString(),
);
core.setOutput("mcp_config", mcpConfig);
} catch (error) {
diff --git a/src/mcp/github-file-ops-server.ts b/src/mcp/github-file-ops-server.ts
index 19834c9..1a3e4ba 100644
--- a/src/mcp/github-file-ops-server.ts
+++ b/src/mcp/github-file-ops-server.ts
@@ -439,6 +439,122 @@ server.tool(
},
);
+// Update Claude comment tool
+server.tool(
+ "update_claude_comment",
+ "Update the Claude comment with progress and results (automatically handles both issue and PR comments)",
+ {
+ body: z.string().describe("The updated comment content"),
+ },
+ async ({ body }) => {
+ try {
+ const githubToken = process.env.GITHUB_TOKEN;
+ const claudeCommentId = process.env.CLAUDE_COMMENT_ID;
+ const eventName = process.env.GITHUB_EVENT_NAME;
+ const isPR = process.env.IS_PR === "true";
+
+ if (!githubToken) {
+ throw new Error("GITHUB_TOKEN environment variable is required");
+ }
+ if (!claudeCommentId) {
+ throw new Error("CLAUDE_COMMENT_ID environment variable is required");
+ }
+
+ const owner = REPO_OWNER;
+ const repo = REPO_NAME;
+ const commentId = parseInt(claudeCommentId, 10);
+
+ // Determine if this is a PR review comment based on event type
+ const isPullRequestReviewComment =
+ eventName === "pull_request_review_comment";
+
+ let response;
+ let updateUrl: string;
+
+ if (isPullRequestReviewComment) {
+ // Use the PR review comment API
+ updateUrl = `${GITHUB_API_URL}/repos/${owner}/${repo}/pulls/comments/${commentId}`;
+ } else {
+ // Use the issue comment API (works for both issues and PR general comments)
+ updateUrl = `${GITHUB_API_URL}/repos/${owner}/${repo}/issues/comments/${commentId}`;
+ }
+
+ response = await fetch(updateUrl, {
+ method: "PATCH",
+ headers: {
+ Accept: "application/vnd.github+json",
+ Authorization: `Bearer ${githubToken}`,
+ "X-GitHub-Api-Version": "2022-11-28",
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({ body }),
+ });
+
+ if (!response.ok) {
+ const errorText = await response.text();
+
+ // If PR review comment update fails, fall back to issue comment API
+ if (isPullRequestReviewComment && response.status === 404) {
+ const fallbackUrl = `${GITHUB_API_URL}/repos/${owner}/${repo}/issues/comments/${commentId}`;
+ response = await fetch(fallbackUrl, {
+ method: "PATCH",
+ headers: {
+ Accept: "application/vnd.github+json",
+ Authorization: `Bearer ${githubToken}`,
+ "X-GitHub-Api-Version": "2022-11-28",
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({ body }),
+ });
+
+ if (!response.ok) {
+ const fallbackErrorText = await response.text();
+ throw new Error(
+ `Failed to update comment: ${response.status} - ${fallbackErrorText}`,
+ );
+ }
+ } else {
+ throw new Error(
+ `Failed to update comment: ${response.status} - ${errorText}`,
+ );
+ }
+ }
+
+ const updatedComment = await response.json();
+
+ return {
+ content: [
+ {
+ type: "text",
+ text: JSON.stringify(
+ {
+ id: updatedComment.id,
+ html_url: updatedComment.html_url,
+ updated_at: updatedComment.updated_at,
+ },
+ null,
+ 2,
+ ),
+ },
+ ],
+ };
+ } catch (error) {
+ const errorMessage =
+ error instanceof Error ? error.message : String(error);
+ return {
+ content: [
+ {
+ type: "text",
+ text: `Error: ${errorMessage}`,
+ },
+ ],
+ error: errorMessage,
+ isError: true,
+ };
+ }
+ },
+);
+
async function runServer() {
const transport = new StdioServerTransport();
await server.connect(transport);
diff --git a/src/mcp/install-mcp-server.ts b/src/mcp/install-mcp-server.ts
index 462967d..9233f4b 100644
--- a/src/mcp/install-mcp-server.ts
+++ b/src/mcp/install-mcp-server.ts
@@ -5,6 +5,7 @@ export async function prepareMcpConfig(
owner: string,
repo: string,
branch: string,
+ claudeCommentId?: string,
): Promise {
try {
const mcpConfig = {
@@ -35,6 +36,9 @@ export async function prepareMcpConfig(
REPO_NAME: repo,
BRANCH_NAME: branch,
REPO_DIR: process.env.GITHUB_WORKSPACE || process.cwd(),
+ ...(claudeCommentId && { CLAUDE_COMMENT_ID: claudeCommentId }),
+ GITHUB_EVENT_NAME: process.env.GITHUB_EVENT_NAME || "",
+ IS_PR: process.env.IS_PR || "false",
},
},
},
diff --git a/test/create-prompt.test.ts b/test/create-prompt.test.ts
index 94064b6..fa98ebd 100644
--- a/test/create-prompt.test.ts
+++ b/test/create-prompt.test.ts
@@ -636,7 +636,8 @@ describe("buildAllowedToolsString", () => {
expect(result).toContain("LS");
expect(result).toContain("Read");
expect(result).toContain("Write");
- expect(result).toContain("mcp__github__update_issue_comment");
+ expect(result).toContain("mcp__github_file_ops__update_claude_comment");
+ expect(result).not.toContain("mcp__github__update_issue_comment");
expect(result).not.toContain("mcp__github__update_pull_request_comment");
expect(result).toContain("mcp__github_file_ops__commit_files");
expect(result).toContain("mcp__github_file_ops__delete_files");
@@ -660,8 +661,9 @@ describe("buildAllowedToolsString", () => {
expect(result).toContain("LS");
expect(result).toContain("Read");
expect(result).toContain("Write");
+ expect(result).toContain("mcp__github_file_ops__update_claude_comment");
expect(result).not.toContain("mcp__github__update_issue_comment");
- expect(result).toContain("mcp__github__update_pull_request_comment");
+ expect(result).not.toContain("mcp__github__update_pull_request_comment");
expect(result).toContain("mcp__github_file_ops__commit_files");
expect(result).toContain("mcp__github_file_ops__delete_files");
});