Publish & verify an MCP server
Applies to SDK 0.16+ · Last updated: 2026-06-12
This guide is for developers who want to list their own MCP server in the AgentNode registry. If instead you want to use AgentNode as an MCP server inside Claude Code or Cursor, see MCP Integration — that is the consumer side and unrelated to publishing.
AgentNode lists MCP servers that are already published on npm or PyPI. No code is uploaded — you point AgentNode at the package with a manifest, and AgentNode re-verifies the package, its version, ownership, and (via an automated sandbox smoke check) that the server starts and answers the MCP protocol. A passing check is a review signal only: MCP listings stay review-gated and a human approves them — nothing is auto-published.
The flow at a glance
init --type mcp → scaffold a manifest
edit + pin → set npm/PyPI package, pin the exact version, declare permissions
mcp verify → local checks (schema, package/version, permissions)
mcp submit → server re-verifies authoritatively; enters review
mcp ownership → prove you control the package (publish-challenge)
sandbox smoke → AgentNode starts the server in an isolated sandbox
mcp status → track review + gate signals
review → a human approves; only then can it be publishedPrerequisites
- The AgentNode CLI installed (see Installation) and an API key available as
AGENTNODE_API_KEY(or passed with--token). - A publisher profile on your account (submitting requires one).
- Your MCP server already published as a public npm or PyPI package, at a concrete version (not a floating tag).
- A launch command that starts the server over stdio — e.g.
npx -y your-pkg@1.2.3(npm) oruvx your-pkg==1.2.3(PyPI). - The source repository that owns the package (used for ownership checks).
1 — Scaffold the listing
Create a listing project with an MCP manifest and a README:
$ agentnode init --type mcpThis writes an agentnode.yaml (manifest version 0.3, runtime: mcp) with placeholders you must fill in, plus a README.md with the verify → submit steps. Unlike a tool pack, an MCP listing uploads no code — it only references the upstream npm/ PyPI package.
2 — The manifest
The listing is described by agentnode.yaml. The MCP-specific fields live under mcp_server. Fill in exactly one of npm_package / pypi_package, pin the version in command, and set source_repo to the repo that owns the package.
Required fields
| Field | Example | Notes |
|---|---|---|
| manifest_version | "0.3" | Fixed |
| runtime | "mcp" | Identifies the listing as an MCP server |
| package_id | "example-mcp" | Catalog slug |
| name / summary / description | "Example MCP" | Display metadata |
| version | "1.0.0" | The listing version (semver) |
| publisher | "your-publisher-slug" | Your publisher identifier |
| mcp_server.command | ["npx","-y","example-mcp@1.2.3"] | Launch command — must PIN the exact version |
| mcp_server.npm_package OR pypi_package | "example-mcp" | Exactly one; the other omitted |
| mcp_server.source_repo | "https://github.com/you/example-mcp" | Must match the package's registry metadata |
Example — npm-backed MCP
manifest_version: "0.3"
package_id: "example-mcp"
package_type: "toolpack"
name: "Example MCP"
publisher: "your-publisher-slug"
version: "1.0.0"
summary: "An example MCP server listing."
description: |
Lists an existing npm MCP server in the AgentNode catalog.
runtime: "mcp"
install_mode: "package"
hosting_type: "agentnode_hosted"
mcp_server:
command: ["npx", "-y", "example-mcp@1.2.3"] # pin the EXACT version
npm_package: "example-mcp"
source_repo: "https://github.com/your-org/example-mcp"
tags: []
categories: []
compatibility:
frameworks: ["generic"]
# Declare honestly — verification compares this against what the server requests.
permissions:
network:
level: "restricted"
allowed_domains: []
filesystem:
level: "none"
code_execution:
level: "none"
data_access:
level: "input_only"
user_approval:
required: "high_risk_only"Example — PyPI-backed MCP
Same manifest, but swap the mcp_server block to use pypi_package and a uvx command with a == version pin:
mcp_server:
command: ["uvx", "example-mcp==1.2.3"] # pin with ==
pypi_package: "example-mcp"
source_repo: "https://github.com/your-org/example-mcp"The names above are placeholders — replace them with your real package and repo.
3 — Pin the package version
The version must be pinned in mcp_server.command — @1.2.3 for npm, ==1.2.3 for PyPI. An unpinned command (e.g. npx -y example-mcp with no version) is not reproducible and is flagged on verify and submit. A verification result is bound to that exact package + version + command, so publishing a new package version means re-verifying and re-submitting the listing for the new version.
4 — Verify locally
Run the local checks against your manifest. Add --test to also start the server and run the MCP initialize + tools/list handshake locally; add --json to get the machine-readable report (this is what mcp submit attaches).
$ agentnode mcp verify . # schema, package, version, permission checks
$ agentnode mcp verify . --test # also run the local protocol test
$ agentnode mcp verify . --json # JSON report (attach on submit)The report ends in a status such as TESTED (protocol test passed), RESOLVED (package + version resolved), REVIEW_NEEDED, MAINTAINER_ACTION_REQUIRED, or INVALID. The command exits non-zero on INVALID, so it is CI-gateable. Local verification is a helpful pre-check — it does not replace the server-side re-verification, ownership proof, or the sandbox smoke check below.
5 — Submit for the catalog
Submit the manifest and its verification report. Use --dry-run to verify without sending; --test to run the protocol test first. Authentication uses --token or AGENTNODE_API_KEY.
$ agentnode mcp submit . --token $AGENTNODE_API_KEY
$ agentnode mcp submit . --dry-run # verify only, don't sendOn submit, AgentNode re-verifies the registry facts itself (package existence, resolved version, repo consistency) — your local report is advisory; the server result is authoritative. You get a submission id and a starting status. A submission never goes live automatically.
You can have only one open submission for the same package + version at a time — a second one is rejected as a duplicate until the first is resolved.
6 — Prove package ownership
Ownership is a separate axis from the source-repo match: you prove you can publish the package with a one-time publish-challenge. Issue a challenge, add the returned keyword to your package and publish a new version (only someone with publish rights can), then verify.
# 1. issue a one-time challenge (token is shown once)
$ agentnode mcp ownership challenge example-mcp --registry npm --token $AGENTNODE_API_KEY
# 2. add the returned keyword to your package metadata, publish a new version
# 3. verify — checks the latest published version for the keyword
$ agentnode mcp ownership verify example-mcp --registry npm --token $AGENTNODE_API_KEYverify reports one of:
| Status | Meaning | Next step |
|---|---|---|
| verified | The keyword was found in the latest published version — ownership recorded | Nothing — you're done (the claim is time-limited; re-verify if it later expires) |
| pending | Challenge issued, keyword not yet found in a published version | Publish a new version with the keyword, then verify again |
| expired | The challenge's time window elapsed | Issue a new challenge and retry |
| package-not-found | The package doesn't resolve on the registry | Check the registry + package name |
| registry-unavailable | The registry was temporarily unreachable | Retry verify shortly (transient) |
Verifying ownership publishes nothing on its own — it is one of the signals a reviewer needs before a listing can go live.
7 — The automated sandbox smoke check
After you submit, AgentNode runs an automated sandbox smoke check for npm/PyPI MCP submissions. It is a technical executability + protocol check, not a safety or trust guarantee.
What it checks
- the pinned package can be installed in an isolated sandbox,
- the MCP server starts,
- it answers the MCP
initializeflow, and - it answers tools discovery (
tools/list).
What it does not do
- It is not a full security audit, and it is not a safety or trustworthiness certification of the package.
- It does not assess functional quality, and does not guarantee every later use will succeed.
How it runs
The check runs with restricted permissions and bounded resources, with the install phase separate from the run phase; the run phase is network-isolated, and the sandbox is cleaned up automatically afterward.
Result semantics
| Result | Meaning | Effect |
|---|---|---|
| passed | The server started and answered initialize + tools discovery | A positive review signal (does not auto-publish) |
| failed (startup crash / protocol error / tools/list error) | The server is objectively broken | Blocks — fix and resubmit |
| failed (install / timeout / registry issue) | A transient/environmental problem | Kept for review; can be rechecked — not an auto-reject |
| deferred (host resources low) | The host was momentarily low on RAM/disk, so the check was not run | Kept for review; can be rechecked later |
| unavailable / skipped | The check could not run (e.g. credentials required) | Kept for review |
A temporary infrastructure problem never auto-rejects a submission, and a passing check never auto-publishes it — it is one input to the human review.
8 — Track your submission
$ agentnode mcp status <submission_id> --token $AGENTNODE_API_KEY
$ agentnode mcp status <submission_id> --jsonThe status reflects where the submission is in review:
| Status | Shown as | Meaning |
|---|---|---|
| pending / quarantined_review | Under Review | Held for human review — not live |
| action_required | Action Required | A check needs fixing — update and resubmit |
| needs_changes | Changes Requested | A reviewer asked for changes |
| approved | Approved | Cleared for publication — still not live yet |
| rejected | Not Accepted | Not accepted |
| published | (live) | Live in the catalog |
9 — Review & listing
- MCP submissions remain review-gated. The technical gates (registry verification, ownership, sandbox smoke) are inputs to a human review — they are not the decision.
- Publishers cannot publish their own listing. Publishing is an administrative action; a passing smoke plus verified ownership does not make a listing live on its own.
- Approval (
approved) means a reviewer cleared it — it is a pre-publish state, still not live, until it is actually published. - A listing may still require additional editorial or security review before it goes live.
10 — Changes & new versions
- Publishing a new package version means a new listing version: re-run
mcp verifyandmcp submitfor it (verification is bound to the exact package + version + command). - While a submission is
action_requiredorneeds_changes, you fix the manifest and re-submit an updated verification report for the same package. - A verified ownership claim is time-limited; if it expires, issue a new challenge and verify again.
- Re-running the registry verification on an existing submission (for example if a registry was temporarily unavailable) is a reviewer action, not a publisher one.
Troubleshooting
| You see | Meaning | Next step |
|---|---|---|
| Manifest runtime must be 'mcp' | runtime is not set to mcp | Set runtime: "mcp" |
| Manifest must have mcp_server block | mcp_server is missing | Add the mcp_server block with command + npm/pypi_package |
| Package / version not found | The package or pinned version isn't on the registry | Publish it, or fix the name/version in command |
| Command is not pinned | The launch command has no exact version | Pin @x.y.z (npm) or ==x.y.z (PyPI) |
| Verification report status is not valid / INVALID | The attached report is missing or INVALID | Re-run agentnode mcp verify . --test --json |
| An open submission already exists | A duplicate for the same package + version is in the pipeline | Wait for it to resolve, or update that submission |
| No publish-challenge to verify | You ran verify before issuing a challenge | Run mcp ownership challenge first |
| The challenge has expired | The challenge window elapsed | Issue a new challenge and retry |
| Smoke: startup crash / protocol error / tools/list error | The server is objectively broken in the sandbox | Fix the server, publish a fixed version, resubmit |
| Smoke: install / timeout / resources | A transient or environmental issue | It stays reviewable and can be rechecked — no action needed to avoid rejection |
Security & trust model
- The sandbox smoke is a limited technical check (does it start and speak the protocol), not a comprehensive security certification.
- You remain responsible for the package and code you list.
- Do not put secrets in the manifest. If the server needs credentials, declare only the required environment keys — never paste tokens or credentials into manifests, reports, or logs.
- A registry listing is not a guarantee of safety; users should still review third-party MCP servers before use.
Full quick sequence
# 1. scaffold
$ agentnode init --type mcp
# 2. edit agentnode.yaml: set npm_package/pypi_package, pin the version in
# command, set source_repo, declare permissions
# 3. verify locally
$ agentnode mcp verify . --test --json
# 4. submit (server re-verifies authoritatively; enters review)
$ agentnode mcp submit . --token $AGENTNODE_API_KEY
# 5. prove ownership
$ agentnode mcp ownership challenge <package> --registry npm --token $AGENTNODE_API_KEY
# ...add the keyword, publish a new version...
$ agentnode mcp ownership verify <package> --registry npm --token $AGENTNODE_API_KEY
# 6. track status (a human reviews; listings stay review-gated)
$ agentnode mcp status <submission_id> --token $AGENTNODE_API_KEYFor the individual commands see the CLI Reference. To use AgentNode itself as an MCP server in your editor, see MCP Integration.