Get Started

The recommended path is the one-command installer, which configures Claude Code, Claude Desktop, Cursor, VS Code, and Windsurf automatically. You can also run NDP standalone with Node.js 18+ or Python.

Installation

Terminal
git clone https://github.com/eddyficial/ndp.git
cd ndp

That is it. No npm install. NDP uses only built-in Node.js modules.

Running the Demo

Open three terminal windows. Start two MCP servers and one AI agent.

Terminal 1 -- Math Server

node provider-agent.js

Terminal 2 -- String Server

node provider-agent-2.js

Terminal 3 -- AI Agent (Caller)

node caller-agent.js

The caller discovers both servers and calls tools across them:

Adding Your Own Tools

Edit provider-agent.js and add entries to the tools object. Each tool needs a handler function, description, and input schema.

provider-agent.js
const tools = {
  // Your custom tool
  weather: {
    description: 'Get weather for a city',
    args: ['city'],
    allowedAgents: null, // null = all agents, or ['agent-id'] to restrict
    inputSchema: {
      type: 'object',
      properties: {
        city: { type: 'string', description: 'City name' },
      },
      required: ['city'],
    },
    handler: async ({ city }, context) => {
      // context.agentId tells you who is calling
      // Call an API, query a database, run Ollama, etc.
      return { city, temp: 72, condition: 'sunny' };
    },
  },
};

