GitHub Pull Requests
Pull requests to The Smarter Project’s repositories, opened as the caller.
create_pull_request() writes a change as one commit on a new branch, and opens a pull
request from it, with GitHub’s REST api alone, without a clone:
GET /repos/{owner}/{repo}/git/ref/heads/{base}: the base branch’s latest commit.GET /repos/{owner}/{repo}/git/trees/{sha}: the trees of the folders of the changed files, so that an executable file stays executable, and a symbolic link or a folder is never overwritten by a file.POST /repos/{owner}/{repo}/git/trees: the base commit’s tree, with the changes.POST /repos/{owner}/{repo}/git/commits: the commit, optionally with its author.POST /repos/{owner}/{repo}/git/refs: the new branch. GitHub refuses a branch that exists, so the tool never changes an existing branch, e.g.main, nor anyone’s work.POST /repos/{owner}/{repo}/pulls: the pull request.
Like create_issue(), it writes as the caller,
with the caller’s own classic personal access token, which needs the public_repo scope,
and never writes a credential (see refuse_secrets()).
It never changes a file under .github/: GitHub would refuse it without the workflow
scope, and a workflow that a pull request changes may run with the repository’s secrets.
Note
Experimental. The MCPServer was designed and coded by Claude Code (Anthropic’s Claude Opus 5.5), with Lawrence McDaniel as co-author. It is experimental, and will be documented.
- class smarter.apps.mcpserver.github.pulls.GitHubCommitAuthor(**data)[source]
Bases:
BaseModelThe author of a commit, as git records it.
- model_config = {'extra': 'forbid', 'frozen': True}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class smarter.apps.mcpserver.github.pulls.GitHubPullRequest(**data)[source]
Bases:
BaseModelA pull request that GitHub created, with the fields that the tool reports.
GitHub’s response has many more fields, which are ignored.
- model_config = {'extra': 'ignore', 'frozen': True}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class smarter.apps.mcpserver.github.pulls.PullRequestFile(**data)[source]
Bases:
BaseModelOne file that a pull request changes: its whole new content, or its deletion.
- model_config = {'extra': 'forbid', 'frozen': True}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class smarter.apps.mcpserver.github.pulls.PullRequestWriter(repository, token)[source]
Bases:
objectWrite a change as one commit on a new branch, and open a pull request from it.
- Parameters:
repository (
ProjectRepository) – The repository.token (
str) – The caller’s classic personal access token, fromvalidate_token().
- existing_entry(root_tree, path)[source]
Return the tree entry of a path at the base commit, or None if it does not exist.
- request(method, path, action, expected=200, json=None, not_found=None)[source]
Send one request to the repository’s api, and return GitHub’s response, if it succeeded.
- Parameters:
method (
str) – The HTTP method.path (
str) – The path after/repos/{owner}/{repo}, e.g./git/refs.action (
str) – What the request does, for the error message, e.g.create the branch.expected (
int) – The status of success.json (
dict[str,Any] |None) – The request’s JSON body, if any.not_found (
str|None) – What a 404 means, if not that the repository was not found.
- Return type:
Response- Returns:
GitHub’s response.
- Raises:
SmarterMCPServerToolError – If GitHub could not be reached, or refused the request.
- tree_entries(root_tree, files)[source]
Return the entries of the new tree: each file’s content and mode, or its deletion.
- Parameters:
root_tree (
str) – The sha of the base commit’s tree.files (
list[PullRequestFile]) – The changed files.
- Return type:
- Returns:
The entries, for
POST /git/trees.- Raises:
SmarterMCPServerToolError – If a deleted file does not exist, or a path is a folder or a symbolic link.
- write(branch, base, title, body, commit_message, files, author, draft)[source]
Write the commit on a new branch, and open the pull request.
- Raises:
SmarterMCPServerToolError – If a step fails. If the branch was created, but the pull request was not, the error says so.
- Return type:
- smarter.apps.mcpserver.github.pulls.create_pull_request(repository, branch, title, body, commit_message, files, token, base=None, author=None, draft=False)[source]
Open a pull request in a repository of The Smarter Project, as the owner of a GitHub token.
The change is one commit, on a new branch from the latest commit of
base. Each file is given whole: its new content, or its deletion. A changed file keeps its mode, e.g. an executable stays executable.- Parameters:
repository (
ProjectRepository) – The repository.branch (
str) – The new branch, e.g.claude/fix-plugin-timeout. It must not exist.title (
str) – The pull request’s title.body (
str) – The pull request’s description, in Markdown.PULL_REQUEST_FOOTERis appended.commit_message (
str) – The commit’s message.files (
list[PullRequestFile]) – The changed files.token (
SecretStr|None) – The caller’s classic personal access token.base (
str|None) – The branch to merge into, and to branch from. Defaults to the repository’s default branch.author (
GitHubCommitAuthor|None) – The commit’s author and committer. Defaults to the token’s owner.draft (
bool) – Whether to open it as a draft.
- Return type:
- Returns:
The new pull request.
- Raises:
SmarterMCPServerToolError – If the token is not a classic personal access token, the branch name or a file is not valid, the change holds a credential, or GitHub could not be reached, or refused a step, e.g. because the branch exists.
- smarter.apps.mcpserver.github.pulls.validate_branch(name)[source]
Return a branch name, if git and GitHub accept it.
- Parameters:
name (
str) – The branch name, e.g.claude/fix-plugin-timeout.- Return type:
- Returns:
The name.
- Raises:
SmarterMCPServerToolError – If git would refuse the name.
- smarter.apps.mcpserver.github.pulls.validate_files(files)[source]
Return a pull request’s files, if they are a change that the tool may write.
- Parameters:
files (
list[PullRequestFile]) – The files.- Return type:
- Returns:
The files.
- Raises:
SmarterMCPServerToolError – If there are none or too many, a path is not a plain relative path, is under
.github/, or appears twice, or a file has both or neither of content anddelete.