VoidnetVoid Docs
MCP

MCP Buyer Guide

Discover, purchase, and query MCP tools published on Voidnet Console

This guide covers everything you need to discover, purchase, and query apps published by developers on the Voidnet Console marketplace.

New to Voidnet? Get Started walks you through credentials and your first call.


Overview

A buyer is a user who discovers apps in the Voidnet Console marketplace and calls them through the Voidnet. The Voidnet handles authentication, rate limiting, metering, and billing — so you only need valid credentials and the app's public name.

Your Client (Key or OAuth Token)  →  Voidnet  →  Publisher's MCP Server

The Voidnet supports three authentication methods:

MethodCredentialUse Case
API Keysvnb-sk-* / vai-sk-*Simple, long-lived secrets for developers
OAuth Client CredentialsJWT from /oauth/tokenProduction systems, CI/CD
OAuth Authorization Code + PKCEJWT from /oauth/tokenInteractive clients (Claude Desktop, Cursor, VS Code)

Prerequisites

  • A Voidnet Console account (sign up)
  • An API key for authentication (see below)
  • Basic understanding of JSON-RPC 2.0 and MCP protocol

Authentication

API Keys

API keys are the simplest way to authenticate. Generate them from the API Keys page under the Buyer section of your Console dashboard:

PrefixTypeUse Case
vnb-sk-Standard Buyer Service KeyGeneral purpose
vai-sk-Ambient KeyAutomated/integrated workflows
vnb-sk-a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6

Security rules:

  • Save your key immediately — it's shown only once at creation
  • Never expose keys in client-side code, version control, or logs
  • Rotate keys periodically from the Console
  • Revoke compromised keys immediately

OAuth Access Tokens

For production systems, you can use OAuth 2.0 access tokens instead of raw API keys. The Voidnet runs its own authorization server and supports three grant types:

Grant TypeUse Case
client_credentialsMachine-to-machine (API key → short-lived JWT)
authorization_codeInteractive clients (Claude Desktop, Cursor, VS Code) with PKCE
refresh_tokenRotate expired access tokens without re-login

Access tokens are JSON Web Tokens (JWTs) signed with RS256. They expire after a configurable period (default 1 hour) and can be used anywhere you'd use an API key.

When to use which

SituationRecommended
Local development, testingAPI key (vnb-sk-*)
Production services, CI/CDJWT access token (client_credentials)
Interactive AI clients (Claude, Cursor, VS Code)Authorization Code + PKCE
Highly sensitive environmentsRotate API key → short-lived JWT per session

Getting an Access Token

Client Credentials (machine-to-machine)

Exchange your vnb-sk-* key for a JWT access token:

curl -X POST https://api.openvoidnet.com/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials" \
  -d "client_id=vnb-sk-a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6"

Successful response:

{
  "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "mcp:tools"
}

The returned access_token is a JWT you can use in the Authorization header instead of your raw API key.

Notes:

  • The client_id is your full API key — no separate client_secret is needed
  • A scope parameter may be provided (optional, defaults to mcp:tools)
  • The aud claim is always the Voidnet issuer URL — the token endpoint accepts no client-controlled audience input

Authorization Code + PKCE (interactive clients)

For interactive clients (Claude Desktop, Cursor, VS Code) with a human in the loop:

  1. Client discovers metadata from GET /.well-known/oauth-authorization-server
  2. Client opens browser to GET /authorize?client_id=...&redirect_uri=...&code_challenge=...&code_challenge_method=S256&response_type=code
  3. User logs in and consents on the gateway-hosted page
  4. Gateway redirects to redirect_uri?code=...&state=...
  5. Client exchanges code for tokens: POST /oauth/token with grant_type=authorization_code, code, redirect_uri, code_verifier
  6. Response includes access_token (JWT), refresh_token (30-day, rotated on use)

Required PKCE parameters:

  • code_challenge — 43-char base64url (S256 of code_verifier)
  • code_challenge_method — must be S256
  • code_verifier — 43-128 char unreserved string (used at token exchange)

Refresh Token (rotate without re-login)

