Skip to main content
The GitHub plugin lets your MCP tools interact with GitHub on behalf of your users. You can list and filter issues in any repository, open new issues with assignees and labels, and search across all public and private repositories the connected account can access. All requests go through the Toolshed auth layer — your tools never handle GitHub tokens directly.

Authentication

The plugin uses OAuth 2.0 with the repo and read:user scopes. To connect a user’s GitHub account, redirect them to the login endpoint:
GET /api/auth/github/login?userId=YOUR_USER_ID
Toolshed handles the OAuth redirect, code exchange, and encrypted token storage. After the user authorizes the app, the callback stores their credentials and they are ready to use GitHub tools.
YOUR_USER_ID is the identifier your application uses to track users. It is stored alongside the encrypted token so Toolshed can retrieve the right credentials at tool invocation time.

Connecting a user

1

Initiate the OAuth flow

Send the user to the login URL. In a web app this is typically a redirect; in a CLI you can open it in the browser.
GET /api/auth/github/login?userId=user_abc123
2

User authorizes on GitHub

GitHub presents the standard OAuth consent screen. The user approves the repo and read:user scopes.
3

Toolshed stores the token

The callback handler exchanges the code, encrypts the access token, and stores it against the userId. No further action is required.

Disconnecting

To revoke and remove a user’s GitHub connection, send:
DELETE /api/auth/github?userId=YOUR_USER_ID
Toolshed attempts to revoke the token at GitHub and removes the stored credentials.

Available tools

The GitHub plugin exposes three tools. Read-only tools (github.issues.list and github.repos.search) are safe to auto-approve by MCP clients. The github.issues.create tool is marked destructive and requires explicit user confirmation via the MCP elicitation flow before proceeding.
Lists issues in a GitHub repository. You can filter by state and labels and control how many results are returned. The tool reads from the GitHub REST API using the authenticated user’s token.Parameters:
ParameterTypeRequiredDefaultDescription
ownerstringYesRepository owner (user or organization login)
repostringYesRepository name
state"open" | "closed" | "all"No"open"Filter issues by state
labelsstring[]NoFilter to issues that have all of these labels
limitintegerNo30Maximum number of issues to return (must be positive)
Returns:An object with an issues array. Each issue contains:
FieldTypeDescription
numbernumberIssue number
titlestringIssue title
statestring"open" or "closed"
labelsstring[]Label names applied to the issue
created_atstringISO 8601 creation timestamp
urlstringHTML URL of the issue on GitHub
Example invocation:
{
  "tool": "github.issues.list",
  "input": {
    "owner": "acme-corp",
    "repo": "api-service",
    "state": "open",
    "labels": ["bug"],
    "limit": 10
  }
}
Creates a new issue in a GitHub repository. This tool is marked destructive — Toolshed will pause and ask the user for explicit confirmation before the issue is created. If the user declines or cancels the elicitation prompt, the operation is aborted and no issue is created.
This tool requires user confirmation via the MCP elicitation flow. Your MCP host must support elicitation for this tool to complete successfully.
Parameters:
ParameterTypeRequiredDescription
ownerstringYesRepository owner (user or organization login)
repostringYesRepository name
titlestringYesIssue title
bodystringNoIssue description (Markdown supported)
labelsstring[]NoLabels to apply to the new issue
assigneesstring[]NoGitHub usernames to assign to the issue
Returns:
FieldTypeDescription
numbernumberIssue number of the newly created issue
urlstringHTML URL of the new issue on GitHub
Example invocation:
{
  "tool": "github.issues.create",
  "input": {
    "owner": "acme-corp",
    "repo": "api-service",
    "title": "Rate limiter returns 500 on burst traffic",
    "body": "Reproduces under load. See attached trace.",
    "labels": ["bug", "priority-high"],
    "assignees": ["jsmith"]
  }
}
Searches GitHub repositories using a query string. The query syntax is the same as the GitHub search bar — you can use qualifiers like language:typescript, org:acme-corp, or topic:mcp. Results include both public repositories and private repositories accessible to the authenticated user.Parameters:
ParameterTypeRequiredDefaultDescription
querystringYesGitHub search query string
limitintegerNo10Maximum number of repositories to return (must be positive)
Returns:An object with a repos array. Each repository contains:
FieldTypeDescription
full_namestringowner/repo slug
descriptionstring | nullRepository description
starsnumberStargazer count
urlstringHTML URL of the repository on GitHub
Example invocation:
{
  "tool": "github.repos.search",
  "input": {
    "query": "org:acme-corp topic:api",
    "limit": 5
  }
}

Composing tools

These tools are designed to work together. A common pattern is to search for the right repository first, then list or create issues against it:
// 1. Find the repository
{ "tool": "github.repos.search", "input": { "query": "org:acme-corp api-service" } }

// 2. List open bugs in that repo
{ "tool": "github.issues.list", "input": { "owner": "acme-corp", "repo": "api-service", "state": "open", "labels": ["bug"] } }

// 3. Create a new issue (requires user confirmation)
{ "tool": "github.issues.create", "input": { "owner": "acme-corp", "repo": "api-service", "title": "..." } }
Pass the url field from github.repos.search results or github.issues.list results back to the user as a link — it points directly to the resource on GitHub.com.