apiblaze 0.21.58 → 0.21.60
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/dist/index.js +44 -7
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -34,7 +34,7 @@ var __toESM = (mod, isNodeMode, target2) => (target2 = mod != null ? __create(__
|
|
|
34
34
|
var version;
|
|
35
35
|
var init_package = __esm({
|
|
36
36
|
"package.json"() {
|
|
37
|
-
version = "0.21.
|
|
37
|
+
version = "0.21.60";
|
|
38
38
|
}
|
|
39
39
|
});
|
|
40
40
|
|
|
@@ -5302,6 +5302,7 @@ var init_directory_probes = __esm({
|
|
|
5302
5302
|
var directory_exports = {};
|
|
5303
5303
|
__export(directory_exports, {
|
|
5304
5304
|
ATTESTATIONS: () => ATTESTATIONS,
|
|
5305
|
+
AUTH_MODES: () => AUTH_MODES,
|
|
5305
5306
|
PLATFORMS: () => PLATFORMS,
|
|
5306
5307
|
attestationId: () => attestationId,
|
|
5307
5308
|
blockerLines: () => blockerLines,
|
|
@@ -5309,6 +5310,7 @@ __export(directory_exports, {
|
|
|
5309
5310
|
fetchDirectoryReport: () => fetchDirectoryReport,
|
|
5310
5311
|
isApiError: () => isApiError,
|
|
5311
5312
|
isReady: () => isReady,
|
|
5313
|
+
parseAuthMode: () => parseAuthMode,
|
|
5312
5314
|
parseCompliant: () => parseCompliant,
|
|
5313
5315
|
parsePlatforms: () => parsePlatforms,
|
|
5314
5316
|
printReport: () => printReport
|
|
@@ -5317,6 +5319,12 @@ function attestationId(flag) {
|
|
|
5317
5319
|
const f = flag.trim().toLowerCase();
|
|
5318
5320
|
return ATTESTATIONS.find((a) => a.id === f || a.flags.includes(f))?.id ?? null;
|
|
5319
5321
|
}
|
|
5322
|
+
function parseAuthMode(raw) {
|
|
5323
|
+
if (raw === void 0) return void 0;
|
|
5324
|
+
const v = String(raw).trim().toLowerCase();
|
|
5325
|
+
if (AUTH_MODES.includes(v)) return v;
|
|
5326
|
+
throw new Error(`Unknown --auth-mode "${raw}". Use signin (OAuth sign-in, the default) or open (no sign-in: public, read-only data).`);
|
|
5327
|
+
}
|
|
5320
5328
|
function directoryBodyFromFlags(f) {
|
|
5321
5329
|
const m = {};
|
|
5322
5330
|
if (f.privacyUrl) m.privacy_url = f.privacyUrl;
|
|
@@ -5329,6 +5337,8 @@ function directoryBodyFromFlags(f) {
|
|
|
5329
5337
|
if (f.iconUrl) m.icon_url = f.iconUrl;
|
|
5330
5338
|
if (f.vulnContact) m.vuln_contact = f.vulnContact;
|
|
5331
5339
|
if (f.allowedOrigin?.length) m.allowed_origins = f.allowedOrigin.map((o) => o.trim()).filter(Boolean);
|
|
5340
|
+
const mode = parseAuthMode(f.authMode);
|
|
5341
|
+
if (mode) m.auth_mode = mode;
|
|
5332
5342
|
const out = {};
|
|
5333
5343
|
if (Object.keys(m).length) out.directory_metadata = m;
|
|
5334
5344
|
if (f.openaiChallenge?.trim()) out.openai_challenge_token = f.openaiChallenge.trim();
|
|
@@ -5409,7 +5419,7 @@ function blockerLines(r, platforms) {
|
|
|
5409
5419
|
function isApiError(e, status2) {
|
|
5410
5420
|
return e instanceof ApiError && (status2 === void 0 || e.status === status2);
|
|
5411
5421
|
}
|
|
5412
|
-
var import_chalk17, PLATFORMS, ATTESTATIONS, reportPath;
|
|
5422
|
+
var import_chalk17, PLATFORMS, ATTESTATIONS, AUTH_MODES, reportPath;
|
|
5413
5423
|
var init_directory = __esm({
|
|
5414
5424
|
"src/lib/directory.ts"() {
|
|
5415
5425
|
"use strict";
|
|
@@ -5432,6 +5442,7 @@ var init_directory = __esm({
|
|
|
5432
5442
|
{ id: "content_13_no_ads", flags: ["content-13-no-ads", "content-13", "content_13_no_ads"], label: "Content suitable for 13+ and no advertising (ChatGPT)", platforms: ["chatgpt"] },
|
|
5433
5443
|
{ id: "no_restricted_data", flags: ["no-restricted-data", "no_restricted_data"], label: "No card data, health records, government ids or credentials are collected (ChatGPT)", platforms: ["chatgpt"] }
|
|
5434
5444
|
];
|
|
5445
|
+
AUTH_MODES = ["signin", "open"];
|
|
5435
5446
|
reportPath = (proj2) => `/projects/${encodeURIComponent(proj2.projectId)}/${encodeURIComponent(proj2.apiVersion)}/directory-report`;
|
|
5436
5447
|
}
|
|
5437
5448
|
});
|
|
@@ -11039,6 +11050,27 @@ async function promptForMissing(r, interactive2, defaults = { prompts: [] }, pla
|
|
|
11039
11050
|
}
|
|
11040
11051
|
return out;
|
|
11041
11052
|
}
|
|
11053
|
+
function isOpenMode(r) {
|
|
11054
|
+
return r.target?.project?.authMode === "open";
|
|
11055
|
+
}
|
|
11056
|
+
function toolReadsOnly(t) {
|
|
11057
|
+
if (t.annotations && typeof t.annotations.readOnlyHint === "boolean") return t.annotations.readOnlyHint && t.annotations.destructiveHint !== true;
|
|
11058
|
+
return /^(get|head)$/i.test((t.method ?? "").trim());
|
|
11059
|
+
}
|
|
11060
|
+
var OPEN_MODE_QUESTION = "Every tool only reads. Is this public data that needs no account? Then the connector can skip sign-in (Anthropic allows it for public data; your API host keeps its own keys).";
|
|
11061
|
+
async function askOpenMode(caller, proj2, r, opts, interactive2, say) {
|
|
11062
|
+
if (opts.authMode !== void 0) return false;
|
|
11063
|
+
if (isOpenMode(r)) return false;
|
|
11064
|
+
const tools = r.target?.tools ?? [];
|
|
11065
|
+
if (!tools.length || !tools.every(toolReadsOnly)) return false;
|
|
11066
|
+
if (!interactive2) return false;
|
|
11067
|
+
const { default: inquirer3 } = await import("inquirer");
|
|
11068
|
+
const { open } = await inquirer3.prompt([{ type: "confirm", name: "open", message: OPEN_MODE_QUESTION, default: false }]);
|
|
11069
|
+
if (!open) return false;
|
|
11070
|
+
await patchProject(caller, proj2, { directory_metadata: { auth_mode: "open" } }, "Open mode: no sign-in on the connector");
|
|
11071
|
+
say(import_chalk28.default.green(" \u2713 open mode: the connector takes no sign-in (public data); no reviewer account is needed."));
|
|
11072
|
+
return true;
|
|
11073
|
+
}
|
|
11042
11074
|
async function promptListingBasics(r, interactive2, defaults, given, platforms = PLATFORMS) {
|
|
11043
11075
|
const meta = r.target?.metadata ?? {};
|
|
11044
11076
|
const gpt = platforms.includes("chatgpt");
|
|
@@ -11293,6 +11325,7 @@ async function runConnector(target2, opts) {
|
|
|
11293
11325
|
const changed = await fixToolDescriptions(proj2, r.report.project.environment, interactive2, say);
|
|
11294
11326
|
if (changed) r = await fetchDirectoryReport(caller, proj2, { platforms });
|
|
11295
11327
|
}
|
|
11328
|
+
if (await askOpenMode(caller, proj2, r, opts, interactive2, say)) r = await fetchDirectoryReport(caller, proj2, { platforms });
|
|
11296
11329
|
const basics = await promptListingBasics(r, interactive2, defaults, opts, platforms);
|
|
11297
11330
|
if (!isReady(r, platforms) || Object.keys(basics).length) {
|
|
11298
11331
|
const asked = { ...basics, ...isReady(r, platforms) ? {} : await promptForMissing(r, interactive2, defaults, platforms) };
|
|
@@ -11339,7 +11372,7 @@ async function runConnector(target2, opts) {
|
|
|
11339
11372
|
console.log();
|
|
11340
11373
|
console.log(import_chalk28.default.green.bold(` ${r.rendered.headline}`));
|
|
11341
11374
|
console.log(` Submission packet: ${import_chalk28.default.cyan(mdPath)} and ${import_chalk28.default.cyan(jsonPath)}`);
|
|
11342
|
-
console.log(import_chalk28.default.dim(" (the packet carries the reviewer credentials \u2014 keep it out of git)"));
|
|
11375
|
+
console.log(import_chalk28.default.dim(isOpenMode(r) ? " (open mode: no reviewer credentials in the packet; the connector takes no sign-in)" : " (the packet carries the reviewer credentials \u2014 keep it out of git)"));
|
|
11343
11376
|
printSubmitSteps(r, mdPath);
|
|
11344
11377
|
console.log(import_chalk28.default.dim(` ${r.report.disclaimer}`));
|
|
11345
11378
|
}
|
|
@@ -11446,10 +11479,11 @@ async function headStatus(u) {
|
|
|
11446
11479
|
}
|
|
11447
11480
|
function printSubmitSteps(r, mdPath) {
|
|
11448
11481
|
const url = r.report.project.publishedUrl ?? "(the MCP URL in the packet)";
|
|
11482
|
+
const open = isOpenMode(r);
|
|
11449
11483
|
console.log();
|
|
11450
11484
|
console.log(import_chalk28.default.bold(" Submit (you do this part; the packet has every value to paste):"));
|
|
11451
|
-
console.log(` 1. Test it yourself first: add ${import_chalk28.default.cyan(url)} as a custom connector in Claude (Settings \u2192 Connectors) and in ChatGPT (Developer mode), sign in with the reviewer account, run a tool.`);
|
|
11452
|
-
console.log(` 2. Claude: ${import_chalk28.default.underline(PORTALS.claude)} \u2192 Submit new \u2192 MCP connector. Paste the listing, the reviewer credentials and the test steps from ${import_chalk28.default.cyan(import_path4.default.basename(mdPath))}.`);
|
|
11485
|
+
console.log(` 1. Test it yourself first: add ${import_chalk28.default.cyan(url)} as a custom connector in Claude (Settings \u2192 Connectors) and in ChatGPT (Developer mode), ${open ? "no sign-in needed (open mode)" : "sign in with the reviewer account"}, run a tool.`);
|
|
11486
|
+
console.log(` 2. Claude: ${import_chalk28.default.underline(PORTALS.claude)} \u2192 Submit new \u2192 MCP connector. Paste the listing, ${open ? "Authentication: None with the access instructions" : "the reviewer credentials"} and the test steps from ${import_chalk28.default.cyan(import_path4.default.basename(mdPath))}.`);
|
|
11453
11487
|
console.log(` 3. ChatGPT: ${import_chalk28.default.underline(PORTALS.chatgpt)} \u2192 the same packet, plus the 5 + 3 test cases it lists.`);
|
|
11454
11488
|
console.log(` 4. Keep the reviewer account alive; a nightly re-check emails you if the listing drifts.`);
|
|
11455
11489
|
console.log();
|
|
@@ -12236,6 +12270,9 @@ and attestations. \`--compliant\` makes the ${B.thingShort} meet them to the let
|
|
|
12236
12270
|
(Enter accepts), and waits for ONE CNAME (mcp.yourdomain.com \u2192 proxy.abz.run) \u2014 the user adds it at their DNS
|
|
12237
12271
|
provider; relay the exact record it prints. For ChatGPT it also asks for the challenge token the OpenAI portal
|
|
12238
12272
|
issues for the domain (\`--openai-challenge <token>\`).
|
|
12273
|
+
- Sign-in: by default the connector takes OAuth sign-in (API keys keep working alongside) and a reviewer
|
|
12274
|
+
account is created for the packet. Public, read-only data can skip sign-in \u2014 Anthropic allows it: when every
|
|
12275
|
+
tool is read-only the flow asks once (y/N), or pass \`--auth-mode open\`. The API host keeps its own doors.
|
|
12239
12276
|
- When every check passes it prints the compliance table (one row per requirement: met or not, why, and the
|
|
12240
12277
|
policy page it comes from) and writes the submission packet. The user submits the packet to Anthropic or
|
|
12241
12278
|
OpenAI themselves; listing decisions are theirs.
|
|
@@ -20245,7 +20282,7 @@ program.command("login").description(`Authenticate with ${B.product}`).option("-
|
|
|
20245
20282
|
process.exit(1);
|
|
20246
20283
|
}
|
|
20247
20284
|
});
|
|
20248
|
-
program.command("create").description(`Put an app that is already DEPLOYED behind ${B.product}: a public URL and an MCP address for AI agents in front of your URL or OpenAPI spec. Included: API keys, sign-in, ownership rules, rate limits. No login needed. (App on this machine? Use \`dev\`.) Add --compliant to make it a Claude connector, or a ChatGPT plugin with --compliant chatgpt, that meets the directory's policies.`).option("--name <name>", B.cli === "mcpblaze" ? "MCP server name (becomes <name>-<tenant>.mcpblaze.com)" : "Proxy name (becomes <name>.abz.run)").option("--target <url|file>", "What to proxy \u2014 pass ANY of: a target server base URL (https://httpbin.org), a local OpenAPI file (./openapi.yaml), or a remote OpenAPI URL (https://acme.com/openapi.yaml). Spec inputs are detected automatically; routes, API version and environments then come from the spec").addOption(new import_commander.Option("--openapi <file|url>", "Deprecated alias \u2014 --target now detects spec files/URLs itself").hideHelp()).addOption(new import_commander.Option("--openapispec <file|url>", "Deprecated alias for --openapi").hideHelp()).option("--team <id|name>", "Team to create under (defaults to your active team)").option("--auth <type>", "Open ONE door only: api_key | oauth (sign in with GitHub, APIblaze-hosted) | none. Omitted = both doors.").option("--apikey", "API-key door only (no sign-in): the bootstrap keys are minted and printed; callers send X-API-Key, agents connect with a key.").option("--oauth [config]", `Sign-in door only (no API key). Bare = APIblaze-hosted GitHub sign-in. '{"iss","aud","jwks"}' = trust YOUR hosted login's JWTs. '{"provider","clientId","clientSecret"?}' = APIblaze-hosted login page with YOUR OAuth app (github \xB7 google \xB7 microsoft \xB7 facebook \xB7 auth0 \xB7 oidc); the secret is optional except for github and facebook. '{"provider":"oidc","issuer":"https://acme.okta.com/oauth2/default","clientId":"\u2026"}' = any OpenID Connect IdP by issuer (Okta \xB7 Entra \xB7 Keycloak \xB7 Cognito \xB7 \u2026).`).option("--identified", "Require every call to identify its end user (X-End-User-Id from a backend key, or a login token \u2014 a client key alone cannot); unattributed calls are rejected").option("--iam", `Turn IAM on for the ${B.thingShort}'s tenant so users & groups apply to identified calls`).option("--apiversion <version>", `API version to create (e.g. 2.0.0). Creating a new version of a ${B.thingShort} you own adds a version to the existing project.`).option("--tenant <slug>", `Tenant to attach the ${B.thingShort} to (created if new). Omitted \u2192 your team's most-recently-used tenant.`).option("--product <slug>", "Product tag to group this project under in the portal (team-scoped; anonymous create). Defaults to your team's existing/placeholder tag.").option("--display-name <name>", "Human-friendly display name").option("--subdomain <slug>", "Explicit subdomain (defaults to --name)").option("--config <file>", "JSON file with the full request body (anonymous create): requests_auth, login providers + client/server token types, scopes, callback URLs, etc. See apiblaze_anonymous.yaml. Flags override its fields.").option("-y, --yes", "Skip the confirmation prompt").option("--auto", `Zero prompts, start to finish: generates the ${B.thingShort} name when --name is omitted (from the target host, salted), takes every confirmation as yes, auto-picks the tenant. Implies --yes.`).option("--new-session", "Start a fresh anonymous session (do not group with prior anonymous creates)").option("--json", "Output machine-readable JSON (non-interactive)").option("--compliant [directories...]", `Directory-ready in one command, to the letter of that directory's policies: create the ${B.thingShort} from --target (an OpenAPI URL/file), apply the safe fixes, set up the custom MCP domain (--domain, one CNAME), ask for every listing answer with the spec's proposal pre-filled (cut to the portal's limits), create the reviewer account, write the submission packet. Bare = claude; or claude \xB7 chatgpt \xB7 all. Ends with the compliance table: every rule the listing satisfies and the policy page it comes from. Same as \`${B.cli} connector <spec> --compliant \u2026\`.`).addOption(new import_commander.Option("--policy [directories...]", "Older spelling of --compliant").hideHelp()).option("--domain <host>", "With --compliant: the MCP server's custom hostname (mcp.<your domain>); asked for when missing, suggested from the spec").option("--wait <minutes>", "With --compliant: how long to wait for the custom domain to activate once its CNAME is in place (default 15; 0 = do not wait)").option("--directory-ready", "Make it directory-ready for the Claude and ChatGPT directories: OAuth door, custom-domain checks, listing fields; the readiness report runs after the create and a blocker exits 1").option("--privacy-url <url>", "Directory listing: public https privacy policy").option("--support <email|url>", "Directory listing: support contact").option("--docs-url <url>", "Directory listing: public documentation URL (the developer portal by default)").option("--prompt <text>", "Directory listing: an example prompt (repeat the flag; three are needed)", collect, []).option("--server-name <name>", 'Directory listing: the name (2\u201340 chars, no "MCP"/"Plugin" suffix)').option("--tagline <text>", "Directory listing: one-line tagline").option("--description <text>", "Directory listing: description").option("--icon-url <url>", "Directory listing: square icon (https)").option("--vuln-contact <email|url>", "Directory listing: vulnerability-disclosure contact").option("--attest <id>", "Attest (repeatable): guidelines \xB7 own-backend \xB7 no-financial \xB7 no-genai-media \xB7 no-prompt-injection \xB7 no-conversation-data \xB7 public-docs (Claude's seven) \xB7 no-digital-goods \xB7 content-13-no-ads \xB7 no-restricted-data (ChatGPT)", collect, []).option("--allowed-origin <origin>", "Directory mode: an extra browser origin allowed on the MCP host (repeatable)", collect, []).option("--openai-challenge <token>", "ChatGPT: the domain-verification token the OpenAI portal shows under Plugins \u2192 Connect MCP server").action(async (opts) => {
|
|
20285
|
+
program.command("create").description(`Put an app that is already DEPLOYED behind ${B.product}: a public URL and an MCP address for AI agents in front of your URL or OpenAPI spec. Included: API keys, sign-in, ownership rules, rate limits. No login needed. (App on this machine? Use \`dev\`.) Add --compliant to make it a Claude connector, or a ChatGPT plugin with --compliant chatgpt, that meets the directory's policies.`).option("--name <name>", B.cli === "mcpblaze" ? "MCP server name (becomes <name>-<tenant>.mcpblaze.com)" : "Proxy name (becomes <name>.abz.run)").option("--target <url|file>", "What to proxy \u2014 pass ANY of: a target server base URL (https://httpbin.org), a local OpenAPI file (./openapi.yaml), or a remote OpenAPI URL (https://acme.com/openapi.yaml). Spec inputs are detected automatically; routes, API version and environments then come from the spec").addOption(new import_commander.Option("--openapi <file|url>", "Deprecated alias \u2014 --target now detects spec files/URLs itself").hideHelp()).addOption(new import_commander.Option("--openapispec <file|url>", "Deprecated alias for --openapi").hideHelp()).option("--team <id|name>", "Team to create under (defaults to your active team)").option("--auth <type>", "Open ONE door only: api_key | oauth (sign in with GitHub, APIblaze-hosted) | none. Omitted = both doors.").option("--apikey", "API-key door only (no sign-in): the bootstrap keys are minted and printed; callers send X-API-Key, agents connect with a key.").option("--oauth [config]", `Sign-in door only (no API key). Bare = APIblaze-hosted GitHub sign-in. '{"iss","aud","jwks"}' = trust YOUR hosted login's JWTs. '{"provider","clientId","clientSecret"?}' = APIblaze-hosted login page with YOUR OAuth app (github \xB7 google \xB7 microsoft \xB7 facebook \xB7 auth0 \xB7 oidc); the secret is optional except for github and facebook. '{"provider":"oidc","issuer":"https://acme.okta.com/oauth2/default","clientId":"\u2026"}' = any OpenID Connect IdP by issuer (Okta \xB7 Entra \xB7 Keycloak \xB7 Cognito \xB7 \u2026).`).option("--identified", "Require every call to identify its end user (X-End-User-Id from a backend key, or a login token \u2014 a client key alone cannot); unattributed calls are rejected").option("--iam", `Turn IAM on for the ${B.thingShort}'s tenant so users & groups apply to identified calls`).option("--apiversion <version>", `API version to create (e.g. 2.0.0). Creating a new version of a ${B.thingShort} you own adds a version to the existing project.`).option("--tenant <slug>", `Tenant to attach the ${B.thingShort} to (created if new). Omitted \u2192 your team's most-recently-used tenant.`).option("--product <slug>", "Product tag to group this project under in the portal (team-scoped; anonymous create). Defaults to your team's existing/placeholder tag.").option("--display-name <name>", "Human-friendly display name").option("--subdomain <slug>", "Explicit subdomain (defaults to --name)").option("--config <file>", "JSON file with the full request body (anonymous create): requests_auth, login providers + client/server token types, scopes, callback URLs, etc. See apiblaze_anonymous.yaml. Flags override its fields.").option("-y, --yes", "Skip the confirmation prompt").option("--auto", `Zero prompts, start to finish: generates the ${B.thingShort} name when --name is omitted (from the target host, salted), takes every confirmation as yes, auto-picks the tenant. Implies --yes.`).option("--new-session", "Start a fresh anonymous session (do not group with prior anonymous creates)").option("--json", "Output machine-readable JSON (non-interactive)").option("--compliant [directories...]", `Directory-ready in one command, to the letter of that directory's policies: create the ${B.thingShort} from --target (an OpenAPI URL/file), apply the safe fixes, set up the custom MCP domain (--domain, one CNAME), ask for every listing answer with the spec's proposal pre-filled (cut to the portal's limits), create the reviewer account, write the submission packet. Bare = claude; or claude \xB7 chatgpt \xB7 all. Ends with the compliance table: every rule the listing satisfies and the policy page it comes from. Same as \`${B.cli} connector <spec> --compliant \u2026\`.`).addOption(new import_commander.Option("--policy [directories...]", "Older spelling of --compliant").hideHelp()).option("--domain <host>", "With --compliant: the MCP server's custom hostname (mcp.<your domain>); asked for when missing, suggested from the spec").option("--wait <minutes>", "With --compliant: how long to wait for the custom domain to activate once its CNAME is in place (default 15; 0 = do not wait)").option("--auth-mode <mode>", "With --compliant: how directory clients get in. signin (default) = OAuth sign-in on the connector, API keys alongside; open = no sign-in at all, for public read-only data (Anthropic allows it) \u2014 the API host keeps its own doors. Asked once when every tool is read-only.").option("--directory-ready", "Make it directory-ready for the Claude and ChatGPT directories: OAuth door, custom-domain checks, listing fields; the readiness report runs after the create and a blocker exits 1").option("--privacy-url <url>", "Directory listing: public https privacy policy").option("--support <email|url>", "Directory listing: support contact").option("--docs-url <url>", "Directory listing: public documentation URL (the developer portal by default)").option("--prompt <text>", "Directory listing: an example prompt (repeat the flag; three are needed)", collect, []).option("--server-name <name>", 'Directory listing: the name (2\u201340 chars, no "MCP"/"Plugin" suffix)').option("--tagline <text>", "Directory listing: one-line tagline").option("--description <text>", "Directory listing: description").option("--icon-url <url>", "Directory listing: square icon (https)").option("--vuln-contact <email|url>", "Directory listing: vulnerability-disclosure contact").option("--attest <id>", "Attest (repeatable): guidelines \xB7 own-backend \xB7 no-financial \xB7 no-genai-media \xB7 no-prompt-injection \xB7 no-conversation-data \xB7 public-docs (Claude's seven) \xB7 no-digital-goods \xB7 content-13-no-ads \xB7 no-restricted-data (ChatGPT)", collect, []).option("--allowed-origin <origin>", "Directory mode: an extra browser origin allowed on the MCP host (repeatable)", collect, []).option("--openai-challenge <token>", "ChatGPT: the domain-verification token the OpenAI portal shows under Plugins \u2192 Connect MCP server").action(async (opts) => {
|
|
20249
20286
|
try {
|
|
20250
20287
|
const compliant = opts.compliant ?? opts.policy;
|
|
20251
20288
|
if (compliant !== void 0 && compliant !== false) {
|
|
@@ -20265,7 +20302,7 @@ function collect(value, previous) {
|
|
|
20265
20302
|
return [...previous ?? [], value];
|
|
20266
20303
|
}
|
|
20267
20304
|
program.command("check").description(`Readiness report for the Claude and ChatGPT directories (--directory-ready): what passes, every blocker with its fix, and the ${B.thingShort}'s published URL. Exit 1 while a blocker remains.`).argument("[project]", `The ${B.thingShort} (project name)`).option("--directory-ready", "The directory readiness checks (the only mode today)").option("--compliant [directory]", "Which directory's policies to check against: bare = claude; or claude \xB7 chatgpt \xB7 all (repeat or comma-separate)", collect, []).addOption(new import_commander.Option("--policy <directory>", "Older spelling of --compliant").hideHelp()).addOption(new import_commander.Option("--platform <list>", "Older spelling of --compliant").hideHelp()).option("--stage <stage>", "create (relaxed: docs URL is a warning) \xB7 ready (the submission gate, default)").option("--refresh-snapshot", "Re-take the listing snapshot (after you edited the listing in the portals)").option("--no-probe", "Skip the live probes from this machine (report what the server can see)").option("--team <id|name>", "Team the project is in (defaults to your active team)").option("--apiversion <version>", "API version (defaults to the project's)").option("--json", "Print the raw report JSON (report, rendered text, target)").action(action((project, opts) => runCheck(project, { ...opts, noProbe: opts.probe === false })));
|
|
20268
|
-
var connector = program.command("connector").description(`A compliant Claude connector (--compliant chatgpt: a ChatGPT plugin), directory-ready in one command: from a project or straight from an OpenAPI URL \u2014 creates the ${B.thingShort} if needed, applies the safe fixes, sets up the custom MCP domain (one CNAME), pre-fills every listing answer from the spec, creates the reviewer account, and writes the submission packet when every check passes (you submit it to Anthropic and OpenAI yourself)`).argument("[project-or-spec]", `The ${B.thingShort} (project name), or an OpenAPI URL/file to create a directory-ready ${B.thingShort} from first`).option("--domain <host>", "Custom hostname for the MCP server (mcp.<your domain>); asked for when missing, suggested from the spec").option("--wait <minutes>", "How long to wait for the custom domain to activate once its CNAME is in place (default 15; 0 = do not wait)").option("--name <name>", `When creating from a spec: the ${B.thingShort} name (default: derived from the spec host)`).option("--privacy-url <url>", "Public https privacy policy").option("--support <email|url>", "Support contact").option("--docs-url <url>", "Public documentation URL").option("--prompt <text>", "An example prompt (repeatable; three are needed)", collect, []).option("--server-name <name>", 'Listing name (2\u201340 chars, no "MCP"/"Plugin" suffix)').option("--tagline <text>", "One-line tagline").option("--description <text>", "Description").option("--icon-url <url>", "Square icon (https)").option("--vuln-contact <email|url>", "Vulnerability-disclosure contact").option("--attest <id>", "Attest (repeatable): guidelines \xB7 own-backend \xB7 no-financial \xB7 no-genai-media \xB7 no-prompt-injection \xB7 no-conversation-data \xB7 public-docs (Claude's seven) \xB7 no-digital-goods \xB7 content-13-no-ads \xB7 no-restricted-data (ChatGPT). Alone, this only records the attestation.", collect, []).option("--allowed-origin <origin>", "An extra browser origin allowed on the MCP host (repeatable)", collect, []).option("--openai-challenge <token>", "ChatGPT: the domain-verification token the OpenAI portal shows under Plugins \u2192 Connect MCP server; served verbatim at /.well-known/openai-apps-challenge on your MCP domain").option("--full", "Run the full flow even when only --attest was given").option("--compliant [directory]", "Which directory's policies this run must satisfy: bare = claude; or claude \xB7 chatgpt \xB7 all (repeat or comma-separate)", collect, []).addOption(new import_commander.Option("--policy <directory>", "Older spelling of --compliant").hideHelp()).addOption(new import_commander.Option("--platform <list>", "Older spelling of --compliant").hideHelp()).option("--out <dir>", "Where to write connector-packet-<project>.md/.json (default: current directory)").option("-y, --yes", "No questions: apply the flags, report, exit 1 on a blocker").option("--team <id|name>", "Team the project is in (defaults to your active team)").option("--apiversion <version>", "API version (defaults to the project's)").option("--json", "Output machine-readable JSON").action(action(async (project, opts) => {
|
|
20305
|
+
var connector = program.command("connector").description(`A compliant Claude connector (--compliant chatgpt: a ChatGPT plugin), directory-ready in one command: from a project or straight from an OpenAPI URL \u2014 creates the ${B.thingShort} if needed, applies the safe fixes, sets up the custom MCP domain (one CNAME), pre-fills every listing answer from the spec, creates the reviewer account, and writes the submission packet when every check passes (you submit it to Anthropic and OpenAI yourself)`).argument("[project-or-spec]", `The ${B.thingShort} (project name), or an OpenAPI URL/file to create a directory-ready ${B.thingShort} from first`).option("--domain <host>", "Custom hostname for the MCP server (mcp.<your domain>); asked for when missing, suggested from the spec").option("--wait <minutes>", "How long to wait for the custom domain to activate once its CNAME is in place (default 15; 0 = do not wait)").option("--auth-mode <mode>", "How directory clients get in: signin (default) = OAuth sign-in on the connector, API keys alongside; open = no sign-in at all, for public read-only data (Anthropic allows it) \u2014 the API host keeps its own doors. Asked once when every tool is read-only.").option("--name <name>", `When creating from a spec: the ${B.thingShort} name (default: derived from the spec host)`).option("--privacy-url <url>", "Public https privacy policy").option("--support <email|url>", "Support contact").option("--docs-url <url>", "Public documentation URL").option("--prompt <text>", "An example prompt (repeatable; three are needed)", collect, []).option("--server-name <name>", 'Listing name (2\u201340 chars, no "MCP"/"Plugin" suffix)').option("--tagline <text>", "One-line tagline").option("--description <text>", "Description").option("--icon-url <url>", "Square icon (https)").option("--vuln-contact <email|url>", "Vulnerability-disclosure contact").option("--attest <id>", "Attest (repeatable): guidelines \xB7 own-backend \xB7 no-financial \xB7 no-genai-media \xB7 no-prompt-injection \xB7 no-conversation-data \xB7 public-docs (Claude's seven) \xB7 no-digital-goods \xB7 content-13-no-ads \xB7 no-restricted-data (ChatGPT). Alone, this only records the attestation.", collect, []).option("--allowed-origin <origin>", "An extra browser origin allowed on the MCP host (repeatable)", collect, []).option("--openai-challenge <token>", "ChatGPT: the domain-verification token the OpenAI portal shows under Plugins \u2192 Connect MCP server; served verbatim at /.well-known/openai-apps-challenge on your MCP domain").option("--full", "Run the full flow even when only --attest was given").option("--compliant [directory]", "Which directory's policies this run must satisfy: bare = claude; or claude \xB7 chatgpt \xB7 all (repeat or comma-separate)", collect, []).addOption(new import_commander.Option("--policy <directory>", "Older spelling of --compliant").hideHelp()).addOption(new import_commander.Option("--platform <list>", "Older spelling of --compliant").hideHelp()).option("--out <dir>", "Where to write connector-packet-<project>.md/.json (default: current directory)").option("-y, --yes", "No questions: apply the flags, report, exit 1 on a blocker").option("--team <id|name>", "Team the project is in (defaults to your active team)").option("--apiversion <version>", "API version (defaults to the project's)").option("--json", "Output machine-readable JSON").action(action(async (project, opts) => {
|
|
20269
20306
|
if (!project) throw new Error(`Which ${B.thingShort}? ${B.cli} connector <project> \xB7 ${B.cli} connector https://\u2026/openapi.yaml \xB7 ${B.cli} connector reviewer <project>`);
|
|
20270
20307
|
await runConnector(project, opts);
|
|
20271
20308
|
}));
|