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.
Files changed (54) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/README.md +109 -19
  3. package/dist/agent-plugins.d.ts +6 -0
  4. package/dist/agent-plugins.js +76 -0
  5. package/dist/cdp.d.ts +49 -0
  6. package/dist/cdp.js +253 -0
  7. package/dist/checks/ard.d.ts +67 -0
  8. package/dist/checks/ard.js +215 -0
  9. package/dist/checks/auth.js +2 -1
  10. package/dist/checks/chain.d.ts +45 -0
  11. package/dist/checks/chain.js +171 -0
  12. package/dist/checks/listing.js +23 -14
  13. package/dist/checks/oauth.d.ts +45 -0
  14. package/dist/checks/oauth.js +64 -0
  15. package/dist/checks/readiness.d.ts +58 -0
  16. package/dist/checks/readiness.js +230 -0
  17. package/dist/checks/tools.js +120 -7
  18. package/dist/checks/vercel.d.ts +27 -0
  19. package/dist/checks/vercel.js +153 -0
  20. package/dist/cli.js +54 -6
  21. package/dist/core.d.ts +1 -0
  22. package/dist/core.js +21 -5
  23. package/dist/demo.d.ts +60 -0
  24. package/dist/demo.js +573 -0
  25. package/dist/drift.js +17 -7
  26. package/dist/evals.d.ts +34 -0
  27. package/dist/evals.js +75 -0
  28. package/dist/extras.js +1 -1
  29. package/dist/images.d.ts +21 -0
  30. package/dist/images.js +99 -0
  31. package/dist/listings.d.ts +14 -0
  32. package/dist/listings.js +39 -0
  33. package/dist/mcp-client.d.ts +1 -5
  34. package/dist/mcp-client.js +8 -1
  35. package/dist/mcp-server.js +21 -11
  36. package/dist/packs.d.ts +53 -18
  37. package/dist/packs.js +426 -92
  38. package/dist/report.js +30 -13
  39. package/dist/skills.d.ts +21 -0
  40. package/dist/skills.js +180 -0
  41. package/dist/submissions.js +2 -1
  42. package/dist/types.d.ts +37 -4
  43. package/dist/types.js +1 -0
  44. package/dist/version.d.ts +1 -1
  45. package/dist/version.js +1 -1
  46. package/dist/video.d.ts +58 -0
  47. package/dist/video.js +190 -0
  48. package/dist/zip.d.ts +16 -2
  49. package/dist/zip.js +65 -5
  50. package/package.json +4 -1
  51. package/schema.json +86 -12
  52. package/schemas/agent-plugins-1.0.0/LICENSE +202 -0
  53. package/schemas/agent-plugins-1.0.0/mcp.schema.json +120 -0
  54. 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 { chatgptPack, claudePack, directoriesPack, simplePack, writePack } from './packs.js';
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 store = positionals[0] === 'directories' ? null : asStore(positionals[0]);
144
- const token = values.token ?? process.env.MCPLANE_TOKEN;
145
- const pack = !store ? directoriesPack(m) : store === 'chatgpt' ? await chatgptPack(m, token) : store === 'claude-connectors' ? await claudePack(m, token) : await simplePack(m, store);
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
- console.log(`Wrote ${written.join(', ')}`);
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('Tool-annotation justifications are cut at 200 characters without warning.');
24
- r.push('ChatGPT allows one version in review at a time. To change a submission, Cancel Review and resubmit the same draft.');
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
- const [authC, listing, repo] = await Promise.all([
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 all = [...server.checks, ...authC, ...toolChecks(server.tools), ...listing, ...repo];
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
+ };