Spec Version: 1.0.0
This document defines the canonical Agent Plugin Specification v1.0.0 for packaging agent extensions into distributable plugins.
The smallest useful plugin is a directory with one skill.
hello-plugin/
├── plugin.json
└── skills/
└── greet/
└── SKILL.md
./plugin.json
{
"$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
"name": "hello-plugin"
}./skills/greet/SKILL.md
---
name: greet
description: Greet the user and offer help.
---
Greet the user and offer help.A host that supports skills can load this plugin by reading plugin.json and discovering skills/greet/SKILL.md. How the host exposes the skill to users or models is outside this specification.
Note: Agent Plugin v1 standardizes two component types: Agent Skills and MCP servers. Other capabilities are outside the portable v1 format.
- Status and version
- Conformance language
- Terminology
- Plugin package model
- Manifest
- Component discovery
- Component definitions
- Client extensions
- Environment variables and placeholder expansion
- Versioning
- Host conformance
Non-normative material
This specification defines version 1.0.0 of the Agent Plugin format.
Plugin hosts and plugin packages claiming conformance to Agent Plugin v1 MUST implement or follow the requirements in this document.
Governance for the Agent Plugins project is defined separately from the portable package format in the Technical Charter.
In the normative sections of this document, the key words MUST, MUST NOT, REQUIRED, SHOULD, SHOULD NOT, RECOMMENDED, MAY, and OPTIONAL are to be interpreted as described in RFC 2119 and RFC 8174 when, and only when, they appear in all capitals.
The Quick Start, Appendix A, Design Decisions, and Future Considerations sections are non-normative. All other sections are normative.
| Term | Meaning | Description |
|---|---|---|
| Plugin | Package unit | A self-contained directory with a manifest and optional components. |
| Plugin root | Filesystem root | The top-level directory of a plugin package. |
| Manifest | Metadata document | A plugin.json file at the plugin root. |
| Component | Plugin-provided capability | A skill or MCP server configuration. |
| Host | Plugin runtime | A tool that discovers, installs, loads, and executes plugin components. |
| Extension namespace | Client-owned identifier | A reverse-domain identifier used for client-specific manifest data, a client-specific top-level directory, or both. |
| Extension directory | Client-owned file root | A top-level directory whose name is exactly an extension namespace and whose contents are defined by that namespace's owning client. |
- A plugin is a directory rooted at a single filesystem location.
- A plugin MUST include a manifest at
plugin.jsonin the plugin root. - When a host discovers, reads, or executes a file or directory supplied by the plugin package, the filesystem-resolved path MUST remain within the filesystem-resolved plugin root. Symlinks, junctions, reparse points, and equivalent filesystem mechanisms MAY resolve to targets within the plugin root, but hosts MUST reject package paths that resolve outside it.
- A configuration field defined by this specification as a plugin-relative path MUST begin with
./, be resolved against the plugin root, and remain within the filesystem-resolved plugin root after resolution. - Configuration values not defined as paths, including command arguments and environment variable values, are opaque strings. Hosts MUST NOT interpret them as package paths for the purpose of enforcing this section.
Example: valid and invalid relative paths
{
"$schema": "https://agent-plugins.org/schemas/1.0.0/mcp.schema.json",
"mcpServers": {
"server": {
"type": "stdio",
"command": "./bin/server",
"cwd": "./data"
}
}
}{
"$schema": "https://agent-plugins.org/schemas/1.0.0/mcp.schema.json",
"mcpServers": {
"server": {
"type": "stdio",
"command": "../bin/server",
"cwd": "data"
}
}
}The first example is valid — both paths start with ./ and stay within the plugin root. The second is invalid — ../bin/server escapes the plugin root and data is not a plugin-relative path.
These containment rules govern access to files supplied by the plugin package. They do not sandbox a plugin subprocess or restrict paths supplied at runtime. §7.2.1 separately defines containment for a configured working directory rooted in the host-managed PLUGIN_DATA directory.
When a path fails a containment requirement, the host MUST apply the narrowest applicable failure boundary:
- If
plugin.jsondoes not resolve within the plugin root, the host MUST reject the plugin. - If a fixed component location does not resolve within the plugin root, the host MUST treat that component type as invalid under §6.2.
- If a discovered
SKILL.mddoes not resolve within the plugin root, the host MUST skip that skill under §7.1. - If an MCP server
commandorcwdfails containment, the host MUST treat that server entry as invalid under §7.2.2. - For any other package path that resolves outside the plugin root, the host MUST deny access to that path.
A plugin that uses both portable component types and a client extension can have the following layout:
my-plugin/
├── plugin.json
├── skills/
│ └── summarize/
│ ├── SKILL.md
│ ├── scripts/
│ │ └── analyze.sh
│ └── references/
│ └── checklist.md
├── mcp.json
├── com.example.client/
│ └── hooks/
├── LICENSE
└── CHANGELOG.md
See also: §5 Manifest for manifest rules, §6 Component discovery for fixed component locations and missing-location behavior, and §8 Client extensions for client extension conventions.
Hosts MUST check for a manifest at plugin.json in the plugin root.
The Agent Plugin core specification defines exactly one portable manifest per plugin. No other file can replace, supplement, or override the core fields in root plugin.json.
A host loads and validates root plugin.json before discovering components or applying client-specific behavior.
See also: §11 Host conformance for requirements around supporting
plugin.json.
The manifest MUST be JSON and MUST contain a top-level object. Its schema is closed: the only permitted top-level fields are $schema, name, version, description, author, homepage, repository, license, keywords, and extensions.
If plugin.json contains any other top-level field, it does not conform to the schema. Hosts MUST report and ignore each unknown field and MUST continue loading the plugin if the manifest otherwise satisfies this section. Hosts MUST NOT assign semantics to unknown fields. Client-specific manifest data belongs under extensions as defined in §8.
A non-object extensions field is handled as defined in §8.1. Every permitted field otherwise MUST match the type and constraints defined below. Any schema violation other than an unknown top-level field or a non-object extensions field is fatal: the host MUST reject the plugin and MUST NOT discover or execute any of its components.
The official machine-readable schema is schemas/1.0.0/plugin.schema.json. The specification text is authoritative if it conflicts with the schema.
The required $schema field identifies the Agent Plugin specification version targeted by the plugin and its corresponding manifest schema. For Agent Plugin 1.0.0, its value MUST be the canonical identifier https://agent-plugins.org/schemas/1.0.0/plugin.schema.json.
Hosts MUST use a recognized $schema value to select locally supported manifest validation and interpretation rules. A host MAY map multiple canonical identifiers to the same implementation only when it explicitly recognizes those Agent Plugin versions as compatible. Hosts MUST NOT retrieve a schema while loading a plugin. If a host does not support the declared Agent Plugin version or an explicitly recognized compatible version, it MUST reject the plugin and SHOULD report the unsupported version.
Example: minimal manifest
{
"$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
"name": "minimal-plugin"
}Example: full manifest
{
"$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
"name": "plugin-name",
"version": "1.2.0",
"description": "Brief plugin description",
"author": {
"name": "Author Name",
"email": "author@example.com",
"url": "https://example.com"
},
"homepage": "https://docs.example.com/plugin",
"repository": "https://github.com/example/plugin",
"license": "MIT",
"keywords": ["keyword1", "keyword2"],
"extensions": {
"com.example.client": {
"setting": true
}
}
}| Field | Type | Description |
|---|---|---|
$schema |
string | Canonical plugin manifest schema identifier defined in §5.2. |
name |
string | Human-readable plugin name. |
If a required field is missing, has the wrong type, is empty, or otherwise violates its requirements, the manifest is invalid. Hosts MUST reject the plugin and MUST NOT discover or execute any of its components. Hosts SHOULD report which required field is invalid.
| Field | Type | Description |
|---|---|---|
version |
string | Version string (Semantic Versioning RECOMMENDED). Used for update checks and cache freshness. |
description |
string | Short description of plugin purpose. |
author |
object | Author object with optional name, email, and url string fields. |
homepage |
string | Documentation or homepage URL. |
repository |
string | Source repository URL. |
license |
string | License identifier (SPDX identifier RECOMMENDED). |
keywords |
string[] | Search and discovery tags. |
The author object MAY contain only the name, email, and url fields, each with a string value. Any other field or value type makes the manifest invalid.
Except where this specification states an explicit constraint, metadata fields are validated only by their JSON types. Hosts MUST NOT reject a manifest solely because version is not valid Semantic Versioning; homepage, repository, or author.url is not a recognized URL; author.email is not a recognized email address; or license is not an SPDX identifier.
The manifest name value MUST satisfy all of the following:
| Constraint | Requirement | Description |
|---|---|---|
| Length | 1-64 characters | The name MUST be between 1 and 64 characters inclusive. |
| Character set | a-z, 0-9, -, . |
Lowercase alphanumeric characters, hyphens, and periods only. |
| Start and end | Alphanumeric | The first and last characters MUST be alphanumeric. |
| Repetition | No -- or .. |
Consecutive hyphens and consecutive periods are not allowed. |
Periods are allowed in plugin names.
Valid names: my-plugin, acme.tools, lint3r, a
Invalid names: My-Plugin (uppercase), -start (leading hyphen), has--double (consecutive hyphens), too.many..dots (consecutive periods), `` (empty)
The optional extensions field contains client-specific manifest data keyed by extension namespace. See §8 for processing rules.
See also: §4 Plugin package model for directory layout conventions.
Hosts MUST discover each supported component type from its fixed location. plugin.json cannot override these locations or contain inline component configuration.
Core component locations:
| Component | Fixed location | Pattern |
|---|---|---|
| Skills | skills/ |
Subdirectories containing SKILL.md |
| MCP servers | mcp.json |
JSON configuration |
Example: given a plugin reports-plugin with this layout:
reports-plugin/
├── plugin.json
├── skills/summarize/SKILL.md
└── mcp.json
The host discovers skill summarize from skills/ and MCP servers from mcp.json.
If a fixed component location is absent, the host MUST NOT treat that as an error.
If a fixed component location is present but does not resolve to the expected filesystem kind — for example, skills does not resolve to a directory or mcp.json does not resolve to a regular file — the host MUST treat that component type as invalid and continue loading other supported component types.
See also: §6 Component discovery for how component files are located.
Agent Plugin v1 defines exactly two portable component types: skills and MCP servers. Other capabilities are outside the v1 format and do not affect conformance.
Hosts MUST ignore component types they do not support.
Agent Skills MUST conform to the Agent Skills specification. That specification is the source of truth for the SKILL.md format, frontmatter fields, and directory layout (scripts/, references/, assets/).
This specification defines how Agent Skills are discovered within a plugin, not the skill format itself or how hosts expose skills to users or models.
The fixed discovery location is skills/. Each immediate child directory containing a path named exactly SKILL.md that resolves to a regular file is treated as one skill. Hosts MUST NOT recursively search deeper descendants for additional skills.
If a discovered skill does not conform to the Agent Skills specification, the host MUST skip that skill and continue loading other skills and component types. The host SHOULD report the invalid skill.
Example: a skill directory named deploy inside skills/:
skills/
└── deploy/
├── SKILL.md # name: deploy
├── scripts/
│ └── rollback.sh
└── references/
└── runbook.md
The Model Context Protocol specification defines MCP wire behavior and lifecycle semantics. Agent Plugin defines the mcp.json configuration format used to locate and connect to MCP servers in a plugin. Hosts map this portable format to their native configuration; its field names and values need not match a host-native format.
The MCP configuration path is mcp.json at the plugin root. MCP configuration MUST NOT be declared inline in plugin.json or loaded from any alternative core path.
mcp.json MUST be a JSON object containing the required $schema and mcpServers fields, with no other top-level fields. mcpServers MUST be an object whose member names identify servers and whose member values are server configuration objects. An empty mcpServers object is valid.
The official machine-readable schema is schemas/1.0.0/mcp.schema.json. The specification text is authoritative if it conflicts with the schema. The schema exposes #/$defs/server so that hosts can validate each server independently and preserve the failure boundaries in §7.2.2.
The required $schema field identifies the Agent Plugin specification version targeted by the MCP configuration and its corresponding MCP schema. For Agent Plugin 1.0.0, its value MUST be the canonical identifier https://agent-plugins.org/schemas/1.0.0/mcp.schema.json.
Hosts MUST use a recognized $schema value to select locally supported MCP configuration validation and interpretation rules. A host MAY map multiple canonical identifiers to the same implementation only when it explicitly recognizes those Agent Plugin versions as compatible. Hosts MUST NOT retrieve a schema while loading a plugin.
Each server configuration MUST contain a type field and match exactly one of the closed variants below. An unknown field, an unknown type value, or a field belonging to another variant makes that server entry invalid.
| Field | Type | Required | Description |
|---|---|---|---|
type |
"stdio" |
Yes | Selects the MCP stdio transport. |
command |
string | Yes | Executable token to launch. |
args |
string[] | No | Arguments passed to the executable. |
env |
object of strings | No | Environment variables supplied to the process. |
cwd |
string | No | Working directory for the process. |
The command field MUST contain a single executable token, not a shell command string. It MUST be either a bare executable name or a plugin-relative path beginning with ./. Hosts MUST resolve bare names using the platform's executable search rules and MUST resolve plugin-relative paths against the plugin root. Hosts MUST NOT perform placeholder expansion in command.
Whether a configured PATH environment value participates in resolving a bare command is host-defined. Plugins claiming conformance MUST NOT depend on that behavior. A plugin that bundles an executable in the package MUST use a plugin-relative command.
Hosts MAY use a platform-specific command interpreter when required to launch the resolved executable, such as a .bat or .cmd script on Windows, but MUST preserve command as one token and pass args separately.
When cwd is omitted, hosts MUST use the plugin root as the subprocess working directory. When present, cwd MUST have one of these forms:
- A plugin-relative path beginning with
./. - Exactly
${PLUGIN_ROOT}or a path beginning with${PLUGIN_ROOT}/. - Exactly
${PLUGIN_DATA}or a path beginning with${PLUGIN_DATA}/.
Hosts MUST expand placeholders before resolving cwd. A plugin-relative or ${PLUGIN_ROOT}-rooted value MUST remain within the filesystem-resolved plugin root. A ${PLUGIN_DATA}-rooted value MUST remain within the filesystem-resolved plugin data directory. Any other form or any post-resolution escape makes that server entry invalid under §7.2.2.
The args, env, and cwd fields in a stdio server configuration MUST support ${PLUGIN_ROOT} and ${PLUGIN_DATA} expansion.
| Field | Type | Required | Description |
|---|---|---|---|
type |
"streamable-http" or "sse" |
Yes | Selects the remote MCP transport. |
url |
string | Yes | MCP endpoint URL. |
headers |
object of strings | No | Fixed HTTP headers sent when connecting to the configured origin. |
streamable-http selects the current MCP Streamable HTTP transport. sse selects the deprecated HTTP+SSE transport defined by the MCP 2024-11-05 specification; it does not refer to SSE responses or streams used within Streamable HTTP.
The url value MUST be an absolute HTTP or HTTPS URL and MUST NOT contain user information or a fragment. Non-loopback endpoints MUST use HTTPS. HTTP MAY be used when the URL host is exactly localhost or an IP literal in a loopback range.
Header names and values MUST be valid HTTP header fields. Header names are case-insensitive; an entry containing the same header name more than once under different casing is invalid. Hosts MUST NOT perform placeholder or environment-variable expansion in url, header names, or header values.
Header values are visible package data, not a portable secret mechanism. Plugins MUST NOT embed credentials or other secrets in headers. Headers generated by the host to implement HTTP, MCP, or authorization take precedence over configured headers with the same case-insensitive name. A host MUST NOT forward configured headers to a different origin through a redirect or legacy SSE endpoint event without explicit user authorization.
Agent Plugin v1 defines no OAuth configuration or portable credential-reference fields. Authorization discovery, user interaction, and credential storage are host-managed. An authorization failure is a connection failure for that server, not invalid plugin configuration.
A host that supports Agent Plugin MCP servers MUST support both stdio and streamable-http. Support for sse is OPTIONAL. A host MUST use the transport declared by type and MUST NOT reinterpret streamable-http as legacy HTTP+SSE or automatically fall back to it.
Example: mcp.json
{
"$schema": "https://agent-plugins.org/schemas/1.0.0/mcp.schema.json",
"mcpServers": {
"local-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"
}
},
"legacy-events": {
"type": "sse",
"url": "https://legacy.example.com/sse"
}
}
}- Hosts that support MCP servers MUST load configuration only from
mcp.jsonat the plugin root. - If
mcp.jsonis not valid JSON, targets an Agent Plugin version for which the host has no supported or explicitly recognized compatible version, targets a different Agent Plugin version thanplugin.json, or does not satisfy the other top-level requirements in §7.2.1, the host MUST disable MCP for that plugin and continue loading other component types. The host SHOULD report the invalid, unsupported, or mismatched configuration. - If an individual server entry does not satisfy the requirements in §7.2.1, the host MUST skip that server and continue loading other servers and component types. The host SHOULD report the invalid entry.
- If the host does not support a valid
sseentry, it MUST skip that server and continue loading other servers and component types. The host SHOULD report the unsupported transport. - If a server fails to start, connect, authenticate, or complete the MCP handshake, the host MUST continue loading other servers and component types. The host SHOULD report the connection failure.
Client-specific manifest data MUST be represented under a reverse-domain namespace in extensions. Client-specific files MUST be represented under a top-level directory named for that namespace. A client MAY use either representation or both.
A client SHOULD base its namespace on a domain name it controls and SHOULD keep the namespace stable. For example, a client that controls example.com could use com.example.client.
Agent Plugin assigns no portable semantics to client extension data or files. Each client defines the contents and behavior of its own namespace, including how its manifest data and directory contents relate.
The optional extensions field in plugin.json MUST be an object whose member names are client extension namespaces and whose member values are objects.
Example:
{
"$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
"name": "example-plugin",
"extensions": {
"com.example.client": {
"setting": true
}
}
}If extensions is not an object, the host MUST report and ignore the field and continue loading portable components. A host MUST ignore manifest entries for namespaces it does not implement without validating the contents of their values. Validation and failure handling within an implemented namespace are defined by that client.
The extension directory for a namespace is the top-level directory named after it. For example, files for com.example.client belong in com.example.client/.
Example: a file-only client extension
my-plugin/
├── plugin.json
├── skills/
│ └── summarize/
│ └── SKILL.md
└── com.example.client/
└── hooks/
└── hooks.json
A host that implements file-based behavior for a namespace MUST look for it in the corresponding top-level directory.
See also: §7.2 MCP servers for the fields where plugin variable expansion applies, and §4.1 General requirements for path safety rules.
Hosts that launch plugin subprocesses (i.e., stdio MCP servers) MUST provide PLUGIN_ROOT and PLUGIN_DATA in each subprocess environment. PLUGIN_ROOT is the absolute path to the filesystem-resolved plugin root. PLUGIN_DATA is the absolute path to a host-managed persistent data directory dedicated to that installed plugin instance.
The host chooses the PLUGIN_DATA location. It MUST create the directory before launching a plugin subprocess, MUST make it writable to that subprocess, and MUST preserve its contents across plugin updates. The host MAY delete the directory when the plugin is uninstalled.
Use PLUGIN_DATA for: installed dependencies (node_modules, virtual environments), generated code, caches, and other plugin state that should persist across updates. Use PLUGIN_ROOT for referencing bundled scripts, binaries, and config files that ship with the plugin.
The host chooses the base subprocess environment and MAY inherit, omit, or sanitize ambient variables. After placeholder expansion, entries in a stdio server's env object MUST overlay the base environment and replace same-name entries according to platform environment-name semantics. The host MUST then set PLUGIN_ROOT and PLUGIN_DATA to the values defined above, replacing any entries with equivalent names according to platform environment-name semantics.
Except for the platform executable search used to resolve a bare command, plugins claiming conformance MUST NOT depend on a base-environment variable unless this specification requires that variable or the server configuration supplies it explicitly.
Example: a host loading the plugin devtools from /home/alex/.agents/plugins/devtools sets:
PLUGIN_ROOT=/home/alex/.agents/plugins/devtools
PLUGIN_DATA=/home/alex/.agents/plugins/data/devtools
Hosts that launch plugin subprocesses MUST expand ${PLUGIN_ROOT} and ${PLUGIN_DATA} in supported configuration fields. Expansion is a single, non-recursive textual replacement of every exact occurrence of either placeholder. Text introduced by a replacement MUST NOT be scanned for further placeholders.
Expansion applies to every string element of args, every string value in env, and the cwd string. It does not apply to env keys, command, or fixed component locations.
Unrecognized placeholder-like text MUST remain literal. Hosts MUST NOT perform any other placeholder or environment-variable expansion.
Configured env values are visible package data, not a portable secret mechanism. Plugins MUST NOT embed credentials or other secrets in env.
An MCP server's env object MUST NOT contain entries named PLUGIN_ROOT or PLUGIN_DATA. Such an entry makes that server configuration invalid under §7.2.2. Hosts MUST supply the reserved environment variables themselves.
Example: plugin variable expansion in MCP
{
"$schema": "https://agent-plugins.org/schemas/1.0.0/mcp.schema.json",
"mcpServers": {
"database": {
"type": "stdio",
"command": "npx",
"args": ["--config", "${PLUGIN_ROOT}/config/db.json"],
"cwd": "${PLUGIN_ROOT}",
"env": {
"DATA_DIR": "${PLUGIN_DATA}/database"
}
}
}
}The version in §1 identifies the complete Agent Plugin specification release, including its normative text, plugin manifest schema, and MCP configuration schema. Every specification release MUST publish both schemas with the same version as the specification, even when a schema's validation rules are unchanged from the previous release.
A plugin's required plugin.json $schema value declares the Agent Plugin version that the package targets. When mcp.json is present, the version in its $schema value MUST match the version declared by plugin.json. A mismatch makes the MCP configuration invalid under §7.2.2 but does not invalidate other component types.
A change to either schema requires a new specification release. Published canonical schema identifiers MUST NOT be reassigned to different schema contents. Existing plugins MAY continue targeting an older Agent Plugin version; hosts determine support using the declared canonical identifiers and any explicit compatibility mappings.
Plugins SHOULD use Semantic Versioning for version.
| Segment | Meaning | Description |
|---|---|---|
| Major | Breaking change | Incompatible behavior or schema change. |
| Minor | Backward-compatible feature | New behavior without breaking existing hosts or users. |
| Patch | Backward-compatible fix | Corrective change without intended behavioral break. |
Hosts MAY use version to determine whether updates are available and whether caches are stale.
A conformant host MUST satisfy all applicable requirements in sections 1–10. At minimum, it:
- Can load a plugin from a directory path.
- Selects a locally supported plugin manifest schema from
$schema, then parses and validates the closedplugin.jsonschema using the non-fatal exceptions in §5.2 and §8.1. - Ignores unimplemented members of
extensionswithout validating the contents of their values. - For each core component type it supports, discovers components in its fixed location.
- If it supports MCP servers, selects a locally supported MCP configuration schema from
$schemaand supports both thestdioandstreamable-httpvariants inmcp.json. - If the host launches plugin subprocesses (i.e., stdio MCP servers), provides
PLUGIN_ROOTandPLUGIN_DATAand expands both variables in runtime configuration values (args,env,cwd). - For stdio MCP servers, resolves
commandas a single executable token and uses the plugin root as the default subprocess working directory. - Supports at least one core component type (skills or MCP servers).
A host is not required to support every core component type. For example, a skills-only host can conform without supporting MCP servers, provided it satisfies all applicable requirements.
- Hosts MUST ignore unsupported component types.
- An unknown top-level field or a non-object
extensionsfield is non-fatal under §5.2 and §8.1. Any otherplugin.jsonschema violation is fatal to the plugin: the host MUST reject the plugin and MUST NOT discover or execute any of its components. - A failure isolated to a component type, component entry, or component process MUST NOT prevent the host from loading independently valid components. Hosts MUST apply the failure behavior defined for that component in §6 and §7.
- Hosts SHOULD report invalid configuration and component failures. Hosts MAY report partially unsupported plugins, but lack of support for a component type or client extension is not itself an error.
This checklist is for convenience only — when it conflicts with the spec text above, the spec governs.
- Parse and validate
plugin.json(§5.1, §5.2) - Validate required
$schemaandnamefields (§5.3) - Validate plugin name against naming constraints (§5.5)
- Report and ignore unknown
plugin.jsonfields (§5.2) - Ignore unimplemented namespaces in
extensionswithout validating the contents of their values (§8.1) - Reject package paths that resolve outside the plugin root (§4.1)
- Discover implemented file-based extensions from their top-level namespace directories (§8.2)
- Scan the fixed location for each supported component type (§6.1)
- Ignore missing fixed locations without error (§6.2)
- Select a supported
$schema, then validate the closedmcp.jsonschema and each server variant (§7.2.1) - If supporting MCP, implement both stdio and Streamable HTTP (§7.2.1)
- Treat legacy HTTP+SSE as optional and never as an automatic fallback (§7.2.1)
- Enforce remote URL and literal-header requirements (§7.2.1)
- If the host launches plugin subprocesses, provide
PLUGIN_ROOTand a dedicated writablePLUGIN_DATAdirectory (§9.1) - Resolve MCP server
commandas a single bare or plugin-relative executable token (§7.2.1) - Use the plugin root as the default MCP server working directory (§7.2.1)
- Validate explicit
cwdforms and post-resolution containment (§7.2.1) - Overlay configured
enventries on a host-selected base environment (§9.1) - Set host-provided
PLUGIN_ROOTandPLUGIN_DATAafter applying configuredenv, replacing equivalent names according to platform environment-name semantics (§9.1) - Do not require configured
PATHto affect bare-command resolution (§7.2.1) - Expand only
${PLUGIN_ROOT}and${PLUGIN_DATA}in MCP serverargs,env, andcwdfields (§9.2)
- Ignore unsupported component types (§11.3)
- Skip unsupported legacy HTTP+SSE servers without affecting other components (§7.2.2)
- Continue loading when an independent component fails (§11.3)
- Support at least one core component type (§11.1)
This section explains why key design choices were made. It is for context only — the binding rules are in the normative sections above.
Plugins use filesystem directories as the package unit rather than archive formats (.zip, .tar.gz) or registry-fetched bundles. This keeps plugins inspectable with standard tools (ls, cat, git), editable in-place during development, and compatible with version control without special tooling. Fixed root-level locations such as skills/ and mcp.json eliminate discovery indirection, alternate-source precedence, and manifest configuration that every host would otherwise need to implement.
Agent Plugin v1 focuses on Agent Skills and MCP because both have established specifications outside this project and meaningful cross-host adoption. Other proposed component types — such as commands, hooks, agents, rules, and LSP servers — remain too host-specific for a stable portable contract and are outside portable v1 until their formats converge.
Every conformant host MUST check plugin.json at the plugin root (§5.1). This gives plugin authors a single guaranteed manifest that works across all hosts without client-specific path knowledge.
Restricting root plugin.json to known fields enables strict validation, typo detection, and schema-driven key completion. Client experiments cannot claim arbitrary top-level fields; they are contained under reverse-domain keys in extensions. Unknown top-level fields remain schema violations, but hosts report and ignore them instead of rejecting an otherwise valid plugin.
Reverse-domain identifiers provide a decentralized convention for avoiding collisions without requiring a central client-name registry. The same identifier can be used for manifest data and a client-specific directory, while either representation can exist independently. Extension directories remain top-level to keep plugin layouts flat and convention-driven.
Existing hosts use incompatible MCP configuration shapes and infer transports differently. Agent Plugin therefore defines an explicit closed union whose meaning is independent of any host-native format. Distinguishing Streamable HTTP from legacy HTTP+SSE also prevents an unexpected fallback to the deprecated transport.
plugin.json and mcp.json schemas use the Agent Plugin specification version rather than independent version sequences. This gives plugin authors and hosts one portable format version to understand, prevents mixed-version packages, and lets $schema select the complete validation and interpretation contract — including requirements that JSON Schema cannot express. Republishing an unchanged schema with a new specification release is a small maintenance cost compared with exposing three independent compatibility timelines.
MCP server arguments often need absolute paths at runtime. ${PLUGIN_ROOT} provides an unambiguous, host-resolved anchor for bundled files, while ${PLUGIN_DATA} identifies host-managed writable state that persists when package contents are replaced during an update. The command field does not use interpolation: a ./ path is resolved directly against the plugin root, and a bare name uses the platform's executable search rules. Treating command as one token avoids requiring hosts to parse and escape user-authored shell command strings. Hosts differ in inherited environment and PATH behavior, so Agent Plugin standardizes configured environment overrides but leaves bare-command search host-defined; plugin-relative commands provide deterministic bundled execution.
When an MCP server fails to start or connect, the host continues loading the plugin's remaining components (§11.3). A plugin that provides skills and an MCP server should not become entirely unusable because one server is unavailable. The spec pairs non-fatal component failures with diagnostic requirements so that failures are visible rather than silent.
Everything in this section is deferred from v1.0.0. Nothing here is required for conformance. These items may be addressed in future versions.
v1.0.0 does not define a trust model, permission system, or sandboxing requirements for plugins. A future version should address:
- Permission declarations in the manifest (e.g., filesystem access, network access, tool access)
- Host-enforced capability restrictions per plugin
- User consent flows for plugin installation and capability grants
- Approval UX for MCP servers that execute arbitrary commands or access external services
- Graduated trust levels (e.g., "sandboxed", "user-approved", "organization-approved")
v1.0.0 does not specify how hosts or users can verify the origin or integrity of a plugin. A future version may define:
- Cryptographic signature verification for published plugins
- Attestation chains linking a published plugin to its source repository and build
- Host-side policies for requiring signatures from trusted publishers
MCP servers often need credentials or API keys at runtime. v1.0.0 does not specify how sensitive values should be provided, stored, or scoped. A future version may define:
- A
secretsmanifest field or separate secrets configuration - Host-mediated secret injection that avoids plaintext in config files
- Scoping rules that prevent one plugin from accessing another plugin's secrets
- Rotation and revocation semantics for plugin-held credentials
Organizations deploying plugins at scale need policy enforcement that v1.0.0 does not address. A future version may define:
- Allowlist and blocklist policies for plugin installation by name, publisher, or signature
- Organization-scoped plugin registries with approval workflows
- Centralized configuration overrides that take precedence over user-level plugin settings
- Compliance reporting for plugin installation and usage events
v1.0.0 defines failure-reporting requirements but does not standardize diagnostic or lifecycle event schemas. A future version may define:
- A standard event schema for plugin install, enable, disable, update, and uninstall actions
- Recommended fields: timestamp, actor (user or automation), plugin name, plugin version, action, outcome
- Integration points for forwarding audit events to external logging or SIEM systems
- Retention and access policies for audit records
Plugins currently cannot declare dependencies on other plugins. A future version may define:
- A
dependenciesmanifest field with version constraints - Resolution order and conflict handling for transitive dependencies
- Peer dependency semantics for shared components
No test harness or validation tool is specified. A future version may define:
- A
testmanifest field or convention - A standard plugin linter or validator command
- Conformance test suites for host implementations