Building Plugins
A memoryblock plugin is an npm package that extends blocks with additional tools, capabilities, or integrations. This guide covers everything from structure to publishing.
Plugin Structure
@memoryblock/plugin-example/
├── src/
│ └── index.ts ← Entry point, exports tools
├── package.json
└── tsconfig.json
Minimal package.json
{
"name": "@memoryblock/plugin-example",
"version": "0.1.0",
"type": "module",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"scripts": { "build": "tsc -p tsconfig.json" },
"dependencies": {},
"peerDependencies": {
"@memoryblock/tools": "^0.3.0"
}
}
Minimal index.ts
import type { Tool, ToolContext } from '@memoryblock/tools';
export const tools: Tool[] = [
{
name: 'example_tool',
description: 'A brief description of what this tool does.',
input_schema: {
type: 'object',
properties: {
query: { type: 'string', description: 'The input query.' },
},
required: ['query'],
},
execute: async (params: { query: string }, context: ToolContext) => {
// Your tool logic here
return { result: `Processed: ${params.query}` };
},
},
];
Registry Entry
Every plugin available through mblk add must be registered in packages/plugins/installer/registry/plugins.json:
{
"id": "example",
"name": "Example Plugin",
"description": "What it does in one line",
"package": "@memoryblock/plugin-example",
"version": "0.1.0",
"toolNames": ["example_tool"],
"requiresAuth": [],
"category": "utility"
}
Registry Fields
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | ✓ | Unique plugin identifier, used with mblk add <id> |
name |
string | ✓ | Human-readable name |
description |
string | ✓ | One-line description |
package |
string | ✓ | npm package name |
version |
string | ✓ | Semver version |
toolNames |
string[] | ✓ | Tool names exported by the plugin |
requiresAuth |
string[] | ✓ | Auth keys needed (e.g., ["brave"], ["aws"]) |
category |
string | ✓ | Category: search, web, cloud, security, core, utility |
status |
string | Set to "upcoming" if not yet available |
|
core |
boolean | true = can’t be uninstalled by users |
|
blockSpecific |
boolean | true = plugin can have per-block settings |
|
settings |
object | Settings schema (see below) |
Plugin Settings
Plugins can declare configurable settings in their registry entry. These settings are:
- Stored at workspace level:
<workspace>/plugin-settings/<pluginId>.json - Editable via
mblk settings <plugin-id>(CLI) or the web dashboard settings panel - Auto-rendered — no UI code needed from the plugin developer
Settings Schema
{
"settings": {
"maxResults": {
"type": "number",
"label": "Max results per search",
"default": 5,
"min": 1,
"max": 20
},
"provider": {
"type": "select",
"label": "Search Provider",
"default": "brave",
"options": ["brave", "google"]
},
"enabled": {
"type": "toggle",
"label": "Enable this feature",
"default": true
}
}
}
Field Types
| Type | Rendered As | Extra Properties |
|---|---|---|
text |
Text input | placeholder |
password |
Masked input | placeholder |
number |
Number input | min, max |
select |
Dropdown | options (string array) |
toggle |
On/off switch | — |
All field types support label (required), default (optional).
Core Plugins
Plugins marked with "core": true in the registry:
- Are always installed and can’t be uninstalled
- Appear in the onboarding wizard as “installed” with a disabled toggle
- Should still declare a settings schema if configurable
- Example:
agents(multi-agent orchestration)
Block-Specific Plugins
Plugins with "blockSpecific": true:
- Can have per-block settings overrides in the block’s settings panel
- Users can enable/disable these plugins per block
- Example:
agents(different max sub-agents per block)
If not blockSpecific, the plugin uses workspace-level settings only.
The Tool Interface
Each tool must conform to the Tool interface from @memoryblock/tools:
interface Tool {
name: string; // Unique tool name (snake_case)
description: string; // shown to the LLM
input_schema: {
type: 'object';
properties: Record<string, unknown>;
required?: string[];
};
execute: (params: any, context: ToolContext) => Promise<unknown>;
}
ToolContext
Your execute function receives a ToolContext with:
| Property | Type | Description |
|---|---|---|
blockPath |
string | Absolute path to the block directory |
workingDir |
string | Current working directory |
sandbox |
boolean | Whether sandboxing is active |
permissions |
object | { scope, allowShell, allowNetwork, maxTimeout } |
workspacePath |
string | Root workspace path |
Limitations
- No direct file system access outside the block’s scope (enforced by
ToolSandbox) - No shell access unless
permissions.allowShellistrue - Sensitive files are blocked —
.env,auth.json, SSH keys, etc. - Timeouts — tool execution is capped by
permissions.maxTimeout - No DOM access — plugins run server-side only
- One namespace — tool names must be globally unique across all plugins
Example: Minimal Plugin from Scratch
// src/index.ts
import type { Tool, ToolContext } from '@memoryblock/tools';
export const tools: Tool[] = [
{
name: 'get_weather',
description: 'Get current weather for a city.',
input_schema: {
type: 'object',
properties: {
city: { type: 'string', description: 'City name' },
},
required: ['city'],
},
execute: async (params: { city: string }, _context: ToolContext) => {
const res = await fetch(`https://wttr.in/${encodeURIComponent(params.city)}?format=j1`);
const data = await res.json();
return { weather: data };
},
},
];
Registry entry:
{
"id": "weather",
"name": "Weather",
"description": "Get current weather information",
"package": "@memoryblock/plugin-weather",
"version": "0.1.0",
"toolNames": ["get_weather"],
"requiresAuth": [],
"category": "utility",
"settings": {
"units": { "type": "select", "label": "Temperature Units", "default": "celsius", "options": ["celsius", "fahrenheit"] }
}
}
Install: mblk add weather
Settings: mblk settings weather
Remove: mblk remove weather
Publishing
- Build your plugin:
npm run build - Submit a PR adding your registry entry to
packages/plugins/installer/registry/plugins.json - Publish to npm:
npm publish --access public - Users install via:
mblk add <your-plugin-id>