Skip to content

Proxy Overview

The NostrMCPProxy is a powerful, client-side bridging component in the @contextvm/sdk. Its primary function is to act as a local proxy that translates communication between a standard MCP client and a remote, Nostr-based MCP server.

The proxy manages two transports simultaneously:

  1. MCP Host Transport: This is a standard MCP transport (like StdioServerTransport) that communicates with a local MCP client application.
  2. Nostr Client Transport: This is a NostrClientTransport that communicates with the remote MCP server over the Nostr network.

The proxy sits in the middle, seamlessly forwarding messages between these two transports. When the local client sends a request, the proxy forwards it over Nostr. When the remote server sends a response, the proxy relays it back to the local client.

The NostrMCPProxy is particularly useful in the following scenarios:

  • Integrating with Existing Clients: If you have an existing MCP client that does not have native Nostr support, you can use the proxy to enable it to communicate with Nostr-based MCP servers without modifying the client’s code. The client simply connects to the proxy’s local transport.
  • Simplifying Client-Side Logic: The proxy abstracts away all the complexities of Nostr communication (signing, relay management, encryption), allowing your main client application to remain simple and focused on its core tasks.
  • Local Development and Testing: The proxy can be a valuable tool for local development, allowing you to easily test a client against a remote Nostr server.

To create a NostrMCPProxy, you need to provide a configuration object that implements the NostrMCPProxyOptions interface:

export interface NostrMCPProxyOptions {
mcpHostTransport: Transport;
nostrTransportOptions: NostrTransportOptions;
}
  • mcpHostTransport: An instance of a server-side MCP transport that the local client will connect to. For example, new StdioServerTransport().
  • nostrTransportOptions: The full configuration object required by the NostrClientTransport. This includes the signer and the remote serverPubkey, and may also include relayHandler when you want explicit control over the operational relay set.

This example demonstrates how to create a proxy that listens for a local client over standard I/O and connects to a remote server over Nostr.

import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { NostrMCPProxy } from '@contextvm/sdk';
import { PrivateKeySigner } from '@contextvm/sdk';
import { ApplesauceRelayPool } from '@contextvm/sdk';
// 1. Configure the signer and relay handler for the Nostr connection
const signer = new PrivateKeySigner('your-private-key');
const relayPool = new ApplesauceRelayPool(['wss://relay.damus.io']);
const REMOTE_SERVER_PUBKEY = 'remote-server-public-key';
// 2. Configure the transport for the local client
// In this case, a stdio transport that the local client can connect to
const hostTransport = new StdioServerTransport();
// 3. Create the proxy instance
const proxy = new NostrMCPProxy({
mcpHostTransport: hostTransport,
nostrTransportOptions: {
signer,
relayHandler: relayPool,
serverPubkey: REMOTE_SERVER_PUBKEY,
},
});
// 4. Start the proxy
await proxy.start();
console.log('Proxy is running. Connect your local MCP client.');
// To stop the proxy: await proxy.stop();

In this setup, a separate MCP client process could connect to this proxy’s StdioServerTransport and it would be transparently communicating with the remote server on Nostr.

Note: relayHandler is optional on the underlying NostrClientTransport. Include it when you want explicit relay control; omit it when you want the SDK to resolve relays dynamically from server hints and discovery metadata.

Next, we’ll look at the server-side equivalent of the proxy: