Skip to content
Docs

The Complete Guide to Agent Plugins

Package Agent Skills and MCP servers into portable plugins that work across compatible AI agent clients with the Agent Plugins specification.

Ben SabicContent Engineer

AI agent clients each developed their own plugin formats, even when plugins contain the same underlying components. Authors rearrange or duplicate skills and MCP server configuration for every client, so a plugin packaged for one tool often needs adaptation before another can use it.

Agent Plugins solves this with an open, vendor-neutral specification for portable plugins. Version 1.0 defines a shared format for Agent Skills and MCP servers that any compatible client can discover and load consistently.

Copy link to headingOverview

In this guide, you'll learn:

  • What Agent Plugins is and the problem it solves
  • The structure of a plugin package and its manifest
  • How skills and MCP servers work as portable components
  • How client extensions add client-specific behavior without breaking portability
  • How clients load plugins and isolate failures
  • How to build your first plugin

Copy link to headingWhat is Agent Plugins?

Agent Plugins is a specification that defines a small interoperability floor for the parts of a plugin that can be portable across clients. An Agent Plugin is a self-contained directory with a required manifest (plugin.json) and optional components in fixed locations. Version 1.0 defines exactly two portable component types, both built on established specifications:

Component typeFixed locationGoverned by
Skillsskills/Agent Skills specification
MCP serversmcp.jsonModel Context Protocol specification

Agent Plugins doesn't redefine either format. It defines where components live inside a plugin, how clients discover and validate them, and how failures are isolated so one broken component doesn't take down the rest.

The specification is openly licensed and developed in public. Its initial Technical Steering Committee includes Core Maintainers from Amazon, Cursor, Microsoft, OpenAI, and Vercel, and proposals begin in GitHub Discussions where anyone can participate and help shape the specification.

Copy link to headingWhy a portable format matters

The specification separates portable behavior from client-owned behavior:

  • Portable: package structure, manifest validation, component discovery, MCP configuration, plugin environment variables, and failure isolation.
  • Client-owned: installation sources and marketplaces, enablement and update flows, permission prompts and sandboxing, and how skills are surfaced.

This split lets shared components use one predictable structure while clients keep full control of distribution, trust policy, and user experience. Clients can also adopt component types incrementally, so a skills-only client conforms without supporting MCP servers, as long as it supports at least one of the two.

Copy link to headingAnatomy of a plugin

A plugin is a directory rooted at a single filesystem location. A complete plugin with skills, an MCP server, and a client extension looks like this:

my-plugin/
├── plugin.json
├── skills/
│ └── summarize/
│ ├── SKILL.md
│ ├── scripts/
│ └── references/
├── mcp.json
└── com.example.client/
└── hooks/

Each part has a fixed role:

  • plugin.json identifies the plugin and the Agent Plugins version it targets. It's the only required file.
  • skills/ contains Agent Skills, one per immediate child directory.
  • mcp.json configures stdio, Streamable HTTP, or legacy HTTP+SSE MCP servers.
  • Reverse-domain directories like com.example.client/ hold client-specific files that other clients can safely ignore.

One rule governs the whole package: every file a client discovers, reads, or executes must resolve within the plugin root, even after resolving symlinks and equivalent filesystem mechanisms. Plugin-relative paths in configuration begin with ./ and cannot escape the package.

Copy link to headingThe plugin manifest

Every plugin contains exactly one portable manifest at plugin.json.

The minimal manifest sits in the plugin root and needs only two fields:

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

The manifest schema is closed, meaning only these top-level fields are permitted:

FieldRequiredPurpose
$schemaYesSelects the Agent Plugins version and validation contract.
nameYesHuman-readable plugin name and package identifier.
versionNoPlugin version; Semantic Versioning is recommended.
descriptionNoShort description of the plugin.
authorNoObject with optional name, email, and url strings.
homepageNoDocumentation or homepage URL.
repositoryNoSource repository URL.
licenseNoLicense string; an SPDX identifier is recommended.
keywordsNoArray of search and discovery strings.
extensionsNoClient-owned data keyed by reverse-domain namespace.