curl -X POST https://api.openvoidnet.com/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=refresh_token" \
  -d "refresh_token=<old_refresh_token>" \
  -d "client_id=vnb-sk-..."

Response includes new access_token + rotated refresh_token. Old refresh token is invalidated.

Token expiration

Access tokens have an exp claim. When a token expires, the Voidnet returns api_key_expired (401). You should:

  1. Detect the 401 response
  2. Request a new token from /oauth/token (client_credentials or refresh_token)
  3. Retry the request with the new token

Apps and Purchasing

Browse the Marketplace. Each app lists its publisher, name, description, tier (free/paid), and capabilities. To query an app you need the publisher's username and app name — these form the public route.

  • Free tier: click "Get" to start using immediately (rate limits apply).
  • Paid tier: click Subscribe/Purchase. Paid access runs on wallet: top up at Console → Wallet ($5–$1000 via Stripe), and the price deducts automatically.
  • Rules: one active purchase per buyer per app; upgrades allowed, downgrades not; meter resets on a rolling 30-day window.

Making Requests (stateless MCP 2026-07-28)

All app requests go through the Voidnet at a single endpoint.

POST https://api.openvoidnet.com/v1-beta/{adapter}/{username}/{appname}
ParameterDescriptionExample
adapterProtocol adapter type (mcp)mcp
usernamePublisher's public usernameacmecorp
appnameApp name (unique per publisher)weather-tools
HeaderRequiredDescription
Authorization: Bearer <credential>YesYour API key (vnb-sk-*) or JWT access token (eyJ...)
Content-Type: application/jsonYesRequest body format
MCP-Protocol-VersionYesMust be 2026-07-28
Mcp-MethodYesJSON-RPC method name (e.g., tools/call)
Mcp-NameYesTool/resource/prompt name (e.g., tools/call)

Stateless MCP 2026-07-28 — No sessions, no initialize handshake, no Mcp-Session-Id header, no GET/DELETE endpoints. SSE streams are per-request on POST; close = cancel.

Request body

The body is a standard JSON-RPC 2.0 request. The _meta object in params may include protocolVersion, clientInfo, clientCapabilities.

{
  "jsonrpc": "2.0",
  "id": "1",
  "method": "tools/call",
  "params": {
    "name": "get_forecast",
    "arguments": { "location": "London", "days": 3 }
  }
}

Complete example (API key)

curl -X POST https://api.openvoidnet.com/v1-beta/mcp/acmecorp/weather-tools \
  -H "Authorization: Bearer vnb-sk-a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6" \
  -H "Content-Type: application/json" \
  -H "MCP-Protocol-Version: 2026-07-28" \
  -H "Mcp-Method: tools/call" \
  -H "Mcp-Name: get_forecast" \
  -d '{
    "jsonrpc": "2.0",
    "id": "1",
    "method": "tools/call",
    "params": {
      "name": "get_forecast",
      "arguments": { "location": "London", "days": 3 }
    }
  }'

Complete example (JWT access token)

TOKEN="eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."

curl -X POST https://api.openvoidnet.com/v1-beta/mcp/acmecorp/weather-tools \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -H "MCP-Protocol-Version: 2026-07-28" \
  -H "Mcp-Method: tools/call" \
  -H "Mcp-Name: get_forecast" \
  -d '{
    "jsonrpc": "2.0",
    "id": "1",
    "method": "tools/call",
    "params": {
      "name": "get_forecast",
      "arguments": { "location": "London", "days": 3 }
    }
  }'

MCP Methods

The apps you query speak the MCP protocol (version 2026-07-28). Here are the methods you can call:

Discover the server's capabilities and supported versions:

curl -X POST https://api.openvoidnet.com/v1-beta/mcp/acmecorp/weather-tools \
  -H "Authorization: Bearer vnb-sk-..." \
  -H "Content-Type: application/json" \
  -H "MCP-Protocol-Version: 2026-07-28" \
  -H "Mcp-Method: server/discover" \
  -H "Mcp-Name: server/discover" \
  -d '{"jsonrpc":"2.0","id":"1","method":"server/discover"}'

Response includes supportedVersions, capabilities, serverInfo, instructions.

