Skip to main content
Glama

ContribScout

CI License: MIT Model Context Protocol

An MCP server that scores GitHub repository maintainer health, so you can find good first issues on projects that actually merge newcomer pull requests.

It also ships a CLI and a local React dashboard over the same engine.

Why

Searching GitHub for is:issue is:open label:"good first issue" returns thousands of results with no indication of whether anyone is still maintaining the project. It is easy to spend an evening on a clean pull request that then sits unreviewed for months because the repository was abandoned a year ago.

ContribScout scores the repository behind each issue before recommending it:

  1. Query GitHub for beginner-labeled candidate issues.

  2. Pull repository activity metrics: median response time, merge rate, commit recency, contributor count.

  3. Combine them into a 0-100 health score.

  4. Drop dead repositories and rank what is left.

Related MCP server: Narad GitHub Agent

Screenshots

The bundled dashboard (npm run ui) against the live GitHub API:

Find Issues

Repo Health

Find issues ranked by repository health

Repository health audit

Check Issue

Compare

Issue claim status verdict

Side-by-side repository comparison

Contribution guide summary

How the score works

Each repository is graded out of 100 across four pillars:

Pillar

Weight

Measures

Maintainer responsiveness

35

Median latency from issue creation to the first non-bot maintainer reply

PR merge rate

30

Closed pull requests that were merged rather than quietly abandoned

Commit recency

20

Time since the latest commit on the default branch

Contributor velocity

15

Unique active committers in the past 90 days

Grades: VIBRANT 85-100, HEALTHY 70-84, MODERATE 45-69, STALE 0-44.

Three details matter more than the weights:

  • Only comments from accounts with OWNER, MEMBER or COLLABORATOR association count toward response time. Replies from other users and from greeting bots such as github-actions and stale[bot] are ignored, otherwise a welcoming bot makes a dead repository look responsive.

  • Merge rate uses merged / closed rather than raw PR volume. Plenty of repositories receive pull requests and close them without merging, and that distinction is the whole point.

  • Recency decays in steps, so a repository with no commits for several months cannot score well on activity no matter how good its other pillars look.

Issue freshness

A healthy repository can still hold issues opened two years ago and never touched. When ranking results, a freshness penalty is applied on top of the repository score:

  • Under 14 days idle: no penalty.

  • Past that, exponential decay subtracting up to 25 points, saturating near 180 days.

  • The displayed score is the repository health minus that penalty, so a fresh issue outranks a stale one from an equally healthy repository.

The repository score itself is never modified. Searches default to a 60-day activity window and cover good first issue, beginner and first-timers-only, merged and deduplicated.

Setup

Requires Node.js 22 or newer (the SQLite cache depends on better-sqlite3 13) and a GitHub personal access token. Public repository data needs no scopes; the token raises your rate limit from about 60 requests per hour to 5,000.

Add the server to your Claude Desktop config, at ~/Library/Application Support/Claude/claude_desktop_config.json on macOS or %APPDATA%\Claude\claude_desktop_config.json on Windows:

{
  "mcpServers": {
    "contribscout": {
      "command": "npx",
      "args": ["-y", "contribscout"],
      "env": { "GITHUB_TOKEN": "ghp_your_github_token_here" }
    }
  }
}

To run from a local checkout, point it at your build instead:

{
  "mcpServers": {
    "contribscout": {
      "command": "node",
      "args": ["/absolute/path/to/contribscout/dist/index.js"],
      "env": { "GITHUB_TOKEN": "ghp_your_github_token_here" }
    }
  }
}

MCP tools

find_good_first_issues

Beginner-labeled issues ranked by repository health adjusted for issue freshness.

  • language (string, required): "typescript", "python", "rust", "go".

  • topics (string[], optional): topic keywords, for example ["cli", "web"].

  • min_stars (number, optional, default 0): minimum repository stars.

  • min_score (number, optional, default 50): minimum health score.

  • limit (number, optional, default 5): how many issues to return.

"Find me 3 good first issues in Python machine learning libraries with active maintainers."

get_repo_health

Full four-pillar audit of one repository.

  • owner (string, required), repo (string, required).

  • bypass_cache (boolean, optional, default false): force a fresh scan.

"Check the maintainer health and PR merge rate for colinhacks/zod."

get_contribution_guide

Finds and summarizes CONTRIBUTING.md, extracting setup, test commands, PR rules and code conventions.

  • owner (string, required), repo (string, required).

"Summarize the setup and testing guidelines from facebook/react's contributing guide."

check_issue_status

Audits one issue for claim conflicts before you start. Detects assignees, cross-referenced pull requests including those from forks, whether a maintainer replied, and how long the issue has been idle.

Verdict

