VoidnetVoid Docs
Publisher guide

MCP Publisher Guide

Build, deploy, and publish MCP servers on the Voidnet Console platform

This guide covers everything you need to build, deploy, and publish an MCP server on Voidnet Console — from server implementation to Stripe payout configuration.


Overview

A publisher is a developer who builds and hosts an MCP server and makes it available to buyers through the Voidnet Console marketplace. The Voidnet proxies buyer requests to your server, enforces rate limits and metering, and handles billing. Your server only needs to implement the standard MCP protocol and validate the publisher API key.

Your Apps / AI (Key or OAuth Token)  →  Voidnet  →  Your MCP Server

                                          Publisher API Key
                                          (always vnp-sk-*)

Buyers authenticate to the Voidnet using either an API key (vnb-sk-*) or an OAuth 2.0 access token (JWT). The Voidnet validates their identity, then proxies the request to your server with your publisher API key (vnp-sk-*) in the Authorization header. Your server never sees the buyer's credentials — only the publisher key you already trust.


Publisher API Key

Every published app gets a publisher API key. This key is generated in the Voidnet when you publish an app and is shown only once — save it securely.

vnp-sk-27fc6268dc64a9ba2c4cb92489e9175c9bf404e260beb268b976f1a56582eff3

How it's used

When the Voidnet proxies a request to your server, it sends the key in the Authorization header:

Authorization: Bearer vnp-sk-27fc6268...

Your server must validate this header on every request and reject invalid or missing keys with a 401 response.

Key lifecycle

  • Generate — Created when you publish an app or manually from the Console
  • Revoke — You can revoke keys at any time; revoked keys immediately stop working
  • Rotate — Generate a new key, update your server, then revoke the old one
  • Storage — Keys are encrypted at rest in the Voidnet database

Server Requirements

Your MCP server must meet these requirements to work with Voidnet Console:

1. HTTPS

All communication with the Voidnet is over HTTPS. You'll need a valid TLS certificate.

2. Single MCP endpoint

The Voidnet sends all MCP requests to a single endpoint on your server — typically /mcp. This single endpoint handles all MCP methods (initialize, tools/list, tools/call, resources/list, prompts/list, etc.).

3. Protocol version

Voidnet Console currently supports MCP protocol version 2025-11-25. Your server should:

  • Accept the MCP-Protocol-Version: 2025-11-25 header
  • Return 2025-11-25 in the initialize response
  • Reject unsupported versions

4. Authentication

Your server must validate the Authorization: Bearer <key> header and return 401 for invalid or missing keys. See Authentication below.

5. Session management

The Voidnet uses MCP-Session-Id headers to track sessions per buyer-app-publisher combination. Your server should:

  • Generate a session ID on initialize and return it as the MCP-Session-Id response header
  • Validate the MCP-Session-Id header on subsequent requests
  • Handle DELETE requests to terminate sessions

Authentication

The authentication contract between the Voidnet and your server is:

Request:
  Authorization: Bearer vnp-sk-27fc6268...

Response (valid key):
  200 OK

Response (invalid or missing key):
  401 Unauthorized
  {
    "jsonrpc": "2.0",
    "error": {
      "code": -32001,
      "message": "Unauthorized",
      "data": "Invalid or missing publisher API key"
    }
  }

Validate on every request, including initialize. If the key is invalid, return 401 immediately — do not process the MCP request.


MCP Protocol

Your server must implement the following MCP 2025-11-25 methods:

initialize

The Voidnet sends an initialize request to start a session:

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "initialize",
  "params": {
    "protocolVersion": "2025-11-25",
    "capabilities": {},
    "clientInfo": {
      "name": "voidnet",
      "version": "1.0.0"
    }
  }
}

Your response must include your server's capabilities and a MCP-Session-Id header:

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "protocolVersion": "2025-11-25",
    "capabilities": {
      "tools": {},
      "resources": { "subscribe": false, "listChanged": false },
      "prompts": {}
    },
    "serverInfo": {
      "name": "my-server",
      "version": "1.0.0"
    }
  }
}