tools/list

Discover what tools an app provides:

curl -X POST https://api.openvoidnet.com/v1-beta/mcp/acmecorp/weather-tools \
  -H "Authorization: Bearer vnb-sk-..." \
  -H "Content-Type: application/json" \
  -H "MCP-Protocol-Version: 2026-07-28" \
  -H "Mcp-Method: tools/list" \
  -H "Mcp-Name: tools/list" \
  -d '{
    "jsonrpc": "2.0",
    "id": "1",
    "method": "tools/list"
  }'

Response includes tools array with ttlMs and cacheScope for spec-sanctioned caching.

tools/call

Execute a tool with arguments:

curl -X POST https://api.openvoidnet.com/v1-beta/mcp/acmecorp/weather-tools \
  -H "Authorization: Bearer vnb-sk-..." \
  -H "Content-Type: application/json" \
  -H "MCP-Protocol-Version: 2026-07-28" \
  -H "Mcp-Method: tools/call" \
  -H "Mcp-Name: get_forecast" \
  -d '{
    "jsonrpc": "2.0",
    "id": "2",
    "method": "tools/call",
    "params": {
      "name": "get_forecast",
      "arguments": { "location": "London", "days": 3 }
    }
  }'

Response includes resultType (complete or input_required for MRTR).

prompts/list

curl -X POST https://api.openvoidnet.com/v1-beta/mcp/acmecorp/weather-tools \
  -H "Authorization: Bearer vnb-sk-..." \
  -H "MCP-Protocol-Version: 2026-07-28" \
  -H "Mcp-Method: prompts/list" \
  -H "Mcp-Name: prompts/list" \
  -d '{"jsonrpc":"2.0","id":"3","method":"prompts/list"}'

prompts/get

curl -X POST https://api.openvoidnet.com/v1-beta/mcp/acmecorp/weather-tools \
  -H "Authorization: Bearer vnb-sk-..." \
  -H "MCP-Protocol-Version: 2026-07-28" \
  -H "Mcp-Method: prompts/get" \
  -H "Mcp-Name: prompts/get" \
  -d '{"jsonrpc":"2.0","id":"4","method":"prompts/get","params":{"name":"weather_summary","arguments":{"location":"London"}}}'

resources/list

curl -X POST https://api.openvoidnet.com/v1-beta/mcp/acmecorp/weather-tools \
  -H "Authorization: Bearer vnb-sk-..." \
  -H "MCP-Protocol-Version: 2026-07-28" \
  -H "Mcp-Method: resources/list" \
  -H "Mcp-Name: resources/list" \
  -d '{"jsonrpc":"2.0","id":"5","method":"resources/list"}'

resources/read

curl -X POST https://api.openvoidnet.com/v1-beta/mcp/acmecorp/weather-tools \
  -H "Authorization: Bearer vnb-sk-..." \
  -H "MCP-Protocol-Version: 2026-07-28" \
  -H "Mcp-Method: resources/read" \
  -H "Mcp-Name: resources/read" \
  -d '{"jsonrpc":"2.0","id":"6","method":"resources/read","params":{"uri":"weather://London/current"}}'

subscriptions/listen (optional)

For servers that support change notifications:

curl -X POST https://api.openvoidnet.com/v1-beta/mcp/acmecorp/weather-tools \
  -H "Authorization: Bearer vnb-sk-..." \
  -H "MCP-Protocol-Version: 2026-07-28" \
  -H "Mcp-Method: subscriptions/listen" \
  -H "Mcp-Name: subscriptions/listen" \
  -d '{"jsonrpc":"2.0","id":"7","method":"subscriptions/listen","params":{"notifications":[]}}'

OAuth Endpoints

The Voidnet exposes the following OAuth 2.0 endpoints:

EndpointDescription
POST /oauth/tokenIssue access tokens (client_credentials, authorization_code, refresh_token)
GET /authorizeOAuth 2.1 authorization code + PKCE (interactive)
POST /authorizeProcess login+consent, issue authorization code
GET /.well-known/oauth-authorization-serverRFC 8414 AS metadata
GET /.well-known/oauth-protected-resourceRFC 9728 resource metadata
GET /.well-known/jwks.jsonVoidnet's public signing keys

