dsh-agent-plugins-market 0.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +171 -0
- package/README.zh.md +171 -0
- package/client/client.js +954 -0
- package/client/client.js.map +1 -0
- package/cordis.patch.yml +4 -0
- package/lib/commands-mounts.js +169 -0
- package/lib/context.js +80 -0
- package/lib/discovery/manifests.js +214 -0
- package/lib/discovery/surfaces.js +232 -0
- package/lib/discovery.js +234 -0
- package/lib/git.js +52 -0
- package/lib/hooks-mounts.js +95 -0
- package/lib/index.js +73 -0
- package/lib/manager.js +490 -0
- package/lib/mcp-config.js +100 -0
- package/lib/mcp-mounts.js +88 -0
- package/lib/paths.js +85 -0
- package/lib/routes.js +208 -0
- package/lib/skills-parse.js +114 -0
- package/lib/skills-provider.js +170 -0
- package/lib/state.js +64 -0
- package/lib/types/commands-mounts.d.ts +29 -0
- package/lib/types/context.d.ts +13 -0
- package/lib/types/discovery/manifests.d.ts +55 -0
- package/lib/types/discovery/surfaces.d.ts +15 -0
- package/lib/types/discovery.d.ts +16 -0
- package/lib/types/git.d.ts +8 -0
- package/lib/types/hooks-mounts.d.ts +19 -0
- package/lib/types/index.d.ts +27 -0
- package/lib/types/manager.d.ts +87 -0
- package/lib/types/mcp-config.d.ts +28 -0
- package/lib/types/mcp-mounts.d.ts +31 -0
- package/lib/types/paths.d.ts +29 -0
- package/lib/types/routes.d.ts +11 -0
- package/lib/types/skills-parse.d.ts +22 -0
- package/lib/types/skills-provider.d.ts +16 -0
- package/lib/types/state.d.ts +6 -0
- package/lib/types/types.d.ts +165 -0
- package/lib/types/validate.d.ts +34 -0
- package/lib/types.js +10 -0
- package/lib/validate.js +199 -0
- package/package.json +114 -0
- package/schemas/1.0.0/mcp.schema.json +120 -0
- package/schemas/1.0.0/plugin.schema.json +65 -0
- package/schemas/README.md +14 -0
package/lib/validate.js
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* agent-plugins.org v1.0.0 validation: vendored JSON Schemas plus the
|
|
3
|
+
* specification's semantic filesystem rules.
|
|
4
|
+
*
|
|
5
|
+
* The schemas live under `schemas/1.0.0/` and are bundled into the package —
|
|
6
|
+
* the spec forbids retrieving a schema while loading a plugin. Schema
|
|
7
|
+
* validation is one failure boundary (per server / per manifest); the
|
|
8
|
+
* semantic pass then enforces §4 path containment, `$schema` recognition, and
|
|
9
|
+
* the `${PLUGIN_ROOT}` / `${PLUGIN_DATA}` expansion the spec makes mandatory.
|
|
10
|
+
*/
|
|
11
|
+
import { readFile, realpath } from 'node:fs/promises';
|
|
12
|
+
import { dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';
|
|
13
|
+
import { fileURLToPath } from 'node:url';
|
|
14
|
+
// The 2020-12 dist build's d.ts resolves to a CJS namespace under NodeNext;
|
|
15
|
+
// the runtime default export is the class itself (module.exports = Ajv2020).
|
|
16
|
+
import Ajv2020Default from 'ajv/dist/2020.js';
|
|
17
|
+
const SCHEMAS_DIR = join(dirname(fileURLToPath(import.meta.url)), '..', 'schemas', '1.0.0');
|
|
18
|
+
const Ajv2020Class = Ajv2020Default;
|
|
19
|
+
export const PLUGIN_SCHEMA_ID = 'https://agent-plugins.org/schemas/1.0.0/plugin.schema.json';
|
|
20
|
+
export const MCP_SCHEMA_ID = 'https://agent-plugins.org/schemas/1.0.0/mcp.schema.json';
|
|
21
|
+
let ajvPromise;
|
|
22
|
+
/** Lazily build one Ajv instance holding the two vendored schemas. */
|
|
23
|
+
async function ajv() {
|
|
24
|
+
ajvPromise ??= (async () => {
|
|
25
|
+
const instance = new Ajv2020Class({ strict: false });
|
|
26
|
+
for (const name of ['plugin.schema.json', 'mcp.schema.json']) {
|
|
27
|
+
const schemaText = await readFile(join(SCHEMAS_DIR, name), 'utf8');
|
|
28
|
+
instance.addSchema(JSON.parse(schemaText));
|
|
29
|
+
}
|
|
30
|
+
return instance;
|
|
31
|
+
})();
|
|
32
|
+
return ajvPromise;
|
|
33
|
+
}
|
|
34
|
+
/** Validate one JSON document against a vendored schema; errors joined for surfacing. */
|
|
35
|
+
export async function validateAgainstSchema(schemaId, document) {
|
|
36
|
+
const instance = await ajv();
|
|
37
|
+
const validate = instance.getSchema(schemaId);
|
|
38
|
+
if (validate === undefined)
|
|
39
|
+
return [`no bundled validator for ${schemaId}`];
|
|
40
|
+
validate(document);
|
|
41
|
+
return (validate.errors ?? []).map((error) => `${error.instancePath === '' ? 'root' : error.instancePath} ${error.message ?? 'invalid'}`);
|
|
42
|
+
}
|
|
43
|
+
/** Whether a `$schema` value selects the local v1.0.0 ruleset. */
|
|
44
|
+
export function isRecognizedSchema(value) {
|
|
45
|
+
return value === PLUGIN_SCHEMA_ID || value === MCP_SCHEMA_ID;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Spec §4 containment: a plugin-relative path must begin with `./` and, after
|
|
49
|
+
* resolution against the plugin root, stay inside the filesystem-resolved
|
|
50
|
+
* plugin root. Symlinks resolving outside the root are rejected.
|
|
51
|
+
* @returns `undefined` when contained, or the rejection reason.
|
|
52
|
+
*/
|
|
53
|
+
export async function pathContainmentError(pluginRoot, value) {
|
|
54
|
+
const raw = value.replace(/^\$\{PLUGIN_ROOT\}(\/|$)/, './');
|
|
55
|
+
if (!raw.startsWith('./'))
|
|
56
|
+
return `path "${value}" must begin with "./" (or ${'${PLUGIN_ROOT}'})`;
|
|
57
|
+
const candidate = resolve(pluginRoot, raw.slice(2));
|
|
58
|
+
let rootResolved;
|
|
59
|
+
try {
|
|
60
|
+
rootResolved = await realpath(pluginRoot);
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
rootResolved = resolve(pluginRoot);
|
|
64
|
+
}
|
|
65
|
+
const rootPrefix = rootResolved.endsWith(sep) ? rootResolved : `${rootResolved}${sep}`;
|
|
66
|
+
let candidateResolved;
|
|
67
|
+
try {
|
|
68
|
+
candidateResolved = await realpath(candidate);
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
candidateResolved = candidate;
|
|
72
|
+
}
|
|
73
|
+
if (candidateResolved !== rootResolved && !candidateResolved.startsWith(rootPrefix)) {
|
|
74
|
+
return `path "${value}" resolves outside the plugin root`;
|
|
75
|
+
}
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
78
|
+
/** Validate a plugin manifest per the vendored schema plus `$schema` recognition. */
|
|
79
|
+
export async function validatePluginManifest(raw) {
|
|
80
|
+
const errors = [];
|
|
81
|
+
if (typeof raw !== 'object' || raw === null)
|
|
82
|
+
return ['manifest is not a JSON object'];
|
|
83
|
+
const record = raw;
|
|
84
|
+
if (!isRecognizedSchema(record['$schema'])) {
|
|
85
|
+
errors.push(`unrecognized $schema ${JSON.stringify(record['$schema'])}; this manager supports agent-plugins 1.0.0 only`);
|
|
86
|
+
}
|
|
87
|
+
errors.push(...await validateAgainstSchema(PLUGIN_SCHEMA_ID, raw));
|
|
88
|
+
return errors;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Parse and validate an `mcp.json` document: schema first, then §4 path
|
|
92
|
+
* containment for `command` and `cwd` of every stdio server.
|
|
93
|
+
* @returns the validated config plus per-problem strings; a failed `$schema`
|
|
94
|
+
* or schema body drops the whole file, while per-server path problems
|
|
95
|
+
* invalidate only their server.
|
|
96
|
+
*/
|
|
97
|
+
const KNOWN_MCP_TRANSPORTS = new Set(['stdio', 'streamable-http', 'sse']);
|
|
98
|
+
export async function validateMcpJson(pluginRoot, raw, options) {
|
|
99
|
+
if (typeof raw !== 'object' || raw === null)
|
|
100
|
+
return { errors: ['mcp.json is not a JSON object'] };
|
|
101
|
+
const record = raw;
|
|
102
|
+
const errors = [];
|
|
103
|
+
const strict = options?.strict !== false;
|
|
104
|
+
if (strict) {
|
|
105
|
+
if (!isRecognizedSchema(record['$schema'])) {
|
|
106
|
+
return { errors: [`unrecognized mcp.json $schema ${JSON.stringify(record['$schema'])}; this manager supports agent-plugins 1.0.0 only`] };
|
|
107
|
+
}
|
|
108
|
+
const schemaErrors = await validateAgainstSchema(MCP_SCHEMA_ID, raw);
|
|
109
|
+
if (schemaErrors.length > 0)
|
|
110
|
+
return { errors: schemaErrors };
|
|
111
|
+
}
|
|
112
|
+
// Lenient native-client files may omit the `mcpServers` wrapper and put the
|
|
113
|
+
// server map at the top level (Claude Code `.mcp.json` shorthand).
|
|
114
|
+
let servers = record['mcpServers'];
|
|
115
|
+
if (typeof servers !== 'object' || servers === null) {
|
|
116
|
+
if (strict || record['$schema'] !== undefined || !Object.values(record).every(value => typeof value === 'object' && value !== null)) {
|
|
117
|
+
return { errors: ['mcp.json is missing mcpServers'] };
|
|
118
|
+
}
|
|
119
|
+
servers = record;
|
|
120
|
+
}
|
|
121
|
+
const valid = {};
|
|
122
|
+
for (const [name, value] of Object.entries(servers)) {
|
|
123
|
+
if (typeof value !== 'object' || value === null) {
|
|
124
|
+
errors.push(`server "${name}": not an object`);
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
const server = value;
|
|
128
|
+
// Claude Code dialects: `http`/`streamable-http` are the same remote
|
|
129
|
+
// transport, and `local` or a missing `type` (with `command`) mean stdio.
|
|
130
|
+
let type = typeof server.type === 'string' ? server.type : server.command !== undefined ? 'stdio' : undefined;
|
|
131
|
+
if (type === 'local')
|
|
132
|
+
type = 'stdio';
|
|
133
|
+
if (type === 'http')
|
|
134
|
+
type = 'streamable-http';
|
|
135
|
+
if (type === undefined || !KNOWN_MCP_TRANSPORTS.has(type)) {
|
|
136
|
+
errors.push(`server "${name}": unsupported transport ${JSON.stringify(server.type)} (supported: stdio, streamable-http, sse)`);
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
if (type !== 'stdio') {
|
|
140
|
+
valid[name] = { ...server, type };
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
const stdioServer = server;
|
|
144
|
+
const problems = [];
|
|
145
|
+
if (typeof stdioServer.command !== 'string') {
|
|
146
|
+
errors.push(`server "${name}": stdio servers require a command`);
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
if (stdioServer.command.includes('/')) {
|
|
150
|
+
if (!stdioServer.command.startsWith('./')) {
|
|
151
|
+
problems.push(`command "${stdioServer.command}" must be a bare executable name or a plugin-relative path beginning with "./"`);
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
const reason = await pathContainmentError(pluginRoot, stdioServer.command);
|
|
155
|
+
if (reason !== undefined)
|
|
156
|
+
problems.push(reason);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
if (stdioServer.cwd !== undefined && !stdioServer.cwd.startsWith('${PLUGIN_DATA}')) {
|
|
160
|
+
// `.` is the Codex dialect spelling for the plugin root.
|
|
161
|
+
const cwd = stdioServer.cwd === '.' ? './' : stdioServer.cwd;
|
|
162
|
+
const reason = await pathContainmentError(pluginRoot, cwd);
|
|
163
|
+
if (reason !== undefined)
|
|
164
|
+
problems.push(reason);
|
|
165
|
+
}
|
|
166
|
+
if (problems.length > 0) {
|
|
167
|
+
errors.push(...problems.map(problem => `server "${name}": ${problem}`));
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
valid[name] = { ...server, type: 'stdio' };
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return { config: { schema: typeof record['$schema'] === 'string' ? record['$schema'] : 'native-client', servers: valid }, errors };
|
|
174
|
+
}
|
|
175
|
+
/** Expand `${PLUGIN_ROOT}`, `${PLUGIN_DATA}`, and `${NAME}` (process env) in one string.
|
|
176
|
+
* Claude Code aliases `${CLAUDE_PLUGIN_ROOT}` / `${CLAUDE_PLUGIN_DATA}` and
|
|
177
|
+
* `${NAME:-default}` fallbacks are honored for unset/empty env vars. */
|
|
178
|
+
export function expandPlaceholders(value, pluginRoot, pluginData, env = process.env) {
|
|
179
|
+
return value.replace(/\$\{([A-Za-z_][A-Za-z0-9_]*)(?::-([^}]*))?\}/g, (match, name, fallback) => {
|
|
180
|
+
if (name === 'PLUGIN_ROOT' || name === 'CLAUDE_PLUGIN_ROOT')
|
|
181
|
+
return pluginRoot;
|
|
182
|
+
if (name === 'PLUGIN_DATA' || name === 'CLAUDE_PLUGIN_DATA')
|
|
183
|
+
return pluginData;
|
|
184
|
+
return env[name] || fallback || '';
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
/** Resolve an expanded plugin-relative cwd to an absolute path. */
|
|
188
|
+
export function resolveCwd(value, pluginRoot, pluginData) {
|
|
189
|
+
if (value.startsWith('${PLUGIN_DATA}'))
|
|
190
|
+
return resolve(pluginData, value.slice('${PLUGIN_DATA}'.length).replace(/^\/+/, ''));
|
|
191
|
+
if (value.startsWith('${PLUGIN_ROOT}'))
|
|
192
|
+
return resolve(pluginRoot, value.slice('${PLUGIN_ROOT}'.length).replace(/^\/+/, ''));
|
|
193
|
+
return resolve(pluginRoot, value.replace(/^\.\//, ''));
|
|
194
|
+
}
|
|
195
|
+
/** Whether one absolute path equals or lies under another absolute path. */
|
|
196
|
+
export function isWithin(root, candidate) {
|
|
197
|
+
const relativePath = relative(root, candidate);
|
|
198
|
+
return relativePath === '' || (!relativePath.startsWith('..') && !isAbsolute(relativePath));
|
|
199
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dsh-agent-plugins-market",
|
|
3
|
+
"description": "Bring the Claude Code / Codex / Cursor plugin-marketplace ecosystem into DeepSeek Harness (DSH): install & inject agent plugins — skills, MCP servers, hooks, slash commands — from git marketplace repos (agent-plugins.org v1.0.0, .claude-plugin, .codex-plugin, .cursor-plugin, .kimi-plugin), with a Web GUI market page.",
|
|
4
|
+
"version": "0.4.3",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "lib/index.js",
|
|
7
|
+
"types": "lib/types/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./lib/types/index.d.ts",
|
|
11
|
+
"default": "./lib/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./client": "./client/client.js",
|
|
14
|
+
"./cordis.patch.yml": "./cordis.patch.yml",
|
|
15
|
+
"./package.json": "./package.json"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"lib",
|
|
19
|
+
"client",
|
|
20
|
+
"schemas",
|
|
21
|
+
"cordis.patch.yml",
|
|
22
|
+
"LICENSE",
|
|
23
|
+
"README.md",
|
|
24
|
+
"README.zh.md"
|
|
25
|
+
],
|
|
26
|
+
"scripts": {
|
|
27
|
+
"typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.client.json --noEmit",
|
|
28
|
+
"build": "tsc -p tsconfig.json && pnpm run build:client",
|
|
29
|
+
"build:client": "tsdown && node scripts/normalize-client-banner.mjs",
|
|
30
|
+
"test": "vitest run",
|
|
31
|
+
"prepack": "pnpm run build"
|
|
32
|
+
},
|
|
33
|
+
"dsh": {
|
|
34
|
+
"bundle": {
|
|
35
|
+
"patch": "./cordis.patch.yml"
|
|
36
|
+
},
|
|
37
|
+
"client": {
|
|
38
|
+
"inject": [
|
|
39
|
+
"@deepseek-ai/dsh-client-connection",
|
|
40
|
+
"@deepseek-ai/dsh-client-runtime",
|
|
41
|
+
"@deepseek-ai/dsh-client-locale",
|
|
42
|
+
"@deepseek-ai/dsh-client-ui-settings",
|
|
43
|
+
"@deepseek-ai/dsh-client-ui-theme"
|
|
44
|
+
],
|
|
45
|
+
"platform": "web"
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
"license": "MIT",
|
|
49
|
+
"repository": {
|
|
50
|
+
"type": "git",
|
|
51
|
+
"url": "git+https://github.com/Sivan757/dsh-agent-plugins-market.git"
|
|
52
|
+
},
|
|
53
|
+
"keywords": [
|
|
54
|
+
"deepseek",
|
|
55
|
+
"deepseek-harness",
|
|
56
|
+
"harness",
|
|
57
|
+
"dsh",
|
|
58
|
+
"dsh-plugin",
|
|
59
|
+
"agent-plugins",
|
|
60
|
+
"agent-plugin",
|
|
61
|
+
"plugin-marketplace",
|
|
62
|
+
"marketplace",
|
|
63
|
+
"claude-code",
|
|
64
|
+
"claude",
|
|
65
|
+
"codex",
|
|
66
|
+
"cursor",
|
|
67
|
+
"skills",
|
|
68
|
+
"mcp",
|
|
69
|
+
"mcp-servers",
|
|
70
|
+
"hooks",
|
|
71
|
+
"suite",
|
|
72
|
+
"ai-agents"
|
|
73
|
+
],
|
|
74
|
+
"peerDependencies": {
|
|
75
|
+
"@deepseek-ai/cordis": "^4.0.1",
|
|
76
|
+
"@deepseek-ai/dsh-hooks-claude-code": "^0.1.0-rc.6",
|
|
77
|
+
"@deepseek-ai/dsh-mcp-client": "^0.1.0-rc.6",
|
|
78
|
+
"@deepseek-ai/dsh-skill": "^0.1.0-rc.6"
|
|
79
|
+
},
|
|
80
|
+
"peerDependenciesMeta": {
|
|
81
|
+
"@deepseek-ai/dsh-mcp-client": {
|
|
82
|
+
"optional": true
|
|
83
|
+
},
|
|
84
|
+
"@deepseek-ai/dsh-hooks-claude-code": {
|
|
85
|
+
"optional": true
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
"dependencies": {
|
|
89
|
+
"ajv": "^8.17.1",
|
|
90
|
+
"yaml": "^2.7.0"
|
|
91
|
+
},
|
|
92
|
+
"devDependencies": {
|
|
93
|
+
"@deepseek-ai/cordis": "^4.0.1",
|
|
94
|
+
"@deepseek-ai/dsh-client-ui-primitives": "^0.1.0-rc.6",
|
|
95
|
+
"@deepseek-ai/dsh-hooks-claude-code": "0.1.0-rc.6",
|
|
96
|
+
"@deepseek-ai/dsh-llm": "^0.1.0-rc.6",
|
|
97
|
+
"@deepseek-ai/dsh-mcp-client": "^0.1.0-rc.6",
|
|
98
|
+
"@deepseek-ai/dsh-skill": "^0.1.0-rc.6",
|
|
99
|
+
"@tsdown/css": "^0.22.14",
|
|
100
|
+
"@types/node": "^22.15.0",
|
|
101
|
+
"@types/react": "~18.3.1",
|
|
102
|
+
"@types/react-dom": "^19.2.4",
|
|
103
|
+
"jsdom": "^30.0.1",
|
|
104
|
+
"react": "^18.3.1",
|
|
105
|
+
"react-dom": "~18.3.1",
|
|
106
|
+
"tsdown": "^0.22.14",
|
|
107
|
+
"typescript": "^5.8.3",
|
|
108
|
+
"vitest": "^3.2.4"
|
|
109
|
+
},
|
|
110
|
+
"publishConfig": {
|
|
111
|
+
"registry": "https://registry.npmjs.org/"
|
|
112
|
+
},
|
|
113
|
+
"homepage": "https://www.npmjs.com/package/dsh-agent-plugins-market"
|
|
114
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://agent-plugins.org/schemas/1.0.0/mcp.schema.json",
|
|
4
|
+
"title": "Agent Plugins MCP Configuration",
|
|
5
|
+
"description": "Machine-readable schema for mcp.json in Agent Plugins 1.0.0. The Agent Plugins specification defines additional semantic and operational requirements.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"properties": {
|
|
8
|
+
"$schema": {
|
|
9
|
+
"const": "https://agent-plugins.org/schemas/1.0.0/mcp.schema.json",
|
|
10
|
+
"description": "Canonical identifier of the MCP configuration schema for the Agent Plugins version targeted by this document."
|
|
11
|
+
},
|
|
12
|
+
"mcpServers": {
|
|
13
|
+
"type": "object",
|
|
14
|
+
"additionalProperties": {
|
|
15
|
+
"$ref": "#/$defs/server"
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"required": ["$schema", "mcpServers"],
|
|
20
|
+
"additionalProperties": false,
|
|
21
|
+
"$defs": {
|
|
22
|
+
"server": {
|
|
23
|
+
"title": "MCP server",
|
|
24
|
+
"oneOf": [
|
|
25
|
+
{
|
|
26
|
+
"$ref": "#/$defs/stdioServer"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"$ref": "#/$defs/streamableHttpServer"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"$ref": "#/$defs/sseServer"
|
|
33
|
+
}
|
|
34
|
+
]
|
|
35
|
+
},
|
|
36
|
+
"stdioServer": {
|
|
37
|
+
"title": "stdio MCP server",
|
|
38
|
+
"type": "object",
|
|
39
|
+
"properties": {
|
|
40
|
+
"type": {
|
|
41
|
+
"const": "stdio"
|
|
42
|
+
},
|
|
43
|
+
"command": {
|
|
44
|
+
"type": "string",
|
|
45
|
+
"minLength": 1,
|
|
46
|
+
"description": "Executable token. Resolution rules are defined by the Agent Plugins specification."
|
|
47
|
+
},
|
|
48
|
+
"args": {
|
|
49
|
+
"type": "array",
|
|
50
|
+
"items": {
|
|
51
|
+
"type": "string"
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
"env": {
|
|
55
|
+
"type": "object",
|
|
56
|
+
"propertyNames": {
|
|
57
|
+
"not": {
|
|
58
|
+
"enum": ["PLUGIN_ROOT", "PLUGIN_DATA"]
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
"additionalProperties": {
|
|
62
|
+
"type": "string"
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
"cwd": {
|
|
66
|
+
"type": "string",
|
|
67
|
+
"pattern": "^(?:\\./|\\$\\{PLUGIN_ROOT\\}(?:/|$)|\\$\\{PLUGIN_DATA\\}(?:/|$))",
|
|
68
|
+
"description": "Plugin-relative, PLUGIN_ROOT-rooted, or PLUGIN_DATA-rooted working directory. Filesystem containment is validated separately."
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
"required": ["type", "command"],
|
|
72
|
+
"additionalProperties": false
|
|
73
|
+
},
|
|
74
|
+
"streamableHttpServer": {
|
|
75
|
+
"title": "Streamable HTTP MCP server",
|
|
76
|
+
"type": "object",
|
|
77
|
+
"properties": {
|
|
78
|
+
"type": {
|
|
79
|
+
"const": "streamable-http"
|
|
80
|
+
},
|
|
81
|
+
"url": {
|
|
82
|
+
"type": "string",
|
|
83
|
+
"minLength": 1,
|
|
84
|
+
"description": "MCP endpoint URL. URL semantics are defined by the Agent Plugins specification."
|
|
85
|
+
},
|
|
86
|
+
"headers": {
|
|
87
|
+
"$ref": "#/$defs/headers"
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
"required": ["type", "url"],
|
|
91
|
+
"additionalProperties": false
|
|
92
|
+
},
|
|
93
|
+
"sseServer": {
|
|
94
|
+
"title": "Legacy HTTP+SSE MCP server",
|
|
95
|
+
"type": "object",
|
|
96
|
+
"properties": {
|
|
97
|
+
"type": {
|
|
98
|
+
"const": "sse"
|
|
99
|
+
},
|
|
100
|
+
"url": {
|
|
101
|
+
"type": "string",
|
|
102
|
+
"minLength": 1,
|
|
103
|
+
"description": "MCP endpoint URL. URL semantics are defined by the Agent Plugins specification."
|
|
104
|
+
},
|
|
105
|
+
"headers": {
|
|
106
|
+
"$ref": "#/$defs/headers"
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
"required": ["type", "url"],
|
|
110
|
+
"additionalProperties": false
|
|
111
|
+
},
|
|
112
|
+
"headers": {
|
|
113
|
+
"title": "HTTP headers",
|
|
114
|
+
"type": "object",
|
|
115
|
+
"additionalProperties": {
|
|
116
|
+
"type": "string"
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
|
|
4
|
+
"title": "Agent Plugins Manifest",
|
|
5
|
+
"description": "Machine-readable schema for plugin.json in Agent Plugins 1.0.0. The Agent Plugins specification defines additional semantic and operational requirements.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"properties": {
|
|
8
|
+
"$schema": {
|
|
9
|
+
"const": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
|
|
10
|
+
"description": "Canonical identifier of the plugin manifest schema for the Agent Plugins version targeted by this document."
|
|
11
|
+
},
|
|
12
|
+
"name": {
|
|
13
|
+
"type": "string",
|
|
14
|
+
"minLength": 1,
|
|
15
|
+
"maxLength": 64,
|
|
16
|
+
"pattern": "^(?!.*(?:--|\\.\\.))[a-z0-9](?:[a-z0-9.-]*[a-z0-9])?$",
|
|
17
|
+
"description": "Human-readable plugin name."
|
|
18
|
+
},
|
|
19
|
+
"version": {
|
|
20
|
+
"type": "string"
|
|
21
|
+
},
|
|
22
|
+
"description": {
|
|
23
|
+
"type": "string"
|
|
24
|
+
},
|
|
25
|
+
"author": {
|
|
26
|
+
"type": "object",
|
|
27
|
+
"properties": {
|
|
28
|
+
"name": {
|
|
29
|
+
"type": "string"
|
|
30
|
+
},
|
|
31
|
+
"email": {
|
|
32
|
+
"type": "string"
|
|
33
|
+
},
|
|
34
|
+
"url": {
|
|
35
|
+
"type": "string"
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"additionalProperties": false
|
|
39
|
+
},
|
|
40
|
+
"homepage": {
|
|
41
|
+
"type": "string"
|
|
42
|
+
},
|
|
43
|
+
"repository": {
|
|
44
|
+
"type": "string"
|
|
45
|
+
},
|
|
46
|
+
"license": {
|
|
47
|
+
"type": "string"
|
|
48
|
+
},
|
|
49
|
+
"keywords": {
|
|
50
|
+
"type": "array",
|
|
51
|
+
"items": {
|
|
52
|
+
"type": "string"
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
"extensions": {
|
|
56
|
+
"type": "object",
|
|
57
|
+
"description": "Client-specific manifest data keyed by reverse-domain extension namespace. Agent Plugins assigns no semantics to namespace object contents.",
|
|
58
|
+
"additionalProperties": {
|
|
59
|
+
"type": "object"
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
"required": ["$schema", "name"],
|
|
64
|
+
"additionalProperties": false
|
|
65
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Vendored Agent Plugins JSON Schemas
|
|
2
|
+
|
|
3
|
+
These files are pinned copies of the official Agent Plugins 1.0.0 schemas:
|
|
4
|
+
|
|
5
|
+
- source: https://github.com/agentplugins/agent-plugins-spec (schemas/1.0.0/)
|
|
6
|
+
- spec status: version 1.0.0, working draft
|
|
7
|
+
- license: the Agent Plugins specification repository's license
|
|
8
|
+
|
|
9
|
+
They are bundled into the published package because the specification requires
|
|
10
|
+
clients to validate plugin packages without retrieving schemas at load time
|
|
11
|
+
(§7.2.1: "Clients MUST NOT retrieve a schema while loading a plugin").
|
|
12
|
+
|
|
13
|
+
Update procedure: replace both files from the upstream repository at the pinned
|
|
14
|
+
spec version and bump the spec-version references in `src/validate.ts`.
|