After initialize, send notifications/initialized (no response expected).

tools/list

Returns the tools your server provides:

{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "tools": [
      {
        "name": "my_tool",
        "description": "Does something useful",
        "inputSchema": {
          "type": "object",
          "properties": {
            "input": { "type": "string", "description": "The input value" }
          },
          "required": ["input"]
        }
      }
    ]
  }
}

tools/call

Invokes a tool with the provided arguments:

{
  "jsonrpc": "2.0",
  "id": 3,
  "method": "tools/call",
  "params": {
    "name": "my_tool",
    "arguments": { "input": "hello" }
  }
}

The Voidnet sends the tool name in the name field (the MCP spec uses name, not tool). Respond with:

{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "Result: hello"
      }
    ]
  }
}

resources/list (optional)

If your server exposes resources:

{
  "jsonrpc": "2.0",
  "id": 4,
  "result": {
    "resources": [
      {
        "uri": "data://my-resource",
        "name": "My Resource",
        "description": "A data resource",
        "mimeType": "text/plain"
      }
    ]
  }
}

resources/read (optional)

{
  "jsonrpc": "2.0",
  "id": 5,
  "result": {
    "uri": "data://my-resource",
    "mimeType": "text/plain",
    "text": "Resource content here"
  }
}

prompts/list (optional)

{
  "jsonrpc": "2.0",
  "id": 6,
  "result": {
    "prompts": [
      {
        "name": "system_instruction",
        "description": "System prompt template",
        "arguments": [
          { "name": "task", "description": "The task to perform", "required": true }
        ]
      }
    ]
  }
}

prompts/get (optional)

{
  "jsonrpc": "2.0",
  "id": 7,
  "result": {
    "messages": [
      { "role": "system", "content": { "type": "text", "text": "You are a helpful assistant." } }
    ]
  }
}

Server Verification

When you publish an app in the Console, Voidnet performs a live verification of your server:

  1. The Voidnet sends an initialize request to your server
  2. It sends notifications/initialized
  3. It calls tools/list, resources/list, and prompts/list
  4. The discovered capabilities are cached and displayed in the Console

Your server must accept all these requests in a single session (same MCP-Session-Id). The verification determines which tools, resources, and prompts buyers will see.

You can re-verify your server at any time from the app detail page — click Refresh in the MCP Configuration section.


Domain Verification

Before you can publish an app, you must verify ownership of your server's domain:

  1. Initiate — In the Console, start domain verification. A unique verification token is generated.

  2. Place the file — Host the verification file at your domain's root or /.well-known/ directory:

    https://your-domain.com/voidnet-site-verification-<token>.html
  3. Verify — Voidnet Console fetches the file and confirms the content matches the expected token.

  4. Done — The domain is marked as verified and can be used for publishing.

One verified domain can host multiple apps.


Tier Configuration

Every published app has configurable tiers:

Free Tier

  • Meter limit — Max requests per month before the free tier is exhausted
  • Rate limit per minute — Max requests per minute
  • Rate limit per day — Max requests per day
  • Same limits as free tier but higher
  • Price — Set in USD with monthly, yearly, or one-time billing
  • Requires a connected Stripe account (see below)

How tiers work

  1. A buyer discovers your app in the marketplace
  2. If you offer a free tier, the buyer can start using it immediately
  3. If you offer a paid tier, the buyer purchases a subscription
  4. The Voidnet enforces rate limits and metering based on the buyer's tier
  5. When a free tier buyer exhausts their meter, they're prompted to upgrade

Stripe Connect Billing

To accept payments, you need a Stripe Express account connected to Voidnet Console:

  1. Connect — In the Console Payments page, click "Connect with Stripe"
  2. Onboard — Complete Stripe Express onboarding (identity verification, bank account)
  3. Sync — Your Stripe account status appears in the Console

Payout structure

ComponentShare
Publisher payout70%
Voidnet Console platform fee30%

Payouts are sent directly by Stripe to your connected bank account on Stripe's standard payout schedule.

