Appearance
Plugins
A plugin adds MCP tools to the Kadmo runtime without changing the runtime itself. Each plugin is a folder under ~/.kadmo/plugins/ with a plugin.json manifest at its root. The runtime reads that folder when it loads, and the plugin's tools appear in MCP tools/list next to the core tools, for every client of that runtime: a local client using kadmo mcp over stdio, or a remote one using HTTP /mcp (see MCP).
Kadmo agents get their plugins from Kadmo when the agent is set up. Nothing needs to be installed by hand on them. On your own computer, you install plugins from a local folder with kadmo plugin install.
To write one, see Creating a plugin.
Plugins and skill packs
| Plugins | Skill packs | |
|---|---|---|
| What they add | New MCP tools, backed by a program you write | Domain knowledge and workflows |
| Format | plugin.json plus a handler program in any language | Markdown and YAML |
| Installed to | ~/.kadmo/plugins/<name>/ | ~/.kadmo/skills/ |
| Managed with | kadmo plugin list / install / remove | kadmo install / uninstall / registry |
| Good for | Abilities the agent does not have, such as a local command or an API call | Teaching an agent how a specific web app works |
The two work together. A skill pack tells an agent what to do on a site; a plugin gives it a tool it could not use before. See Skill packs.
Claude Code plugins, which the Kadmo app can install on an agent, are a different system. They are not read from ~/.kadmo/plugins/ and are not covered here.
Two runtimes
The manifest's runtime field decides how the runtime hosts the plugin.
process (default) | service | |
|---|---|---|
| How it runs | A new handler process for every tool call | One long-running child process, kept alive by the runtime |
| Protocol | Arguments as JSON on stdin, result as JSON on stdout | The child is an MCP server over stdio |
| State between calls | None | Kept in the child's memory until it exits |
| Where tools come from | The tools array in plugin.json | The child's own tools/list, read when it starts |
| Public tool name | Exactly the declared name | <namespace>_<tool>; namespace defaults to the plugin name |
| Timeout | 30 seconds, fixed | 120 seconds by default; set per service and per tool |
| Calls in parallel | Each call is its own process | Calls to one service run one at a time |
exec is accepted as another spelling of process. Any other value makes the runtime skip the plugin.
What happens on a tool call
| Step | process plugin | service plugin |
|---|---|---|
| 1 | The client calls a tool, for example echo_input | The client calls a namespaced tool, for example counter_increment |
| 2 | Core tools are checked first, then process plugin tools in folder order | Nothing else matched, so the call goes to the service that lists this name |
| 3 | The handler command is started in the plugin folder | The call is queued behind any call already running on that service |
| 4 | The call's arguments object is written to stdin as JSON | The call is forwarded to the child with the original (un-namespaced) tool name |
| 5 | The runtime waits for the handler to exit, then parses stdout | The child's MCP result is returned as it is |
If no core tool, plugin tool or service tool matches, the call fails with Tool not found: <name>.
How plugin tools look in tools/list
Every plugin tool's description gets a [plugin: <name>] prefix, so a model can tell where it came from. The input schema is passed through unchanged.
json
{
"name": "echo_input",
"description": "[plugin: echo-tools] Return the JSON arguments the handler received",
"inputSchema": {
"type": "object",
"properties": { "text": { "type": "string" } },
"required": ["text"]
}
}Order in the list: the core tools first, then process plugin tools, then service plugin tools. A service tool whose namespaced name is already taken is left out with a warning in the log; the rest of that service's tools stay. Your MCP client may add its own prefix (the server name you gave it) when it shows tools to the model.
Managing plugins
| Command | What it does |
|---|---|
kadmo plugin list | Lists the plugins in ~/.kadmo/plugins/ that pass validation, with their tools |
kadmo plugin install <source> | Checks <source>/plugin.json, then copies the folder to ~/.kadmo/plugins/<name>/ |
kadmo plugin remove <name> | Deletes ~/.kadmo/plugins/<name>/ |
Full syntax is in the CLI reference.
bash
kadmo plugin install ./echo-tools
kadmo plugin listtext
Kadmo
✓ Installed plugin: echo-tools
Tools: echo_input, fail_always
Installed Plugins
echo-tools v0.1.0
Echo input back for testing
Tools (2): echo_input, fail_always
Plugins dir: /home/you/.kadmo/pluginsWhat install does, exactly:
<source>must be a local folder. There is no download from a URL or registry.- The target folder name is the manifest's
name, not the source folder's name.removetakes that same name. - If a plugin with that name is already installed, its folder is deleted first and replaced. Files the old copy wrote into its own folder are lost.
- Everything is copied except
.gitand a top-levelnode_modulesfolder. Install your dependencies in the copied folder afterwards if the handler needs them. - The manifest is validated, but tool-name clashes with core tools are not checked at install time. Such a plugin installs, then is skipped when the runtime loads it.
For a service plugin, install and list show no tools (Tools (0):), because its tools are only known once the child is running. The /health endpoint of kadmo serve shows the live tool names (the /health of a client's kadmo mcp has no plugins field):
bash
curl -s http://127.0.0.1:9876/health | jq '.plugins'When changes take effect
The runtime reads ~/.kadmo/plugins/ when it starts and again whenever it reloads its content. Reloads happen on:
| Trigger | Example |
|---|---|
| Runtime start | kadmo serve, or an MCP client starting kadmo mcp |
MCP tools run_workflow and list_workflows | An agent lists or runs a workflow |
| Dashboard and API changes | Opening the workflow list in the dashboard, or saving or installing workflows and packs through it |
There is no file watcher, and the runtime does not tell connected MCP clients that the tool list changed. Most clients read tools/list once when they connect. After installing or removing a plugin, restart kadmo serve, or restart the MCP client session so it starts a fresh kadmo mcp.
On a reload, a service plugin whose plugin.json is unchanged keeps its running child. A removed one is stopped; one whose service block changed is restarted. Changing only the child's code does not restart it; restart the runtime for that.
kadmo serve and kadmo mcp are separate processes. If both run, each loads the plugins and each starts its own copy of every service plugin.
Loading rules
| Situation | Result |
|---|---|
A folder without plugin.json | Skipped, with a warning. Hidden folders are scanned too, so they warn as well |
A symbolic link in ~/.kadmo/plugins/ | Ignored, without a warning. Install a real copy |
plugin.json is not valid JSON, or name, version or description is missing or not a string | Plugin skipped |
runtime: "process" with no tools array, or no valid tool in it | Plugin skipped |
A tool missing name, description, inputSchema or handler, or an inputSchema without a string type | That tool skipped; the others load |
A process tool named like a core tool (for example navigate) | The whole plugin skipped |
Two process plugins declare the same tool name | Both are listed; calls always go to the plugin whose folder sorts first |
runtime: "service" without service.command | Plugin skipped |
Warnings go to the runtime's log (stderr). kadmo plugin list prints the same warnings, which makes it a quick check before you restart anything.
Known issues in this release
kadmo plugin remove <name>does not check the name. It deletes~/.kadmo/plugins/<name>with the name taken as a path, sokadmo plugin remove ..deletes all of~/.kadmo(settings, packs, workflows and plugins),kadmo plugin remove ../skillsdeletes every installed skill pack, andkadmo plugin remove ""deletes every plugin. Each reports success. Only pass a name thatkadmo plugin listshows.kadmo plugin installuses the manifest'snameas a path in the same way. Only install plugins whoseplugin.jsonyou have read; anamesuch as../workflowsreplaces that folder.- Running
kadmo plugin installon a folder that is already inside~/.kadmo/plugins/empties that plugin and still reports success. Install from a copy outside the plugins folder.
Next steps
- Creating a plugin: the manifest, the handler protocol, and service plugins
- CLI reference:
kadmo plugincommands - MCP tools: the core tools plugins sit next to