AS metadata (RFC 8414)

{
  "issuer": "https://api.openvoidnet.com",
  "authorization_endpoint": "https://api.openvoidnet.com/authorize",
  "token_endpoint": "https://api.openvoidnet.com/oauth/token",
  "jwks_uri": "https://api.openvoidnet.com/.well-known/jwks.json",
  "grant_types_supported": ["authorization_code", "client_credentials", "refresh_token"],
  "token_endpoint_auth_methods_supported": ["none", "client_secret_post"],
  "scopes_supported": ["mcp:tools"],
  "response_types_supported": ["code"],
  "code_challenge_methods_supported": ["S256"]
}

Protected resource metadata (RFC 9728)

{
  "authorization_servers": ["https://api.openvoidnet.com"],
  "scopes_supported": ["mcp:tools"],
  "bearer_methods_supported": ["authorization_header"]
}

These endpoints let OAuth-aware clients configure themselves automatically without hardcoding token endpoints or signing keys.


Error Handling

The Voidnet returns errors in one JSON shape. The error field is an object, not a string:

{
  "error": {
    "code": "error_code",
    "message": "Human-readable description",
    "status": 429
  }
}

For the complete catalog, see the Error Reference.


Rate Limits & Metering

The Voidnet enforces a per-minute/per-day rate limit and a monthly meter limit per app. Exceeding either returns a 429:

  • rate_limit_exceeded — too fast. Wait for the window to reset and retry with backoff.
  • meter_limit_exceeded — monthly quota exhausted. Wait for the rolling 30-day reset or upgrade your tier.
  • meter_expired — billing period ended. Wait for the meter to reset.

There are no X-RateLimit-* response headers. Track your remaining quota in the Console under Usage.


Calling Apps from Code

TypeScript / JavaScript

const API_KEY = "vnb-sk-a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6";
const TOKEN_ENDPOINT = "https://api.openvoidnet.com/oauth/token";
const GATEWAY = "https://api.openvoidnet.com";
const USERNAME = "acmecorp";
const APPNAME = "weather-tools";

const COMMON_HEADERS = {
  "MCP-Protocol-Version": "2026-07-28",
  "Content-Type": "application/json"
};

// Option A: API key (simple)
async function callWithKey() {
  const response = await fetch(`${GATEWAY}/v1-beta/mcp/${USERNAME}/${APPNAME}`, {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${API_KEY}`,
      ...COMMON_HEADERS,
      "Mcp-Method": "tools/call",
      "Mcp-Name": "get_forecast"
    },
    body: JSON.stringify({
      jsonrpc: "2.0",
      id: "1",
      method: "tools/call",
      params: {
        name: "get_forecast",
        arguments: { location: "London", days: 3 }
      }
    })
  });
  return await response.json();
}

// Option B: Get an access token first (production)
async function getAccessToken(): Promise<string> {
  const resp = await fetch(TOKEN_ENDPOINT, {
    method: "POST",
    headers: { "Content-Type": "application/x-www-form-urlencoded" },
    body: new URLSearchParams({
      grant_type: "client_credentials",
      client_id: API_KEY
    })
  });
  const data = await resp.json();
  return data.access_token;
}

async function callWithToken() {
  const token = await getAccessToken();
  const response = await fetch(`${GATEWAY}/v1-beta/mcp/${USERNAME}/${APPNAME}`, {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${token}`,
      ...COMMON_HEADERS,
      "Mcp-Method": "tools/list",
      "Mcp-Name": "tools/list"
    },
    body: JSON.stringify({
      jsonrpc: "2.0",
      id: "1",
      method: "tools/list"
    })
  });
  return await response.json();
}

Python

import requests

API_KEY = "vnb-sk-a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6"
GATEWAY = "https://api.openvoidnet.com"
USERNAME = "acmecorp"
APPNAME = "weather-tools"
COMMON_HEADERS = {
    "MCP-Protocol-Version": "2026-07-28",
    "Content-Type": "application/json"
}

