Manifest Reference
NimbleBrain reads Synapse metadata from the _meta["ai.nimblebrain/synapse"] key in your MCPB manifest.json. This is where you declare your app’s name, icon, primary view, sidebar placements, and settings section.
Full manifest structure
Section titled “Full manifest structure”{ "manifest_version": "0.4", "name": "@myorg/my-app", "version": "1.0.0", "description": "My NimbleBrain app", "author": { "name": "My Org", "email": "dev@myorg.com", "url": "https://myorg.com" }, "server": { "type": "python", "mcp_config": { "command": "python", "args": ["-m", "my_app.server"] } }, "_meta": { "ai.nimblebrain/synapse": { "name": "My App", "icon": "database", "primaryView": { "resourceUri": "ui://dashboard" }, "placements": [ { "slot": "sidebar", "resourceUri": "ui://nav", "priority": 50, "label": "My App", "icon": "database", "route": "my-app", "size": "compact" } ], "settings": { "id": "my-app", "label": "My App", "icon": "settings", "resourceUri": "ui://settings" } } }}MCPB base fields
Section titled “MCPB base fields”These fields are defined by the MCPB specification. NimbleBrain supports both v0.3 and v0.4 formats.
| Field | Type | Required | Description |
|---|---|---|---|
manifest_version | string | No | MCPB spec version ("0.3" or "0.4"). |
name | string | Yes | Scoped package name (e.g., @myorg/my-app). |
version | string | Yes | Semver version string. |
description | string | No | Human-readable description. |
author | object | No | Author info: name, email, url. |
server.type | string | Yes | Runtime type: "python", "node", "binary", or "uv". |
server.entry_point | string | No | Entry point file path. |
server.mcp_config | McpConfig | Yes | Spawn configuration (see below). |
_meta | object | No | Extension metadata. NimbleBrain reads _meta["ai.nimblebrain/synapse"]. |
McpConfig
Section titled “McpConfig”| Field | Type | Required | Description |
|---|---|---|---|
command | string | Yes | Executable to run ("python", "node", etc.). |
args | string[] | No | Command-line arguments. Use ${__dirname} for the bundle directory. |
env | Record<string, string> | No | Environment variables passed to the process. |
Synapse metadata: _meta["ai.nimblebrain/synapse"]
Section titled “Synapse metadata: _meta["ai.nimblebrain/synapse"]”| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Display name shown in the sidebar and app list. |
icon | string | Yes | Lucide icon name in kebab-case (e.g., "database", "message-square", "hand"). |
primaryView | object | No | The main view loaded when a user navigates to your app. |
primaryView.resourceUri | string | Yes (if primaryView set) | ui:// URI for the main view (e.g., "ui://dashboard"). |
placements | PlacementDeclaration[] | No | Explicit shell layout placement declarations. See Placements. |
settings object
Section titled “settings object”| Field | Type | Required | Description |
|---|---|---|---|
settings.id | string | Yes | Unique section ID across all bundles. |
settings.label | string | Yes | Tab label in the settings UI. |
settings.icon | string | Yes | Lucide icon name for the settings tab. |
settings.resourceUri | string | Yes | ui:// URI that renders the settings section HTML. |
PlacementDeclaration
Section titled “PlacementDeclaration”Each entry in the placements array:
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
slot | string | Yes | — | Shell slot to fill: "sidebar", "sidebar.conversations", "sidebar.bottom", "main", "toolbar.right". |
resourceUri | string | Yes | — | ui:// URI served by this MCP server. |
priority | number | No | 100 | Sort order within the slot. Lower values appear first. |
label | string | No | — | Human-readable label for sidebar items and tabs. |
icon | string | No | — | Lucide icon name (kebab-case). Falls back to CircleDot if unset or unrecognized. |
route | string | No | — | Route path for "main" slot placements. Registers as /app/<route>. |
size | "compact" | "full" | "auto" | No | — | Size hint for the slot renderer. |
How primaryView and placements interact
Section titled “How primaryView and placements interact”If your manifest has placements, those are used directly. If it only has primaryView (no placements array), NimbleBrain converts it to a single "main" slot placement automatically:
// Legacy conversion (from PlacementRegistry.registerLegacy){ slot: "main", resourceUri: uiMeta.primaryView.resourceUri, label: uiMeta.name, icon: uiMeta.icon, route: bundleName // e.g., "@myorg/my-app"}The route for legacy bundles uses the scoped bundle name as the path. For @myorg/my-app, the URL becomes /app/@myorg/my-app.
Icons use Lucide names. The resolver accepts both kebab-case and PascalCase:
"message-square"resolves to theMessageSquarecomponent"database"resolves toDatabase"hand"resolves toHand
If the icon name is not recognized, CircleDot is used as the default fallback.
Minimal example (UI app)
Section titled “Minimal example (UI app)”The smallest manifest that registers a UI view:
{ "name": "@myorg/hello", "version": "0.1.0", "server": { "type": "node", "mcp_config": { "command": "node", "args": ["${__dirname}/dist/index.js"] } }, "_meta": { "ai.nimblebrain/synapse": { "name": "Hello", "icon": "hand", "primaryView": { "resourceUri": "ui://index" } } }}Minimal example (tools only)
Section titled “Minimal example (tools only)”No _meta needed for tools-only bundles:
{ "name": "@myorg/calculator", "version": "1.0.0", "server": { "type": "python", "mcp_config": { "command": "python", "args": ["-m", "calculator.server"] } }}