Building a Plugin
A NanoFleet plugin is a Docker image that runs an MCP HTTP server. You provide a manifest.json and NanoFleet handles discovery, lifecycle, and agent linking.
manifest.json
The manifest describes your plugin to NanoFleet:
{
"name": "my-plugin",
"version": "1.0.0",
"description": "What this plugin does",
"image": "ghcr.io/your-org/my-plugin:latest",
"mcpPort": 8080,
"requiredEnvVars": ["MY_API_KEY"]
}
With a sidebar UI:
{
"name": "my-plugin",
"version": "1.0.0",
"description": "Plugin with a dashboard UI",
"image": "ghcr.io/your-org/my-plugin:latest",
"mcpPort": 8080,
"uiPort": 3001,
"sidebar": {
"icon": "LayoutDashboard",
"label": "My Plugin",
"route": "/plugins/my-plugin/ui"
},
"requiredEnvVars": []
}
Manifest fields
| Field | Required | Description |
|---|---|---|
name | Yes | Plugin identifier (lowercase, no spaces) |
version | Yes | Semver version string (e.g. 1.0.0) |
description | No | Short description shown in the dashboard |
author | No | Author name or organization |
image | Yes | Docker image to pull and run |
mcpPort | Yes | Port the MCP server listens on inside the container |
uiPort | No | Port the web frontend listens on (required if sidebar is declared) |
sidebar.icon | No | Lucide icon name for the sidebar entry |
sidebar.label | No | Sidebar navigation label |
sidebar.route | No | Frontend route path (convention: /plugins/{name}/ui) |
requiredEnvVars | No | List of env var names that must exist in Settings → API Keys before install |
Environment variables injected automatically
NanoFleet injects these variables into every plugin container at startup:
| Variable | Description |
|---|---|
NANO_API_URL | Internal URL of the NanoFleet API |
NANO_INTERNAL_TOKEN | Bearer token for authenticating API callbacks |
NANO_PLUGIN_ID | Plugin ID assigned by NanoFleet |
MCP server requirements
Your plugin must implement the MCP HTTP protocol with at least these endpoints:
POST /mcp — JSON-RPC endpoint handling:
- initialize
- tools/list
- tools/call
Recommended libraries
TypeScript:
npm install @modelcontextprotocol/sdk
Python:
pip install mcp
Tool call flow
Agents call plugin MCP servers directly — the NanoFleet API is not on the hot path. At install time, NanoFleet calls tools/list to register the plugin’s tools, then injects the plugin URL into each agent’s .mcp.json:
{
"mcpServers": {
"my-plugin": {
"url": "http://nanofleet-plugin-my-plugin:8080/mcp?agent_id=abc123"
}
}
}
The agent_id query parameter lets your plugin scope data per agent.
Agent → POST /mcp (tools/call)
└─▶ Plugin processes the call
└─▶ (optional) Plugin calls NANO_API_URL for context
└─▶ Returns result to agent
Plugin with UI
If your plugin has a web UI (like a Kanban board or dashboard):
- Set
uiPortandsidebarin the manifest - Run your UI server on
uiPortinside the container - NanoFleet proxies requests:
/api/plugins/:name/ui/*→http://container:uiPort/* - A
?nf_token=query parameter is appended automatically for auth
The UI is embedded in the NanoFleet dashboard as an iframe in the sidebar.
Security model
- Network isolation: Your plugin only receives traffic from
nanofleet-net— it cannot be reached from the internet directly. NANO_INTERNAL_TOKEN: Validate this token on any callback endpoints you expose to the NanoFleet API.agent_idscoping: Always scope stored data byagent_idto prevent cross-agent data leakage.