GitHub Issues
GitHub issues of The Smarter Project’s repositories: searched, opened and commented on.
search_issues()asks GitHub’s issue search,GET /search/issues, live, rather than the index: issues change by the minute, and an LLM that is about to open an issue must see one that was opened a minute ago. It searches one repository withrepo:, or all of them withorg:, and drops the results of the organization’s other repositories. Issues are public, so the result does not depend on who asks. Without the caller’s classic token the search is anonymous, and GitHub allows anonymous clients 10 searches a minute for each IP address, which the platform’s users share. A token raises that to 30 for its owner.read_issue()reads an issue and its latest comments, withGET /repos/{owner}/{repo}/issues/{number}and its/comments, so that an LLM can see what an issue already says before it adds to it.create_issue()opens an issue, optionally with labels, withPOST /repos/{owner}/{repo}/issues.close_issue()closes an issue that a merged pull request resolved, with a comment that says why, after GitHub confirms that the pull request was merged.comment_on_issue()adds a comment to an existing issue, withPOST /repos/{owner}/{repo}/issues/{number}/comments.
create_issue() and comment_on_issue() write as the caller, with the caller’s own
classic personal access token, so the issue or comment is the caller’s, and GitHub decides
what the caller may do. Both append a footer that says where the text came from. Never cache
them: every call writes. Neither writes a credential: see
refuse_secrets(). See
smarter.apps.mcpserver.github.client for how the token is checked and kept secret, and how
GitHub’s errors are explained.
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.issues.GitHubComment(**data)[source]
Bases:
BaseModelA comment that GitHub created, with the fields of its response 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.issues.GitHubIssue(**data)[source]
Bases:
BaseModelAn issue that GitHub created, with the fields of its response 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.issues.GitHubIssueClosed(**data)[source]
Bases:
BaseModelAn issue that close_issue closed, with the comment that says why.
- model_config = {'frozen': True}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class smarter.apps.mcpserver.github.issues.GitHubIssueComment(**data)[source]
Bases:
BaseModelA comment on an issue, with the fields that read_issue 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.issues.GitHubIssueDetail(**data)[source]
Bases:
BaseModelOne issue, as
GET /repos/{owner}/{repo}/issues/{number}returns it, with the fields that read_issue reports.GitHub’s response has many more fields, which are ignored. GitHub returns a pull request from this endpoint too, with a
pull_requestfield.- 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.issues.GitHubIssueHit(**data)[source]
Bases:
BaseModelOne issue that GitHub’s search found, 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.issues.GitHubIssueThread(**data)[source]
Bases:
BaseModelAn issue and its latest comments, oldest first.
- comments: list[GitHubIssueComment]
- issue: GitHubIssueDetail
- model_config = {'frozen': True}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class smarter.apps.mcpserver.github.issues.GitHubPullRequestState(**data)[source]
Bases:
BaseModelA pull request, as
GET /repos/{owner}/{repo}/pulls/{number}returns it, with the fields that close_issue reads.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].
- smarter.apps.mcpserver.github.issues.close_issue(repository, number, pull_request_number, comment, token)[source]
Close an issue that a merged pull request resolved, with a comment that says why, as the owner of a GitHub token.
The issue is closed only if GitHub says that the pull request was merged, so that an LLM cannot close an issue on its own judgment alone, nor because a log or an issue told it to. The comment is added first, and the issue is then closed as
completed.- Parameters:
repository (
ProjectRepository) – The repository of the issue and the pull request.number (
int) – The issue’s number.pull_request_number (
int) – The number of the merged pull request that resolved the issue.comment (
str) – Why the issue is resolved, in Markdown.COMMENT_FOOTERis appended.token (
SecretStr|None) – The caller’s classic personal access token.
- Return type:
- Returns:
The closed issue.
- Raises:
SmarterMCPServerToolError – If the token is not a classic personal access token, the comment holds a credential, the pull request was not found or not merged, or GitHub could not be reached, or refused the comment or the closing.
- smarter.apps.mcpserver.github.issues.comment_on_issue(repository, number, body, token)[source]
Add a comment to an issue of a repository of The Smarter Project, as the owner of a GitHub token.
- Parameters:
repository (
ProjectRepository) – The repository.number (
int) – The issue’s number.body (
str) – The comment, in Markdown.COMMENT_FOOTERis appended.token (
SecretStr|None) – The caller’s classic personal access token.
- Return type:
- Returns:
The new comment.
- Raises:
SmarterMCPServerToolError – If the token is not a classic personal access token, the body holds a credential, or GitHub could not be reached, or did not create the comment, e.g. the issue is locked.
- smarter.apps.mcpserver.github.issues.create_issue(repository, title, body, token, labels=())[source]
Open an issue in a repository of The Smarter Project, as the owner of a GitHub token.
- Parameters:
repository (
ProjectRepository) – The repository.title (
str) – The issue’s title.body (
str) – The issue’s body, in Markdown.ISSUE_FOOTERis appended.token (
SecretStr|None) – The caller’s classic personal access token.labels (
tuple[str,...]) – The issue’s labels, e.g.bug. GitHub creates a label that the repository does not have, and silently drops the labels of a caller who cannot push to the repository.
- Return type:
- Returns:
The new issue.
- Raises:
SmarterMCPServerToolError – If the token is not a classic personal access token, the title or body holds a credential, or GitHub could not be reached, or did not create the issue.
- smarter.apps.mcpserver.github.issues.read_issue(repository, number, token)[source]
Read an issue of a repository, and its latest
COMMENTS_PER_PAGEcomments.Issues are public, so the result does not depend on who asks. Without the caller’s classic token the request is anonymous, at GitHub’s anonymous rate limit.
- Parameters:
repository (
ProjectRepository) – The repository.number (
int) – The issue’s number.token (
SecretStr|None) – The caller’s GitHub token, or None. Only a classic personal access token is sent.
- Return type:
- Returns:
The issue and its latest comments, oldest first.
- Raises:
SmarterMCPServerToolError – If GitHub could not be reached, the issue was not found, or GitHub’s response could not be read.
- smarter.apps.mcpserver.github.issues.search_issues(repositories, query, one, state, limit, token)[source]
Search the issues of the repositories, best match first.
- Parameters:
repositories (
tuple[ProjectRepository,...]) – The repositories to search. They have the same owner.query (
str) – The keywords.one (
bool) – Whether to search only the first repository, rather than all of them.state (
Literal['open','closed','all']) –open,closedorall.limit (
int) – The maximum number of issues.token (
SecretStr|None) – The caller’s GitHub token, or None. Only a classic personal access token is sent: otherwise the search is anonymous.
- Return type:
- Returns:
The issues of the repositories.
- Raises:
SmarterMCPServerToolError – If GitHub could not be reached, or refused the search, e.g. its rate limit was reached.