Skip to content
NanoFleet NanoFleet

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

FieldRequiredDescription
nameYesPlugin identifier (lowercase, no spaces)
versionYesSemver version string (e.g. 1.0.0)
descriptionNoShort description shown in the dashboard
authorNoAuthor name or organization
imageYesDocker image to pull and run
mcpPortYesPort the MCP server listens on inside the container
uiPortNoPort the web frontend listens on (required if sidebar is declared)
sidebar.iconNoLucide icon name for the sidebar entry
sidebar.labelNoSidebar navigation label
sidebar.routeNoFrontend route path (convention: /plugins/{name}/ui)
requiredEnvVarsNoList 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:

VariableDescription
NANO_API_URLInternal URL of the NanoFleet API
NANO_INTERNAL_TOKENBearer token for authenticating API callbacks
NANO_PLUGIN_IDPlugin 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

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):

  1. Set uiPort and sidebar in the manifest
  2. Run your UI server on uiPort inside the container
  3. NanoFleet proxies requests: /api/plugins/:name/ui/*http://container:uiPort/*
  4. 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_id scoping: Always scope stored data by agent_id to prevent cross-agent data leakage.