GitHub connector
Two flavours: GitHub App (recommended for organisations) and Personal Access Token (fastest for solo / small teams). Both result in the same indexed content; the App gets you finer-grained per-repo permissions, higher rate limits, and a clean audit log on the GitHub side.
Option A — GitHub App (recommended)
- In the OrgMCP admin console, open Connectors → Add → GitHub.
- Click Install on GitHub →. You'll be bounced to
https://github.com/apps/orgmcp/installations/new. Pick a single repo, an entire org, or selected repos (you can change this later from the GitHub side). - Approve the permissions GitHub asks for. The App requests:
contents: read— fetch file content for indexing and MCP file tools.metadata: read— required by GitHub for any installed App.pull_requests: read,issues: read— enable live MCP tools for PRs and issues (these are not indexed into the knowledge corpus).
- GitHub redirects you back to
<your-tenant>.orgmcp.io/api/oauth/github-app/callback. We persist the installation id as a tenant-shared credential (the platform App private key never leaves deployment config), then bounce you to/app/connectors?status=connected&provider=github-app. - On the connector's Sources tab, pick the repositories to index as knowledge sources. The install is shared by the whole tenant — every member uses the same App installation.
Required role: the install flow is gated to tenant owners and admins. Regular members will see a 403 from /api/oauth/github-app/start — ask your tenant owner to run the install once, after which everyone benefits.
Rotation: we use the App's installation token flow, which rotates automatically every hour. Nothing for you to do.
Option B — Personal Access Token
- On GitHub: Settings → Developer settings → Personal access tokens → Tokens (classic). Create a token with the following scopes:
repo— required for private repos. Usepublic_repoonly if you exclusively want to index public repos.read:org— lets the connector enumerate organisation repositories.
- Set an expiration (we recommend ≤ 90 days) and rotate the token before it expires. Paste the token into Connectors → Add → GitHub (the lower half of the form, below the App-install CTA). The token is stored KMS-encrypted in the per-tenant
connector_credentialstable — never returned to the browser. - Pick the visibility (Whole tenant / Group / Just me) and save. Then open the connector's Sources tab to choose which repositories become knowledge sources.
What gets indexed
- Text files matching the ingest extension allowlist on the crawl branch — markdown, reST, plain text, and common source languages (TypeScript, Python, Go, …) by default. Narrow the set with path allowlists / ignore lists on the source or connector filters below.
- Default branch only — unless a branch allowlist is configured on the connector.
What does not get indexed
- Binary files (images, archives) — they're skipped during ingest.
- Issues, PR descriptions, and comments — those stay available via live MCP tools (
github_list_issues,github_get_pull_request, …) but are not part of the knowledge corpus. - Private repos the connector token doesn't have access to (we surface this as
connector.test.failedin the audit log).
Ingest filters (per-repo)
On the connector's Sources tab you can attach per-repo ingest filters that are read by the GitHub crawler on every sync. Each filter lives under connectors.settings.ingestFilters["owner/name"] and is applied on top of the source-level paths / ignorePaths fields.
- Path allowlist — globs or prefixes (e.g.
docs/**,README.md,docs/). Intersected (AND-ed) with the source's ownpaths; both must allow a file for it to be indexed. Leave empty to skip the filter. - Branch allowlist — exact branch names (without the
refs/heads/prefix). When set, the crawler walks each listed branch instead of the source-levelref/default-branch path. Empty = the sourcerefor the repo's default branch (not every branch). The global per-repo file cap (1000) is shared across all branches, so a wide allowlist can hit it — when that happens the source reports a Partial sync warning naming the cap instead of quietly indexing the first 1000 files. - Since date — inclusive lower bound. The crawler lists commits on each walked branch at/after this timestamp, unions the touched paths, and only indexes files in that set (intersected with path filters). Unchanged older files are skipped on purpose. Very busy repositories may hit a commit-page cap and report a Partial sync warning.
Documents emitted under an active filter carry metadata.connectorFilters = { branchAllowlist, pathAllowlist, sinceDate } (only the keys that applied) so a downstream audit can verify which filter shaped the snapshot. Repos with no filter configured produce a byte-identical document set to the pre-Track-C crawler.
Sync cadence
Scheduled crawls run about every 6 hours. When the tip commit SHA matches the SHA from the previous successful crawl, the index is left untouched. A full re-walk runs at least every 24 hours (reconcile) so force-pushes cannot leave stale chunks. Manual Sync now always re-walks.
A crawl that saw only part of a repository says so. Hitting the 1000-file cap, or a repository large enough that GitHub returns a truncated file listing, sets a Partial sync warning on the source — visible next to its sync badge — because a partial index otherwise looks exactly like a complete one: search simply answers "not found" for files it never saw. Narrow the path filter to bring the important parts back under the cap.
GitHub rate limits are waited out, not surfaced as failures: throttled calls retry with backoff (about 10 seconds of budget for a live tool call, about a minute for a background crawl) using the delay GitHub itself asks for.
Audience visibility
Each repo can be a separate knowledge source with its own audience. Common patterns:
infra/*repos → audience Group: Engineeringhandbookrepo → audience Whole tenant~/notespersonal repo → audience Just me (use the Personal connectors flow)