API
A small HTTP API for listing tools, searching them and publishing your own releases. Built so you can wire publishing into CI and stop doing it by hand.
Authentication
Every request needs an API key, the same kind you mint in your dashboard. Send it as a bearer token. Keys are stored hash-only and shown once, so keep yours in a secret manager.
Authorization: Bearer <your-api-key>
The API is CORS-open because a key is never attached automatically by a browser. Never ship a key in client-side code: anyone who reads it can publish as you.
What it can do
Deliberately small. It lists tools, searches tools, creates a listing and publishes a version of a listing you own. It cannot approve a review, publish without review, delist anything, read another account's data or touch billing. Those stay in the dashboard.
| Endpoint | Does |
|---|---|
GET /api/v1/tools | List and search published tools |
POST /api/v1/tools | Create a listing (as a draft) |
POST /api/v1/tools/{slug}/versions | Publish a version for review |
List and search
One endpoint covers both. Combine q with any filter to narrow the results.
curl "https://mcpcommons.com/api/v1/tools?q=npm&open_source=true" \ -H "Authorization: Bearer $MCPC_API_KEY"
| Parameter | Notes |
|---|---|
q | Matches name, summary, slug and keywords |
category | A category slug, e.g. developer-tools |
transport | stdio or http |
open_source | true for recognized OSI licenses only |
no_setup | true for tools needing no keys or services |
limit, offset | 1 to 100, default 25 |
Create a listing
Creates a draft. It stays private until a version passes review, so this publishes nothing on its own. Requires slug and name, plus link_out_url for link-out listings.
curl -X POST "https://mcpcommons.com/api/v1/tools" \
-H "Authorization: Bearer $MCPC_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"slug": "package-inspector",
"name": "Package Inspector",
"summary": "Deep insight into npm packages",
"listing_class": "third_party_free",
"link_out_url": "https://github.com/you/package-inspector",
"category": "developer-tools",
"tags": ["npm", "security"]
}'Publish a version
Queues the same AI security review the dashboard uses and returns 202. A pass publishes automatically; a flag or fail holds the listing for a human. Versions are immutable, so reusing one returns 409.
This mirrors the creator form field for field. version, repo and tools are required; every other field is optional and, when present, updates the listing the same way the form does. Always send tools, the declared tool surface the review checks your code against. Omitting it is rejected rather than silently publishing an empty surface.
curl -X POST "https://mcpcommons.com/api/v1/tools/package-inspector/versions" \
-H "Authorization: Bearer $MCPC_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"version": "1.2.0",
"repo": "you/package-inspector",
"ref": "v1.2.0",
"language": "typescript",
"transport": "stdio",
"egress_allowlist": ["registry.npmjs.org", "api.osv.dev"],
"tools": [
{ "name": "inspect_package", "description": "Full npm metadata" }
]
}'The API applies exactly the same requirements as the creator form:
- You must own the listing. Someone else's returns the same 404 as one that does not exist.
- GitHub must be connected, since we fetch the source to review it.
- Paid tools need connected Stripe payouts.
- Hosted tools need a payment method on file. Link-out tools do not, because we never run them.
Publishing from GitHub Actions
This is what the API was built for. Publish to MCP Commons every time you cut a release. Add your key as the MCPC_API_KEY repository secret, set SLUG to your listing's slug, then commit this as .github/workflows/mcp-commons.yml.
name: Publish to MCP Commons
on:
release:
types: [published]
jobs:
publish:
runs-on: ubuntu-latest
steps:
- name: Submit the release for review
env:
MCPC_API_KEY: ${{ secrets.MCPC_API_KEY }}
SLUG: your-tool-slug
run: |
# Strip a leading "v" so v1.2.0 becomes 1.2.0
VERSION="${GITHUB_REF_NAME#v}"
RESPONSE=$(mktemp)
STATUS=$(curl -sS -o "$RESPONSE" -w '%{http_code}' \
-X POST "https://mcpcommons.com/api/v1/tools/$SLUG/versions" \
-H "Authorization: Bearer $MCPC_API_KEY" \
-H "Content-Type: application/json" \
-d @- <<JSON
{
"version": "$VERSION",
"repo": "$GITHUB_REPOSITORY",
"ref": "$GITHUB_REF_NAME",
"language": "typescript",
"transport": "stdio",
"egress_allowlist": ["api.example.com"],
"tools": [
{ "name": "your_tool", "description": "What it does" }
]
}
JSON
)
cat "$RESPONSE"
if [ "$STATUS" != "202" ]; then
echo "::error::MCP Commons rejected the release (HTTP $STATUS)"
exit 1
fi
echo "::notice::Queued for security review"A 202 means the version is queued. Watch the listing page for the verdict, or wait for the email we send when the review finishes. The step fails the build on anything else, so a rejected release shows up red in CI instead of passing silently.
Rate limits
Limits are per account, not per key, so extra keys do not raise your allowance. Reads are generous. Writes are tight, because each one queues a review, fetches a repo and can change what the public sees.
| Endpoint | Limit |
|---|---|
GET /api/v1/tools | 120 per minute |
POST /api/v1/tools/{slug}/versions | 10 per hour |
POST /api/v1/tools | 5 per hour |
Each bucket is independent, so exhausting your publish budget never blocks reads. Every response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset. Going over returns 429 with Retry-After in seconds.
Errors
Errors are JSON with a stable error code. Validation errors also name the offending field. Unknown body fields are rejected rather than ignored, so a typo in a CI config fails loudly instead of publishing something you did not intend.
{ "error": "invalid_body", "message": "repo is not valid (owner/repo).", "field": "repo" }| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_query | Bad query parameter |
| 401 | unauthorized | Missing key |
| 401 | invalid_key | Unknown or revoked key |
| 402 | payouts_required | Paid tool without connected payouts |
| 402 | payment_method_required | Hosted tool without a card on file |
| 403 | github_not_connected | Connect GitHub first |
| 404 | no_such_listing | No listing with that slug on your account |
| 409 | slug_taken | That slug is in use |
| 409 | version_exists | Versions are immutable |
| 422 | invalid_body | Body failed validation |
| 429 | rate_limited | Over budget, see Retry-After |
Questions
Open a thread from Support. You will need to be signed in.