Skip to content

Plugins#

Agent Plugins package capabilities into a single distributable folder. They follow the open agent-plugins.org standard (version 1.0.0), so a plugin written for another agent works here unchanged.

Where a skill carries instructions, a plugin can carry instructions and the tools those instructions need. A plugin contributes two kinds of thing, which is the whole of what the standard defines:

  • Skills — ordinary SKILL.md bundles, merged into the agent's skill catalog.
  • MCP (Model Context Protocol) servers — tool servers the runtime launches and exposes to the agent.

There is nothing else to configure. Drop a plugin folder in and its skills and tools appear; delete the folder and they disappear.

Where plugins live#

Plugins are discovered from the agent's plugins directory inside its data dir: ~/.prism/plugins for a native install, /data/plugins in Docker. Override the data dir with PRISM_DATA_DIR, or the plugins dir specifically with PRISM_PLUGINS_DIR — see Configuration.

Each immediate subdirectory holding a plugin.json is one plugin, and the folder name is the plugin's id:

plugins/
└── my-plugin/            # the folder name is the plugin id
    ├── plugin.json       # required
    ├── skills/           # optional
    │   └── greet/
    │       └── SKILL.md
    └── mcp.json          # optional

Installing and removing a plugin#

Installation is out of band, exactly as it is for skills: put the folder in place and the agent picks it up on its next turn — no restart. Clone it, copy it, or ask the agent to fetch it for you with its shell tools; the agent's prompt names the plugins directory, so it knows where to put one.

Removing a plugin is deleting its folder. Its skills leave the catalog and its MCP servers are shut down. Data a plugin's MCP server writes lives outside the plugin folder, in <data dir>/plugin-data/<plugin id>/, so replacing a plugin does not destroy its state.

Warning

Installing a plugin is running its code. A plugin's mcp.json can declare a stdio server, which the runtime starts as a local process on this machine with the same OS user and permissions as the runtime itself — the plugins directory is not a sandbox. Install only plugins you trust, and treat one as you would any binary you were about to run. For a governed boundary around what the agent and its plugins can reach over the network, run Prism under Lens Agents.

plugin.json#

Only $schema and name are required. The smallest valid manifest is:

{
  "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
  "name": "my-plugin"
}

name must be 1–64 characters of lowercase letters, digits, - or ., start and end alphanumeric, and contain no -- or ... It is display metadata, not the plugin's id — the folder name is. Keep the two the same to avoid confusion; a mismatch is reported as a diagnostic rather than treated as an error.

The optional fields are version, description, author, homepage, repository, license, keywords, and extensions. Anything else is reported in the plugin's diagnostics and ignored, so a plugin carrying another agent's settings still loads here.

Skills from a plugin#

Put each skill in its own folder under skills/, in the usual agentskills.io layout. Only immediate children are scanned, and each needs a SKILL.md — nesting skills deeper does not work.

Plugin skills behave like any other skill: the agent sees each one's name and description, and loads the full instructions when a task matches. They are listed by /skills and labelled (plugin: <id>).

Plugin skills rank last in the catalog. If a plugin ships a skill whose name you already use — in the workspace or in your own skills directory — yours wins and the plugin's is skipped. A plugin can add a capability but never shadows one you installed yourself.

MCP servers from a plugin#

mcp.json declares the tool servers to launch:

{
  "$schema": "https://agent-plugins.org/schemas/1.0.0/mcp.schema.json",
  "mcpServers": {
    "probe": {
      "type": "stdio",
      "command": "node",
      "args": ["${PLUGIN_ROOT}/server.js"],
      "env": { "MODE": "live" },
      "cwd": "${PLUGIN_DATA}"
    },
    "api": {
      "type": "streamable-http",
      "url": "https://example.com/mcp"
    }
  }
}

Three transports are supported: stdio (a local subprocess), streamable-http, and the legacy sse.

$schema is optional here. Most mcp.json files — the ones written for other agents — omit it, and those load unchanged: the file is read as Agent Plugins 1.0.0 and a note appears in /plugins. When it is present it must name a version this runtime implements, or the file is refused.

Two variables expand in args, in env values, and in cwd:

  • ${PLUGIN_ROOT} — the plugin's own folder.
  • ${PLUGIN_DATA} — its persistent data folder, created before the server starts.

Each rule below drops only the offending server, not the whole file — which is why a paste from another agent's config can come up one tool server short:

  • command takes one token — a bare name found on PATH, or a ./ path inside the plugin. Put flags in args: "command": "npx", "args": ["-y", "server"], not "command": "npx -y server". Neither variable is substituted in command.
  • The remote transport is streamable-http, the spec's name for it. "type": "http" is rejected. Omitting type altogether is tolerated: the entry is read as stdio and noted in diagnostics.
  • cwd defaults to the plugin folder and must stay inside ${PLUGIN_ROOT} or ${PLUGIN_DATA}.
  • env must not define PLUGIN_ROOT or PLUGIN_DATA — both names are reserved for the expansions above.
  • A remote url must be https, unless it points at loopback.
  • Do not put secrets in env or headers. A plugin folder is shared as-is, and the standard treats both as public package data.

Tool names#

A plugin's tools are named <pluginId>__<serverName>__<toolName>, so two plugins can expose a tool of the same name without clashing, and a plugin can never take over a built-in tool's name. Names are capped at 64 characters — Bedrock's Converse API limit — and anything longer is truncated with a stable suffix, so a long id plus a long tool name still resolves to one predictable name.

The /plugins command#

Both the terminal UI and the web UI expose a /plugins slash command (type / in the chat input). It takes no arguments: it lists each installed plugin with its version and description, the skills and MCP servers it contributes, and any problems found while loading it. GET /agents/plugins returns the same information as an array, with each plugin's load problems in its diagnostics field.

When a plugin is broken#

A bad plugin is skipped, never fatal — the agent keeps working, and the failure is always as narrow as possible:

Problem Effect
plugin.json malformed, or name breaks the rules The plugin is skipped entirely, and does not appear in /plugins — the reason is in the runtime log only.
Targets a spec version this runtime does not implement The plugin is skipped; the log names the version it asked for.
Unknown fields in plugin.json Reported in diagnostics and ignored; the plugin loads.
mcp.json malformed No MCP servers load — but the plugin's skills still do.
One server entry invalid That server is skipped; the others still start.
A server is slow to start (a cold npx fetch, say) Retried later; the rest of the plugin is unaffected.
A SKILL.md missing its name or description That skill is skipped; its siblings still load.

What is not supported#

The standard defines skills and MCP servers, and nothing else. Plugins carrying commands, hooks, or subagents for another agent are still valid here — those parts are ignored rather than rejected, along with any reverse-domain extension folders such as com.example.client/. There is also no plugin registry or marketplace: the standard does not define one, so installation stays a matter of putting a folder in place.