# Option A: API key (simple)
response = requests.post(
    f"{GATEWAY}/v1-beta/mcp/{USERNAME}/{APPNAME}",
    headers={
        "Authorization": f"Bearer {API_KEY}",
        **COMMON_HEADERS,
        "Mcp-Method": "tools/call",
        "Mcp-Name": "get_forecast"
    },
    json={
        "jsonrpc": "2.0",
        "id": "1",
        "method": "tools/call",
        "params": {
            "name": "get_forecast",
            "arguments": {"location": "London", "days": 3}
        }
    }
)
data = response.json()
print(data["result"])

# Option B: Get an access token first (production)
token_resp = requests.post(
    "https://api.openvoidnet.com/oauth/token",
    data={
        "grant_type": "client_credentials",
        "client_id": API_KEY
    }
)
token = token_resp.json()["access_token"]

response = requests.post(
    f"{GATEWAY}/v1-beta/mcp/{USERNAME}/{APPNAME}",
    headers={
        "Authorization": f"Bearer {token}",
        **COMMON_HEADERS,
        "Mcp-Method": "tools/list",
        "Mcp-Name": "tools/list"
    },
    json={"jsonrpc": "2.0", "id": "1", "method": "tools/list"}
)

cURL (reusable)

GATEWAY="https://api.openvoidnet.com"
API_KEY="vnb-sk-a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6"
USERNAME="acmecorp"
APPNAME="weather-tools"

# Authenticate with API key directly
curl -X POST "$GATEWAY/v1-beta/mcp/$USERNAME/$APPNAME" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -H "MCP-Protocol-Version: 2026-07-28" \
  -H "Mcp-Method: tools/list" \
  -H "Mcp-Name: tools/list" \
  -d '{
    "jsonrpc": "2.0",
    "id": "1",
    "method": "tools/list"
  }'

# Or exchange for a JWT access token first
TOKEN=$(curl -s -X POST "$GATEWAY/oauth/token" \
  -d "grant_type=client_credentials" \
  -d "client_id=$API_KEY" | jq -r '.access_token')

curl -X POST "$GATEWAY/v1-beta/mcp/$USERNAME/$APPNAME" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -H "MCP-Protocol-Version: 2026-07-28" \
  -H "Mcp-Method: tools/list" \
  -H "Mcp-Name: tools/list" \
  -d '{"jsonrpc":"2.0","id":"1","method":"tools/list"}'

FAQ

Do I need to purchase an app before calling it?

Yes — even free tiers require a purchase record. Click "Get" in the marketplace to activate a free app. This creates the necessary record for the Voidnet to authorize your requests.

How do I find which apps I've purchased?

Go to the Usage page in your Console dashboard under the Buyer section. You'll see all apps you've purchased, their tier status, API call counts, and remaining meter usage.

Can I use the same API key for multiple apps?

Yes — a single API key works across all apps you purchase.

How do I know which methods an app supports?

Call server/discover (recommended first) or tools/list, prompts/list, resources/list to discover capabilities.

What's the difference between vnb-sk- and vai-sk- keys?

Both authenticate you to the Voidnet. vnb-sk- keys are standard buyer service keys created from the Console. vai-sk- keys are ambient keys used for integrated or automated workflows.

When should I use a JWT access token instead of my API key?

Use JWT access tokens in production systems, CI/CD pipelines, and shared environments. They're short-lived (default 1 hour), reducing the risk of credential exposure. Use raw API keys for local development and testing.

Can I use both API keys and JWT tokens?

Yes — the Voidnet accepts both. OAuth access tokens (eyJ...) and API keys (vnb-sk-* / vai-sk-*) are both valid in the Authorization: Bearer header. The Voidnet detects the format automatically.

What happens when my access token expires?

The Voidnet returns api_key_expired (401). Request a new token from POST /oauth/token using your API key (client_credentials) or refresh_token, then retry.

Can my organization use Okta or Entra ID to authenticate?

Not yet. The Voidnet authorization server issues tokens via client_credentials (exchange API key for JWT) and authorization_code + PKCE (interactive). Enterprise identity federation (jwt-bearer) is not currently supported.

On this page