plugins/ to give your managed ADK or LangGraph agent reusable skills, MCP servers, or both. Harnest reads its declarations and connects them to the framework’s native runtime. You do not import the plugin or register its components in Python. Advanced-mode applications retain their native composition and must wire equivalent capabilities themselves.
Need Python APIs, SDK dependencies, typed context, or lifecycle behavior? Build a Harnest Extension in
extensions/. Application hooks and resource factories belong in lifecycle/.Add a plugin
From the agent folder, install a reviewed local package into the project:plugins/<manifest-name> through same-filesystem staging. It
rejects links, special files, and an existing destination. Pass --force only
when you intend to replace that complete installed package; a failed final swap
restores the previous package.
The installer currently accepts local directories. It does not invent a
registry or download protocol that the Agent Plugins specification does not
define. harnest extensions search remains the separate discovery command for
executable Harnest Extensions.
Place each package in its own directory. Keep the package’s root plugin.json intact:
plugins/warehouse/plugin.json
$schema shown above and a name. That name identifies the plugin, even when its enclosing directory has a different name. Both component locations are optional: a skills-only, MCP-only, or manifest-only package is valid.
Plugin skills join the agent’s skill registry and load on demand through list_skills, load_skill, and load_skill_resource. Plugin MCP servers join direct connections from mcp/. Use a skill to explain when to call its tools, which inputs they need, and how to interpret their output.
Rebuild after adding a package, or use development reload while serving locally.
Attach a plugin after compilation
Agent Desktop can attach Agent Plugins when it creates a session. The desktop client owns discovery and download: it resolves the user-provided Git or marketplace URL, creates a ZIP withplugin.json at its root, and sends that immutable snapshot to Harnest. Harnest does not fetch a plugin URL.
POST /sessions
sha256 is optional. When supplied, it must match the decoded ZIP. Harnest always computes its own digest and returns each plugin’s name and sha256 in the session metadata.plugins array. The archive itself stays in private session application data so a durable session can recover its exact environment after a server restart.
The plugin set is fixed when the session is created. Create another session to add, remove, or update a plugin. Dynamic attachment currently requires a managed root Agent; managed Graph and advanced applications retain their compiled capability wiring.
Harnest accepts at most 16 plugins per session and regular files only. It rejects encrypted members, links, absolute or parent paths, case-insensitive path collisions, more than 256 files, files larger than 4 MiB, archives larger than 8 MiB, and expanded content larger than 32 MiB. The server’s configured
limits.max_request_bytes also applies to the base64 JSON request and may impose a lower effective limit.
Configure MCP servers
Portable MCP declarations live in rootmcp.json, not Python factories. Each server declares its transport explicitly:
plugins/warehouse/mcp.json
Harnest opens connections at runtime through the ADK or LangGraph adapter. Compilation reads configuration without starting an MCP server.
Local processes and persistent data
For a package that includesserver.py, a stdio declaration can use:
plugins/warehouse/mcp.json
mcp.json into a dependency installer. command is one executable name, such as python, or a bundled executable path beginning with ./; it is not a shell command string.
Harnest supplies both variables to each stdio subprocess. Persistent data lives below
$XDG_DATA_HOME/harnest/agent-plugins, or ~/.local/share/harnest/agent-plugins when XDG_DATA_HOME is unset. Set HARNEST_PLUGIN_DATA_DIR to override that base directory. Harnest separates data by installation and plugin; package updates do not erase it.
Only ${PLUGIN_ROOT} and ${PLUGIN_DATA} expand, and only in stdio args, env values, and cwd. Other placeholders stay literal. Do not override the reserved variables in env. An omitted cwd uses the package directory. An explicit cwd must start with ./, ${PLUGIN_ROOT}, or ${PLUGIN_DATA} and remain inside the corresponding directory after resolution.
Remote connections and credentials
Remote URLs require HTTPS except for loopback hosts. URL and header values are literal:${TOKEN} does not read an environment variable. Do not embed secrets in plugin headers or stdio environment declarations.
Harnest-owned MCP HTTP clients inherit the process’s standard uppercase and
lowercase HTTP(S) and ALL_PROXY variables. Released installs include SOCKS
transport support, including socks5h:// proxy URLs. This preserves
operator-managed enterprise egress. Remove the relevant proxy variables from
the Harnest process when a connection must bypass environment proxy discovery;
proxy URLs and credentials are omitted from client-construction diagnostics.
Authentication is client-managed; Agent Plugins 1.0 does not define portable credential references or OAuth configuration. When your application needs custom credential resolution, configure a direct MCP client with Harnest’s credential providers.
Validation and diagnostics
Harnest validates the manifest before discovering components. An invalid manifest rejects that plugin. Invalid skill entries or MCP server entries are skipped with diagnostics while valid siblings continue loading. An invalidmcp.json disables that plugin’s MCP component without disabling its skills.
Unknown client namespaces in the manifest’s extensions field and matching client-specific directories are ignored. They do not become Harnest Extensions or lifecycle hooks. Harnest does not import arbitrary Python modules from a standard plugin.
Author Agent Skills
Write focused instructions and load supporting resources on demand.
Build a Harnest Extension
Package Python functionality, lifecycle behavior, and typed context.