Expand description
An implementation of the Agent Plugins specification v1.0.0 — the open, vendor-neutral format for packaging Agent Skills and MCP servers into distributable plugins.
§Design
The crate is built around three ideas, each expressed in its types:
Parse, don’t validate. Constraint-carrying values get their own types:
a PluginName proves §5.5, a RelativePath proves ./-rooted
containment, an McpUrl proves the §7.2.1 URL rules, a Cwd can only
be one of the three permitted working-directory forms. If you hold the
value, the check already happened.
Failure boundaries as return types. The spec is precise about how far
a failure spreads: a bad manifest rejects the plugin (Rejection), a
bad mcp.json disables one component (McpOutcome::Disabled), a bad
skill or server entry skips only itself (a Diagnostic). Nothing fails
silently and nothing fails wider than the spec allows.
Sans-IO. The Loading state machine speaks the specification and
never touches a filesystem. It asks Questions; you answer from
wherever the plugin lives. Batteries are included for the common cases —
load_dir for real directories, MemSource for tests and archives,
the Source trait for anything else synchronous — and the machine
itself for async or exotic IO.
§Loading from a directory
use agent_plugins::McpOutcome;
let plugin = agent_plugins::load_dir("path/to/my-plugin")?;
println!("{} v{}", plugin.manifest.name,
plugin.manifest.version.as_deref().unwrap_or("unversioned"));
for skill in &plugin.skills {
println!("skill {}: {}", skill.meta.name, skill.meta.description);
}
if let McpOutcome::Configured(mcp) = &plugin.mcp {
println!("{} MCP server(s)", mcp.servers.len());
}
for diagnostic in &plugin.diagnostics {
eprintln!("note: {diagnostic}");
}§Loading from anywhere: drive the machine yourself
The loader asks four kinds of questions. Answer them from an archive, a database, an HTTP range request, an async runtime — the machine cannot tell the difference:
use agent_plugins::{Answer, Loading, Question};
let mut loading = Loading::start();
while let Some(question) = loading.question() {
let answer = match &question {
Question::Kind(path) => stat(path).await,
Question::Confined(_) => Answer::Confined(true), // archives have no symlinks
Question::Read(path) => fetch(path).await,
Question::List(path) => index(path).await,
};
loading.answer(answer)?;
}
let plugin = loading.finish()?;§Launching a stdio MCP server
Turn validated configuration into a runnable process with the §9.1 environment contract already sequenced:
use agent_plugins::{Anchors, McpOutcome, McpServer};
let anchors = Anchors::new("/plugins/my-plugin", "/plugins/data/my-plugin");
if let McpOutcome::Configured(mcp) = &plugin.mcp {
for entry in &mcp.servers {
if let McpServer::Stdio(server) = &entry.server {
std::fs::create_dir_all(&anchors.plugin_data).ok(); // §9.1
let mut child = server.launch_plan(&anchors).to_command().spawn()?;
}
}
}§Skill bodies are documents, not strings
A skill’s instructions arrive as a Document: a preamble plus a tree of
Sections. Skills load progressively, and this lets a client hand a
model one section rather than the whole file — and follow the
LinkTarget::InPackage links to the references/ and scripts/ files
the body points at.
let skill = Document::parse(
"# Deploy\n\nShip it.\n\n## Rollback\n\nSee [the runbook](references/runbook.md).\n",
);
for (depth, section) in skill.outline() {
println!("{:indent$}{}", "", section.heading(), indent = depth * 2);
}
let rollback = skill.section(["Deploy", "Rollback"]).unwrap();
assert_eq!(rollback.slug(), "rollback");
assert_eq!(
rollback.links()[0].target,
LinkTarget::InPackage("references/runbook.md".into()),
);§Conformance
This crate implements the full client-side checklist of the specification (Appendix A): manifest validation with the exact §5.2 fatal/non-fatal split, fixed-location component discovery, per-boundary failure isolation, §7.2.1 transport validation, and §9 placeholder expansion. The test suite runs a fixture corpus shared with the sibling TypeScript implementation.
Structs§
- Anchors
- The two path anchors a client provides to a plugin subprocess (§9.1).
- Answer
Mismatch - The reply did not match the pending question — a driver bug, not a plugin problem.
- Author
- Author metadata: a closed object of three optional strings (§5.4).
- Diagnostic
- One reported, non-fatal loading decision.
- DirEntry
- One entry from a directory listing.
- DirSource
- A plugin package rooted at a real directory.
- Document
- A parsed Markdown document: a preamble and a tree of sections.
- Extensions
- Client extension data from the manifest
extensionsfield (§8.1). - Heading
Level - A heading depth: 1–6, as Markdown defines and no more.
- Launch
Plan - Everything needed to launch one stdio MCP server.
- Link
- An inline Markdown link,
[text](target). - Loaded
Plugin - A fully loaded plugin: the §11.1 conformance outcome.
- Loading
- The Agent Plugins loading conversation.
- Manifest
- A validated plugin manifest.
- McpConfig
- A validated
mcp.json: the servers that survived per-entry validation, in declaration order. - McpUrl
- An MCP endpoint URL that satisfied §7.2.1: absolute
http/https, no user information, no fragment, andhttponly toward loopback. - MemSource
- A plugin package held entirely in memory.
- Package
Path - A
/-separated path to a file or directory inside a plugin package, relative to the plugin root. - Plugin
Name - A validated plugin name (§5.5): 1–64 characters of
a-z,0-9,-,.; alphanumeric at both ends; no--or..runs. - Relative
Path - A configured plugin-relative path: begins with
./and, resolved purely lexically, never leaves the plugin root (§4.1). - Remote
Server - A remote server: Streamable HTTP or legacy SSE (§7.2.1).
- Section
- One heading and everything beneath it.
- Server
Entry - One named server from
mcpServers. - Skill
- One valid skill discovered under
skills/. - Skill
Meta - Validated
SKILL.mdfrontmatter per the Agent Skills specification. - Slug
- A URL-safe identifier derived from heading text, unique within a document.
- Stdio
Server - A stdio server: how to launch the subprocess (§7.2.1).
- Template
- A configured string from
args,env, orcwd, parsed for expansion.
Enums§
- Answer
- The caller’s reply to the pending
Question. - Command
- The
commandfield: one executable token, never a shell string, never expanded (§7.2.1). - Cwd
- The working directory of a stdio server, in the three permitted forms of
§7.2.1 — plus the default. Any other shape never becomes a
Cwd. - File
Kind - What kind of entry a package path resolves to.
- Invalid
Name - Exactly which §5.5 constraint a candidate name broke.
- Link
Target - Where a link points, once classified.
- Manifest
Rejection - A fatal manifest problem: the plugin MUST be rejected and none of its components discovered or executed (§5.2, §5.3).
- McpDisabled
Reason - Why MCP was disabled for the whole plugin (§7.2.2 rule 2, §6.2).
- McpOutcome
- What became of the MCP component type (§6.2, §7.2.2).
- McpServer
- The closed union of §7.2.1 server variants, discriminated by
type. - Origin
- Where in the package a diagnostic points.
- Placeholder
- The two placeholders §9.2 defines — and the only two it permits.
- Program
- The resolved program to execute.
- Question
- A question the loader needs answered before it can continue.
- Rejection
- The plugin was rejected outright — nothing may be discovered or executed (§5.2, §5.3, §4.1 rule 1).
- Relative
Path Error - Why a string was refused as a plugin-relative path.
- Rule
- The closed set of non-fatal report conditions defined by the specification.
- Segment
- One parsed piece of a configured string.
- Server
Invalid - Why one server entry was skipped (§7.2.2 rule 3).
- Skill
Invalid - Why a discovered skill was skipped (§7.1).
- Spec
Version - The Agent Plugins specification versions this crate recognizes.
- Transport
- The three declared transports.
- UrlInvalid
- Why a URL failed §7.2.1.
Constants§
- MCP_
SCHEMA_ 1_ 0_ 0 - The canonical
$schemaidentifier for Agent Plugins 1.0.0 MCP configuration (§7.2.1). - PLUGIN_
SCHEMA_ 1_ 0_ 0 - The canonical
$schemaidentifier for Agent Plugins 1.0.0 manifests (§5.2).
Traits§
- Source
- A synchronous supplier of plugin package bytes.
Functions§
- load
- Load a plugin by running the full loading conversation against a source.
- load_
dir - Load the plugin rooted at
pathfrom the filesystem. - parse_
skill_ md - Parse and validate the contents of a
SKILL.mdfound atskills/<directory>/SKILL.md.