Meaning

AVAILABLE

Unassigned, no linked PRs, recent activity

CLAIMED

Assigned to someone with no PR yet, so coordinate first

IN_PROGRESS

An open pull request already references this issue

CLOSED

Issue is closed

STALE

Untouched for 90 or more days, likely obsolete

  • owner (string, required), repo (string, required), issue_number (number, required).

"Is colinhacks/zod issue #42 actually free to work on?"

compare_repos

Scores 2 to 5 repositories side by side and recommends one.

  • repos (string[], required): "owner/name" entries, full GitHub URLs also accepted.

  • bypass_cache (boolean, optional, default false).

"Compare zod, joi and yup. Which has the healthiest maintainer community?"

Caching

Results are cached locally in SQLite via better-sqlite3 in WAL mode. A first scan of a repository costs roughly 13 API requests and about two seconds; repeat lookups are served from disk. Repository health uses a 24-hour TTL, contribution guides seven days, and not-found guides are cached too because a missing CONTRIBUTING.md otherwise costs six probe requests every time.

Inspect or empty the cache with contribscout cache stats and contribscout cache clear. It lives at ~/.contribscout/cache.db; set CONTRIBSCOUT_CACHE_DB to move it, or to :memory: for an ephemeral run.

A scan aborts rather than scoring a repository from partial data, so a rate limit or an outage cannot be frozen into the cache as a STALE verdict.

Rate limits

Repository scans run at most five at a time, and concurrent scans of the same repository share one execution, which matters because a page of search results often contains several issues from the same project. A search peaks at roughly 13 concurrent requests rather than the few hundred an unbounded fan-out would produce, which is what keeps GitHub's secondary rate limiter out of the way.

Transient failures and rate-limit hits are retried by Octokit's bundled plugins, with all logging routed to stderr so the MCP stdio stream stays clean. Every successful tool response ends with a quota line such as API quota: 4,950/5,000 · resets 13:58, read from failed responses as well as successful ones so it stays accurate while you are being throttled.

Dashboard notes

The dashboard renders markdown assembled from arbitrary repositories, including issue titles and verbatim CONTRIBUTING.md excerpts, so it treats that content as untrusted. Link targets are restricted to http(s), mailto, same-origin paths and anchors, so a javascript: URL renders as plain text. Responses carry a content security policy, X-Content-Type-Options: nosniff and Referrer-Policy: no-referrer. Only loopback Host headers are served, which blocks DNS rebinding from a page you happen to have open, and clearing the cache requires POST so it cannot be triggered by a cross-site image tag.

CLI

git clone https://github.com/deahmedbacha/contribscout.git
cd contribscout
npm install
cp .env.example .env   # add your GITHUB_TOKEN
npm run build
npm test

# Score one repository
npx tsx src/cli.ts score colinhacks/zod

# Rank beginner-friendly issues
npx tsx src/cli.ts find typescript cli --limit=6 --min-stars=100 --min-score=60

# Summarize contribution guidelines
npx tsx src/cli.ts guide facebook/react

# Check whether an issue is free to work on
npx tsx src/cli.ts check colinhacks/zod#42
npx tsx src/cli.ts check https://github.com/facebook/react/issues/28123

# Compare candidates
npx tsx src/cli.ts compare colinhacks/zod hapijs/joi

# Cache
npx tsx src/cli.ts cache stats
npx tsx src/cli.ts cache clear

# Machine-readable output, available on every command
npx tsx src/cli.ts score vercel/next.js --json

Development

npm install
npx playwright install chromium   # only needed for screenshot capture

npm run build     # tsc + vite build, outputs dist/ and dist/ui/
npm test

npm run ui        # serves dist/ui and the JSON API on 127.0.0.1:6277
npm run ui:dev    # Vite dev server on :5173 with HMR, proxies /api to the above

node scripts/capture.mjs   # regenerates docs/screenshots, needs GITHUB_TOKEN

npm run ui serves the built assets, so run npm run build first.

Layout: src/github/ holds the GitHub domain modules (client, errors, search, issues, analysis, health, guide). src/core.ts holds the search and compare flows shared by the MCP server, the CLI and the dashboard, so the three surfaces cannot drift apart. src/concurrency.ts bounds and coalesces the API fan-out. src/mcp/tools.ts defines the tool schemas and handlers. ui/src is the React dashboard.

Tests never touch your real cache: vitest.config.ts points CONTRIBSCOUT_CACHE_DB at :memory:.

Publishing

npm login
npm publish --access public

Registries that list MCP servers: the official registry, Smithery (a smithery.yaml is already included), Glama, and the awesome-mcp-servers list.

License

MIT

Related MCP Connectors

Related MCP Servers