mcplane 0.4.1 → 0.5.1
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/CHANGELOG.md +37 -0
- package/README.md +109 -19
- package/dist/agent-plugins.d.ts +6 -0
- package/dist/agent-plugins.js +76 -0
- package/dist/cdp.d.ts +49 -0
- package/dist/cdp.js +253 -0
- package/dist/checks/ard.d.ts +67 -0
- package/dist/checks/ard.js +215 -0
- package/dist/checks/auth.js +2 -1
- package/dist/checks/chain.d.ts +45 -0
- package/dist/checks/chain.js +171 -0
- package/dist/checks/listing.js +23 -14
- package/dist/checks/oauth.d.ts +45 -0
- package/dist/checks/oauth.js +64 -0
- package/dist/checks/readiness.d.ts +58 -0
- package/dist/checks/readiness.js +230 -0
- package/dist/checks/tools.js +120 -7
- package/dist/checks/vercel.d.ts +27 -0
- package/dist/checks/vercel.js +153 -0
- package/dist/cli.js +54 -6
- package/dist/core.d.ts +1 -0
- package/dist/core.js +21 -5
- package/dist/demo.d.ts +60 -0
- package/dist/demo.js +573 -0
- package/dist/drift.js +17 -7
- package/dist/evals.d.ts +34 -0
- package/dist/evals.js +75 -0
- package/dist/extras.js +1 -1
- package/dist/images.d.ts +21 -0
- package/dist/images.js +99 -0
- package/dist/listings.d.ts +14 -0
- package/dist/listings.js +39 -0
- package/dist/mcp-client.d.ts +1 -5
- package/dist/mcp-client.js +8 -1
- package/dist/mcp-server.js +21 -11
- package/dist/packs.d.ts +53 -18
- package/dist/packs.js +426 -92
- package/dist/report.js +30 -13
- package/dist/skills.d.ts +21 -0
- package/dist/skills.js +180 -0
- package/dist/submissions.js +2 -1
- package/dist/types.d.ts +37 -4
- package/dist/types.js +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/video.d.ts +58 -0
- package/dist/video.js +190 -0
- package/dist/zip.d.ts +16 -2
- package/dist/zip.js +65 -5
- package/package.json +4 -1
- package/schema.json +86 -12
- package/schemas/agent-plugins-1.0.0/LICENSE +202 -0
- package/schemas/agent-plugins-1.0.0/mcp.schema.json +120 -0
- package/schemas/agent-plugins-1.0.0/plugin.schema.json +65 -0
package/dist/cli.js
CHANGED
|
@@ -7,7 +7,7 @@ import { preflight } from './preflight.js';
|
|
|
7
7
|
import { printPreflight } from './report.js';
|
|
8
8
|
import { STORE_NAMES } from './types.js';
|
|
9
9
|
import { recordDecision, recordSubmitted, status } from './submissions.js';
|
|
10
|
-
import {
|
|
10
|
+
import { PACKS, packFor, writePack } from './packs.js';
|
|
11
11
|
import { drift, printDrift, takeSnapshot } from './drift.js';
|
|
12
12
|
import { publish } from './publish.js';
|
|
13
13
|
import { lanes, runLane, tryLinks } from './extras.js';
|
|
@@ -23,18 +23,30 @@ Usage
|
|
|
23
23
|
--verbose List passing checks too
|
|
24
24
|
--register Also test OAuth client registration (writes test clients)
|
|
25
25
|
--token <token> Access token for servers behind sign-in (or MCPLANE_TOKEN)
|
|
26
|
+
--sign-in <url> A sign-in page your consent screen uses, checked for bot walls (repeatable)
|
|
26
27
|
mcplane submitted <store> Record a submission and log it to Review Times
|
|
27
28
|
--date YYYY-MM-DD --kind new|update|resubmission --version x.y.z
|
|
28
29
|
--app-id asdk_app_... ChatGPT: your app id, so its draft date is checked
|
|
29
30
|
--private Keep it local; don't log to Review Times
|
|
30
31
|
mcplane decided <store> approved|rejected|withdrawn [--date YYYY-MM-DD]
|
|
31
32
|
mcplane status Every submission, how long it's waited, and the store's typical wait
|
|
32
|
-
mcplane pack <store> Write a submission pack to .mcplane/packs (chatgpt, claude-connectors, cursor, muse, directories)
|
|
33
|
+
mcplane pack <store> Write a submission pack to .mcplane/packs (chatgpt, claude-connectors, vercel-connect, cursor, muse, directories)
|
|
34
|
+
pack ard An ARD manifest for /.well-known/ard.json
|
|
35
|
+
pack claude-eval A "claude plugin eval" suite from your review tests
|
|
36
|
+
--tools <file> A saved tools/list result, for servers behind sign-in (or pass --token)
|
|
33
37
|
mcplane drift [--store <id>]... What changed since each store saw your server, and what each needs
|
|
34
38
|
--ci Exit 1 when a store needs a new version or an edit
|
|
35
39
|
mcplane baseline <store> [--version x.y.z] Record a listing that's already live as the drift baseline
|
|
36
40
|
mcplane publish <store> [--yes] Publish where the store allows it (mcp-registry, grok); dry run without --yes
|
|
37
41
|
mcplane try Install links for every client, for you and your testers
|
|
42
|
+
mcplane demo Record the review demo video in ChatGPT desktop from your positive tests (macOS)
|
|
43
|
+
--only 1,3 Which tests to record (default: all)
|
|
44
|
+
--out <file> Where to write it (default: .mcplane/packs/chatgpt/demo.mp4)
|
|
45
|
+
--approve Click "Allow once" when ChatGPT asks to run a tool
|
|
46
|
+
--plugin <name> The plugin to @mention, as ChatGPT names it (default: title)
|
|
47
|
+
--work Record in Work mode instead of Chat
|
|
48
|
+
--keep-open Leave ChatGPT running afterwards
|
|
49
|
+
--yes Don't ask before driving ChatGPT
|
|
38
50
|
mcplane listings [--store <id>]... Where you're listed, and whether what went live matches your server (--ci)
|
|
39
51
|
mcplane lanes List lanes; run one with "mcplane <lane>" (built in: check, watch, release)
|
|
40
52
|
mcplane fleet [--root <dir>] Every project under a folder: blockers, store updates needed, reviews waiting
|
|
@@ -65,6 +77,8 @@ async function main() {
|
|
|
65
77
|
verbose: { type: 'boolean' },
|
|
66
78
|
register: { type: 'boolean' },
|
|
67
79
|
token: { type: 'string' },
|
|
80
|
+
tools: { type: 'string' },
|
|
81
|
+
'sign-in': { type: 'string', multiple: true },
|
|
68
82
|
date: { type: 'string' },
|
|
69
83
|
kind: { type: 'string' },
|
|
70
84
|
version: { type: 'string' },
|
|
@@ -74,6 +88,13 @@ async function main() {
|
|
|
74
88
|
root: { type: 'string' },
|
|
75
89
|
quick: { type: 'boolean' },
|
|
76
90
|
yes: { type: 'boolean' },
|
|
91
|
+
only: { type: 'string' },
|
|
92
|
+
out: { type: 'string' },
|
|
93
|
+
approve: { type: 'boolean' },
|
|
94
|
+
plugin: { type: 'string' },
|
|
95
|
+
work: { type: 'boolean' },
|
|
96
|
+
'keep-open': { type: 'boolean' },
|
|
97
|
+
port: { type: 'string' },
|
|
77
98
|
},
|
|
78
99
|
allowPositionals: true,
|
|
79
100
|
});
|
|
@@ -108,6 +129,8 @@ async function main() {
|
|
|
108
129
|
}
|
|
109
130
|
if (cmd === 'preflight') {
|
|
110
131
|
const m = values.url ? await draftManifest(values.url) : await loadManifest();
|
|
132
|
+
if (values['sign-in']?.length)
|
|
133
|
+
m.server.signIn = [...(m.server.signIn ?? []), ...values['sign-in']];
|
|
111
134
|
const stores = (values.store ?? []);
|
|
112
135
|
for (const s of stores)
|
|
113
136
|
if (!(s in STORE_NAMES))
|
|
@@ -140,11 +163,13 @@ async function main() {
|
|
|
140
163
|
}
|
|
141
164
|
if (cmd === 'pack') {
|
|
142
165
|
const m = await loadManifest();
|
|
143
|
-
const
|
|
144
|
-
|
|
145
|
-
|
|
166
|
+
const name = positionals[0];
|
|
167
|
+
if (!PACKS.includes(name))
|
|
168
|
+
asStore(name);
|
|
169
|
+
const pack = await packFor(m, name, { token: values.token ?? process.env.MCPLANE_TOKEN, tools: values.tools });
|
|
146
170
|
const written = await writePack(pack);
|
|
147
|
-
|
|
171
|
+
const dirs = [...new Set(written.map((w) => w.split('/').slice(0, 3).join('/')))];
|
|
172
|
+
console.log(written.length > 6 ? `Wrote ${written.length} files under ${dirs.join(', ')}/` : `Wrote ${written.join(', ')}`);
|
|
148
173
|
if (pack.problems.length) {
|
|
149
174
|
console.log('\nFix before submitting:');
|
|
150
175
|
for (const p of pack.problems)
|
|
@@ -226,6 +251,29 @@ async function main() {
|
|
|
226
251
|
console.log(`${t.client.padEnd(22)} ${t.how}`);
|
|
227
252
|
return;
|
|
228
253
|
}
|
|
254
|
+
if (cmd === 'demo') {
|
|
255
|
+
const m = await loadManifest();
|
|
256
|
+
if (values.port && !/^\d+$/.test(values.port))
|
|
257
|
+
throw new Error('--port takes a port number, e.g. 9333.');
|
|
258
|
+
const { demo } = await import('./demo.js');
|
|
259
|
+
const r = await demo(m, {
|
|
260
|
+
only: values.only,
|
|
261
|
+
out: values.out,
|
|
262
|
+
approve: values.approve,
|
|
263
|
+
plugin: values.plugin,
|
|
264
|
+
work: values.work,
|
|
265
|
+
keepOpen: values['keep-open'],
|
|
266
|
+
yes: values.yes,
|
|
267
|
+
port: values.port ? Number(values.port) : undefined,
|
|
268
|
+
token: values.token ?? process.env.MCPLANE_TOKEN,
|
|
269
|
+
});
|
|
270
|
+
const mins = Math.floor(r.seconds / 60);
|
|
271
|
+
console.log(`\nWrote ${r.out} (${r.scenes} scene${r.scenes === 1 ? '' : 's'}, ${mins ? `${mins}m ` : ''}${Math.round(r.seconds % 60)}s).`);
|
|
272
|
+
for (const n of r.notes)
|
|
273
|
+
console.log(` ! ${n}`);
|
|
274
|
+
console.log('Watch it, upload it where a reviewer can open it without signing in, set chatgpt.demoVideo to that URL, then run "mcplane pack chatgpt".');
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
229
277
|
if (cmd === 'listings' || cmd === 'pull') {
|
|
230
278
|
const m = await loadManifest();
|
|
231
279
|
const stores = (values.store?.length ? values.store : storesOf(m));
|
package/dist/core.d.ts
CHANGED
|
@@ -14,5 +14,6 @@ export declare function preflight(m: Manifest, opts?: {
|
|
|
14
14
|
}): Promise<PreflightResult>;
|
|
15
15
|
export { draftManifest, forStore, storesOf, SCHEMA_URL } from './draft.js';
|
|
16
16
|
export { toolChecks } from './checks/tools.js';
|
|
17
|
+
export { validateArd, ardManifest } from './checks/ard.js';
|
|
17
18
|
export { STORE_NAMES } from './types.js';
|
|
18
19
|
export type { Check, Level, Manifest, StoreId, Tool } from './types.js';
|
package/dist/core.js
CHANGED
|
@@ -2,10 +2,15 @@
|
|
|
2
2
|
* mcplane's checks for any runtime with fetch (Workers, Deno, browsers' servers).
|
|
3
3
|
* Import from "mcplane/core".
|
|
4
4
|
*/
|
|
5
|
+
import { ardChecks } from './checks/ard.js';
|
|
5
6
|
import { authChecks } from './checks/auth.js';
|
|
7
|
+
import { chainChecks } from './checks/chain.js';
|
|
6
8
|
import { listingChecks, repoChecks } from './checks/listing.js';
|
|
9
|
+
import { discover } from './checks/oauth.js';
|
|
10
|
+
import { readinessChecks } from './checks/readiness.js';
|
|
7
11
|
import { serverChecks } from './checks/server.js';
|
|
8
12
|
import { toolChecks } from './checks/tools.js';
|
|
13
|
+
import { VERCEL_REMINDERS, vercelChecks } from './checks/vercel.js';
|
|
9
14
|
import { storesOf } from './draft.js';
|
|
10
15
|
/** Things no script can see, which have still cost real submissions. */
|
|
11
16
|
function reminders(m, stores) {
|
|
@@ -18,10 +23,10 @@ function reminders(m, stores) {
|
|
|
18
23
|
r.push('If a tool writes somewhere public (posts, sends, publishes), give reviewers a safe target: a sandbox account or a "playground" option that validates and then discards. Reviewers test writes; they shouldn’t post to a real timeline.');
|
|
19
24
|
}
|
|
20
25
|
if (stores.includes('chatgpt')) {
|
|
21
|
-
r.push('ChatGPT needs a demo video recorded in developer mode that shows the tools your test cases use. Re-record it whenever tools change.');
|
|
26
|
+
r.push('ChatGPT needs a demo video recorded in developer mode that shows the tools your test cases use. Re-record it whenever tools change ("mcplane demo" records it on a Mac with ChatGPT desktop).');
|
|
22
27
|
r.push('After "Submit for Review" the ChatGPT portal shows nothing for about 20 seconds. Confirm the status on the plugins list, not the button.');
|
|
23
|
-
r.push('
|
|
24
|
-
r.push('ChatGPT allows one version in review at a time. To change a submission, Cancel Review
|
|
28
|
+
r.push('OpenAI no longer asks for hint justifications: its automated review checks each tool’s hints. If it flags one you believe is right, appeal with an explanation.');
|
|
29
|
+
r.push('ChatGPT allows one version in review at a time, and a rescan doesn’t update the tools it was submitted with. To change a submission, Cancel Review (back to Draft), reconnect if tools changed so ChatGPT rediscovers them, and resubmit.');
|
|
25
30
|
}
|
|
26
31
|
if (stores.includes('claude-connectors') || stores.includes('claude-plugins')) {
|
|
27
32
|
if (stores.includes('claude-connectors'))
|
|
@@ -30,6 +35,8 @@ function reminders(m, stores) {
|
|
|
30
35
|
r.push('Run "claude plugin validate --strict" in the plugin repo; the portal validates every commit on the branch it tracks.');
|
|
31
36
|
r.push('Claude: "Passed review" is not the same as listed. Check claude.ai/directory for your listing after approval; with the new portal you choose when to publish.');
|
|
32
37
|
}
|
|
38
|
+
if (stores.includes('vercel-connect') && m.server.auth === 'oauth')
|
|
39
|
+
r.push(...VERCEL_REMINDERS);
|
|
33
40
|
return r;
|
|
34
41
|
}
|
|
35
42
|
/** Runtime-neutral: fetch only. Node adds socket checks (TLS 1.2) through extraChecks; see preflight-node. */
|
|
@@ -37,16 +44,25 @@ export async function preflight(m, opts = {}) {
|
|
|
37
44
|
const stores = opts.stores?.length ? opts.stores : storesOf(m);
|
|
38
45
|
const auth = m.server.auth ?? 'none';
|
|
39
46
|
const server = await serverChecks(m.server.url, auth, opts.token, opts.extraChecks);
|
|
40
|
-
|
|
47
|
+
// One read of the OAuth discovery documents, shared by the sign-in chain, Vercel Connect and readiness checks.
|
|
48
|
+
const oauth = auth === 'oauth' ? await discover(m.server.url).catch(() => null) : null;
|
|
49
|
+
// A server that doesn't answer at all has already failed; probing it for the next revision adds nothing.
|
|
50
|
+
const down = server.checks.some((c) => c.id === 'server.reachable' && c.level === 'fail');
|
|
51
|
+
const [authC, chain, listing, repo, ard, readiness] = await Promise.all([
|
|
41
52
|
auth === 'oauth' ? authChecks(m.server.url, { register: opts.register }) : Promise.resolve([]),
|
|
53
|
+
auth === 'oauth' ? chainChecks(m, oauth).catch(() => []) : Promise.resolve([]),
|
|
42
54
|
listingChecks(m, server.tools, stores),
|
|
43
55
|
repoChecks(m, stores),
|
|
56
|
+
ardChecks(m),
|
|
57
|
+
down ? Promise.resolve([]) : readinessChecks(m.server.url, auth, { token: opts.token, oauth }),
|
|
44
58
|
]);
|
|
45
|
-
const
|
|
59
|
+
const vercel = stores.includes('vercel-connect') ? vercelChecks(m, oauth) : [];
|
|
60
|
+
const all = [...server.checks, ...authC, ...chain, ...toolChecks(server.tools), ...listing, ...repo, ...vercel, ...ard, ...readiness];
|
|
46
61
|
// Keep checks that apply to every store or to one we're submitting to.
|
|
47
62
|
const checks = all.filter((c) => !c.stores?.length || c.stores.some((s) => stores.includes(s)));
|
|
48
63
|
return { checks, reminders: reminders(m, stores), stores };
|
|
49
64
|
}
|
|
50
65
|
export { draftManifest, forStore, storesOf, SCHEMA_URL } from './draft.js';
|
|
51
66
|
export { toolChecks } from './checks/tools.js';
|
|
67
|
+
export { validateArd, ardManifest } from './checks/ard.js';
|
|
52
68
|
export { STORE_NAMES } from './types.js';
|
package/dist/demo.d.ts
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { Manifest } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Every label mcplane relies on in ChatGPT desktop (checked against 26.903, 1 October 2026).
|
|
4
|
+
* When a release renames something, this is the one place to fix.
|
|
5
|
+
*/
|
|
6
|
+
export declare const UI: {
|
|
7
|
+
hideSidebar: string;
|
|
8
|
+
showSidebar: string;
|
|
9
|
+
newChat: string;
|
|
10
|
+
chatMode: string;
|
|
11
|
+
workMode: string;
|
|
12
|
+
addMenu: string;
|
|
13
|
+
send: string[];
|
|
14
|
+
stop: string[];
|
|
15
|
+
/** Buttons on a tool approval card. */
|
|
16
|
+
approval: string[];
|
|
17
|
+
/** What --approve clicks, first match wins. Never "Always allow": a demo shouldn't change your settings. */
|
|
18
|
+
allow: string[];
|
|
19
|
+
/** The collapsed summary of tool calls ("Worked for 5s"), opened at the end of each scene. */
|
|
20
|
+
activity: string;
|
|
21
|
+
signIn: string[];
|
|
22
|
+
/** Part of the message box's accessible name: "Message ChatGPT", "Ask ChatGPT", "Work with ChatGPT". */
|
|
23
|
+
composer: string;
|
|
24
|
+
/** The @mention pill keeps the plugin's id here; developer-mode plugins are "created-by-me". */
|
|
25
|
+
mentionAttr: string;
|
|
26
|
+
devMode: string;
|
|
27
|
+
};
|
|
28
|
+
/** "1,3" or "2-4" to zero-based indexes into the positive tests, in the order given. */
|
|
29
|
+
export declare function pickTests(count: number, only?: string): number[];
|
|
30
|
+
export interface DemoOptions {
|
|
31
|
+
/** Positive tests to record, e.g. "1,3" (default: all). */
|
|
32
|
+
only?: string;
|
|
33
|
+
/** Where to write the video (default: .mcplane/packs/chatgpt/demo.mp4). */
|
|
34
|
+
out?: string;
|
|
35
|
+
/** Click "Allow once" on tool approval cards. */
|
|
36
|
+
approve?: boolean;
|
|
37
|
+
/** Leave ChatGPT running afterwards (it keeps its debugging port open until you quit it). */
|
|
38
|
+
keepOpen?: boolean;
|
|
39
|
+
/** Don't ask first. */
|
|
40
|
+
yes?: boolean;
|
|
41
|
+
/** The plugin to @mention (default: the manifest's title). */
|
|
42
|
+
plugin?: string;
|
|
43
|
+
/** Record in Work mode instead of Chat. */
|
|
44
|
+
work?: boolean;
|
|
45
|
+
port?: number;
|
|
46
|
+
token?: string;
|
|
47
|
+
dir?: string;
|
|
48
|
+
log?: (line: string) => void;
|
|
49
|
+
}
|
|
50
|
+
export interface DemoResult {
|
|
51
|
+
out: string;
|
|
52
|
+
seconds: number;
|
|
53
|
+
scenes: number;
|
|
54
|
+
notes: string[];
|
|
55
|
+
}
|
|
56
|
+
export declare function demo(m: Manifest, o?: DemoOptions): Promise<DemoResult>;
|
|
57
|
+
export declare const _test: {
|
|
58
|
+
pickTests: typeof pickTests;
|
|
59
|
+
PAGE: string;
|
|
60
|
+
};
|