NIPs by PolleramaCommunity NIPs, surfaced by trustConnect
npub1mgvlrnf5hm9...

NIP-MACHINE-HANDLERS: Machine Application Handlers

Published Apr 2, 2026
kind 31990

NIP-MACHINE-HANDLERS

Machine Application Handlers

draft optional

Authors: forgesworn

This NIP extends NIP-89 by defining how kind:31990 handler information events can advertise machine-to-machine transports, specifically MCP (Model Context Protocol) servers. It introduces no new event kinds.

Standalone. This NIP works independently on any Nostr application. It composes with NIP-89 (handler discovery), NIP-90 (DVM announcements), and NIP-46 (remote signers), but does not depend on them.

Design principle: Discovery tells you where to connect, not what to do once connected. Transport metadata belongs in the handler event; capability negotiation belongs in the protocol handshake.

Rationale

NIP-89 enables clients to discover applications that handle unknown event kinds. Its platform tags (web, ios, android) assume human-facing applications with URL templates. However, machine-to-machine handlers are increasingly common on Nostr:

  • NIP-90 Data Vending Machines publish kind:31990 events to advertise supported job kinds
  • NIP-46 remote signers publish kind:31990 events with connection metadata (relay, nostrconnect_url tags)
  • MCP servers handle Nostr events programmatically but have no standard way to advertise their transport

Each project has invented its own approach: DVMs ignore platform tags entirely, NIP-46 uses custom tags, and MCP bridge projects have built parallel discovery layers. This NIP standardises machine handler discovery using NIP-89's existing tag convention.

MCP (Model Context Protocol) is an open standard for machine tool interoperability adopted by Anthropic, OpenAI, Google, Microsoft, Cursor, and others. It is not a single-vendor protocol.

NIP-89 does not define a closed set of platform tags. NIP-46 already extends kind:31990 with signer-specific tags for machine-to-machine use. This NIP follows the same pattern for MCP transports.

Relationship to community NIPs

Several community NIPs address agent communication (kinds 25800-25806, 31430) and trust service discovery (kinds 37570-37576). These define new event kinds for agent-to-agent messaging and capability negotiation. This NIP takes a deliberately different approach: no new kinds, no messaging protocol, just transport metadata on existing handler events. It operates at the discovery layer, not the communication layer, and composes with any messaging or trust NIP.

Specification

A machine application handler is a standard kind:31990 event (as defined in NIP-89) with one or more mcp platform tags describing how to connect to the handler.

Handler information

{
  "kind": 31990,
  "pubkey": "<application-pubkey>",
  "content": "<optional-kind:0-style-metadata>",
  "tags": [
    ["d", <random-id>],
    ["k", <supported-event-kind>],
    ["alt", "MCP handler for kind <supported-event-kind>"],
    ["mcp", "<endpoint>", "<transport>"]
  ]
}

Tags

TagStatusDescription
dREQUIREDRandom identifier. Combines with pubkey for deduplication per NIP-89.
kREQUIREDSupported event kind(s). Multiple k tags allowed. Same semantics as NIP-89.
mcpREQUIREDMCP transport endpoint. At least one MUST be present. Multiple allowed.
altRECOMMENDEDHuman-readable description per NIP-31 for clients that do not support this NIP.

The content field follows the NIP-89 convention: an optional stringified JSON object matching kind:0 metadata (name, about, picture). If empty, clients SHOULD fall back to the pubkey's kind:0 profile.

MCP transport tag

The mcp tag describes how to connect to the MCP server:

["mcp", <endpoint>, <transport>]

Two transport values are defined:

stdio -- local process
["mcp", "npx nostr-bray", "stdio"]

The endpoint is a shell command. The client spawns the process and communicates over stdin/stdout per the MCP specification. See Security Considerations for constraints on stdio execution.

http -- remote HTTP endpoint
["mcp", "https://mcp.example.com/sse", "http"]

The endpoint is an HTTPS URL. The client connects using the MCP Streamable HTTP transport. Endpoints MUST use HTTPS.

Multiple transports

A handler MAY include multiple mcp tags offering different transports for the same server:

{
  "kind": 31990,
  "pubkey": "<pubkey>",
  "content": "{\"name\":\"My MCP Server\",\"about\":\"Handles paid API events\"}",
  "tags": [
    ["d", "my-mcp-server"],
    ["k", "31402"],
    ["alt", "MCP handler for kind 31402 (paid API services)"],
    ["mcp", "npx my-mcp-server", "stdio"],
    ["mcp", "https://mcp.example.com/sse", "http"]
  ]
}

Clients SHOULD select the best available transport based on their capabilities. A suggested preference order is stdio (lowest latency) > http (widely supported), though clients MAY override this based on user preferences or security policy.

Discovery Flow