Copy link to headingName constraints

Plugin names are 1 to 64 characters and follow strict rules so they work as identifiers across different clients:

ConstraintRequirement
Character setLowercase ASCII letters, digits, hyphens, and periods only
Start and endFirst and last characters must be alphanumeric
RepetitionNo consecutive hyphens (--) or periods (..)

For example, my-plugin, acme.tools, and lint3r are valid, while My-Plugin, -start, and has--double are not.

Copy link to headingHow clients handle manifest errors

Only two schema violations are non-fatal: an unknown top-level field and a non-object extensions field. In both cases, the client reports and ignores the problem and continues loading. Any other violation, such as a missing name or an unsupported $schema, is fatal: the client rejects the plugin without discovering or executing any of its components. This closed design enables strict validation and typo detection while keeping client experiments contained under extensions.

Copy link to headingSkills

Agent Plugins uses the Agent Skills specification without redefining it. The plugin format defines only where skills are discovered and how failures are isolated.

Each skill lives in an immediate child directory of skills/:

skills/
└── deploy/
├── SKILL.md
├── scripts/
│ └── rollback.sh
└── references/
└── runbook.md

Discovery follows three rules:

  • An immediate child of skills/ is a discovered skill when it has a SKILL.md
  • Clients do not recursively search deeper descendants for additional skills.
  • If one discovered skill is invalid, the client skips it, reports it when practical, and continues loading other skills and component types.

Skills can contain any additional files they need. Directories like scripts/, references/, and assets/ are common conventions from the Agent Skills specification, not an exhaustive allowlist.

The plugin is still considered valid if the skills/ directory is missing.

Copy link to headingMCP servers

The mcp.json file at the plugin root configures MCP connections in a closed format that clients map to their native configuration.

It contains only $schema and mcpServers at the top level:

mcp.json
{
"$schema": "https://agent-plugins.org/schemas/1.0.0/mcp.schema.json",
"mcpServers": {
"validator": {
"type": "stdio",
"command": "./bin/validator",
"args": ["--data", "${PLUGIN_DATA}/validator"],
"env": {
"CONFIG": "${PLUGIN_ROOT}/config.json"
},
"cwd": "${PLUGIN_ROOT}"
},
"deployment-api": {
"type": "streamable-http",
"url": "https://deploy.example.com/mcp",
"headers": {
"X-Tenant": "public-tenant"
}
}
}
}

Copy link to headingTransports

Each server entry declares its transport with a type field and only the fields allowed for that transport:

TypeRequired fieldsNotes
stdiotype, commandOptional args, env, and cwd. Launches a local subprocess.
streamable-httptype, urlCurrent remote MCP transport; optional literal headers.
ssetype, urlDeprecated HTTP+SSE transport; client support is optional.

An MCP-capable client supports at least one of stdio and streamable-http and should support both. The declared transport is used for the initial connection attempt; Agent Plugins defines no fallback behavior if that attempt fails.

Copy link to headingstdio commands

The command field is one executable token, not a shell command string. It's either a bare executable name resolved by platform search rules or a plugin-relative path beginning with ./. A plugin that bundles its own executable must use a plugin-relative command, since configured PATH behavior is client-defined. When cwd is omitted, the plugin root is the working directory.

Copy link to headingPlugin variables

Clients provide two environment variables to every stdio subprocess:

  • PLUGIN_ROOT: the absolute, filesystem-resolved plugin root. Use it to reference bundled scripts, binaries, and config files.
  • PLUGIN_DATA: a dedicated writable data directory that persists across plugin updates. Use it for installed dependencies, caches, and generated state.

Clients expand ${PLUGIN_ROOT} and ${PLUGIN_DATA} in args, env values, and cwd. Expansion is textual, single-pass, and non-recursive, and it never applies to env keys, command, remote URLs, or headers. A plugin cannot override the two reserved variables; an env entry named PLUGIN_ROOT or PLUGIN_DATA invalidates that server entry.

