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 TDP standalone with Node.js 18+ or Python.
Installation
git clone https://github.com/eddyficial/tdp.git
cd tdp
.\install.ps1One command. The installer configures all five AI tools, installs dependencies, starts the server manager in the background, and launches the 5 demo servers automatically. No manual terminal windows needed.
Running the Demo
After running install.ps1, everything starts automatically. The server manager launches all 5 demo servers in the background. No manual terminal windows needed.
5 demo servers ship out of the box
servers/
calculator_server.py # add, subtract, multiply, divide, sqrt, percentage
file_server.py # read_file, list_directory, file_info, file_exists
system_server.py # system_info, network_info, disk_usage, current_time
weather_server.py # get_weather, get_forecast
joke_server.py # get_joke, get_jokes_by_category, list_categories, random_joke20 tools available immediately
The bridge re-scans every 15 seconds for new servers and uses fresh connections per tool call, so there are no stale connections.
The bridge discovers all servers and exposes their tools:
Adding Your Own Tools
Write a *_server.py script and drop it in the servers/ folder. The server manager picks it up automatically within 15 seconds. No restarts, no config changes.
import asyncio, os, sys
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "python"))
from tdp_config import SHARED_SECRET
from lib.discovery import TdpServiceProvider, get_local_ip
from lib.connection import start_server
from lib.mcp import McpServer
tools = {
"my_tool": {
"description": "Does something useful",
"args": ["input"],
"allowedAgents": None,
"inputSchema": {
"type": "object",
"properties": { "input": { "type": "string" } },
"required": ["input"],
},
"handler": lambda args: f"Processed: {args['input']}",
},
}
async def main():
mcp = McpServer(tools, server_name="my-custom-server")
async def on_ready(conn):
await mcp.attach(conn)
server = await start_server(41250, SHARED_SECRET, on_ready)
discovery = TdpServiceProvider("my-custom-server", 41250,
[{"name": n, "description": t["description"], "args": t["args"]}
for n, t in tools.items()])
await discovery.start()
await asyncio.Future()
asyncio.run(main())Drop that file into servers/ and the bridge picks it up on its next scan (every 15 seconds). The bridge uses fresh connections per tool call, so there are never stale connections. Your new tools appear in Claude Code, Cursor, VS Code, Claude Desktop, and Windsurf automatically.
Configuration
Edit tdp.config.js or set environment variables.
| Setting | Env Var | Default | Description |
|---|---|---|---|
| sharedSecret | TDP_SECRET | tdp-prototype-... | HMAC auth secret |
| agentSecrets | -- | null | Per-agent secrets { agentId: secret } |
| allowedAgents | -- | null | Agent allow list (null = all) |
| manifestSecret | -- | null | HMAC key to sign broadcasts |
| trustedManifestSecret | -- | null | Only accept signed manifests |
| discoveryPort | -- | 41234 | UDP broadcast port |
| discoveryInterval | -- | 10000 | Broadcast interval (ms) |
| dataPort | -- | 41235 | TCP data port |
| authTimeout | -- | 5000 | Auth timeout (ms) |
| rpcTimeout | -- | 10000 | RPC 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.
// 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.
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.
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.
// Provider signs manifests
manifestSecret: 'my-manifest-signing-key',
// Caller only accepts signed manifests
trustedManifestSecret: 'my-manifest-signing-key',Shell bypass protection (command filter)
MCP permissions only gate tool access. An agent with read-only MCP tools can still use PowerShell to run SQL writes directly. TDP includes a command filter that installs as a Claude Code hook and blocks shell commands that violate the security profile.
read-write No restrictions. All shell commands allowed.
read-only SQL reads OK, writes blocked. GET OK, POST/PUT/DELETE blocked.
no-network All network access via shell blocked (curl, wget, ssh).
strict Blocks writes, network, and destructive commands.py security\install_hook.py # read-only profile
py security\install_hook.py --profile strict # strict profile
py security\install_hook.py --remove # remove the hookThe filter is included in the installer. Edit security/rules.json to customize blocked patterns. All blocked commands are logged to security/blocked.log.
System tray app
The TDP tray app sits in the Windows notification area and gives you real-time visibility into server health. The icon color changes based on status: green when all servers are running, yellow when some are down, red when all are down.
Right-click menu:
- Live server count and per-server status (port + running/down)
- Start All / Stop All / Restart Dead Servers
- Switch security profiles (read-write, read-only, no-network, strict)
- Open Status Dashboard
- Open Website
The menu refreshes every time you open it.
The tray app starts automatically on boot via Windows Task Scheduler.
To run manually: pythonw tdp_tray.pyWeb dashboard
A real-time web dashboard for monitoring and managing your TDP servers. Shows server health, security profiles, tool call analytics, and recent activity. Start, stop, and restart servers from the browser. Live updates via WebSocket.
py dashboard/server.py # starts on http://localhost:41200The dashboard runs locally and talks directly to your TDP servers. No data leaves your machine. You can also open it from the system tray menu.
Status terminal
A lightweight terminal-based status check. Shows all servers, bridge connection, and security profile. Auto-restarts dead servers.
py tdp_status.py # live dashboard (refreshes every 5s)
py tdp_status.py --once # print status onceMulti-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
TDP 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 TDP runs automatically when your machine boots.
git clone https://github.com/eddyficial/tdp.git
cd tdp
.\install.ps1What it does:
- +Configures Claude Code as an MCP server in your settings
- +Adds TDP to Claude Desktop config (claude_desktop_config.json)
- +Configures Cursor and VS Code MCP settings
- +Configures Windsurf MCP settings
- +Installs npm dependencies
- +Creates Windows Task Scheduler startup tasks for servers and tray app
- +Launches the system tray app for monitoring and management
How auto-discovery works
When an TDP 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.
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 itWrapping 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 TDP by writing a thin provider wrapper. The tool logic stays the same. You just add TDP discovery and auth on top.
import config from './tdp.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 TDP 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 TDP 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 TDP standalone with Node.js or Python.
Claude Code (CLI)
AvailableConfigured by install.ps1. TDP 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
AvailableConfigured by install.ps1. TDP is added to the MCP settings for both editors. Discovered tools appear without manual config.
Claude Desktop
AvailableConfigured by install.ps1. TDP is added to claude_desktop_config.json so LAN servers appear in Claude Desktop without editing JSON files.
Windsurf
AvailableConfigured by install.ps1. TDP is added to Windsurf MCP settings. Discovered tools are available inside Windsurf sessions.
Ollama
PlannedExpose local Ollama models as TDP tools. Other agents on the LAN can call your local LLM for inference.
Python (standalone)
Availableprovider_agent.py and caller_agent.py with mDNS discovery. pip install zeroconf, then run.
Node.js (standalone)
Availableprovider-agent.js and caller-agent.js with UDP discovery. Zero dependencies, just run with Node.js 18+.
Logging
Since TDP has no central gateway for logging, each agent can independently log events. Enable file logging by setting the file option.
const logger = new TdpLogger('my-agent', {
console: true,
file: './tdp.log', // set to null to disable
});
// Events logged: discover, connect, auth,
// tool-call, tool-result, tool-error,
// disconnect, health