API & MCP docs

Every feature on this site is one HTTP call away — for you and for your AI agent. Machine-readable twins: llms.txt · llms-full.txt · openapi.json

GitHub Stats SVG renders live GitHub stats cards as SVG. The whole integration is one <img> tag pointing at /api/card. This page documents everything around that: the REST API, the stats-as-JSON endpoint, the MCP server any AI agent can connect to, and the controls that let a GitHub user revoke, purge, or block their data here.

Connect an AI agent (MCP)

The MCP endpoint is streamable HTTP, stateless, no auth — one URL is the entire setup. Protocol revisions 2025-06-18 and 2025-03-26; legacy SSE-transport clients are not supported.

https://george.khananaev.com/github-stats/mcp

Smoke test from a terminal:

curl -s https://george.khananaev.com/github-stats/mcp \
  -H 'content-type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

MCP tools

ToolWhat it doesLimit
list_card_typesCatalog of cards, themes, metrics, parameters, and limits
generate_card_urlValidate params → URL + markdown + HTML. No render — the default choice
preview_cardRender one card now, returning the SVG source30/min/IP
get_user_statsA profile's numbers as JSON: counts, rank, languages, top repos, freshness30/min/IP
register_cardMint a stable /c/ URL; returns a one-time manage key5/h/IP
inspect_cardManage key → registered settings (never secrets)30/h/IP
revoke_cardManage key → permanently delete the registration30/h/IP
purge_user_cacheDelete all cached data for a username2/h/IP · 1/day/user
opt_out / opt_inOwner-verified render block (and its reversal)30/h/IP
read_docsThe complete machine reference (llms-full.txt)
search / fetchChatGPT-connector contract over the same objectsfetch: 30/min/IP

Tool failures come back in-band (isError: true with a plain-English message and a machine code), never as JSON-RPC errors. Every result carries identical text and structuredContent payloads.

REST API

RouteMethodWhat happens
/api/cardGETAnonymous render, fully driven by query params
/api/statsGET?user=<username> → the same numbers as JSON (counts, rank, languages, top repos, fetchedAt)
/c/<token>GETA registration's default card; /c/<token>/<card> and /c/<token>/badge/<metric> switch variants
/api/registerPOST{username, pat?, …} → mints a card + one-time manage key
/api/revokePOST{manageKey} → deletes a registration, permanently
/api/inspectPOST{manageKey} → the registration's settings
/api/purgePOST{username} → clears all cached data for that user
/api/optout · /api/optinPOST{username, pat} → owner-verified render block / reversal
/api/healthGET{"ok":true}

Card parameters (on /api/card as query params, on /api/register as body fields): user, card (stats · langs · streak · badge · repos · activity · trophies · heatmap · monthly · weekdays), theme (default · dark · dracula · tokyonight · gruvbox · catppuccin), metric (stars · followers · commits · prs · issues · repos), layout (bars · donut), hide (stars,commits,prs,issues,followers,contributed), hide_border, radius (0–24), cacheHours (anonymous 6–168, with a token 1–168), and per-color overrides bg · title · text · accent · border. The full table with defaults and clamping rules lives in llms-full.txt and openapi.json.

# a card
curl 'https://george.khananaev.com/github-stats/api/card?user=octocat&card=stats&theme=dark'

# the same numbers as JSON
curl 'https://george.khananaev.com/github-stats/api/stats?user=octocat'

# register → revoke
curl -X POST https://george.khananaev.com/github-stats/api/register \
  -H 'content-type: application/json' -d '{"username":"octocat","theme":"dracula"}'
curl -X POST https://george.khananaev.com/github-stats/api/revoke \
  -H 'content-type: application/json' -d '{"manageKey":"mk_…"}'

Error model: image routes always answer HTTP 200 with a themed SVG, even for errors — never a broken image. JSON routes fail as {"error": "…", "code": "…", "retryAfterS"?: n} with stable machine codes (rate_limited, not_found, opted_out, invalid_params, …). Every public response carries access-control-allow-origin: * — there are no cookies and no ambient credentials anywhere.

Your data, your controls

ControlWho can use itWhat it does
RevokeWhoever holds the manage keyDeletes one registration (and its encrypted token). Its /c/ URLs stop at the origin instantly.
PurgeAnyone, tightly rate-limitedDeletes every cached render and cached GitHub data record for a username. Registrations are never touched.
Opt-outThe account owner, verifiedPurge plus a persistent block: no cards, no stats JSON, no new registrations for that username until an owner-verified opt-in.

Ownership verification for opt-out/opt-in: any GitHub token whose own identity is the username — classic or fine-grained, zero scopes are enough. It is used for exactly one identity probe and never stored or logged. Honest latency caveat: origin effects are immediate, but copies already sitting in the CDN or GitHub's camo proxy fade out on their own within the card's cache window.

# clear my cached data
curl -X POST https://george.khananaev.com/github-stats/api/purge \
  -H 'content-type: application/json' -d '{"username":"octocat"}'

# stop rendering me entirely (token proves it's you; zero scopes needed)
curl -X POST https://george.khananaev.com/github-stats/api/optout \
  -H 'content-type: application/json' -d '{"username":"octocat","pat":"github_pat_…"}'

Rate limits

ScopeLimitApplies to
card30/min/IP/api/card, /api/stats, preview_card, get_user_stats, fetch
registered120/min/IP/c/*
register5/h/IP/api/register, register_card
manage30/h/IPrevoke, inspect, optout, optin
purge2/h/IP + 1/day/usernamepurge
mcp60/min/IPevery /mcp request

Notes for agents