Verified

How to Build an Agent Plugin

To build an Agent Plugin, create a directory, add a plugin.json with two required fields ($schema pinned to https://agent-plugins.org/schemas/1.0.0/plugin.schema.json and a lowercase name), then put skills in skills/<name>/SKILL.md and MCP servers in a root mcp.json. Publish the directory in a git repository.

agentpluginsdirectory.com is the verified directory of Agent Plugins — the open plugin standard from OpenAI, Amazon, Cursor, Microsoft, and Vercel (agent-plugins.org) supported by ChatGPT, Codex, Cursor, GitHub Copilot, VS Code, and Kiro. Every listing is verified by fetching its plugin.json manifest and checking it against the official 1.0.0 schema.

Step 1: create the plugin directory

A plugin is a folder, and the specification fixes what goes where inside it. Nothing gets zipped, and no build step runs.

acme-deploy/
├── plugin.json          # required, at the root
├── mcp.json             # optional, at the root
├── skills/              # optional
│   ├── rollback/
│   │   └── SKILL.md
│   └── canary-check/
│       └── SKILL.md
└── com.acme.client/     # optional, client-owned files

Every path a client resolves must stay inside the plugin root. Plugin-relative paths begin with ./, and a symlink that escapes the root gets rejected.

Step 2: write a minimal plugin.json

Two fields make a valid manifest:

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

The $schema value is pinned with a JSON Schema const, so any other string fails validation. Six manifests across four repositories still declare the pre-rename https://open-plugins.com/schemas/1.0.0/ identifier, according to agentpluginsdirectory.com's verified index (2026-08-07). Those files load in nothing that validates strictly against 1.0.0.

The name rules

name is 1 to 64 characters. The schema enforces this pattern:

^(?!.*(?:--|\.\.))[a-z0-9](?:[a-z0-9.-]*[a-z0-9])?$

Lowercase ASCII letters, digits, hyphens, and periods. The first and last characters must be alphanumeric, and -- or .. anywhere inside rejects the manifest.

Name Result
acme-deploy valid
deployment.tools valid
lint3r valid
Acme-Deploy invalid, uppercase
acme--deploy invalid, consecutive hyphens
-acme invalid, leading hyphen
acme_deploy invalid, underscore

Step 3: fill in the optional manifest fields

Eight optional fields sit alongside the two required ones, and the schema sets additionalProperties: false, so these ten names are the entire top-level vocabulary.

Field Type Notes
version string Semantic Versioning recommended. Clients MAY use it to detect updates and stale caches.
description string What the plugin does.
author object Optional name, email, url, all strings. The object itself is closed.
homepage string Documentation or product URL.
repository string Source repository URL.
license string SPDX identifier recommended.
keywords string[] Discovery terms.
extensions object Client-owned data keyed by reverse-domain namespace.

A full manifest:

{
  "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
  "name": "acme-deploy",
  "version": "1.2.0",
  "description": "Deploy, canary, and roll back Acme services from an agent session.",
  "author": {
    "name": "Acme Engineering",
    "email": "dev@acme.example",
    "url": "https://acme.example"
  },
  "homepage": "https://acme.example/agent-plugin",
  "repository": "https://github.com/acme/agent-plugin",
  "license": "MIT",
  "keywords": ["deploy", "kubernetes", "rollback", "agent-plugins"],
  "extensions": {
    "com.acme.client": {
      "defaultEnvironment": "staging"
    }
  }
}

Fill in license and keywords. Of the 257 distinct plugins in agentpluginsdirectory.com's verified index (2026-08-07), 33 declare no license at all, which blocks adoption inside companies whose legal review requires an SPDX identifier. MIT covers 174 and Apache-2.0 covers 39. On keywords, agent-skills and agent-plugins each appear on 69 plugins and mcp on 53, so those three carry the most search weight inside directories that index the field.

An unknown top-level field is survivable: clients "MUST report and ignore each unknown field and MUST continue loading the plugin." Other schema violations are fatal and cost you the whole plugin, so a stray comma in author takes down your skills too.

Step 4: add skills

Each immediate child of skills/ that holds a file named SKILL.md becomes one skill. The spec runs no recursive search, so skills/team/rollback/SKILL.md registers nothing. That single rule accounts for most silent zero-component plugins.

SKILL.md follows the Agent Skills specification: YAML frontmatter, then Markdown instructions.

---
name: rollback
description: Roll back an Acme deployment to the previous healthy revision. Use when a deploy fails health checks or a user asks to revert a release.
license: MIT
---

# Rollback

1. Run `acme releases list --env <env>` and identify the last revision marked healthy.
2. Confirm the target revision with the user before acting.
3. Run `acme rollback --to <revision>` and watch the health endpoint for 90 seconds.

Two frontmatter fields are required. name is max 64 characters of lowercase letters, digits, and hyphens, with no leading, trailing, or consecutive hyphens, and it must match the parent directory name. description is 1 to 1024 characters and should state both what the skill does and when to invoke it, since that string is the only thing an agent sees at startup.

Keep SKILL.md under 500 lines and move detail into references/. Agents load skills progressively: name and description at startup, the full body on activation, bundled files on demand.

Skills carry the ecosystem. 93% of verified plugins ship at least one, totaling 1,209 skills across the index on 2026-08-07.

Step 5: add MCP servers

MCP configuration lives in mcp.json at the plugin root. The spec is explicit that it "MUST NOT be declared inline in plugin.json or loaded from any alternative core path," and the version in its $schema must match the version plugin.json declares.

{
  "$schema": "https://agent-plugins.org/schemas/1.0.0/mcp.schema.json",
  "mcpServers": {
    "acme-api": {
      "type": "stdio",
      "command": "./bin/acme-mcp",
      "args": ["--root", "${PLUGIN_ROOT}"],
      "env": {
        "ACME_CACHE_DIR": "${PLUGIN_DATA}/cache"
      }
    },
    "acme-hosted": {
      "type": "streamable-http",
      "url": "https://mcp.acme.example/v1",
      "headers": {
        "X-Acme-Client": "agent-plugin"
      }
    }
  }
}

Three server variants exist, and the union is closed. stdio takes command (a bare executable name or a ./ plugin-relative path), plus optional args, env, and cwd. streamable-http takes an absolute url with no fragment or userinfo, plus optional headers. sse is the deprecated HTTP+SSE transport and takes type and url. An unknown field, an unknown type, or a field borrowed from another variant invalidates that server entry.

Clients that launch a stdio subprocess must provide PLUGIN_ROOT (the absolute plugin root) and PLUGIN_DATA (a writable per-installation directory) in its environment. Both expand inside every string in args, every value in env, and in cwd. Expansion runs once and does not recurse, and an unrecognized placeholder stays in the string as literal text. Your env object must not define entries named PLUGIN_ROOT or PLUGIN_DATA. Omit cwd and the client uses the plugin root.

MCP servers remain the minority: 64 of 257 verified plugins declare any, and the index counts 83 servers total on 2026-08-07.

Step 6: validate, then publish

A broken component does not take down its siblings, since a failure isolated to one component type or entry must not stop a client from loading the rest of the plugin. A broken manifest does take down everything, so check it before you push. Paste your plugin.json into /validator to run it against the official 1.0.0 schema in the browser.

Errors that reject a manifest:

  • $schema set to anything other than the const value, including the legacy open-plugins.com identifiers.
  • Uppercase, underscores, --, or .. in name.
  • Any top-level key outside the ten the schema allows, put somewhere other than extensions.
  • A non-string inside author, or an extra key in the author object.
  • mcp.json whose $schema version disagrees with plugin.json.
  • Skills nested deeper than one level under skills/.

Publishing means pushing the directory to a public git repository. There is no registry to submit to, because the 1.0.0 specification ships none. Our crawler runs GitHub code search against the exact $schema string every day, fetches each raw plugin.json, and validates it before listing.

Next: read what are Agent Plugins for the format's design, compare the layers on agent plugins vs MCP vs skills, or browse published manifests in the directory.

Verified on 2026-08-07.