sequenceDiagram
    participant App as MCP Client / AI Agent
    participant Relay as Nostr Relay
    participant Handler as MCP Server

    App->>Relay: 1. REQ {kinds:[31990], #k:["31402"]}
    Relay-->>App: 2. EVENT (kind 31990 with mcp tags)
    App->>App: 3. Parse mcp tags, select transport
    alt stdio transport
        App->>Handler: 4a. Spawn process (npx nostr-bray)
        Handler-->>App: 5a. MCP handshake over stdin/stdout
    else http transport
        App->>Handler: 4b. Connect to HTTPS endpoint
        Handler-->>App: 5b. MCP handshake over SSE
    end
    App->>Handler: 6. tools/list
    Handler-->>App: 7. Available tools and schemas
    App->>Handler: 8. tools/call
    Handler-->>App: 9. Result

By event kind

A client that encounters an unknown event kind and wants to find an MCP handler:

["REQ", <id>, { "kinds": [31990], "#k": [<desired-event-kind>] }]

Filter results for events containing mcp tags. Optionally, use NIP-89's kind:31989 recommendation flow to rank handlers by social graph trust.

Coexistence with NIP-89

A single kind:31990 event MAY contain both human-facing platform tags (web, ios) and machine-facing mcp tags. This allows one handler event to serve both audiences:

{
  "kind": 31990,
  "pubkey": "<pubkey>",
  "content": "{\"name\":\"402.pub\",\"about\":\"L402 service directory\"}",
  "tags": [
    ["d", "402-pub"],
    ["k", "31402"],
    ["alt", "L402 service directory -- web viewer and MCP server"],
    ["web", "https://402.pub/#<bech32>", "naddr"],
    ["mcp", "npx 402-mcp", "stdio"],
    ["mcp", "https://mcp.402.pub/sse", "http"]
  ]
}

Coexistence with NIP-46

A remote signer that also offers an MCP interface MAY include both NIP-46 tags and mcp tags on the same kind:31990 event:

{
  "kind": 31990,
  "pubkey": "<signer-pubkey>",
  "content": "{\"name\":\"My Signer\",\"about\":\"Remote signer with MCP interface\"}",
  "tags": [
    ["d", "my-signer"],
    ["k", "24133"],
    ["alt", "Remote signer (NIP-46) with MCP transport"],
    ["relay", "wss://relay.example.com"],
    ["nostrconnect_url", "bunker://<signer-pubkey>?relay=wss://relay.example.com"],
    ["mcp", "https://signer.example.com/mcp", "http"]
  ]
}

Security Considerations

stdio transport

The stdio transport instructs clients to execute a shell command. This is a significant attack surface.

Clients MUST:

  • Only execute stdio commands from handler events published by explicitly trusted pubkeys. Discovering a handler via relay query alone is NOT sufficient trust.
  • Prompt the user for confirmation before spawning any process, displaying the exact command to be executed.
  • Never pass untrusted event content or tag values as arguments to the spawned command without sanitisation.

Clients SHOULD:

  • Maintain an allowlist of trusted handler pubkeys or use NIP-89 kind:31989 recommendations from the user's social graph as a trust signal.
  • Sandbox spawned processes where the operating system supports it.

http transport

Endpoints MUST use HTTPS. Clients MUST NOT connect to plain HTTP endpoints.

Clients SHOULD verify the handler pubkey's reputation via NIP-89 recommendations or other trust mechanisms before sending requests to unknown HTTP endpoints.

General

Handler events are replaceable (addressable by pubkey + d tag). A compromised pubkey could publish a malicious handler update. Clients SHOULD pin known-good handler events by event ID when operating in automated or unattended mode.

Why not existing approaches?

Why not NIP-89 as-is?

NIP-89's platform tags use URL templates with <bech32> placeholders, designed for redirecting humans to web pages or native apps. Machine handlers need transport metadata (a command to spawn or an HTTP endpoint to connect to), not a URL template. The mcp tag follows NIP-89's tag convention while providing the information machines need to establish a connection.

Why not NIP-90 DVM discovery?

NIP-90 DVMs already use kind:31990 for discovery, but with no transport information -- clients must know how to speak the DVM job protocol (kind 5xxx/6xxx/7xxx). This NIP complements NIP-90 by letting DVMs that also expose an MCP interface advertise it alongside their existing kind:31990 events.

Why not a new event kind?

There is no need. kind:31990 already means "this pubkey handles these event kinds." The only missing piece is how to connect for machine-to-machine use. A new platform tag value conveys this within the existing NIP-89 framework.

Why not community agent NIPs?

Community NIPs for agent communication (kinds 25800-25806) and trust service machines (kinds 37570-37576) define new event kinds for messaging and capability negotiation. This NIP deliberately avoids new kinds. It operates at the discovery layer -- how to find and connect to a machine handler -- not the communication layer. A handler discovered via this NIP could speak any protocol once connected: MCP, DVM jobs, or custom agent messaging.

Reference implementations

  • nostr-bray -- MCP server for Nostr, publishes kind:31990 handler events
  • 402-mcp -- MCP server for L402/x402 paid API consumption
  • satgate -- Lightning-paid AI inference gateway, announces via kind 31402