Copy link to headingRemote connections and security

Remote configuration follows strict safety rules:

  • URLs are absolute HTTP or HTTPS, without user information or fragments. Non-loopback endpoints use HTTPS.
  • Configured headers are literal, visible package data. Plugins must not embed credentials or secrets in headers or env.
  • Clients never forward configured headers to a different origin through redirects without explicit user authorization.
  • Agent Plugins 1.0.0 defines no portable OAuth or credential-reference fields. Authentication remains client-managed, and an authorization failure is a connection failure, not invalid package configuration.

Copy link to headingClient extensions

Client extensions let a client add behavior without expanding the portable core. Reverse-domain identifiers avoid collisions without a central registry. For example, the client that controls example.com could use com.example.client as its namespace in two places:

  • Manifest data: namespace-keyed object under extensions in plugin.json.
  • Extension directory: top-level directory named exactly after the namespace.
plugin.json
{
"$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
"name": "example-plugin",
"extensions": {
"com.example.client": {
"setting": true
}
}
}

Clients can use either representation or both, and the namespace owner defines their contents, validation, and failure behavior. Other clients ignore namespaces they don't implement without validating their contents, so extensions never affect portability or conformance.

Copy link to headingHow clients load plugins

Conformant clients follow a fixed loading sequence:

  1. Establish the filesystem-resolved plugin root.
  2. Locate and validate root plugin.json using the locally supported rules selected by $schema. Clients never retrieve schemas while loading a plugin.
  3. Reject the plugin for fatal manifest violations and report the non-fatal cases.
  4. Discover each supported component type from its fixed location.
  5. Apply the failure boundary defined for each component type or entry.
  6. Apply implemented client-extension namespaces and ignore all others.

Copy link to headingFailure isolation

Failures are scoped to the narrowest relevant boundary, so one broken piece never takes down independently valid components:

FailureScope of impact
Fatal plugin.json violationEntire plugin rejected
Invalid top-level mcp.jsonMCP disabled for the plugin; skills still load
Invalid individual MCP server entryOnly that server skipped
Server fails to start, connect, or authenticateOnly that server affected; loading continues
Invalid individual skillOnly that skill skipped; siblings still load
Fixed location has wrong filesystem kindOnly that component type invalid
Missing fixed locationNot an error; valid absence

Copy link to headingVersioning

One version number identifies the complete specification release, including its normative text and both schemas. This keeps compatibility simple:

  • The $schema value in plugin.json declares the Agent Plugins version the package targets. For 1.0.0, it's https://agent-plugins.org/schemas/1.0.0/plugin.schema.json.
  • When mcp.json is present, its $schema version must match the version declared by plugin.json. A mismatch invalidates only the MCP configuration, not other component types.
  • Published canonical schema identifiers are never reassigned to different contents, and plugins may keep targeting older versions according to each client's compatibility policy.

For the plugin's own version field, Semantic Versioning is recommended: major for breaking changes, minor for backward-compatible features, and patch for fixes. Clients may use it for update checks and cache freshness.

Copy link to headingBuild your first plugin

Only two files are needed for a minimal working plugin.

Copy link to heading1. Create the directory structure

hello-plugin/
├── plugin.json
└── skills/
└── greet/
└── SKILL.md

Copy link to heading2. Create the manifest

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

Copy link to heading3. Create the skill

SKILL.md
---
name: greet
description: Greet the user and offer help.
---
Greet the user and offer help.

Skills-capable clients load the plugin.json, discover the immediate children of skills/, and validate each SKILL.md against the Agent Skills specification.

To add MCP servers, place mcp.json at the plugin root using the same Agent Plugins schema version. For a copyable package with a complete manifest and a real skill, see the Agent Plugins example repository.

You can validate your files against the canonical JSON Schemas:

The specification text is authoritative if it conflicts with a machine-readable schema.

Copy link to headingNext steps