GitBanners API docs
Everything GitBanners does has an address. A banner is a URL, the data behind it is a JSON API, and the same operations are tools on an MCP server. None of it needs a key, an account or a build step.
Quick start
Put a GitHub login, or owner/repo, in the path and add .svg or .png:
https://gitbanners.com/markeljan.svghttps://gitbanners.com/vercel/next.js/contributors.png?theme=dracula
In a README, wrap the image in a link to its page:
markdown[](https://gitbanners.com/markeljan)
Software should ask the API instead of building URLs by hand. It checks that the target exists and answers with the image URLs and the embed code:
bashcurl "https://gitbanners.com/api/v1/banner?target=vercel/next.js"
URL patterns
URLs are shaped like GitHub's own. The same path is a page, an image or a Markdown document, depending on its ending.
| URL | Answers with |
|---|---|
/{owner} | The page of a user or an organization. |
/{owner}.svg, /{owner}.png | The banner of that account, drawn with its default preset. |
/{owner}/{preset}.svg | One preset of a profile, such as /torvalds/streak.svg. |
/{owner}/{repo} | The page of a repository. |
/{owner}/{repo}.svg | The banner of a repository. |
/{owner}/{repo}/{preset}.svg | One preset of a repository, such as /vercel/next.js/contributors.svg. |
/embed/{owner}, /embed/{owner}/{repo} | The image without an extension. The format follows the Accept header. |
/b/{id}.svg, /b/{id}.png | A saved banner, by its id. |
/{owner}.md, /{owner}/{repo}.md | The page as Markdown: who it is, the numbers, every banner URL. |
{owner}is the login of a GitHub user or organization. It is not case-sensitive; links are printed in lower case.- A second segment that is the id of a profile preset (
overview,activity,stats,repos,languages,streak,wrapped,card) selects that preset. Anything else is read as a repository name. A repository that shares its name with a preset is written with its own preset:/{owner}/{repo}/overview.svg. - A login that collides with a route of this site is written with
@:/@docs.svgis the banner of the GitHub account named docs. .svgand.pngare honoured on the last segment only, so/vercel/next.jsis a repository and not a file.- Options go in the query string and are the same for every form:
?theme=dracula&size=og. A saved banner keeps its own options and ignores them.
Image responses
A well-formed image URL always answers 200 with an image. A README shows a broken-image icon for any other status, so an unknown login or a GitHub outage is drawn as a small card instead, and the X-Banner-State header says which it was.
X-Banner-State | Meaning | Kept by the CDN for |
|---|---|---|
ok | Drawn from complete data. | 15 minutes |
provisional | Drawn while GitHub was still computing part of the data. | 1 minute |
not_found | No account or public repository has that name. | 5 minutes |
unavailable | GitHub could not be asked and no earlier copy exists. | 30 seconds |
error | Drawing failed. | 30 seconds |
Cache-Control: public, max-age=600lets browsers and GitHub's image proxy reuse an image for 10 minutes. The CDN refreshes its own copy every 15 minutes, serves the previous one while it does, and keeps serving it for up to 7 days if GitHub cannot be reached.Access-Control-Allow-Origin: *andCross-Origin-Resource-Policy: cross-origin: a banner can be embedded, fetched and drawn on a canvas from any site.- SVG answers carry a
Content-Security-Policythat allows no scripts and no external resources. Avatars are inlined, so the image needs nothing from the network. ?scale=1,2or3sets the pixel density of a PNG. README banners default to 2, the fixed social sizes to 1.?download=1asks the browser to save the file.- A URL that cannot be a banner answers
404and no image: as a problem (not_found) when a login or repository name is too long or malformed or the path has more than three segments, and as the HTML 404 page when the first segment is a route of this site or contains a character no GitHub login can.
Content negotiation
The bare URL of a banner page answers with what the client asks for.
| Request | Answer |
|---|---|
Accept: text/html, Accept: */* or no Accept header | The HTML page. |
Accept: text/markdown, alone or listed before text/html | The page as Markdown. |
Accept: image/* without text/html, which is what an <img> tag sends | The image. |
Negotiated answers carry Vary: Accept. Embed snippets always use the explicit .svg or .png URL, which answers the same for every client.
Embedding
Markdown for a README. The image links to its page, where a reader can copy the banner for themselves:
markdown[](https://gitbanners.com/markeljan)
HTML that follows the reader's light or dark theme on GitHub:
html<a href="https://gitbanners.com/markeljan"><picture><source media="(prefers-color-scheme: dark)" srcset="https://gitbanners.com/markeljan.svg?theme=github-dark"><img src="https://gitbanners.com/markeljan.svg?theme=github-light" alt="GitHub banner for markeljan"></picture></a>
GitHub data is refreshed every 15 minutes, the CDN copy of an image every 15 minutes, and GitHub's image proxy keeps its copy for 10 minutes. A banner in a README therefore trails GitHub by less than an hour.
Variants and themes
A banner is a preset (what it shows), a size (the canvas), a theme (the colours) and optional overrides. GET /api/v1/options returns everything in this section as JSON.
Presets
There are 16 presets. The kind of the target decides which ones apply; an id that does not exist for the kind falls back to its default.
| For | Preset | URL | Shows |
|---|---|---|---|
| User | overview | /{owner}.svg | Identity, headline numbers and the contribution graph. |
| User | activity | /{owner}/activity.svg | Only the contribution graph, with the yearly total. |
| User | stats | /{owner}/stats.svg | Eight headline numbers for the last 12 months. |
| User | repos | /{owner}/repos.svg | Pinned or most-starred repositories above the contribution graph. |
| User | languages | /{owner}/languages.svg | Language mix across public repositories. |
| User | streak | /{owner}/streak.svg | Current and longest streak over the last year of activity. |
| User | wrapped | /{owner}/wrapped.svg | A poster of one calendar year: the total, the graph, streak, best day, busiest month and top repositories. |
| User | card | /{owner}/card.svg | Small README card with three numbers. |
| Repository | overview | /{owner}/{repo}.svg | Name, description, headline numbers and the language bar. |
| Repository | activity | /{owner}/{repo}/activity.svg | A year of commits as a contribution-style calendar, with the headline numbers. |
| Repository | contributors | /{owner}/{repo}/contributors.svg | The people behind the repository, as an avatar grid. |
| Repository | social | /{owner}/{repo}/social.svg | Poster sized for the repository social preview and link previews. |
| Repository | release | /{owner}/{repo}/release.svg | Latest release, open issues and pull requests, and commits per week. |
| Organization | overview | /{owner}.svg | Identity, headline numbers and the faces of public members. |
| Organization | repos | /{owner}/repos.svg | The organization's most-starred public repositories. |
| Organization | activity | /{owner}/activity.svg | A year of commits across the organization's top repositories, as a calendar. |
Sizes
size | Name | Pixels | For |
|---|---|---|---|
readme | README | 846 wide, height follows the content | Fits the GitHub README column. Height follows the content. |
x | X header | 1500 by 500 | Profile header on X. Also fits Bluesky and Mastodon. |
linkedin | LinkedIn banner | 1584 by 396 | Background image of a personal LinkedIn profile. |
og | Link preview | 1200 by 630 | Open Graph image for link previews in chats and feeds. |
social | GitHub social preview | 1280 by 640 | Repository social preview. Upload it in the repo settings. |
square | Square | 1080 by 1080 | Square post for feeds. |
width (320 to 3000) and height (120 to 3000) set a custom canvas in pixels. A custom width without a height keeps the automatic height.
Themes
There are 24 themes. The default is github-dark, and an unknown id falls back to it. Every colour of a theme can be overridden with the parameters below.
theme | Name | Mode | Background | Accent |
|---|---|---|---|---|
github-dark | GitHub Dark | dark | #0d1117 | #4493f8 |
github-light | GitHub Light | light | #ffffff | #0969da |
github-dark-dimmed | GitHub Dark Dimmed | dark | #212830 | #478be6 |
github-dark-high-contrast | GitHub Dark High Contrast | dark | #010409 | #74b9ff |
github-light-high-contrast | GitHub Light High Contrast | light | #ffffff | #023b95 |
github-halloween | GitHub Halloween | dark | #0d1117 | #4493f8 |
github-halloween-light | GitHub Halloween Light | light | #ffffff | #0969da |
github-winter | GitHub Winter | dark | #0d1117 | #4493f8 |
github-winter-light | GitHub Winter Light | light | #ffffff | #0969da |
github-dark-classic | GitHub Dark Classic | dark | #0d1117 | #4493f8 |
dracula | Dracula | dark | #282a36 | #ff79c6 |
tokyo-night | Tokyo Night | dark | #1a1b26 | #bb9af7 |
catppuccin-mocha | Catppuccin Mocha | dark | #1e1e2e | #cba6f7 |
catppuccin-latte | Catppuccin Latte | light | #eff1f5 | #8839ef |
nord | Nord | dark | #2e3440 | #88c0d0 |
gruvbox-dark | Gruvbox Dark | dark | #282828 | #fabd2f |
one-dark | One Dark | dark | #21252b | #61afef |
solarized-dark | Solarized Dark | dark | #002b36 | #2aa198 |
solarized-light | Solarized Light | light | #fdf6e3 | #d33682 |
rose-pine | Rosé Pine | dark | #191724 | #ebbcba |
monokai | Monokai | dark | #272822 | #e6db74 |
synthwave-84 | SynthWave '84 | dark | #262335 | #36f9f6 |
vercel | Vercel | dark | #000000 | #0072f5 |
ayu-dark | Ayu Dark | dark | #0d1017 | #e6b450 |
Query parameters
| Parameter | Value | What it does | Example |
|---|---|---|---|
size | readme | x | linkedin | og | social | square | Canvas. readme is 846 px wide with automatic height; the others are fixed social sizes. | size=og |
width | integer 320-3000 | Custom canvas width in pixels. Overrides size. | width=495 |
height | integer 120-3000 | Custom canvas height in pixels. Without it a custom width gets an automatic height. | height=195 |
theme | theme id | Colour theme. Default github-dark. See /themes for all of them. | theme=dracula |
bg | hex colour without # | Background colour, on top of the theme. | bg=0d1117 |
surface | hex colour without # | Colour of cards and tiles inside the banner. | surface=151b23 |
border_color | hex colour without # | Colour of outlines and hairlines. | border_color=3d444d |
text | hex colour without # | Primary text colour. | text=f0f6fc |
muted | hex colour without # | Secondary text and icon colour. | muted=9198a1 |
accent | hex colour without # | Accent colour for links, highlights and charts. | accent=4493f8 |
heat | hex colour without #, one or five separated by commas | Contribution graph colours. One colour is turned into a five-step ramp; five are used as given, from empty to busiest. | heat=a855f7 |
font | mona | mono | Typeface: Mona Sans (default) or Mona Sans Mono. | font=mono |
radius | integer 0-64 | Outer corner radius in pixels. | radius=0 |
border | 0 | 1 | Draw the outer 1 px border. | border=0 |
title | text, at most 80 characters | Custom headline replacing the default title. | title=Open source work |
year | integer from 2008 | Calendar year for profile banners. Default: the last 12 months. | year=2025 |
stats | comma-separated stat ids | Which numbers to show, in order, e.g. contributions, commits, pullRequests, stars, followers. | stats=contributions,stars,followers |
show | comma-separated section ids | Explicit sections in render order, replacing the preset's own: header, stats, heatmap, streak, repos, languages, orgs, people, activity, contributors. | show=header,heatmap,languages |
hide | comma-separated element ids | Elements to leave out: avatar, bio, meta, title, legend, labels, topics, description. | hide=bio,legend |
count | integer 1-30 | How many repositories, contributors or people to show. | count=4 |
brand (Pro) | 0 | 1 | Show the small site mark. Turning it off needs Pro. | brand=0 |
animate (Pro) | 0 | 1 | Animate the contribution graph (SVG only). Needs a saved Pro banner. | animate=1 |
Parsing is lenient on purpose: an unknown parameter is ignored and an invalid value falls back to the default, so a typo never breaks an image that is already embedded somewhere. The parameters marked Pro are honoured on saved banners of Pro accounts only.
REST API
The JSON API lives under https://gitbanners.com/api/v1. It is read-only (GET, HEAD and OPTIONS), needs no key, and sends Access-Control-Allow-Origin: *, so a browser can call it from any site. /openapi.json describes it in OpenAPI 3.1.
| Operation | Request | Returns |
|---|---|---|
getOptions | GET /api/v1/options | An OptionsCatalog. |
search | GET /api/v1/search | A SearchResult: the query and a list of suggestions. |
getBanner | GET /api/v1/banner | A BannerDescription. |
getOwner | GET /api/v1/owners/{login} | A User or an Organization. |
getRepository | GET /api/v1/repos/{owner}/{repo} | A Repository. |
getIndex | GET /api/v1 | An ApiIndex. |
getApiRoot | GET /api | An ApiIndex. |
Answers are JSON and may be cached: Cache-Control: public, max-age=60 for account and repository data, max-age=300 for search and the options catalog. Every answer, errors included, carries the rate limit headers and a Link header to the OpenAPI description, the API catalog and this page.
List presets, themes, sizes and parameters
GET /api/v1/options. Everything a banner URL can say: the presets for users, organizations and repositories, the colour themes with their palettes, the canvas sizes, the fonts and every documented query parameter. Takes no parameters, so it also works as a first call to check that the API is reachable.
bashcurl "https://gitbanners.com/api/v1/options"
Returns: An OptionsCatalog.
Search accounts and repositories by prefix
GET /api/v1/search. Typeahead over GitHub: accounts whose login starts with the query, or the repositories of one owner when the query is written as owner/prefix. The query must be 2 to 140 characters long.
q(query, required): The start of a login such asverc, orowner/prefixsuch asvercel/nefor repositories.
bashcurl "https://gitbanners.com/api/v1/search?q=verc"
Returns: A SearchResult: the query and a list of suggestions.
Describe one banner: URLs, embed code, size
GET /api/v1/banner. The image URLs, embed snippets, dimensions and alt text of one banner, after checking with GitHub that the target exists. Takes the same option parameters as the image URLs and answers with the canonical form of the banner: GitHub's own capitalisation, default values left out of the query.
target(query, required): A GitHub login such asvercel, or a repository asowner/namesuch asvercel/next.js. A github.com URL works too.preset(query, optional): Preset id for the kind of target. An id that does not exist for the kind falls back to its default preset.- Every banner parameter as a query parameter, such as
theme,sizeoraccent.
bashcurl "https://gitbanners.com/api/v1/banner?target=vercel/next.js&preset=contributors&theme=dracula"
Returns: A BannerDescription.
Get a user or an organization
GET /api/v1/owners/{login}. A GitHub user or organization as normalized JSON: profile, statistics, the contribution calendar with streaks, top repositories and languages. The kind field says which of the two it is.
login(path, required): GitHub user or organization login.year(query, optional): Calendar year for a user's contribution calendar and statistics, from 2008 to the current year. Omit it for the last 12 months.view(query, optional):previewanswers faster for users, from one upstream request: profile and contribution calendar, withcomplete: falseand the remaining statisticsnull. Defaultfull.
bashcurl "https://gitbanners.com/api/v1/owners/vercel"
Returns: A User or an Organization.
Get a repository
GET /api/v1/repos/{owner}/{repo}. A public repository as normalized JSON: counts, languages, a year of weekly commit activity, star history, the latest release and top contributors. A renamed repository answers under its current name.
owner(path, required): Login of the user or organization that owns the repository.repo(path, required): Repository name as it appears on github.com.
bashcurl "https://gitbanners.com/api/v1/repos/vercel/next.js"
Returns: A Repository.
Get the API index
GET /api/v1. Where everything is: the current version, the OpenAPI description, the docs, the MCP endpoint and one URL template per operation and image form.
bashcurl "https://gitbanners.com/api/v1"
Returns: An ApiIndex.
Get the API root
GET /api. The unversioned entry point. It answers with the same index as the current version, so a client that only knows the host can find the versioned operations from here.
bashcurl "https://gitbanners.com/api"
Returns: An ApiIndex.
Image operations
The image URLs are part of the same OpenAPI description. They answer with image/svg+xml or image/png instead of JSON, and follow the rules under image responses.
Draw the banner of a user or an organization
GET /{owner}.{format}. The live banner image of a GitHub user or organization, drawn with the default preset. A well-formed URL always answers 200 with an image: an unknown login or an upstream failure is drawn as a card and reported in the X-Banner-State header, because an embedded image must never turn into a broken-image icon.
owner(path, required): GitHub user or organization login. Write@loginfor a login that collides with a route of this site, such as@docs.format(path, required): Image format. SVG is the form to embed in a README; PNG is for surfaces that do not draw SVG.scale(query, optional): PNG pixel density. Default 2 for README banners (automatic height) and 1 for the fixed social sizes. Ignored for SVG.download(query, optional): Set to 1 to have the browser save the image instead of showing it.- Every banner parameter as a query parameter, such as
theme,sizeoraccent.
bashcurl -o banner.svg "https://gitbanners.com/markeljan.svg"
Returns: An SVG or PNG image.
Draw the banner of a repository, or a profile preset
GET /{owner}/{repo}.{format}. The live banner image of a public repository. When the second segment is the id of a profile preset (such as activity, stats or streak) the answer is that preset of the owner's banner instead. A third segment selects a repository preset: /{owner}/{repo}/{preset}.{format}. A well-formed URL always answers 200 with an image, like the owner form.
owner(path, required): Login of the user or organization.repo(path, required): Repository name, or one of the profile preset ids: overview, activity, stats, repos, languages, streak, wrapped, card.format(path, required): Image format. SVG is the form to embed in a README; PNG is for surfaces that do not draw SVG.scale(query, optional): PNG pixel density. Default 2 for README banners (automatic height) and 1 for the fixed social sizes. Ignored for SVG.download(query, optional): Set to 1 to have the browser save the image instead of showing it.- Every banner parameter as a query parameter, such as
theme,sizeoraccent.
bashcurl -o banner.png "https://gitbanners.com/vercel/next.js.png"
Returns: An SVG or PNG image.
Errors
Every API answer that is not a success is application/problem+json (RFC 9457). Branch on code, show title and detail to a person, and follow resolution.
json{"documentation_url": "https://gitbanners.com/docs#errors","type": "https://gitbanners.com/docs#error-not_found","title": "Not found","status": 404,"detail": "No public GitHub user or organization is named no-such-login-here.","code": "not_found","resolution": "Check the spelling on github.com, then retry.","instance": "/api/v1/owners/no-such-login-here"}
| Member | What it holds |
|---|---|
type | A URL that identifies the kind of problem. It points at the row for the code in the table below. |
title | A short summary, the same for every case of a code. |
status | The HTTP status code, repeated. |
detail | What went wrong this time. |
code | A stable identifier to branch on. |
resolution | What the caller can do about it. |
instance | The path and query of the request. |
documentation_url | This section. |
Codes of the public API and the image URLs:
| Code | Status | Meaning | What to do |
|---|---|---|---|
invalid_request | 400 | A parameter is missing, malformed or out of range. | Read detail and resolution, fix the request, then retry. The same request will fail again. |
not_found | 404 | No public GitHub user, organization or repository has that name. A private repository counts as not found. An image URL answers with this code when it cannot be a banner at all. | Check the spelling on github.com, or resolve a partial name with the search operation. |
api_route_not_found | 404 | The path is not an operation of the API. | Find the operations in /openapi.json or /.well-known/api-catalog. |
method_not_allowed | 405 | The path exists, but not for this HTTP method. The public API is read-only. | Retry with GET. The Allow header lists what is supported. |
rate_limited | 429 | The client sent more requests than its quota allows. | Wait the number of seconds in Retry-After, then retry. |
internal_error | 500 | The request failed for a reason that is not the caller's. | Retry in a moment. If it keeps failing, open an issue. |
upstream_rate_limited | 503 | GitHub is rate limiting this service and no earlier copy of the data exists. | Retry after the number of seconds in Retry-After. |
upstream_unavailable | 503 | GitHub did not answer in time and no earlier copy of the data exists. | Retry after the number of seconds in Retry-After. |
The web app's own account routes (saved banners, the signed-in user) use the same format with these codes. They work with a browser session from this site only and are not part of the public API:
| Code | Status | Meaning | What to do |
|---|---|---|---|
bad_request | 400 | The request could not be understood, for example a body that is not valid JSON. | Fix the request, then retry. |
invalid_body | 400 | The JSON body failed validation. | The errors member names each field and what is wrong with it. |
unauthorized | 401 | Nobody is signed in, or the session is no longer valid. | Sign in with GitHub and try again. |
forbidden | 403 | The signed-in account may not do this. | Read detail for the reason. |
cross_origin_request | 403 | A request that changes account data came from another site. | Account data can only be changed from this site itself. |
pro_required | 403 | The feature needs Pro. | Star the repository on GitHub, then sign in again. See pricing. |
banner_limit_reached | 403 | The plan's number of saved banners is used up. | Delete a saved banner, or unlock Pro for a higher limit. |
login_changed | 409 | The GitHub login this session was created with now belongs to another account. | Sign in with GitHub again and retry. |
payload_too_large | 413 | The request body is larger than 16 KB. | Send a smaller body. |
unsupported_media_type | 415 | The body was not sent as JSON. | Send it with Content-Type: application/json. |
origin_mismatch | 500 | Sign-in is misconfigured: the site's canonical address does not lead back to it. | Nothing a visitor can fix. Please report it. |
accounts_unavailable | 503 | Accounts are not configured on this deployment. | Public banners and the API work without an account. |
unavailable | 503 | The account database cannot be reached right now. | Try again after the number of seconds in Retry-After. |
Rate limits
Requests are counted per client IP address, in short windows. An IPv6 client is counted as its /64 network.
| Policy | Applies to | Quota |
|---|---|---|
api | Every operation under /api/v1 except search, unknown paths under /api, and the MCP endpoint. | 120 requests per 60 seconds |
search | GET /api/v1/search. Each call can cost a request to GitHub. | 60 requests per 60 seconds |
Every API answer carries the IETF rate limit fields:
RateLimit-Policy: "api";q=120;w=60RateLimit: "api";r=119;t=60
qis the quota andwthe length of the window in seconds.ris what is left in the current window andtthe seconds until it resets.- Past the quota the answer is
429with the coderate_limitedand aRetry-Afterheader. Wait that many seconds before the next request. - If the counter itself cannot be reached, requests go through and only
RateLimit-Policyis sent.
Banner images and pages are not limited per client. They are cached instead, so embedding a banner on a busy page costs one render per cache lifetime.
Data and freshness
- Banners and API answers are built from public GitHub data only: profiles, public repositories and the public contribution calendar.
- Private repositories are never read or named. If a user turned on "Private contributions" in their GitHub profile settings, GitHub includes those counts in the public calendar, and a banner shows them as counts.
- GitHub data is refreshed every 15 minutes. When GitHub cannot be reached, the last good copy is used for up to 7 days.
fetchedAton every entity says when its data was read from GitHub.
Versioning and deprecation
The version is in the path: /api/v1. Within a version, changes only add: new operations, new optional parameters, new members in a response. Clients should ignore members they do not know.
A change that would break a client ships under a new path (/api/v2), and the old version keeps answering while it is being retired. A retiring operation says so in its responses:
Deprecation: the date from which the operation counts as deprecated (RFC 9745).Sunset: the date after which it may stop answering (RFC 8594), at least 90 days after the deprecation date.Linkwithrel="successor-version": the operation to move to.
Every API answer already carries a Link header with rel="deprecation" that points at this section, so a client can find the policy from any response. No operation is deprecated today.
Image URLs follow the same idea from the other side: they ignore what they do not understand, so a banner embedded today keeps drawing when parameters are added later.
Authentication
None. Every operation on this page is public and needs no API key, token or sign-up.
Sign in with GitHub exists for the web app only, to save banners and unlock Pro. It is a browser session that works from this site alone, and it is not part of the API.
MCP server
The same data is available to agents as tools on a Model Context Protocol server at https://gitbanners.com/mcp. It speaks Streamable HTTP, is stateless, and needs no credentials. Only POST is served; GET and DELETE answer 405.
| Tool | Returns |
|---|---|
get_banner | Image URLs, embed snippets, size and alt text of one banner, plus every preset for the target. |
search_github | Accounts for a login prefix, or repositories for owner/prefix, as suggestions. |
get_owner | Normalized public profile of a user or organization: counts, contributions, streaks, top repositories, languages. |
get_repository | Normalized public repository: stars, forks, issues, languages, weekly commits, latest release, top contributors. |
list_banner_options | Every preset, theme, size, font and query parameter a banner URL accepts. |
Add it to a client that reads an mcpServers configuration:
json{"mcpServers": {"gitbanners": {"type": "http","url": "https://gitbanners.com/mcp"}}}
Or call it by hand:
bashcurl -X POST "https://gitbanners.com/mcp" \-H "Content-Type: application/json" \-H "Accept: application/json, text/event-stream" \-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"get_banner","arguments":{"target":"vercel/next.js"}}}'
- Every tool is read-only and declares it (
readOnlyHint). Results come as structured content that matches the tool's output schema, and as the same JSON in a text block. - A failed lookup is a tool result with
isErrorand the samecodevalues as the REST API. An unknown tool or a malformed message is a JSON-RPC error. - Calls count against the
apiquota (120 requests per 60 seconds). - The server card is at /mcp/server-card and /.well-known/mcp/server-card.json; the registry manifest is /server.json.
Tools in the browser
In a browser that implements WebMCP, the site registers tools on document.modelContext so an agent working in the page can use it directly: search_github, get_banner and list_banner_options read, and save_banner and update_saved_banner store a banner in the account of the signed-in visitor.
Agent skill
An agent skill that teaches the URL grammar and the machine interfaces is published at /.well-known/agent-skills/gitbanners/SKILL.md. The index at /.well-known/agent-skills/index.json lists it with the SHA-256 digest of the file, so a client can verify what it downloaded.
Markdown
Content pages and banner pages have a Markdown version, for agents that would rather not parse HTML.
- Add
.mdto the URL: /docs.md, /pricing.md,/vercel.md,/vercel/next.js.md. The homepage is /index.md. - Or send
Accept: text/markdownto the page URL. The answer carriesVary: Accept. - Each document opens with front matter:
title,description,canonicalandlast-updated. - A path that is nothing answers
404in Markdown too, with links to the indexes below. - The Markdown of an account or a repository lists who it is, its headline numbers, and the image URL of every preset.
Machine-readable files
| URL | What it is |
|---|---|
| /llms.txt | Index of the site for language models. |
| /llms-full.txt | Every content page as one Markdown document. |
| /docs/llms.txt, /api/llms.txt | Section indexes: the topics of this page, and one entry per API operation. |
| /openapi.json | OpenAPI 3.1 description. |
| /.well-known/api-catalog | API catalog (RFC 9727). |
| /.well-known/ard.json, /.well-known/ai-catalog.json | Catalogs of the agent-facing resources. |
| /.well-known/agent-skills/index.json | Agent skills index. |
| /mcp/server-card, /server.json | MCP server card and registry manifest. |
| /sitemap.xml, /robots.txt | Sitemap and crawler rules. |