feat: support Agent Plugins (#81)

Signed-off-by: Jonah Snider <jonah@jonahsnider.com>
This commit is contained in:
Jonah Snider
2026-08-18 07:28:10 -07:00
committed by GitHub
parent 77a54f7850
commit 6b48aeddf9
8 changed files with 153 additions and 6 deletions
+3
View File
@@ -23,5 +23,8 @@ jobs:
- name: Validate skills
run: npm run validate
- name: Validate Agent Plugin
run: npm run validate:agent-plugin
- name: Validate Cursor plugin
run: npm run validate:cursor-plugin
+1 -1
View File
@@ -48,7 +48,7 @@ The repo uses npm (not pnpm).
1. Fork the repo
2. Install dependencies with `npm ci`
3. Make your changes in `skills/<skill-name>/`
4. Run `npm run validate:all` to check skill and plugin validity
4. Run `npm run validate:all` to check Agent Skills, Agent Plugins, and client plugin validity
5. Submit a PR
### Adding to an existing skill
+9 -3
View File
@@ -13,6 +13,7 @@ Collection of resources to help AI agents build better with [Sanity](https://www
- **MCP server:** Direct access to your Sanity projects (content, datasets, releases, schemas) and agent rules.
- **Agent skills:** Comprehensive best practices skills for Sanity development, content modeling, SEO/AEO, and experimentation. Includes 21 integration/topic guides and 26 focused best-practice rules.
- **Agent Plugin:** `plugin.json`, `skills/`, and `mcp.json` components for any Agent Plugins-compatible client.
- **Claude Code plugin:** MCP server, agent skills, and slash commands for Claude Code users. Available on the [official Anthropic plugin marketplace](https://claude.com/plugins/sanity).
- **Cursor plugin:** MCP server, agent skills, and commands on the [Cursor Marketplace](https://cursor.com/marketplace/sanity).
- **Codex plugin:** MCP server and agent skills for [OpenAI Codex](https://developers.openai.com/codex) users.
@@ -25,7 +26,7 @@ Choose your path based on how you want agents to work with Sanity:
1. **MCP server** — Give your agent always up-to-date rules and full access to your Sanity projects. No local files to maintain. Works with Cursor, VS Code, Claude Code, Lovable, v0, Replit, OpenCode, and other MCP-compatible clients.
2. **Agent skills** — Install best practices skills for Sanity, content modeling, SEO/AEO, and experimentation. Works with Cursor, Claude Code, and any [Agent Skills](https://agentskills.io)-compatible agent.
3. **Plugin** — Install the Sanity plugin for Cursor or Claude Code. Bundles MCP server, agent skills, and commands.
3. **Plugin** — Install the Sanity plugin for Cursor, Claude Code, or any Agent Plugins-compatible client. Bundles MCP server, agent skills, and commands.
4. **Manual installation** — Copy the skill references locally for offline use. You'll need to update them yourself.
### Option 1: Install MCP server (recommended)
@@ -186,7 +187,8 @@ See [Option 3](#option-3-install-plugin) for plugin installation.
### Option 3: Install plugin
Install the Sanity plugin to get MCP server, agent skills, and commands. Available on the [Claude Code marketplace](https://claude.com/plugins/sanity) and [Cursor Marketplace](https://cursor.com/marketplace/sanity).
Install the Sanity plugin to get MCP server, agent skills, and commands.
Available on the [Claude Code marketplace](https://claude.com/plugins/sanity), [Cursor Marketplace](https://cursor.com/marketplace/sanity), or from this repo as an [Agent Plugin](https://agent-plugins.org/).
#### Claude Code
@@ -332,6 +334,8 @@ Just say: "Get started with Sanity" to begin.
sanity-io/agent-toolkit/
├── AGENTS.md # Knowledge router & agent behavior
├── README.md # This file
├── plugin.json # Portable Agent Plugins v1 manifest
├── mcp.json # Portable Agent Plugins v1 MCP configuration
├── .agents/plugins/ # Codex marketplace
│ └── marketplace.json # Codex marketplace metadata
├── .claude-plugin/ # Claude Code plugin configuration (distributed via claude-plugins-official)
@@ -342,7 +346,7 @@ sanity-io/agent-toolkit/
├── .cursor-plugin/ # Cursor plugin configuration (distributed via cursor.com/marketplace)
│ ├── marketplace.json # Cursor marketplace metadata
│ └── plugin.json # Per-plugin manifest
├── .mcp.json # MCP server configuration
├── .mcp.json # Legacy client MCP compatibility configuration
├── assets/ # Plugin branding
│ └── logo.svg # Sanity logo for marketplace display
├── commands/ # Agent commands
@@ -351,6 +355,7 @@ sanity-io/agent-toolkit/
│ ├── typegen.md # /typegen
│ └── deploy-schema.md # /deploy-schema
├── scripts/ # Validation and CI scripts
│ ├── validate-agent-plugin.mjs # Validate manifests against the v1 JSON Schemas
│ └── validate-cursor-plugin.mjs # Cursor plugin validator
└── skills/ # Agent skills (agentskills.io format)
├── sanity-best-practices/ # Comprehensive Sanity skill
@@ -378,6 +383,7 @@ All skills use `references/` for detailed content loaded on demand. The `sanity-
- [Visual Editing guide](https://www.sanity.io/docs/visual-editing)
- [Sanity TypeGen](https://www.sanity.io/docs/sanity-typegen)
- [MCP server docs](https://www.sanity.io/docs/ai/mcp-server)
- [Agent Plugins specification](https://agent-plugins.org/specification)
- [Blueprints Infrastructure as Code](https://www.sanity.io/docs/compute-and-ai/blueprints)
---
+9
View File
@@ -0,0 +1,9 @@
{
"$schema": "https://agent-plugins.org/schemas/1.0.0/mcp.schema.json",
"mcpServers": {
"Sanity": {
"type": "streamable-http",
"url": "https://mcp.sanity.io"
}
}
}
+60 -1
View File
@@ -9,7 +9,25 @@
"version": "1.0.0",
"license": "MIT",
"devDependencies": {
"skills-ref": "^0.1.5"
"ajv": "8.20.0",
"skills-ref": "0.1.5"
}
},
"node_modules/ajv": {
"version": "8.20.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz",
"integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==",
"dev": true,
"license": "MIT",
"dependencies": {
"fast-deep-equal": "^3.1.3",
"fast-uri": "^3.0.1",
"json-schema-traverse": "^1.0.0",
"require-from-string": "^2.0.2"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/epoberezkin"
}
},
"node_modules/argparse": {
@@ -29,6 +47,30 @@
"node": ">=18"
}
},
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"dev": true,
"license": "MIT"
},
"node_modules/fast-uri": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.5.tgz",
"integrity": "sha512-gHwA1O9LDIcKunMKhObS/HimwtehO1nPUECKAu5TpKgaO19fcWEl4bliWe1jWxVFvIXztJjjQ4L8XQ1EU9f7Jw==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/fastify"
},
{
"type": "opencollective",
"url": "https://opencollective.com/fastify"
}
],
"license": "BSD-3-Clause"
},
"node_modules/js-yaml": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
@@ -42,6 +84,23 @@
"js-yaml": "bin/js-yaml.js"
}
},
"node_modules/json-schema-traverse": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
"dev": true,
"license": "MIT"
},
"node_modules/require-from-string": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/skills-ref": {
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/skills-ref/-/skills-ref-0.1.5.tgz",
+4 -1
View File
@@ -11,16 +11,19 @@
"validate:experimentation": "skills-ref validate ./skills/content-experimentation-best-practices",
"validate:pt-serialization": "skills-ref validate ./skills/portable-text-serialization",
"validate:pt-conversion": "skills-ref validate ./skills/portable-text-conversion",
"validate:agent-plugin": "node scripts/validate-agent-plugin.mjs",
"validate:cursor-plugin": "node scripts/validate-cursor-plugin.mjs",
"validate:all": "npm run validate && npm run validate:cursor-plugin"
"validate:all": "npm run validate && npm run validate:agent-plugin && npm run validate:cursor-plugin"
},
"devDependencies": {
"ajv": "8.20.0",
"skills-ref": "0.1.5"
},
"keywords": [
"sanity",
"ai",
"agent",
"agent-plugins",
"skills",
"claude",
"cursor",
+23
View File
@@ -0,0 +1,23 @@
{
"$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
"name": "sanity",
"version": "1.0.0",
"description": "Sanity plugin with an MCP server and agent skills for structured content development.",
"author": {
"name": "Sanity",
"email": "support@sanity.io",
"url": "https://www.sanity.io"
},
"homepage": "https://github.com/sanity-io/agent-toolkit",
"repository": "https://github.com/sanity-io/agent-toolkit",
"license": "MIT",
"keywords": [
"sanity",
"cms",
"content-lake",
"groq",
"content",
"structured-content",
"visual-editing"
]
}
+44
View File
@@ -0,0 +1,44 @@
#!/usr/bin/env node
import { readFile } from "node:fs/promises";
import process from "node:process";
import Ajv2020 from "ajv/dist/2020.js";
const documents = [
{
path: "plugin.json",
schemaUrl:
"https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
},
{
path: "mcp.json",
schemaUrl: "https://agent-plugins.org/schemas/1.0.0/mcp.schema.json",
},
];
const ajv = new Ajv2020({ allErrors: true });
let valid = true;
for (const document of documents) {
const [schemaResponse, data] = await Promise.all([
fetch(document.schemaUrl),
readFile(document.path, "utf8").then(JSON.parse),
]);
if (!schemaResponse.ok) {
throw new Error(
`Unable to load ${document.schemaUrl}: ${schemaResponse.status} ${schemaResponse.statusText}`
);
}
const validate = ajv.compile(await schemaResponse.json());
if (!validate(data)) {
valid = false;
console.error(`${document.path} is invalid:`);
console.error(ajv.errorsText(validate.errors, { separator: "\n" }));
}
}
if (!valid) process.exit(1);
console.log("Agent Plugin manifests are valid.");