Write-back to GitHub

The write-back is where the whole pipeline pays off. You have a list of typed ReviewComment objects. PyGithub accepts them as a single review with inline comment payloads. One create_review call produces one review event in the GitHub UI with all your comments attached.

github_client.py
python
def post_review(
    owner: str,
    repo: str,
    number: int,
    comments: List[ReviewComment],
    summary: str = "",
) -> dict:
    """Post a review back to the PR as a single review with inline comments."""
    gh = _client()
    repository = gh.get_repo(f"{owner}/{repo}")
    pr = repository.get_pull(number)

    prefix = {"info": "[info]", "warning": "[warning]", "critical": "[critical]"}
    commit = list(pr.get_commits())[-1]
    payload = []
    for c in comments:
        payload.append({
            "path": c.file,
            "position": c.line,
            "body": f"{prefix.get(c.severity, '')} {c.suggestion}".strip(),
        })

    review = pr.create_review(
        commit=commit, body=summary or "Automated review.",
        event="COMMENT", comments=payload,
    )
    return {"review_id": review.id, "comment_count": len(payload)}

The function returns a small status dict. review_id lets the caller reference the review later. comment_count is handy for both logging and dedupe checks. Using event="COMMENT" posts the review without approving or requesting changes, which is the right default for a bot.

mcp_server.py
python
if name == "post_review_comments":
    comments = [ReviewComment(**c) for c in arguments["comments"]]
    response = await post_review_comments(
        arguments["owner"],
        arguments["repo"],
        int(arguments["pr_number"]),
        comments,
        arguments.get("summary", ""),
    )
    return _ok(response)

The MCP entrypoint stays thin. It parses the incoming dicts into ReviewComment objects so validation runs before anything hits GitHub. If a client sends a malformed comment, Pydantic raises before a request goes out.

Single-review write path

How typed ReviewComment objects land on GitHub as one review with inline comments.

Bots should almost never approve code. Approval is a human signal of accountability. REQUEST_CHANGES blocks the merge, which is too heavy for most automated feedback. COMMENT posts the review as advisory, which keeps the bot as a helpful collaborator rather than a blocker. A human can still promote a bot review into an approval after reading it.

Quiz: Quiz

Loading practice…