Tools can be sync or async. They receive an arguments object and a context object (with the caller's agentId). Return any JSON-serializable value. The MCP layer wraps it in the standard content array. Set allowedAgents to restrict which agents can call a specific tool.

Configuration

Edit ndp.config.js or set environment variables.

SettingEnv VarDefaultDescription
sharedSecretNDP_SECRETndp-prototype-...HMAC auth secret
agentSecrets--nullPer-agent secrets { agentId: secret }
allowedAgents--nullAgent allow list (null = all)
manifestSecret--nullHMAC key to sign broadcasts
trustedManifestSecret--nullOnly accept signed manifests
discoveryPort--41234UDP broadcast port
discoveryInterval--10000Broadcast interval (ms)
dataPort--41235TCP data port
authTimeout--5000Auth timeout (ms)
rpcTimeout--10000RPC timeout (ms)

Security

Each server independently controls its own access. No central authority. All settings default to null (open) for backward compatibility.

Server-side allow lists

Restrict which agents can connect to a server. Set in the provider script.

provider-agent.js
// Only these agents can connect to this server
const allowedAgents = ['claude-agent-01', 'claude-agent-py'];

// Pass to startServer
startServer(port, secret, onReady, { allowedAgents });

// Set to null to allow all authenticated agents
const allowedAgents = null;

Tool-level permissions

Restrict specific tools to specific agents. Agents that are not authorized will not see the tool in tools/list and cannot call it.

provider-agent.js
const tools = {
  read_data: {
    description: 'Read from database',
    allowedAgents: null, // all agents can read
    handler: (args) => { /* ... */ },
  },
  write_data: {
    description: 'Write to database',
    allowedAgents: ['admin-agent'], // only admin can write
    handler: (args) => { /* ... */ },
  },
};

Per-agent secrets (capability tokens)

Give each agent its own HMAC secret instead of sharing one. Agents not in the map fall back to the shared secret.

ndp.config.js
agentSecrets: {
  'claude-agent-01': 'secret-for-claude',
  'admin-agent': 'secret-for-admin',
},

Manifest trust filtering

Sign broadcast manifests so callers can reject rogue servers. Set the same key on provider and caller.

ndp.config.js
// Provider signs manifests
manifestSecret: 'my-manifest-signing-key',

// Caller only accepts signed manifests
trustedManifestSecret: 'my-manifest-signing-key',

Multi-Server Mesh

The caller agent uses an AgentMesh that connects to all discovered servers independently. It maintains a unified tool index and routes calls to the correct server automatically.

Auto-discovery

New servers are found automatically via UDP broadcast (Node.js) or mDNS (Python). No config changes needed.

Unified tool routing

The mesh indexes all tools across all servers. callTool('add', {a:1, b:2}) routes to whichever server provides 'add'.

Failover

If a server disconnects, its tools are removed from the index. If multiple servers provide the same tool, the mesh tries the next one.

Health checks

The mesh pings every connected server every 15 seconds. Unreachable servers are marked inactive.

Integrations

NDP is a discovery and connection layer. It sits between your AI agent (Claude, GPT, Cursor, etc.) and your MCP servers. Here is how the pieces connect.

One-Command Install

The installer configures all five supported AI tools, installs Node.js dependencies, and creates a Windows startup task so NDP runs automatically when your machine boots.

Terminal (PowerShell)
git clone https://github.com/eddyficial/ndp.git
cd ndp
.\install.ps1

What it does:

  • +Configures Claude Code as an MCP server in your settings
  • +Adds NDP to Claude Desktop config (claude_desktop_config.json)
  • +Configures Cursor and VS Code MCP settings
  • +Configures Windsurf MCP settings
  • +Installs npm dependencies
  • +Creates a Windows Task Scheduler startup task

How auto-discovery works

When an NDP caller agent starts, it scans the LAN for MCP servers. No URLs to configure. No tokens to distribute. Servers announce themselves, and agents find them.

What happens when the caller starts
1. Caller listens for UDP broadcasts (Node.js)
   and mDNS services (Python) on the LAN

2. Provider broadcasts every 10 seconds:
   { agentId: "sql-server", tools: ["query", "insert"], port: 41235 }

3. Caller receives broadcast, connects via TCP

4. HMAC auth handshake (per-connection)

5. MCP initialize, tools/list, tools/call
   Standard JSON-RPC 2.0 from here on

6. If another server appears, the mesh adds it automatically
   If a server disappears, the mesh removes it

Wrapping an existing MCP server

If you already have an MCP server (file system, database, API wrapper, etc.), you can expose it on the LAN via NDP by writing a thin provider wrapper. The tool logic stays the same. You just add NDP discovery and auth on top.

wrapping-example.js
import config from './ndp.config.js';
import { getLocalIp, startBroadcasting } from './lib/discovery.js';
import { startServer } from './lib/connection.js';
import { McpServer } from './lib/mcp.js';

// Your existing tool logic
const tools = {
  query: {
    description: 'Query the production database',
    args: ['sql'],
    allowedAgents: ['data-agent'],  // restrict access
    inputSchema: {
      type: 'object',
      properties: { sql: { type: 'string' } },
      required: ['sql'],
    },
    handler: async ({ sql }) => {
      // Call your existing DB logic here
      const rows = await db.query(sql);
      return rows;
    },
  },
};

// Wrap it with NDP discovery + auth
const mcpServer = new McpServer(tools, { name: 'db-server' });
const manifest = {
  agentId: 'db-server',
  role: 'provider',
  dataPort: 41237,
  ip: getLocalIp(),
  tools: Object.keys(tools).map(n => ({ name: n })),
};

startServer(41237, config.sharedSecret, (conn) => {
  mcpServer.attach(conn);
}, { allowedAgents: ['data-agent', 'admin-agent'] });

startBroadcasting(manifest, config);

Any agent on the LAN running an NDP caller will discover this server automatically and can call its tools if authorized.

Integration with AI tools

The install.ps1 installer configures all five AI tools automatically. You can also run NDP standalone with Node.js or Python.

Claude Code (CLI)

Available

Configured by install.ps1. NDP registers as an MCP server in Claude Code settings. Claude discovers LAN tools automatically and can call them like any other MCP tool.

VS Code / Cursor

Available

Configured by install.ps1. NDP is added to the MCP settings for both editors. Discovered tools appear without manual config.

Claude Desktop

Available

Configured by install.ps1. NDP is added to claude_desktop_config.json so LAN servers appear in Claude Desktop without editing JSON files.

Windsurf

Available

Configured by install.ps1. NDP is added to Windsurf MCP settings. Discovered tools are available inside Windsurf sessions.

Ollama

Planned

Expose local Ollama models as NDP tools. Other agents on the LAN can call your local LLM for inference.

Python (standalone)

Available

provider_agent.py and caller_agent.py with mDNS discovery. pip install zeroconf, then run.

Node.js (standalone)

Available

provider-agent.js and caller-agent.js with UDP discovery. Zero dependencies, just run with Node.js 18+.

Logging

Since NDP has no central gateway for logging, each agent can independently log events. Enable file logging by setting the file option.

caller-agent.js
const logger = new NdpLogger('my-agent', {
  console: true,
  file: './ndp.log',  // set to null to disable
});

// Events logged: discover, connect, auth,
// tool-call, tool-result, tool-error,
// disconnect, health