Pricing model

  • The Voidnet uses the Marketplace / Direct Charges model
  • You are the merchant of record for each transaction
  • The Voidnet creates a PaymentIntent with an application_fee for Voidnet Console's 30%
  • You receive 70% minus any Stripe processing fees

Testing Your Server

1. Local development

Run your MCP server locally with HTTPS (self-signed certs are fine for testing). The Console's verify-server tool supports localhost with rejectUnauthorized: false.

2. Verify server in Console

From the Publish MCP Interface page:

  1. Enter your App Name (unique per publisher)
  2. Select a verified domain — the server URL is auto-populated from your domain
  3. Add a description
  4. Click Verify Server
  5. The Console connects to your server, performs the MCP handshake (initializetools/listresources/listprompts/list), and displays your capabilities
  6. Save your publisher API key — shown once in the success dialog
  7. Configure tiers and click Submit to publish

3. Test with curl

curl -X POST https://gateway.void.net/v1-beta/mcp/your-username/your-app \
  -H "Authorization: Bearer vnb-sk-your-buyer-key" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/list"
  }'

Going Live

Prerequisites checklist

  • Server is running HTTPS with a valid certificate
  • Server validates the Authorization: Bearer <key> header
  • Server implements MCP 2025-11-25 protocol
  • Server exposes at least one tool
  • Domain is verified
  • Stripe Express account is connected (if offering paid tier)

Publishing flow

  1. Go to Console → Publish Apps and select AI Tools (MCP)
  2. Enter your App Name (unique per publisher, like a GitHub repo name)
  3. Select a verified domain to set the server URL
  4. Add a description
  5. Click Verify Server — the Voidnet probes your MCP server with an initialize handshake and discovers its capabilities
  6. Review the detected tools, resources, and prompts
  7. Save your publisher API key (vnp-sk-*) — it's shown only once in the success dialog. Without it, the Voidnet cannot proxy requests to your server
  8. Close the dialog and configure tiers — free, paid, or both, with rate limits and metering limits
  9. Click Submit — your app is created as a draft and immediately published to the marketplace
  10. Your app now appears in Published Apps and the Voidnet Console Marketplace

Drafts

Every app starts as a draft when you first verify the server. Drafts appear in the Publish Apps page under "Continue your drafts" and can be resumed at any time. Publishing (Submitting) sets the status to published, making the app visible in the marketplace.

StatusVisible in marketplaceModifiable
draftNoYes — can edit tiers, re-verify, or delete
publishedYesYes — can update, re-verify, or delete

Managing your app

  • View details — Console → Published Apps → click your app
  • API keys — Generate and revoke keys from the API Keys tab on the app detail page
  • Logo — Upload or remove an app logo from the app detail page (400×400 WebP, PNG, JPEG, or AVIF)
  • Re-verify — Refresh server capabilities from the Overview tab on the app detail page
  • Analytics — Track requests and revenue per app
  • Delete — Remove your app (irreversible) from either the Published Apps list or Publish Apps page

Reference: Server skeleton

A minimal MCP server in TypeScript/Node.js:

import { createServer } from "https";
import { readFileSync } from "fs";

const PUBLISHER_API_KEY = process.env.PUBLISHER_API_KEY;

const server = createServer(
  { key: readFileSync("./key.pem"), cert: readFileSync("./cert.pem") },
  async (req, res) => {
    // 1. Validate publisher API key
    const expected = `Bearer ${PUBLISHER_API_KEY}`;
    if (PUBLISHER_API_KEY && req.headers["authorization"] !== expected) {
      res.writeHead(401, { "Content-Type": "application/json" });
      res.end(JSON.stringify({
        jsonrpc: "2.0",
        error: { code: -32001, message: "Unauthorized" }
      }));
      return;
    }

    // 2. Parse MCP JSON-RPC request
    const body = await parseBody(req);
    const response = await handleMcpRequest(body);

    // 3. Return response
    res.writeHead(200, { "Content-Type": "application/json" });
    res.end(JSON.stringify(response));
  }
);

server.listen(3051);

See the Voidnet test server for a complete reference implementation.

On this page