From d19824853425b5e08c7a32a765ae17b0413baf0b Mon Sep 17 00:00:00 2001 From: chaewon-huh Date: Thu, 2 Jul 2026 10:47:33 +0900 Subject: [PATCH 1/2] feat: mark MCP launch surface coming soon --- README.md | 133 +---- agent/sume-assets/SKILL.md | 17 +- .../sume-assets/references/media-workflows.md | 4 +- agent/sume-avatar/SKILL.md | 2 +- agent/sume-tools/SKILL.md | 29 +- agent/sume-tools/references/mcp-toolsets.md | 51 +- agent/sume/SKILL.md | 10 +- agent/sume/references/safety.md | 6 +- docs/agent-skills.md | 7 +- docs/agent-workflows.md | 22 +- docs/architecture.md | 54 +- docs/mcp-toolsets.md | 149 +---- package.json | 3 +- src/commands/doctor.ts | 23 +- src/commands/mcp.ts | 151 +---- src/commands/setup.ts | 104 +--- src/commands/tools.ts | 6 +- src/index.ts | 4 +- src/lib/bundled-skills-data.ts | 20 +- src/lib/mcp-launch-status.ts | 42 ++ src/lib/tool-registry.ts | 54 +- src/mcp/tools.ts | 6 +- test/cli.test.ts | 528 ++++-------------- test/mcp.test.ts | 65 +-- 24 files changed, 363 insertions(+), 1127 deletions(-) create mode 100644 src/lib/mcp-launch-status.ts diff --git a/README.md b/README.md index d399916..bad8a56 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Sume CLI -Agent-first CLI and MCP tooling for the future `sume.com` public API platform. +Agent-first CLI tooling for the future `sume.com` public API platform. This repository contains the public CLI for the `sume.com` developer platform. It follows these product boundaries: @@ -8,7 +8,6 @@ It follows these product boundaries: - thin CLI wrappers over public API endpoints; - stable JSON for agents and scripts; - explicit API-key configuration; -- MCP tools built from the same API/client boundary; - no direct dependency on app internals, databases, queues, or provider APIs. ## Status @@ -170,7 +169,6 @@ sume jobs events --agent --json sume jobs result --agent --json sume jobs download --output-dir ./outputs --json sume jobs cancel --confirm-submit --agent --json -sume mcp sume tools list --json sume tools schema jobs.result --json sume tools schema avatars.create_photo_url --json @@ -192,11 +190,9 @@ API; it reports version, auth source, API base URL, safety gates, and tool counts. `sume tools list --json` and `sume tools schema --json` expose the -current agent-facing command contracts, safety metadata, confirmation -requirements, and separate CLI/MCP input contracts. `input_schema` describes -CLI flags. `mcp_input_schema` describes the MCP tool payload; submit MCP tools -use `{ "payload": { ...apiBody }, "idempotency_key": "..." }`, with -`avatars.create` also accepting an optional public `model`. +current agent-facing CLI command contracts, safety metadata, confirmation +requirements, and launch status metadata. `input_schema` describes CLI flags. +MCP fields are reported as not launched yet in this public CLI release. Supported API command groups call only current `api.sume.com` API routes: @@ -289,126 +285,19 @@ sume skills install sume-assets --json The bundled skills are current `api.sume.com` packs: `sume`, `sume-tools`, `sume-assets`, `sume-avatar`, and `sume-avatar-video`. They document auth, redaction, Avatar 1.0, Avatar Video 1.0, batch planning, jobs, balance, usage, -MCP setup, and advanced compatibility asset handling. They explicitly exclude +schema discovery, and advanced compatibility asset handling. They explicitly exclude old `sume.so` Brand, Ads, Face Swap, generic generation, raw provider, billing-write, and file workflows. ## MCP -Start the local stdio MCP server: +Sume MCP is coming soon and is not part of this public CLI launch release yet. +Use direct CLI commands today for auth, schema discovery, Avatar, Avatar Video, +jobs, balance, and usage workflows. -```bash -sume mcp -``` - -Set up a supported agent client with the default read-only MCP server: - -```bash -sume setup agent --agent codex -sume setup agent --agent claude-code -sume setup agent --agent cursor -``` - -Install the read-only MCP server config for a supported client: - -```bash -sume mcp install --agent codex -sume mcp install --agent claude-code -sume mcp install --agent cursor -``` - -Preview the generated config without writing files: - -```bash -sume mcp install --agent codex --dry-run -sume mcp install --agent claude-code --dry-run -sume mcp install --agent cursor --dry-run -``` - -Check local MCP client readiness: - -```bash -sume mcp doctor -sume mcp doctor --agent codex --json -``` - -The generated snippets run only `sume mcp`, which exposes the default read-only -toolset. They do not enable write or paid MCP tools. - -The MCP toolset includes read-only inspection tools: - -- `tools.list` -- `tools.schema` -- `health.service` -- `health.v1` -- `account.me` -- `catalog.list` -- `jobs.list` -- `jobs.get` -- `jobs.status` -- `jobs.events` -- `jobs.result` -- `jobs.wait` -- `avatars.list` -- `avatars.get` -- `avatars.wait` -- `avatar-videos.list` -- `avatar-videos.get` - -Submit tools are not exposed by default. Advanced compatibility asset tools are -also not exposed by default because `/v1/assets/*` is hidden from the launch -OpenAPI/catalog. To expose asset registration for a deliberate internal or -agent session, opt into the asset toolset and the write gate: - -```bash -sume mcp --toolsets account,catalog,jobs,assets --allow-write -``` - -That adds: - -- `assets.create` -- `assets.upload_url` -- `assets.upload_file` -- `assets.complete` -- `jobs.cancel` - -`assets.upload_file` is an MCP-only local workflow helper. It creates a signed -upload URL, PUTs the supplied local file bytes to that URL, completes the asset, -and returns only agent-redacted metadata. It does not return the signed upload -URL, storage headers, or the local absolute file path. MCP local file uploads -are capped at 512 MiB in this release; use the lower-level public API upload -URL flow when a host needs full control. - -Paid generation avatar submit tools also require the paid gate: - -```bash -sume mcp --toolsets account,catalog,jobs,avatars,avatar-videos --allow-write --allow-paid -``` - -That adds: - -- `avatars.create` -- `avatars.create_prompt` -- `avatars.create_props` -- `avatars.create_photo_url` -- `avatar-videos.create` - -The submit MCP tools are annotated as non-read-only, URL-returning, and -agent-redaction-required. Asset write helpers are advanced compatibility write -operations but not paid generation calls. Avatar and avatar-video submit tools use -`generation_runtime: sume_api`. `avatars.create` remains the -exact-payload escape hatch. The typed avatar helpers build common Avatar 1.0 -prompt, profile, and public-photo URL requests, add normalized `avatar_summary` -fields for agent readback, and keep signed upload/download URLs internal. Use -`avatars.wait` to poll an avatar job and read grouped public artifact URLs when -available. Their `tools schema` entries also show the required -confirmation gates: CLI submit commands require `--confirm-submit` or -`--confirm-paid` for paid generation submits and `--confirm-submit` for asset -registration. MCP asset registration requires a session started with -`--allow-write`; paid generation submits require both `--allow-write` and -`--allow-paid`. Future file, billing-write, and unsupported generation tools -must remain behind explicit opt-in gates after public API contracts exist. -For a toolset-focused setup guide, see [docs/mcp-toolsets.md](docs/mcp-toolsets.md). +The open-source repository may contain MCP implementation code while the +capability is being prepared. Public MCP setup and server startup are not +launched yet, and the CLI does not write MCP client config in this release. ## Website diff --git a/agent/sume-assets/SKILL.md b/agent/sume-assets/SKILL.md index a5981e1..352a9da 100644 --- a/agent/sume-assets/SKILL.md +++ b/agent/sume-assets/SKILL.md @@ -14,7 +14,8 @@ public HTTPS URLs directly. ```bash sume tools schema assets.create --json -sume tools schema assets.upload_file --json +sume tools schema assets.upload_url --json +sume tools schema assets.complete --json sume tools schema assets.download_url --json ``` @@ -34,18 +35,8 @@ echo the original source URL in readback. ## Direct Upload -For MCP, prefer: - -```bash -sume mcp --toolsets assets --allow-write -``` - -Call `assets.upload_file` with a local path and content type. It performs -upload-url, signed PUT, and complete internally without returning the signed URL -or local absolute path. - -For shell workflows, use `assets upload-url`, PUT bytes outside the CLI, then -`assets complete`. Never paste signed URLs into reports. +Use `assets upload-url`, PUT bytes outside the CLI, then `assets complete`. +Never paste signed URLs into reports. ## Download diff --git a/agent/sume-assets/references/media-workflows.md b/agent/sume-assets/references/media-workflows.md index 58a1778..7d5fa6f 100644 --- a/agent/sume-assets/references/media-workflows.md +++ b/agent/sume-assets/references/media-workflows.md @@ -4,8 +4,8 @@ - Signed upload URLs and headers are temporary credentials. - Do not send Sume API auth headers to signed storage URLs. -- `assets.upload_file` and `sume assets upload-file` style helpers should keep - signed URLs internal and return only redacted asset metadata. +- Direct upload helpers should keep signed URLs internal and return only + redacted asset metadata. ## Download Safety diff --git a/agent/sume-avatar/SKILL.md b/agent/sume-avatar/SKILL.md index 44c5de3..4ff5588 100644 --- a/agent/sume-avatar/SKILL.md +++ b/agent/sume-avatar/SKILL.md @@ -12,7 +12,7 @@ Use this skill for Avatar 1.0 creation and selection. ```bash sume tools schema avatars.create --json sume tools schema avatars.list --json -sume tools schema jobs.wait --json +sume tools schema jobs.watch --json ``` ## Single Avatar diff --git a/agent/sume-tools/SKILL.md b/agent/sume-tools/SKILL.md index c759f7a..8a419be 100644 --- a/agent/sume-tools/SKILL.md +++ b/agent/sume-tools/SKILL.md @@ -1,22 +1,18 @@ --- name: sume-tools -description: Configure Sume.com CLI/MCP for agents, discover tool schemas, install or export bundled Sume skills, inspect balance/usage, and choose safe public-api workflows. +description: Discover Sume.com CLI tool schemas, install or export bundled Sume skills, inspect balance/usage, and choose safe public-api workflows. --- # Sume Tools -Use this skill for setup, MCP toolset selection, schema discovery, and local -skill maintenance. +Use this skill for schema discovery and local skill maintenance. ## Discovery ```bash -sume setup agent --agent codex -sume mcp doctor --json sume doctor --agent --json sume tools list --json sume tools schema avatars.create --json -sume tools schema avatars.create_photo_url --json sume tools schema avatar-videos.create --json sume balance --json sume usage get --json @@ -36,25 +32,8 @@ Skills install into `.agents/skills/` when `.agents/` exists, otherwise ## MCP -Default MCP is read-only: - -```bash -sume mcp -sume mcp install --agent codex -sume mcp doctor --agent codex --json -``` - -Use explicit gates only after approval: - -```bash -sume mcp --toolsets jobs --allow-write -sume mcp --toolsets avatars,avatar-videos --allow-write --allow-paid -``` - -Paid MCP calls still require per-call `idempotency_key` and `max_spend_usd`. -Use `dry_run: true` before submitting. - -Read `references/mcp-toolsets.md` before enabling non-default tools. +Sume MCP is coming soon and is not part of this public CLI launch release yet. +Use direct CLI commands today. ## Not For diff --git a/agent/sume-tools/references/mcp-toolsets.md b/agent/sume-tools/references/mcp-toolsets.md index bf82a9b..7f746bc 100644 --- a/agent/sume-tools/references/mcp-toolsets.md +++ b/agent/sume-tools/references/mcp-toolsets.md @@ -1,46 +1,13 @@ -# MCP Toolsets +# MCP Coming Soon -## Default - -`sume mcp` exposes read-only, agent-redacted tools: - -- `tools.list`, `tools.schema` -- `health.service`, `health.v1` -- `account.me`, `balance.get`, `usage.get` -- `catalog.list` -- `jobs.list`, `jobs.get`, `jobs.status`, `jobs.events`, `jobs.result`, `jobs.wait` -- `avatars.list`, `avatars.get`, `avatars.wait` -- `avatar-videos.list`, `avatar-videos.get` - -## Write Gate - -```bash -sume mcp --toolsets jobs --allow-write -``` - -Adds non-paid writes such as `jobs.cancel`. - -Advanced compatibility asset tools are hidden from the launch OpenAPI/catalog -and are not part of default MCP. Use them only when explicitly requested: +Sume MCP is coming soon and is not part of this public CLI launch release yet. +Use direct CLI commands today for auth, schema discovery, Avatar, Avatar Video, +jobs, balance, and usage workflows. ```bash -sume mcp --toolsets assets --allow-write +sume login +sume doctor --agent --json +sume tools list --json +sume tools schema avatars.create --json +sume tools schema avatar-videos.create --json ``` - -This exposes `assets.create`, `assets.upload_url`, `assets.upload_file`, -`assets.complete`, and readback helpers. - -## Paid Gate - -```bash -sume mcp --toolsets avatars,avatar-videos --allow-write --allow-paid -``` - -Adds paid generation `avatars.create`, `avatars.create_prompt`, -`avatars.create_props`, `avatars.create_photo_url`, and `avatar-videos.create`. - -Paid tool calls require per-call `idempotency_key` and `max_spend_usd`. Use -`dry_run: true` to run a non-submitting Sume cost/readiness preview without creating a job. - -Use `jobs.wait` and `jobs.result` for readback. Do not ask MCP to reveal signed -URLs or private media URLs. diff --git a/agent/sume/SKILL.md b/agent/sume/SKILL.md index 7391370..86eecf9 100644 --- a/agent/sume/SKILL.md +++ b/agent/sume/SKILL.md @@ -1,6 +1,6 @@ --- name: sume -description: Use the Sume.com CLI and MCP server safely for auth, API discovery, avatars, avatar videos, jobs, balance, usage, and choosing focused Sume skills. Use this as the entry skill for current api.sume.com workflows. +description: Use the Sume.com CLI safely for auth, API discovery, avatars, avatar videos, jobs, balance, usage, and choosing focused Sume skills. Use this as the entry skill for current api.sume.com workflows. --- # Sume Skill Router @@ -15,8 +15,7 @@ surfaces. constructing writes. 2. Use `--agent --json` whenever automation reads jobs, avatars, or avatar videos. -3. Ask for explicit approval before `--confirm-submit`, `--confirm-paid`, - `--allow-write`, or `--allow-paid`. +3. Ask for explicit approval before `--confirm-submit` or `--confirm-paid`. 4. Do not print API keys, auth approval URLs/codes in final reports, signed URLs, private media URLs, storage object keys, raw provider identifiers, workspace/user ids, or full result URLs. @@ -43,7 +42,7 @@ the exact pattern. ## Routing -- Use `sume-tools` for MCP setup, schema discovery, and skill maintenance. +- Use `sume-tools` for schema discovery and skill maintenance. - Use `sume-avatar` for creating several avatars and choosing a ready avatar. - Use `sume-avatar-video` for making videos from selected avatars and reading metadata/result state. @@ -53,6 +52,9 @@ the exact pattern. Read `references/safety.md` for auth, paid/write gates, and redaction rules. Read `references/eval-scenarios.md` when validating agent behavior. +Sume MCP is coming soon and is not part of this public CLI launch release yet. +Use direct CLI commands today. + ## Not For Do not use old `sume.so` Brand, Ads, Face Swap, generic image/video generation, diff --git a/agent/sume/references/safety.md b/agent/sume/references/safety.md index fa63455..b6c98f5 100644 --- a/agent/sume/references/safety.md +++ b/agent/sume/references/safety.md @@ -29,9 +29,6 @@ rm -f "$login_log" "$login_log.status" completion, and job cancellation. - `--confirm-paid`: paid generation submits such as Avatar 1.0 and Avatar Video 1.0 creation. -- MCP `--allow-write`: exposes mutating non-paid tools. -- MCP `--allow-paid`: exposes paid generation submit tools and should be paired - with `--allow-write` for submit actions. ## Sensitive Outputs @@ -50,3 +47,6 @@ compatibility tooling only and is hidden from the launch OpenAPI/catalog. Excluded until public contracts exist: old Brand, Ads, Face Swap, generic image/video generation, arbitrary file APIs, provider ids, and billing-write operations. + +Sume MCP is coming soon and is not part of this public CLI launch release yet. +Use direct CLI commands today. diff --git a/docs/agent-skills.md b/docs/agent-skills.md index 8bf6fcf..994aa3e 100644 --- a/docs/agent-skills.md +++ b/docs/agent-skills.md @@ -18,7 +18,7 @@ directories first so the CLI does not guess where an agent should read skills. Bundled skills: - `sume`: router, auth, safety, redaction, eval scenarios. -- `sume-tools`: MCP setup, schema discovery, balance/usage, skill maintenance. +- `sume-tools`: schema discovery, balance/usage, skill maintenance. - `sume-assets`: advanced compatibility asset registration/upload/download helpers; not the default launch media-input path. - `sume-avatar`: Avatar 1.0 prompt/photo/props creation and batch planning. @@ -28,8 +28,6 @@ Bundled skills: Safe setup: ```bash -sume setup agent --agent codex -sume mcp doctor --json sume doctor --agent --json sume tools list --json sume tools schema avatars.create --json @@ -45,3 +43,6 @@ Do not copy old `sume.so` Brand, Ads, Face Swap, generic generation, raw provider, billing-write, file, or asset-search workflows into current Sume agent setup unless those routes appear in the public `api.sume.com` catalog and tool schemas. + +Sume MCP is coming soon and is not part of this public CLI launch release yet. +Use direct CLI commands today. diff --git a/docs/agent-workflows.md b/docs/agent-workflows.md index 1aed2c5..ef8d072 100644 --- a/docs/agent-workflows.md +++ b/docs/agent-workflows.md @@ -11,7 +11,7 @@ Use this sequence for current Avatar 1.0 and Avatar Video 1.0 prompts. ```bash sume doctor --agent --json sume catalog list --json -sume tools schema jobs.wait --json +sume tools schema jobs.watch --json sume tools schema jobs.download --json sume tools schema avatars.create --json sume tools schema avatars.batch.plan --json @@ -121,24 +121,12 @@ After any submit command: 1. Capture `data.job.id` or `data.request_id` from the redacted response. 2. Poll with `sume jobs watch --agent --json` when using the CLI. -3. Poll with MCP `jobs.wait` when using MCP. -4. Read completed output with `sume jobs result --agent --json` or MCP - `jobs.result`. -5. Save media only on request with +3. Read completed output with `sume jobs result --agent --json`. +4. Save media only on request with `sume jobs download --output-dir ./outputs --json`. -MCP submit tools return the same agent-safe next-step guidance. They use the -MCP envelope: - -```json -{ - "payload": { - "avatar_handle": "presenter", - "input": { "type": "prompt", "prompt": "A friendly presenter" } - }, - "idempotency_key": "optional-safe-retry-key" -} -``` +Sume MCP is coming soon and is not part of this public CLI launch release yet. +Use direct CLI commands for current automation. ## Safety diff --git a/docs/architecture.md b/docs/architecture.md index 0dcc2ab..1f206df 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -13,8 +13,8 @@ gates, version, and current tool counts. ## Public API Client -`src/lib/api-client.ts` is the only HTTP boundary. Commands and MCP tools call -this client instead of hand-rolling fetch calls. +`src/lib/api-client.ts` is the only HTTP boundary. Commands call this client +instead of hand-rolling fetch calls. The default base URL is: @@ -52,7 +52,7 @@ Current launch-supported paths are: - `GET /avatar-videos/:id` The Avatar 1.0 and Avatar Video 1.0 model-run routes are public API operations -backed by the configured `api.sume.com` runtime. Commands and MCP tools must not +backed by the configured `api.sume.com` runtime. Commands must not claim media generation has completed unless the API returns a completed job/result. Generic image/video routes and raw provider model ids are not part of the current public CLI surface. @@ -66,21 +66,18 @@ unsupported product-specific generation routes are not called by this CLI until their `sume.com` public contracts are finalized. `/v1/assets/*` is advanced compatibility tooling only because it is hidden from the launch OpenAPI/catalog. Launch generation inputs are URL-first. Signed URL responses -must be redacted in agent output. MCP may compose advanced compatibility asset -routes into local workflow helpers, such as `assets.upload_file`, only when the -asset toolset is explicitly selected. +must be redacted in agent output. MCP is coming soon and is not part of this +public CLI launch release yet. ## Agent Output And Tool Schemas `src/lib/tool-registry.ts` is the source of truth for the current agent-facing tool list, command examples, and safety metadata used by `sume tools`. -Tool schemas intentionally expose two input contracts when an MCP tool exists: -`input_schema` for CLI flags and `mcp_input_schema` for the MCP tool call shape. -Submit MCP tools use a stable envelope with `payload` for the exact public API -request body and optional `idempotency_key` for safe retries. Confirmation -metadata should stay explicit so agents can distinguish CLI confirmation flags -from MCP session gates. +Tool schemas expose `input_schema` for direct CLI flags. `mcp_input_schema` is +`null` in this public launch release because MCP is coming soon and is not +launched yet. Confirmation metadata should stay explicit so agents can +distinguish read operations from writes and paid submits. `src/lib/agent-output.ts` redacts URLs and sensitive account/workspace fields for agent-readable job recovery and MCP responses. Raw public API passthrough @@ -88,8 +85,8 @@ should remain available only through non-agent command modes when a human explicitly needs the original response. Submit and job-read tool schemas should mark that URL-like fields may appear in -raw API responses. Agent-safe CLI and MCP paths must add next-step guidance and -redact those fields before returning output to automation. +raw API responses. Agent-safe CLI paths must add next-step guidance and redact +those fields before returning output to automation. ## Auth And Config @@ -111,25 +108,16 @@ The public API base defaults to `https://api.sume.com/v1`. Browser login derives ## MCP -`src/mcp/server.ts` exposes a testable server factory. `src/mcp/tools.ts` -contains tool definitions that use the same platform/client boundary as the CLI. -`src/mcp/transports/stdio.ts` is the local stdio entrypoint. - -Default MCP exposes tools, health, account, catalog, jobs, avatars, and -avatar-videos as first-class read toolsets. Avatar, avatar-video, and job -readback tools are marked URL-returning where raw API responses may include -Sume-owned or signed URLs. Submit/cancel/upload-complete/upload-file tools are -explicitly annotated as non-read-only and filtered out unless the caller selects -the relevant toolsets and passes the appropriate opt-in flags. Advanced -compatibility asset helpers are available only when the asset toolset is -selected. Asset write helpers and job cancellation require write opt-in only. -Paid generation avatar and avatar-video submit tools require both write and paid -opt-in flags. - -`tools.list` and `tools.schema` are available inside MCP so clients can discover -the same contracts exposed by `sume tools list --json` and -`sume tools schema --json`. `jobs.wait` is a read-only local polling -helper over `/jobs/:id/status`; it does not create live generation work. +MCP is coming soon and is not part of this public CLI launch release yet. +`src/mcp/server.ts`, `src/mcp/tools.ts`, and `src/mcp/transports/stdio.ts` remain +in the open-source repository for future launch work, but the public `sume mcp` +and `sume setup agent` command paths report coming-soon status and do not start +a server or write client config. + +Direct CLI commands are the supported launch surface today. `sume tools list +--json` and `sume tools schema --json` expose CLI command schemas with +`mcp_input_schema: null` and `mcp.status: "coming_soon"` so agents can discover +current command contracts without treating MCP as launched. Bundled agent skill packs live under `agent/` and ship with the npm/package artifact. `src/lib/skills-registry.ts` lists, exports, installs, updates, and diff --git a/docs/mcp-toolsets.md b/docs/mcp-toolsets.md index 4459f64..e2462f2 100644 --- a/docs/mcp-toolsets.md +++ b/docs/mcp-toolsets.md @@ -1,139 +1,26 @@ -# MCP Toolsets +# MCP Coming Soon -This CLI exposes MCP tools for the current `api.sume.com` public API surface. -Do not use this CLI or MCP server for old `sume.so`-only Brand, Ads, Face Swap, -generic generation, billing-write, file, or provider-id workflows unless those -routes appear in the public `sume.com` API catalog. +Sume MCP is coming soon and is not part of this public CLI launch release yet. +Use direct CLI commands today for auth, schema discovery, Avatar, Avatar Video, +jobs, balance, and usage workflows. -## Default Read-Only Server +The open-source repository may contain MCP implementation code while the +capability is being prepared. Public MCP setup and server startup are not +launched yet, and the CLI does not write MCP client config in this release. -```bash -sume mcp -``` - -Set up a supported agent client with the default read-only MCP server: - -```bash -sume setup agent --agent codex -sume setup agent --agent claude-code -sume setup agent --agent cursor -``` +## Supported Launch Surface -Install the read-only MCP server config for a supported client: +Use these direct CLI commands instead: ```bash -sume mcp install --agent codex -sume mcp install --agent claude-code -sume mcp install --agent cursor +sume login +sume doctor --agent --json +sume tools list --json +sume tools schema avatars.create --json +sume tools schema avatar-videos.create --json +sume avatars create --help +sume avatar-videos create --help +sume jobs --help ``` -Preview the generated config without writing files: - -```bash -sume mcp install --agent codex --dry-run -sume mcp install --agent claude-code --dry-run -sume mcp install --agent cursor --dry-run -``` - -Check local MCP client readiness: - -```bash -sume mcp doctor -sume mcp doctor --agent codex --json -``` - -Default MCP is read-only and agent-redacted. It exposes: - -- `tools.list` -- `tools.schema` -- `health.service` -- `health.v1` -- `account.me` -- `balance.get` -- `usage.get` -- `catalog.list` -- `jobs.list` -- `jobs.get` -- `jobs.status` -- `jobs.events` -- `jobs.result` -- `jobs.wait` -- `avatars.list` -- `avatars.get` -- `avatars.wait` -- `avatar-videos.list` -- `avatar-videos.get` - -Use `tools.list` and `tools.schema` inside MCP to inspect the same contracts -available through `sume tools list --json` and -`sume tools schema --json`. -Those contracts also include CLI-only local helpers such as `skills.list`, -`assets.download`, `jobs.download`, `avatars.batch.*`, and -`avatar-videos.batch.*`; they are intentionally not MCP server tools unless a -future public API contract requires them inside MCP. - -## Write-Gated Tools - -Use write-gated tools only after explicit user approval: - -```bash -sume mcp --toolsets account,catalog,jobs --allow-write -``` - -This adds: - -- `jobs.cancel` - -Advanced compatibility asset tools are not part of the launch default MCP -surface because `/v1/assets/*` is hidden from the launch OpenAPI/catalog. Use -them only when a user explicitly asks for that non-primary workflow: - -```bash -sume mcp --toolsets assets --allow-write -``` - -This adds: - -- `assets.create` -- `assets.upload_url` -- `assets.upload_file` -- `assets.complete` - -`assets.upload_file` is the safest MCP local-upload path. It reads one supplied -local file, creates a public API signed upload URL, PUTs bytes to that URL, and -completes the asset. The signed URL, storage headers, and local absolute file -path are not returned. Local MCP uploads are limited to 512 MiB. - -`assets.upload_url` returns a sensitive signed URL in raw API output, so prefer -agent-redacted MCP responses and do not echo signed URLs in final reports. - -## Paid Generation Tools - -Paid generation Avatar and Avatar Video submits require both write and paid -opt-ins: - -```bash -sume mcp --toolsets account,catalog,jobs,avatars,avatar-videos --allow-write --allow-paid -``` - -This adds: - -- `avatars.create` -- `avatars.create_prompt` -- `avatars.create_props` -- `avatars.create_photo_url` -- `avatar-videos.create` - -These tools submit public model-run requests to `api.sume.com`; they do not -claim output is ready. Use `jobs.wait`, `jobs.status`, `jobs.events`, and -`jobs.result` for recovery and readback. - -## Safety Rules - -- Never pass API keys as command-line arguments. -- Do not expose signed upload/download URLs, private media URLs, provider ids, - storage object keys, or raw auth headers in agent reports. -- Do not enable `--allow-write` or `--allow-paid` unless the user explicitly - approved the operation. -- Use `jobs.wait` for bounded polling; it calls `/jobs/:id/status` only and does - not start live generation work. +Watch Sume CLI releases for MCP launch notes. diff --git a/package.json b/package.json index 68a488e..fbc2f5b 100644 --- a/package.json +++ b/package.json @@ -1,13 +1,12 @@ { "name": "@sumelabs/cli", "version": "0.1.0", - "description": "Agent-first CLI and MCP tooling for sume.com", + "description": "Agent-first CLI tooling for sume.com", "type": "module", "license": "MIT", "keywords": [ "sume", "cli", - "mcp", "agent", "public-api" ], diff --git a/src/commands/doctor.ts b/src/commands/doctor.ts index 219c721..3ec9adb 100644 --- a/src/commands/doctor.ts +++ b/src/commands/doctor.ts @@ -8,7 +8,7 @@ import { redactApiKey, resolveConfig, } from "../lib/config.js"; -import { buildMcpDoctorReport } from "../lib/mcp-client-config.js"; +import { mcpComingSoonStatus } from "../lib/mcp-launch-status.js"; import { listToolSchemas } from "../lib/tool-registry.js"; import { renderResult } from "../lib/render.js"; import { section, warn } from "../lib/ui.js"; @@ -29,7 +29,6 @@ export function registerDoctorCommand(program: Command) { const configuredBaseUrl = process.env.SUME_API_BASE_URL ?? localConfig.baseUrl; const apiWarning = getApiBaseUrlDiagnostic(configuredBaseUrl); const tools = listToolSchemas(); - const mcpClients = buildMcpDoctorReport(); const payload = { object: "doctor_report", mode: options.agent ? "agent" : "human", @@ -55,15 +54,11 @@ export function registerDoctorCommand(program: Command) { path: configPath(), }, safety: { - mcp_default: "read_only", + mcp_status: "coming_soon", write_commands_require_confirmation: true, agent_job_outputs_redact_urls: true, }, - mcp_clients: { - ok: mcpClients.ok, - summary: mcpClients.summary, - clients: mcpClients.clients, - }, + mcp: mcpComingSoonStatus(), tools: { count: tools.length, read_only_count: tools.filter((tool) => tool.safety.read_only).length, @@ -77,8 +72,7 @@ export function registerDoctorCommand(program: Command) { "Run sume tools list --json before selecting commands.", "Use sume jobs list/watch/result --agent --json for job recovery.", "Ask for explicit user approval before --confirm-submit or --confirm-paid.", - "Use sume mcp without allow flags for default read-only MCP sessions.", - "Run sume mcp doctor --json to verify local MCP client config.", + "Use direct Sume CLI commands today; MCP is coming soon.", ] : [], }; @@ -95,14 +89,7 @@ export function registerDoctorCommand(program: Command) { ], ["API", resolvedConfig.baseUrl], ["Config", payload.config.path], - ["MCP default", payload.safety.mcp_default], - [ - "MCP clients", - `${payload.mcp_clients.summary.configured}/${payload.mcp_clients.summary.total} configured`, - ], - ...(payload.mcp_clients.summary.misconfigured - ? [warn("One or more MCP client configs are misconfigured.")] - : []), + ["MCP", payload.mcp.status], ...(apiWarning ? [warn(apiWarning.message)] : []), ], }); diff --git a/src/commands/mcp.ts b/src/commands/mcp.ts index 4e791d5..c9d63d2 100644 --- a/src/commands/mcp.ts +++ b/src/commands/mcp.ts @@ -1,28 +1,11 @@ import { Command } from "commander"; import { getMode } from "../lib/command.js"; -import { runSumeMcpStdio } from "../mcp/transports/stdio.js"; import { - DEFAULT_MCP_TOOLSETS, - MCP_TOOLSETS, - type McpToolset, -} from "../mcp/tools.js"; -import { CliError } from "../lib/errors.js"; -import { - buildMcpDoctorReport, - buildMcpInstallDryRun, - installMcpClientConfig, - inspectMcpClientConfig, - supportedMcpClientAgents, -} from "../lib/mcp-client-config.js"; + mcpComingSoonStatus, + mcpNotLaunchedError, +} from "../lib/mcp-launch-status.js"; +import { supportedMcpClientAgents } from "../lib/mcp-client-config.js"; import { renderResult } from "../lib/render.js"; -import { section, warn } from "../lib/ui.js"; - -type McpOptions = { - allowPaid?: boolean; - allowWrite?: boolean; - readOnly?: boolean; - toolsets?: string; -}; type McpInstallOptions = { agent?: string; @@ -33,137 +16,51 @@ type McpDoctorOptions = { agent?: string; }; -const DEFAULT_TOOLSETS = DEFAULT_MCP_TOOLSETS.join(","); - export function registerMcpCommand(program: Command) { const mcp = program - .command("mcp") - .description("Start the Sume MCP server over stdio.") - .option("--read-only", "Force read-only tool exposure.") - .option( - "--toolsets ", - `Comma-separated toolsets to expose. Available: ${MCP_TOOLSETS.join(", ")}.`, - DEFAULT_TOOLSETS, - ) - .option("--allow-write", "Expose mutating MCP tools from selected toolsets.") - .option( - "--allow-paid", - "Expose selected tools that may create paid generation work in the future.", - ) - .action(async (options: McpOptions) => { - const readOnly = Boolean(options.readOnly); - await runSumeMcpStdio({ - allowPaid: readOnly ? false : Boolean(options.allowPaid), - allowWrite: readOnly ? false : Boolean(options.allowWrite), - toolsets: parseToolsets(options.toolsets), - }); + .command("mcp", { hidden: true }) + .description("Sume MCP is coming soon.") + .action(() => { + throw mcpNotLaunchedError(); }); mcp .command("install") - .description("Install MCP client config for the local read-only Sume server.") + .description("Sume MCP client setup is coming soon.") .requiredOption( "--agent ", `Target MCP client. Supported: ${supportedMcpClientAgents().join(", ")}.`, ) - .option("--dry-run", "Print the config snippet without writing files.") - .action((options: McpInstallOptions, command: Command) => { - const result = options.dryRun - ? buildMcpInstallDryRun(options.agent ?? "") - : installMcpClientConfig(options.agent ?? ""); - renderResult(result, { - json: getMode(command).json, - human: [ - options.dryRun ? "Sume MCP install preview" : "Sume MCP installed", - ["Agent", result.agent], - ["Client", result.client], - ["Config", result.config_location], - ["Dry run", result.dry_run], - ["Writes config", result.writes_config], - ["Command", result.command.join(" ")], - "", - "Safety", - ...result.notes.map((note) => `- ${note}`), - "", - "Config snippet", - result.snippet.trimEnd(), - "", - "Next steps", - ...result.next_steps.map((step) => `- ${step}`), - ], - }); + .option("--dry-run", "Preview setup without writing client config.") + .action((_options: McpInstallOptions) => { + throw mcpNotLaunchedError( + "Sume MCP client setup is coming soon and is not launched in this CLI release yet.", + ); }); mcp .command("doctor") - .description("Inspect local MCP client config readiness.") + .description("Show Sume MCP launch status.") .option( "--agent ", - `Only inspect one MCP client. Supported: ${supportedMcpClientAgents().join(", ")}.`, + `Future MCP client to check. Supported: ${supportedMcpClientAgents().join(", ")}.`, ) .action((options: McpDoctorOptions, command: Command) => { - const result = options.agent - ? { - ...buildMcpDoctorReport(), - clients: [inspectMcpClientConfig(options.agent)], - } - : buildMcpDoctorReport(); - const summary = { - total: result.clients.length, - configured: result.clients.filter((client) => client.status === "configured") - .length, - unconfigured: result.clients.filter( - (client) => client.status === "unconfigured", - ).length, - misconfigured: result.clients.filter( - (client) => client.status === "misconfigured", - ).length, - }; const payload = { - ...result, - ok: summary.misconfigured === 0, - summary, + ...mcpComingSoonStatus(), + ...(options.agent ? { agent: options.agent } : {}), }; - const clientLines = payload.clients.flatMap( - (client): Array => [ - `${client.client}`, - ["Status", client.status], - ["Config", client.config_location], - ...(client.issues.length - ? client.issues.map((issue) => warn(issue.message)) - : []), - ], - ); renderResult(payload, { json: getMode(command).json, human: [ - section("Sume MCP doctor"), - ["Configured", `${summary.configured}/${summary.total}`], - ["Misconfigured", summary.misconfigured], + "Sume MCP", + "", + ["Status", payload.status], + ["Launched", payload.launched], "", - ...clientLines, + payload.message, + "Use direct Sume CLI commands today.", ], }); }); } - -function parseToolsets(value: string | undefined): McpToolset[] { - const rawToolsets = (value ?? DEFAULT_TOOLSETS) - .split(",") - .map((toolset) => toolset.trim()) - .filter(Boolean); - if (rawToolsets.length === 0) { - throw new CliError("--toolsets must include at least one toolset.", { - code: "invalid_argument", - }); - } - const valid = new Set(MCP_TOOLSETS); - const invalid = rawToolsets.filter((toolset) => !valid.has(toolset)); - if (invalid.length > 0) { - throw new CliError(`Unknown MCP toolset: ${invalid.join(", ")}`, { - code: "invalid_argument", - hint: `Use one or more of: ${MCP_TOOLSETS.join(", ")}`, - }); - } - return rawToolsets as McpToolset[]; -} diff --git a/src/commands/setup.ts b/src/commands/setup.ts index ec46098..5da03b5 100644 --- a/src/commands/setup.ts +++ b/src/commands/setup.ts @@ -1,20 +1,6 @@ import { Command } from "commander"; -import { getMode, showSubcommandHelp } from "../lib/command.js"; -import { - DEFAULT_AUTH_MODE, - getApiBaseUrlDiagnostic, - readConfig, - redactApiKey, - resolveConfig, -} from "../lib/config.js"; -import { - buildMcpInstallDryRun, - installMcpClientConfig, - inspectMcpClientConfig, - supportedMcpClientAgents, -} from "../lib/mcp-client-config.js"; -import { renderResult } from "../lib/render.js"; -import { section, warn } from "../lib/ui.js"; +import { agentSetupNotLaunchedError } from "../lib/mcp-launch-status.js"; +import { supportedMcpClientAgents } from "../lib/mcp-client-config.js"; type SetupAgentOptions = { agent?: string; @@ -23,89 +9,21 @@ type SetupAgentOptions = { export function registerSetupCommand(program: Command) { const setup = program - .command("setup") - .description("Set up local Sume integrations.") - .action((_options, command: Command) => - showSubcommandHelp(command, { defaultSubcommand: "agent" }), - ); + .command("setup", { hidden: true }) + .description("Sume agent setup is coming soon.") + .action(() => { + throw agentSetupNotLaunchedError(); + }); setup .command("agent") - .description("Set up read-only Sume MCP for a local agent client.") + .description("Sume agent setup is coming soon.") .requiredOption( "--agent ", - `Target MCP client. Supported: ${supportedMcpClientAgents().join(", ")}.`, + `Future agent client. Supported: ${supportedMcpClientAgents().join(", ")}.`, ) .option("--dry-run", "Preview setup without writing client config.") - .action((options: SetupAgentOptions, command: Command) => { - const agent = options.agent ?? ""; - const localConfig = readConfig(); - const resolvedConfig = resolveConfig(); - const configuredBaseUrl = process.env.SUME_API_BASE_URL ?? localConfig.baseUrl; - const apiWarning = getApiBaseUrlDiagnostic(configuredBaseUrl); - const mcp = options.dryRun - ? buildMcpInstallDryRun(agent) - : installMcpClientConfig(agent); - const readiness = inspectMcpClientConfig(agent); - const auth = { - configured: Boolean(resolvedConfig.apiKey), - api_key: redactApiKey(resolvedConfig.apiKey), - auth_mode: resolvedConfig.authMode ?? DEFAULT_AUTH_MODE, - source: process.env.SUME_API_KEY - ? "environment" - : localConfig.apiKey - ? "config" - : "none", - }; - const payload = { - object: "agent_setup", - schema_version: 1, - ok: !readiness.issues.length, - dry_run: Boolean(options.dryRun), - agent: mcp.agent, - client: mcp.client, - auth, - api: { - base_url: resolvedConfig.baseUrl, - configured_base_url: configuredBaseUrl, - warnings: apiWarning ? [apiWarning] : [], - }, - mcp_install: mcp, - mcp_readiness: readiness, - safety: { - mcp_default: "read_only", - write_tools_enabled: false, - paid_tools_enabled: false, - secrets_written: false, - }, - next_steps: [ - ...(!auth.configured ? ["Run sume login before calling Sume API tools."] : []), - `Run sume mcp doctor --agent ${mcp.agent} --json to verify config.`, - "Restart the MCP client so it reloads the Sume server entry.", - "See docs/mcp-toolsets.md for write and paid MCP gate guidance.", - ], - }; - - renderResult(payload, { - json: getMode(command).json, - human: [ - section("Sume agent setup"), - ["Agent", payload.agent], - ["Client", payload.client], - ["Dry run", payload.dry_run], - ["Auth", auth.configured ? `configured (${auth.source})` : "not configured"], - ["MCP config", readiness.status], - ["Config", readiness.config_location], - ...(apiWarning ? [warn(apiWarning.message)] : []), - "", - "Safety", - "- Installed MCP config runs only sume mcp.", - "- Write and paid MCP gates are not persisted.", - "- API keys and environment values are not written.", - "", - "Next steps", - ...payload.next_steps.map((step) => `- ${step}`), - ], - }); + .action((_options: SetupAgentOptions) => { + throw agentSetupNotLaunchedError(); }); } diff --git a/src/commands/tools.ts b/src/commands/tools.ts index cd24dcd..4e2825b 100644 --- a/src/commands/tools.ts +++ b/src/commands/tools.ts @@ -7,14 +7,14 @@ import { renderResult } from "../lib/render.js"; export function registerToolsCommand(program: Command) { const tools = program .command("tools") - .description("Discover Sume CLI and MCP tool contracts.") + .description("Discover Sume CLI command schemas.") .action((_options, command: Command) => showSubcommandHelp(command, { defaultSubcommand: "list" }), ); tools .command("list") - .description("List agent-facing tools with safety metadata.") + .description("List agent-facing CLI command schemas with safety metadata.") .action((_options, command: Command) => { renderResult( { @@ -36,7 +36,7 @@ export function registerToolsCommand(program: Command) { tools .command("schema") - .description("Show one tool schema and safety contract.") + .description("Show one CLI command schema and safety contract.") .argument("", "Tool name, for example jobs.result.") .action((name: string, _options, command: Command) => { const tool = getToolSchema(requireString(name, "name")); diff --git a/src/index.ts b/src/index.ts index 80d020f..136f7c4 100644 --- a/src/index.ts +++ b/src/index.ts @@ -20,6 +20,7 @@ import { registerUsageCommand } from "./commands/usage.js"; import { registerUpdateCommand } from "./commands/update.js"; import { registerVersionCommand } from "./commands/version.js"; import { CliError } from "./lib/errors.js"; +import { mcpComingSoonStatus } from "./lib/mcp-launch-status.js"; import { emitError, outputJson } from "./lib/output.js"; import { colors, @@ -96,8 +97,6 @@ if ( "doctor", "health", "jobs", - "mcp", - "setup", "skills", "tools", "balance", @@ -105,6 +104,7 @@ if ( "update", "version", ], + coming_soon: [mcpComingSoonStatus()], }); process.exit(0); } diff --git a/src/lib/bundled-skills-data.ts b/src/lib/bundled-skills-data.ts index d90ed75..623810f 100644 --- a/src/lib/bundled-skills-data.ts +++ b/src/lib/bundled-skills-data.ts @@ -1,23 +1,23 @@ export const bundledSkillFiles = { "sume": { - "SKILL.md": "---\nname: sume\ndescription: Use the Sume.com CLI and MCP server safely for auth, API discovery, avatars, avatar videos, jobs, balance, usage, and choosing focused Sume skills. Use this as the entry skill for current api.sume.com workflows.\n---\n\n# Sume Skill Router\n\nSume CLI is a thin wrapper over the current `api.sume.com` public API. It must\nnot call Sume databases, internal routes, provider APIs, or old `sume.so`-only\nsurfaces.\n\n## Core Rules\n\n1. Use `sume tools list --json` and `sume tools schema --json` before\n constructing writes.\n2. Use `--agent --json` whenever automation reads jobs, avatars, or\n avatar videos.\n3. Ask for explicit approval before `--confirm-submit`, `--confirm-paid`,\n `--allow-write`, or `--allow-paid`.\n4. Do not print API keys, auth approval URLs/codes in final reports, signed\n URLs, private media URLs, storage object keys, raw provider identifiers,\n workspace/user ids, or full result URLs.\n5. Use current public launch API surfaces only: account, catalog, balance,\n usage, jobs, Avatar 1.0, and Avatar Video 1.0.\n\n## Setup\n\n```bash\nsume --version\nsume auth status --json\nsume doctor --agent --json\n```\n\nUse browser login when the browser is local:\n\n```bash\nsume login\n```\n\nFor remote/headless terminals, use a short-lived background login process and\nshow the URL/code only to the requesting user. See `references/safety.md` for\nthe exact pattern.\n\n## Routing\n\n- Use `sume-tools` for MCP setup, schema discovery, and skill maintenance.\n- Use `sume-avatar` for creating several avatars and choosing a ready avatar.\n- Use `sume-avatar-video` for making videos from selected avatars and reading\n metadata/result state.\n- Use `sume-assets` only for explicitly requested advanced compatibility asset\n workflows; launch generation inputs should be stable public HTTPS URLs.\n\nRead `references/safety.md` for auth, paid/write gates, and redaction rules.\nRead `references/eval-scenarios.md` when validating agent behavior.\n\n## Not For\n\nDo not use old `sume.so` Brand, Ads, Face Swap, generic image/video generation,\nraw provider model, billing-write, file, or asset-search workflows unless they\nappear in the current public `api.sume.com` catalog and tool schemas.\n", "references/eval-scenarios.md": "# Sume Agent Eval Scenarios\n\nUse these scenarios to QA skill routing and safety behavior.\n\n1. Missing auth: agent runs `sume doctor --agent --json`, sees missing auth, and\n asks for login/API-key setup without printing secrets in the final report.\n2. Create several avatars: agent drafts a local avatar batch plan, asks for paid\n approval, submits with idempotency keys, then watches jobs.\n3. Choose an avatar: agent lists ready avatars with `--agent --json`, compares\n names/status/artifacts, and asks the user to choose by taste.\n4. Selected avatar to video: agent uses the chosen ready avatar handle\n with `sume avatar-videos create --confirm-paid --agent --json`, then watches\n and reads result.\n5. Metadata/readback: agent calls `sume avatar-videos get` and\n `sume jobs result --agent --json`, summarizes status, scenes/tags/summary if\n present, and does not paste full URLs.\n6. Paid gate: agent refuses to submit Avatar or Avatar Video jobs until the user\n explicitly authorizes paid generation work.\n", - "references/safety.md": "# Sume Safety Reference\n\n## Auth\n\n- Prefer `sume login` only when the browser is on the same machine.\n- In remote/headless terminals, avoid a long foreground login waiter because\n intermediate auth URLs/codes can be hidden until timeout or persisted in logs.\n- Use a short-lived process log:\n\n```bash\nlogin_log=\"$(mktemp -t sume-login.XXXXXX.log)\"\n(sume login --no-browser --timeout 600 >\"$login_log\" 2>&1; echo $? >\"$login_log.status\") &\nlogin_pid=$!\nsleep 4\nsed -n '1,80p' \"$login_log\"\n```\n\nAfter user approval:\n\n```bash\nwait \"$login_pid\"\nsume auth status --json\nrm -f \"$login_log\" \"$login_log.status\"\n```\n\n## Gates\n\n- `--confirm-submit`: non-paid writes such as asset registration, upload\n completion, and job cancellation.\n- `--confirm-paid`: paid generation submits such as Avatar 1.0 and Avatar Video\n 1.0 creation.\n- MCP `--allow-write`: exposes mutating non-paid tools.\n- MCP `--allow-paid`: exposes paid generation submit tools and should be paired\n with `--allow-write` for submit actions.\n\n## Sensitive Outputs\n\nNever echo API keys, approval codes, signed upload/download URLs, private media\nURLs, storage object keys, raw auth headers, provider ids, workspace/user ids,\nor full result URLs in reports. Use `--agent --json` and summarize redacted\nmetadata.\n\n## Current Public Boundary\n\nAllowed current launch surfaces: `GET /me`, `GET /catalog`, `GET /balance`,\n`GET /usage`, jobs, Avatar 1.0 model runs, Avatar Video 1.0 model runs, avatar\nresources, and avatar-video resources. `/v1/assets/*` is advanced\ncompatibility tooling only and is hidden from the launch OpenAPI/catalog.\n\nExcluded until public contracts exist: old Brand, Ads, Face Swap, generic\nimage/video generation, arbitrary file APIs, provider ids, and billing-write\noperations.\n" + "references/safety.md": "# Sume Safety Reference\n\n## Auth\n\n- Prefer `sume login` only when the browser is on the same machine.\n- In remote/headless terminals, avoid a long foreground login waiter because\n intermediate auth URLs/codes can be hidden until timeout or persisted in logs.\n- Use a short-lived process log:\n\n```bash\nlogin_log=\"$(mktemp -t sume-login.XXXXXX.log)\"\n(sume login --no-browser --timeout 600 >\"$login_log\" 2>&1; echo $? >\"$login_log.status\") &\nlogin_pid=$!\nsleep 4\nsed -n '1,80p' \"$login_log\"\n```\n\nAfter user approval:\n\n```bash\nwait \"$login_pid\"\nsume auth status --json\nrm -f \"$login_log\" \"$login_log.status\"\n```\n\n## Gates\n\n- `--confirm-submit`: non-paid writes such as asset registration, upload\n completion, and job cancellation.\n- `--confirm-paid`: paid generation submits such as Avatar 1.0 and Avatar Video\n 1.0 creation.\n\n## Sensitive Outputs\n\nNever echo API keys, approval codes, signed upload/download URLs, private media\nURLs, storage object keys, raw auth headers, provider ids, workspace/user ids,\nor full result URLs in reports. Use `--agent --json` and summarize redacted\nmetadata.\n\n## Current Public Boundary\n\nAllowed current launch surfaces: `GET /me`, `GET /catalog`, `GET /balance`,\n`GET /usage`, jobs, Avatar 1.0 model runs, Avatar Video 1.0 model runs, avatar\nresources, and avatar-video resources. `/v1/assets/*` is advanced\ncompatibility tooling only and is hidden from the launch OpenAPI/catalog.\n\nExcluded until public contracts exist: old Brand, Ads, Face Swap, generic\nimage/video generation, arbitrary file APIs, provider ids, and billing-write\noperations.\n\nSume MCP is coming soon and is not part of this public CLI launch release yet.\nUse direct CLI commands today.\n", + "SKILL.md": "---\nname: sume\ndescription: Use the Sume.com CLI safely for auth, API discovery, avatars, avatar videos, jobs, balance, usage, and choosing focused Sume skills. Use this as the entry skill for current api.sume.com workflows.\n---\n\n# Sume Skill Router\n\nSume CLI is a thin wrapper over the current `api.sume.com` public API. It must\nnot call Sume databases, internal routes, provider APIs, or old `sume.so`-only\nsurfaces.\n\n## Core Rules\n\n1. Use `sume tools list --json` and `sume tools schema --json` before\n constructing writes.\n2. Use `--agent --json` whenever automation reads jobs, avatars, or\n avatar videos.\n3. Ask for explicit approval before `--confirm-submit` or `--confirm-paid`.\n4. Do not print API keys, auth approval URLs/codes in final reports, signed\n URLs, private media URLs, storage object keys, raw provider identifiers,\n workspace/user ids, or full result URLs.\n5. Use current public launch API surfaces only: account, catalog, balance,\n usage, jobs, Avatar 1.0, and Avatar Video 1.0.\n\n## Setup\n\n```bash\nsume --version\nsume auth status --json\nsume doctor --agent --json\n```\n\nUse browser login when the browser is local:\n\n```bash\nsume login\n```\n\nFor remote/headless terminals, use a short-lived background login process and\nshow the URL/code only to the requesting user. See `references/safety.md` for\nthe exact pattern.\n\n## Routing\n\n- Use `sume-tools` for schema discovery and skill maintenance.\n- Use `sume-avatar` for creating several avatars and choosing a ready avatar.\n- Use `sume-avatar-video` for making videos from selected avatars and reading\n metadata/result state.\n- Use `sume-assets` only for explicitly requested advanced compatibility asset\n workflows; launch generation inputs should be stable public HTTPS URLs.\n\nRead `references/safety.md` for auth, paid/write gates, and redaction rules.\nRead `references/eval-scenarios.md` when validating agent behavior.\n\nSume MCP is coming soon and is not part of this public CLI launch release yet.\nUse direct CLI commands today.\n\n## Not For\n\nDo not use old `sume.so` Brand, Ads, Face Swap, generic image/video generation,\nraw provider model, billing-write, file, or asset-search workflows unless they\nappear in the current public `api.sume.com` catalog and tool schemas.\n" }, "sume-assets": { - "SKILL.md": "---\nname: sume-assets\ndescription: Use advanced compatibility Sume.com asset tools for approved internal/agent workflows; launch Avatar and Avatar Video inputs should use stable public HTTPS URLs directly.\n---\n\n# Sume Assets\n\nUse this skill only when the user explicitly asks for advanced compatibility\n`api.sume.com` asset tooling. `/v1/assets/*` is hidden from the launch\nOpenAPI/catalog; normal Avatar and Avatar Video generation should use stable\npublic HTTPS URLs directly.\n\n## Discover Contracts\n\n```bash\nsume tools schema assets.create --json\nsume tools schema assets.upload_file --json\nsume tools schema assets.download_url --json\n```\n\n## Register Public URL\n\n```bash\nsume assets create \\\n --source-url https://example.com/reference.png \\\n --media-type image \\\n --confirm-submit \\\n --agent \\\n --json\n```\n\nOnly register public HTTPS URLs that the user approved. The public API does not\necho the original source URL in readback.\n\n## Direct Upload\n\nFor MCP, prefer:\n\n```bash\nsume mcp --toolsets assets --allow-write\n```\n\nCall `assets.upload_file` with a local path and content type. It performs\nupload-url, signed PUT, and complete internally without returning the signed URL\nor local absolute path.\n\nFor shell workflows, use `assets upload-url`, PUT bytes outside the CLI, then\n`assets complete`. Never paste signed URLs into reports.\n\n## Download\n\nUse CLI download helpers only when the user asks for local files:\n\n```bash\nsume assets download --output-dir ./outputs --json\nsume jobs download --output-dir ./outputs --json\n```\n\nRead `references/media-workflows.md` for details.\n\n## Not For\n\nDo not use assets as the default launch upload path, and do not pass asset ids\ninto generation requests unless the current OpenAPI schema explicitly accepts\nthem. Do not use old Asset Library scene search or `uploads/presign`; those are\n`sume.so`-only unless the current public catalog exposes them.\n", - "references/media-workflows.md": "# Media Workflows\n\n## Upload Safety\n\n- Signed upload URLs and headers are temporary credentials.\n- Do not send Sume API auth headers to signed storage URLs.\n- `assets.upload_file` and `sume assets upload-file` style helpers should keep\n signed URLs internal and return only redacted asset metadata.\n\n## Download Safety\n\n- Download only into an explicit user-approved output directory.\n- Download helpers should accept only URL fields returned by public Sume job or\n asset responses.\n- Final reports should summarize local filenames, sizes, and counts, not remote\n URLs.\n\n## Asset Usage\n\nLaunch model-run inputs accept URL references where the OpenAPI schema defines\nmedia fields. `/v1/assets/*` remains an advanced compatibility workflow, not the\ndefault public upload path. Do not assume an asset id is valid in a submit\nrequest unless the schema says so.\n" + "references/media-workflows.md": "# Media Workflows\n\n## Upload Safety\n\n- Signed upload URLs and headers are temporary credentials.\n- Do not send Sume API auth headers to signed storage URLs.\n- Direct upload helpers should keep signed URLs internal and return only\n redacted asset metadata.\n\n## Download Safety\n\n- Download only into an explicit user-approved output directory.\n- Download helpers should accept only URL fields returned by public Sume job or\n asset responses.\n- Final reports should summarize local filenames, sizes, and counts, not remote\n URLs.\n\n## Asset Usage\n\nLaunch model-run inputs accept URL references where the OpenAPI schema defines\nmedia fields. `/v1/assets/*` remains an advanced compatibility workflow, not the\ndefault public upload path. Do not assume an asset id is valid in a submit\nrequest unless the schema says so.\n", + "SKILL.md": "---\nname: sume-assets\ndescription: Use advanced compatibility Sume.com asset tools for approved internal/agent workflows; launch Avatar and Avatar Video inputs should use stable public HTTPS URLs directly.\n---\n\n# Sume Assets\n\nUse this skill only when the user explicitly asks for advanced compatibility\n`api.sume.com` asset tooling. `/v1/assets/*` is hidden from the launch\nOpenAPI/catalog; normal Avatar and Avatar Video generation should use stable\npublic HTTPS URLs directly.\n\n## Discover Contracts\n\n```bash\nsume tools schema assets.create --json\nsume tools schema assets.upload_url --json\nsume tools schema assets.complete --json\nsume tools schema assets.download_url --json\n```\n\n## Register Public URL\n\n```bash\nsume assets create \\\n --source-url https://example.com/reference.png \\\n --media-type image \\\n --confirm-submit \\\n --agent \\\n --json\n```\n\nOnly register public HTTPS URLs that the user approved. The public API does not\necho the original source URL in readback.\n\n## Direct Upload\n\nUse `assets upload-url`, PUT bytes outside the CLI, then `assets complete`.\nNever paste signed URLs into reports.\n\n## Download\n\nUse CLI download helpers only when the user asks for local files:\n\n```bash\nsume assets download --output-dir ./outputs --json\nsume jobs download --output-dir ./outputs --json\n```\n\nRead `references/media-workflows.md` for details.\n\n## Not For\n\nDo not use assets as the default launch upload path, and do not pass asset ids\ninto generation requests unless the current OpenAPI schema explicitly accepts\nthem. Do not use old Asset Library scene search or `uploads/presign`; those are\n`sume.so`-only unless the current public catalog exposes them.\n" }, "sume-avatar": { - "SKILL.md": "---\nname: sume-avatar\ndescription: Create, inspect, batch-plan, and select Sume Avatar 1.0 resources with safe paid gates and agent-redacted readback.\n---\n\n# Sume Avatar\n\nUse this skill for Avatar 1.0 creation and selection.\n\n## Discover\n\n```bash\nsume tools schema avatars.create --json\nsume tools schema avatars.list --json\nsume tools schema jobs.wait --json\n```\n\n## Single Avatar\n\n```bash\nsume avatars create \\\n --type prompt \\\n --avatar-handle presenter \\\n --prompt \"Friendly skincare presenter\" \\\n --confirm-paid \\\n --agent \\\n --json\n```\n\nPhoto and profile-style creation are current public inputs:\n\n```bash\nsume avatars create --type photo --avatar-handle photo_ref --image-url https://example.com/person.png --confirm-paid --agent --json\nsume avatars create --type props --avatar-handle profile --ethnicity Asian --sex female --age 28 --confirm-paid --agent --json\n```\n\n## Several Avatars\n\nPlan locally first:\n\n```bash\nsume avatars batch plan ./avatars.json --output-file ./avatars.plan.json --json\n```\n\nAfter explicit paid approval:\n\n```bash\nsume avatars batch create ./avatars.json --state-file ./avatars.state.json --confirm-paid --json\nsume avatars batch watch ./avatars.json --state-file ./avatars.state.json --json\nsume avatars batch result ./avatars.json --state-file ./avatars.state.json --json\n```\n\nUse ready avatar handles with `sume-avatar-video`.\n\n## Selection\n\n```bash\nsume avatars list --ready --agent --json\nsume avatars list --handle presenter --agent --json\nsume avatars get --agent --json\n```\n\nSummarize name, status, creation style, artifacts count, and any taste-relevant\nmetadata. Do not paste raw media URLs.\n", - "references/avatar-batch-manifest.md": "# Avatar Batch Manifest\n\n```json\n{\n \"defaults\": {\n \"mode\": \"async\"\n },\n \"avatars\": [\n {\n \"id\": \"friendly\",\n \"type\": \"prompt\",\n \"avatar_handle\": \"friendly_presenter\",\n \"prompt\": \"Warm, direct-to-camera skincare presenter\"\n },\n {\n \"id\": \"photo\",\n \"type\": \"photo\",\n \"avatar_handle\": \"photo_reference\",\n \"image_url\": \"https://example.com/person.png\"\n },\n {\n \"id\": \"profile\",\n \"type\": \"props\",\n \"avatar_handle\": \"profile_presenter\",\n \"ethnicity\": \"Asian\",\n \"sex\": \"female\",\n \"age\": 28\n }\n ]\n}\n```\n\n`batch plan` is local and no-provider. `batch create` is paid generation\nand must use `--confirm-paid`. Reruns with the same state file should not create\nduplicate jobs for items that already have a job id.\n" + "references/avatar-batch-manifest.md": "# Avatar Batch Manifest\n\n```json\n{\n \"defaults\": {\n \"mode\": \"async\"\n },\n \"avatars\": [\n {\n \"id\": \"friendly\",\n \"type\": \"prompt\",\n \"avatar_handle\": \"friendly_presenter\",\n \"prompt\": \"Warm, direct-to-camera skincare presenter\"\n },\n {\n \"id\": \"photo\",\n \"type\": \"photo\",\n \"avatar_handle\": \"photo_reference\",\n \"image_url\": \"https://example.com/person.png\"\n },\n {\n \"id\": \"profile\",\n \"type\": \"props\",\n \"avatar_handle\": \"profile_presenter\",\n \"ethnicity\": \"Asian\",\n \"sex\": \"female\",\n \"age\": 28\n }\n ]\n}\n```\n\n`batch plan` is local and no-provider. `batch create` is paid generation\nand must use `--confirm-paid`. Reruns with the same state file should not create\nduplicate jobs for items that already have a job id.\n", + "SKILL.md": "---\nname: sume-avatar\ndescription: Create, inspect, batch-plan, and select Sume Avatar 1.0 resources with safe paid gates and agent-redacted readback.\n---\n\n# Sume Avatar\n\nUse this skill for Avatar 1.0 creation and selection.\n\n## Discover\n\n```bash\nsume tools schema avatars.create --json\nsume tools schema avatars.list --json\nsume tools schema jobs.watch --json\n```\n\n## Single Avatar\n\n```bash\nsume avatars create \\\n --type prompt \\\n --avatar-handle presenter \\\n --prompt \"Friendly skincare presenter\" \\\n --confirm-paid \\\n --agent \\\n --json\n```\n\nPhoto and profile-style creation are current public inputs:\n\n```bash\nsume avatars create --type photo --avatar-handle photo_ref --image-url https://example.com/person.png --confirm-paid --agent --json\nsume avatars create --type props --avatar-handle profile --ethnicity Asian --sex female --age 28 --confirm-paid --agent --json\n```\n\n## Several Avatars\n\nPlan locally first:\n\n```bash\nsume avatars batch plan ./avatars.json --output-file ./avatars.plan.json --json\n```\n\nAfter explicit paid approval:\n\n```bash\nsume avatars batch create ./avatars.json --state-file ./avatars.state.json --confirm-paid --json\nsume avatars batch watch ./avatars.json --state-file ./avatars.state.json --json\nsume avatars batch result ./avatars.json --state-file ./avatars.state.json --json\n```\n\nUse ready avatar handles with `sume-avatar-video`.\n\n## Selection\n\n```bash\nsume avatars list --ready --agent --json\nsume avatars list --handle presenter --agent --json\nsume avatars get --agent --json\n```\n\nSummarize name, status, creation style, artifacts count, and any taste-relevant\nmetadata. Do not paste raw media URLs.\n" }, "sume-avatar-video": { - "SKILL.md": "---\nname: sume-avatar-video\ndescription: Create, batch-plan, watch, and inspect Sume Avatar Video 1.0 resources from selected avatars with metadata-aware readback and safe paid gates.\n---\n\n# Sume Avatar Video\n\nUse this skill after a ready avatar is selected.\n\n## Discover\n\n```bash\nsume tools schema avatar-videos.create --json\nsume tools schema avatar-videos.get --json\nsume tools schema jobs.result --json\n```\n\n## Single Video\n\n```bash\nsume avatar-videos create \\\n --avatar-handle \\\n --script \"This serum absorbs quickly.\" \\\n --scene-prompt \"Bright clean studio\" \\\n --confirm-paid \\\n --agent \\\n --json\n```\n\nThen:\n\n```bash\nsume jobs watch --agent --json\nsume jobs result --agent --json\nsume avatar-videos get --agent --json\n```\n\nScripts are estimated locally and by the API; accepted target duration is 4-60\nseconds inclusive. Use handles for avatar handoffs.\nAdd `--product-image` when the user provides a public product/reference image;\nomit it for productless avatar videos.\n\nSummarize status, artifacts, duration, tags, scenes, transcript, and summary\nwhen present. Do not paste full media URLs.\n\n## Batch Videos\n\n```bash\nsume avatar-videos batch plan ./avatar-videos.json --output-file ./avatar-videos.plan.json --json\nsume avatar-videos batch create ./avatar-videos.json --state-file ./avatar-videos.state.json --confirm-paid --json\nsume avatar-videos batch watch ./avatar-videos.json --state-file ./avatar-videos.state.json --json\nsume avatar-videos batch result ./avatar-videos.json --state-file ./avatar-videos.state.json --json\n```\n\nRead `references/avatar-video-batch-manifest.md` for manifest shape.\n\n## Not For\n\nDo not route generic video generation, Ads, UGC Ads, Face Swap, or raw provider\nmodel ids through this skill unless they are added to the current public\n`api.sume.com` catalog.\n", - "references/avatar-video-batch-manifest.md": "# Avatar Video Batch Manifest\n\n```json\n{\n \"defaults\": {\n \"avatar_handle\": \"ready_avatar\",\n \"scene_prompt\": \"Bright studio\",\n \"mode\": \"async\"\n },\n \"videos\": [\n {\n \"id\": \"hook\",\n \"script\": \"This is the quick morning skincare step.\"\n },\n {\n \"id\": \"demo\",\n \"script\": \"Apply a small amount and watch it absorb.\",\n \"title\": \"Application demo\"\n }\n ]\n}\n```\n\n`batch plan` is local and no-provider. `batch create` is paid generation\nand requires `--confirm-paid`. Use a persistent state file so reruns skip items\nthat already have a job id.\n\nScripts are estimated locally and by the API; accepted target duration is 4-60\nseconds inclusive.\nAdd `product_image` in defaults or per-video entries only when the user provides\na public product/reference image.\n" + "references/avatar-video-batch-manifest.md": "# Avatar Video Batch Manifest\n\n```json\n{\n \"defaults\": {\n \"avatar_handle\": \"ready_avatar\",\n \"scene_prompt\": \"Bright studio\",\n \"mode\": \"async\"\n },\n \"videos\": [\n {\n \"id\": \"hook\",\n \"script\": \"This is the quick morning skincare step.\"\n },\n {\n \"id\": \"demo\",\n \"script\": \"Apply a small amount and watch it absorb.\",\n \"title\": \"Application demo\"\n }\n ]\n}\n```\n\n`batch plan` is local and no-provider. `batch create` is paid generation\nand requires `--confirm-paid`. Use a persistent state file so reruns skip items\nthat already have a job id.\n\nScripts are estimated locally and by the API; accepted target duration is 4-60\nseconds inclusive.\nAdd `product_image` in defaults or per-video entries only when the user provides\na public product/reference image.\n", + "SKILL.md": "---\nname: sume-avatar-video\ndescription: Create, batch-plan, watch, and inspect Sume Avatar Video 1.0 resources from selected avatars with metadata-aware readback and safe paid gates.\n---\n\n# Sume Avatar Video\n\nUse this skill after a ready avatar is selected.\n\n## Discover\n\n```bash\nsume tools schema avatar-videos.create --json\nsume tools schema avatar-videos.get --json\nsume tools schema jobs.result --json\n```\n\n## Single Video\n\n```bash\nsume avatar-videos create \\\n --avatar-handle \\\n --script \"This serum absorbs quickly.\" \\\n --scene-prompt \"Bright clean studio\" \\\n --confirm-paid \\\n --agent \\\n --json\n```\n\nThen:\n\n```bash\nsume jobs watch --agent --json\nsume jobs result --agent --json\nsume avatar-videos get --agent --json\n```\n\nScripts are estimated locally and by the API; accepted target duration is 4-60\nseconds inclusive. Use handles for avatar handoffs.\nAdd `--product-image` when the user provides a public product/reference image;\nomit it for productless avatar videos.\n\nSummarize status, artifacts, duration, tags, scenes, transcript, and summary\nwhen present. Do not paste full media URLs.\n\n## Batch Videos\n\n```bash\nsume avatar-videos batch plan ./avatar-videos.json --output-file ./avatar-videos.plan.json --json\nsume avatar-videos batch create ./avatar-videos.json --state-file ./avatar-videos.state.json --confirm-paid --json\nsume avatar-videos batch watch ./avatar-videos.json --state-file ./avatar-videos.state.json --json\nsume avatar-videos batch result ./avatar-videos.json --state-file ./avatar-videos.state.json --json\n```\n\nRead `references/avatar-video-batch-manifest.md` for manifest shape.\n\n## Not For\n\nDo not route generic video generation, Ads, UGC Ads, Face Swap, or raw provider\nmodel ids through this skill unless they are added to the current public\n`api.sume.com` catalog.\n" }, "sume-tools": { - "SKILL.md": "---\nname: sume-tools\ndescription: Configure Sume.com CLI/MCP for agents, discover tool schemas, install or export bundled Sume skills, inspect balance/usage, and choose safe public-api workflows.\n---\n\n# Sume Tools\n\nUse this skill for setup, MCP toolset selection, schema discovery, and local\nskill maintenance.\n\n## Discovery\n\n```bash\nsume setup agent --agent codex\nsume mcp doctor --json\nsume doctor --agent --json\nsume tools list --json\nsume tools schema avatars.create --json\nsume tools schema avatars.create_photo_url --json\nsume tools schema avatar-videos.create --json\nsume balance --json\nsume usage get --json\n```\n\n## Skill Maintenance\n\n```bash\nsume skills list --json\nsume skills install sume --json\nsume skills install sume-avatar --json\nsume skills update --json\n```\n\nSkills install into `.agents/skills/` when `.agents/` exists, otherwise\n`.claude/skills/` when `.claude/` exists.\n\n## MCP\n\nDefault MCP is read-only:\n\n```bash\nsume mcp\nsume mcp install --agent codex\nsume mcp doctor --agent codex --json\n```\n\nUse explicit gates only after approval:\n\n```bash\nsume mcp --toolsets jobs --allow-write\nsume mcp --toolsets avatars,avatar-videos --allow-write --allow-paid\n```\n\nPaid MCP calls still require per-call `idempotency_key` and `max_spend_usd`.\nUse `dry_run: true` before submitting.\n\nRead `references/mcp-toolsets.md` before enabling non-default tools.\n\n## Not For\n\nDo not execute paid creation directly from this skill. Route avatar work to\n`sume-avatar` and video work to `sume-avatar-video`. Route media inputs through\npublic HTTPS URLs unless the user explicitly asks for advanced compatibility\nasset tooling.\n", - "references/mcp-toolsets.md": "# MCP Toolsets\n\n## Default\n\n`sume mcp` exposes read-only, agent-redacted tools:\n\n- `tools.list`, `tools.schema`\n- `health.service`, `health.v1`\n- `account.me`, `balance.get`, `usage.get`\n- `catalog.list`\n- `jobs.list`, `jobs.get`, `jobs.status`, `jobs.events`, `jobs.result`, `jobs.wait`\n- `avatars.list`, `avatars.get`, `avatars.wait`\n- `avatar-videos.list`, `avatar-videos.get`\n\n## Write Gate\n\n```bash\nsume mcp --toolsets jobs --allow-write\n```\n\nAdds non-paid writes such as `jobs.cancel`.\n\nAdvanced compatibility asset tools are hidden from the launch OpenAPI/catalog\nand are not part of default MCP. Use them only when explicitly requested:\n\n```bash\nsume mcp --toolsets assets --allow-write\n```\n\nThis exposes `assets.create`, `assets.upload_url`, `assets.upload_file`,\n`assets.complete`, and readback helpers.\n\n## Paid Gate\n\n```bash\nsume mcp --toolsets avatars,avatar-videos --allow-write --allow-paid\n```\n\nAdds paid generation `avatars.create`, `avatars.create_prompt`,\n`avatars.create_props`, `avatars.create_photo_url`, and `avatar-videos.create`.\n\nPaid tool calls require per-call `idempotency_key` and `max_spend_usd`. Use\n`dry_run: true` to run a non-submitting Sume cost/readiness preview without creating a job.\n\nUse `jobs.wait` and `jobs.result` for readback. Do not ask MCP to reveal signed\nURLs or private media URLs.\n" + "references/mcp-toolsets.md": "# MCP Coming Soon\n\nSume MCP is coming soon and is not part of this public CLI launch release yet.\nUse direct CLI commands today for auth, schema discovery, Avatar, Avatar Video,\njobs, balance, and usage workflows.\n\n```bash\nsume login\nsume doctor --agent --json\nsume tools list --json\nsume tools schema avatars.create --json\nsume tools schema avatar-videos.create --json\n```\n", + "SKILL.md": "---\nname: sume-tools\ndescription: Discover Sume.com CLI tool schemas, install or export bundled Sume skills, inspect balance/usage, and choose safe public-api workflows.\n---\n\n# Sume Tools\n\nUse this skill for schema discovery and local skill maintenance.\n\n## Discovery\n\n```bash\nsume doctor --agent --json\nsume tools list --json\nsume tools schema avatars.create --json\nsume tools schema avatar-videos.create --json\nsume balance --json\nsume usage get --json\n```\n\n## Skill Maintenance\n\n```bash\nsume skills list --json\nsume skills install sume --json\nsume skills install sume-avatar --json\nsume skills update --json\n```\n\nSkills install into `.agents/skills/` when `.agents/` exists, otherwise\n`.claude/skills/` when `.claude/` exists.\n\n## MCP\n\nSume MCP is coming soon and is not part of this public CLI launch release yet.\nUse direct CLI commands today.\n\n## Not For\n\nDo not execute paid creation directly from this skill. Route avatar work to\n`sume-avatar` and video work to `sume-avatar-video`. Route media inputs through\npublic HTTPS URLs unless the user explicitly asks for advanced compatibility\nasset tooling.\n" } } as const; diff --git a/src/lib/mcp-launch-status.ts b/src/lib/mcp-launch-status.ts new file mode 100644 index 0000000..ad42f06 --- /dev/null +++ b/src/lib/mcp-launch-status.ts @@ -0,0 +1,42 @@ +import { CliError } from "./errors.js"; + +export const MCP_COMING_SOON_MESSAGE = + "Sume MCP is coming soon and is not launched in this CLI release yet."; + +export const MCP_DIRECT_CLI_HINT = + "Use direct Sume CLI commands today: sume login, sume tools list --json, sume avatars create --help, sume avatar-videos create --help, sume jobs --help."; + +export const MCP_COMING_SOON_NEXT_STEPS = [ + "Use sume login to authenticate.", + "Use sume tools list --json for command schemas.", + "Use sume avatars, sume avatar-videos, and sume jobs commands for launch workflows.", + "Watch Sume CLI releases for MCP launch.", +]; + +export function mcpComingSoonStatus() { + return { + object: "mcp_status", + status: "coming_soon", + launched: false, + message: MCP_COMING_SOON_MESSAGE, + recommended_surface: "direct_cli", + next_steps: MCP_COMING_SOON_NEXT_STEPS, + }; +} + +export function mcpNotLaunchedError(message = MCP_COMING_SOON_MESSAGE) { + return new CliError(message, { + code: "mcp_not_launched", + hint: MCP_DIRECT_CLI_HINT, + }); +} + +export function agentSetupNotLaunchedError() { + return new CliError( + "Sume agent setup is coming soon and is not launched in this CLI release yet.", + { + code: "agent_setup_not_launched", + hint: `No agent or MCP client config was written. ${MCP_DIRECT_CLI_HINT}`, + }, + ); +} diff --git a/src/lib/tool-registry.ts b/src/lib/tool-registry.ts index b021032..a6f4f06 100644 --- a/src/lib/tool-registry.ts +++ b/src/lib/tool-registry.ts @@ -26,7 +26,6 @@ export type ToolSchema = { description: string; confirmation?: { accepted_flags: string[]; - mcp_session_gates: string[]; required: boolean; }; input_schema: JsonSchema; @@ -41,6 +40,10 @@ export type ToolSchema = { generation_execution: GenerationExecution; generation_runtime: GenerationRuntime; }; + mcp: { + status: "coming_soon"; + launched: false; + }; constraints?: string[]; }; @@ -105,7 +108,6 @@ const communicationProperties = { }; const submitConfirmation = { accepted_flags: ["confirm_submit", "confirm_paid"], - mcp_session_gates: ["allowWrite", "allowPaid"], required: true, }; const avatarModelProperties = { @@ -117,7 +119,6 @@ const avatarModelProperties = { }; const writeConfirmation = { accepted_flags: ["confirm_submit"], - mcp_session_gates: ["allowWrite"], required: true, }; const mcpSubmitProperties = { @@ -379,17 +380,17 @@ const staticToolDefinitions: Record = { ], }, "tools.list": { - command: "MCP tools.list", - description: "List local Sume CLI and MCP tool contracts with safety metadata.", + command: "sume tools list --json", + description: "List local Sume CLI command schemas with safety metadata.", input_schema: objectSchema({}), examples: ["sume tools list --json"], next_steps: [ - "Use tools.schema from MCP or sume tools schema --json to inspect one contract.", + "Use sume tools schema --json to inspect one command contract.", ], }, "tools.schema": { - command: "MCP tools.schema", - description: "Read one local Sume CLI or MCP tool contract by name.", + command: "sume tools schema --json", + description: "Read one local Sume CLI command contract by name.", input_schema: objectSchema( { name: { ...stringProperty, minLength: 1 }, @@ -398,7 +399,7 @@ const staticToolDefinitions: Record = { ), examples: ["sume tools schema jobs.result --json"], next_steps: [ - "Use the returned mcp_input_schema for MCP payloads and input_schema for CLI flags.", + "Use the returned input_schema to construct direct CLI commands.", ], }, "catalog.list": { @@ -742,13 +743,11 @@ const staticToolDefinitions: Record = { "MCP assets.upload_file { path: './reference.png', content_type: 'image/png', media_type: 'image' }", ], next_steps: [ - "The signed upload URL is used internally and redacted from MCP output.", + "Sume MCP is coming soon and this helper is not part of the public CLI launch surface yet.", "Use assets.get to confirm the asset status later.", ], constraints: [ - "Available only when the MCP server is started with --allow-write.", - "Hidden from the default launch MCP server; select --toolsets assets explicitly.", - "MCP local file uploads are limited to 512 MiB.", + "MCP is coming soon and is not launched in this CLI release yet.", ], }, "assets.complete": { @@ -1124,7 +1123,7 @@ const staticToolDefinitions: Record = { ], constraints: [ "Runs through an internal Sume cost/readiness preview before submit.", - "Requires MCP --allow-write --allow-paid gates and per-call max_spend_usd.", + "MCP is coming soon and is not launched in this CLI release yet.", ], generation_execution: "sume_api", generation_runtime: "sume_api", @@ -1158,7 +1157,7 @@ const staticToolDefinitions: Record = { ], constraints: [ "Runs through an internal Sume cost/readiness preview before submit.", - "Requires MCP --allow-write --allow-paid gates and per-call max_spend_usd.", + "MCP is coming soon and is not launched in this CLI release yet.", ], generation_execution: "sume_api", generation_runtime: "sume_api", @@ -1191,7 +1190,7 @@ const staticToolDefinitions: Record = { constraints: [ "Runs through an internal Sume cost/readiness preview before submit.", "Local file upload is deferred until the public URL-first upload helper is available.", - "Requires MCP --allow-write --allow-paid gates and per-call max_spend_usd.", + "MCP is coming soon and is not launched in this CLI release yet.", ], generation_execution: "sume_api", generation_runtime: "sume_api", @@ -1562,7 +1561,9 @@ const cliOnlyToolDefinitions: Record = { }; export const toolSchemas: ToolSchema[] = [ - ...mcpTools.map((tool) => buildSchema(tool.name, tool.description, tool.name)), + ...mcpTools + .map((tool) => buildSchema(tool.name, tool.description, tool.name)) + .filter((tool) => !tool.command.startsWith("MCP ")), ...Object.entries(cliOnlyToolDefinitions).map(([name, definition]) => buildSchema(name, definition.description ?? name, null), ), @@ -1600,19 +1601,28 @@ function buildSchema( description: definition.description ?? description, input_schema: definition.input_schema, inputs: definition.input_schema, - mcp_input_schema: mcpTool - ? (definition.mcp_input_schema ?? definition.input_schema) - : null, + mcp_input_schema: null, examples: definition.examples ?? examplesForTool(name), next_steps: definition.next_steps ?? nextStepsForTool(name), safety, execution: { cli_command: definition.command, - mcp_tool: mcpTool, + mcp_tool: null, generation_execution: generationExecution, generation_runtime: generationRuntime, }, - ...(definition.confirmation ? { confirmation: definition.confirmation } : {}), + mcp: { + status: "coming_soon", + launched: false, + }, + ...(definition.confirmation + ? { + confirmation: { + accepted_flags: definition.confirmation.accepted_flags, + required: definition.confirmation.required, + }, + } + : {}), ...(definition.constraints ? { constraints: definition.constraints } : {}), }; } diff --git a/src/mcp/tools.ts b/src/mcp/tools.ts index c171644..d3b6b19 100644 --- a/src/mcp/tools.ts +++ b/src/mcp/tools.ts @@ -570,7 +570,7 @@ function delay(ms: number) { export const mcpTools: SumeMcpTool[] = [ { name: "tools.list", - description: "List local Sume CLI and MCP tool contracts with safety metadata.", + description: "List local Sume CLI command schemas with safety metadata.", inputSchema: emptyInputSchema, annotations: readOnlyAnnotations("tools.list"), readOnly: true, @@ -586,7 +586,7 @@ export const mcpTools: SumeMcpTool[] = [ }, { name: "tools.schema", - description: "Read one local Sume CLI or MCP tool contract by name.", + description: "Read one local Sume CLI command schema by name.", inputSchema: toolNameInputSchema, annotations: readOnlyAnnotations("tools.schema"), readOnly: true, @@ -802,7 +802,7 @@ export const mcpTools: SumeMcpTool[] = [ { name: "assets.list", description: - "List advanced compatibility workspace-scoped input assets. Hidden from the default launch MCP server.", + "List advanced compatibility workspace-scoped input assets. Hidden from the default public launch surface.", inputSchema: listAssetsInputSchema, annotations: readOnlyAnnotations("assets.list"), returnsSensitiveUrl: true, diff --git a/test/cli.test.ts b/test/cli.test.ts index 5d266a7..a3de8b2 100644 --- a/test/cli.test.ts +++ b/test/cli.test.ts @@ -85,9 +85,13 @@ async function runCli( } } -async function runCliFailure(args: string[], baseUrl: string) { +async function runCliFailure( + args: string[], + baseUrl: string, + extraEnv: Record = {}, +) { try { - await runCli(args, baseUrl); + await runCli(args, baseUrl, extraEnv); } catch (error) { return error as { stdout?: string; stderr?: string }; } @@ -185,14 +189,22 @@ describe("CLI", () => { expect(parsed.commands).toContain("doctor"); expect(parsed.commands).toContain("health"); expect(parsed.commands).toContain("jobs"); - expect(parsed.commands).toContain("setup"); expect(parsed.commands).toContain("skills"); expect(parsed.commands).toContain("tools"); expect(parsed.commands).toContain("update"); expect(parsed.commands).toContain("usage"); + expect(parsed.commands).not.toContain("mcp"); + expect(parsed.commands).not.toContain("setup"); expect(parsed.commands).not.toContain("images"); expect(parsed.commands).not.toContain("videos"); expect(parsed.commands).not.toContain("files"); + expect(parsed.coming_soon).toContainEqual( + expect.objectContaining({ + object: "mcp_status", + status: "coming_soon", + launched: false, + }), + ); }); it("prints help", async () => { @@ -207,12 +219,12 @@ describe("CLI", () => { expect(stdout).toContain("catalog"); expect(stdout).toContain("doctor"); expect(stdout).toContain("health"); - expect(stdout).toContain("mcp"); - expect(stdout).toContain("setup"); expect(stdout).toContain("skills"); expect(stdout).toContain("tools"); expect(stdout).toContain("update"); expect(stdout).toContain("usage"); + expect(stdout).not.toContain("mcp"); + expect(stdout).not.toContain("setup"); expect(stdout).not.toContain("images"); expect(stdout).not.toMatch(/\n\s+videos\s/u); expect(stdout).not.toContain("files"); @@ -428,328 +440,116 @@ describe("CLI", () => { source: "environment", }, safety: { - mcp_default: "read_only", + mcp_status: "coming_soon", write_commands_require_confirmation: true, agent_job_outputs_redact_urls: true, }, + mcp: { + object: "mcp_status", + status: "coming_soon", + launched: false, + }, }); expect(requests).toHaveLength(0); }, ); }); - it("prints MCP install dry-run JSON snippets without writing client config", async () => { + it("reports MCP coming soon without writing client config", async () => { + const homeDir = fs.mkdtempSync(path.join(os.tmpdir(), "sume-cli-mcp-install-")); + try { + const failure = await runCliFailure( + ["mcp", "install", "--agent", "codex", "--dry-run", "--json"], + "http://127.0.0.1/v1", + { HOME: homeDir }, + ); + expect(JSON.parse(failure.stderr ?? "")).toMatchObject({ + error: { + code: "mcp_not_launched", + message: + "Sume MCP client setup is coming soon and is not launched in this CLI release yet.", + hint: expect.stringContaining("Use direct Sume CLI commands today"), + }, + }); + expect(fs.existsSync(path.join(homeDir, ".codex", "config.toml"))).toBe( + false, + ); + } finally { + fs.rmSync(homeDir, { recursive: true, force: true }); + } + }); + + it("reports MCP launch status without calling the API", async () => { await withMockApi( () => ({ data: { ok: true } }), async (baseUrl, requests) => { const { stdout } = await runCli( - ["mcp", "install", "--agent", "codex", "--dry-run", "--json"], + ["--json", "mcp", "doctor"], baseUrl, ); const parsed = JSON.parse(stdout); expect(parsed).toMatchObject({ - object: "mcp_install_dry_run", - agent: "codex", - client: "Codex", - command: ["sume", "mcp"], - config_location: "~/.codex/config.toml", - dry_run: true, - format: "toml", - safety: { - read_only_default: true, - write_tools_enabled: false, - paid_tools_enabled: false, - }, - writes_config: false, + object: "mcp_status", + status: "coming_soon", + launched: false, + recommended_surface: "direct_cli", }); - expect(parsed.snippet).toContain('[mcp_servers.sume]'); - expect(parsed.snippet).not.toContain("allow-write"); - expect(parsed.snippet).not.toContain("allow-paid"); expect(requests).toHaveLength(0); }, ); }); - it("prints MCP doctor readiness without calling the API", async () => { - const homeDir = fs.mkdtempSync(path.join(os.tmpdir(), "sume-cli-mcp-doctor-")); + it("does not write setup agent config before MCP launch", async () => { + const homeDir = fs.mkdtempSync(path.join(os.tmpdir(), "sume-cli-setup-agent-")); try { - await withMockApi( - () => ({ data: { ok: true } }), - async (baseUrl, requests) => { - const { stdout } = await runCli( - ["--json", "mcp", "doctor"], - baseUrl, - { HOME: homeDir }, - ); - const parsed = JSON.parse(stdout); - expect(parsed).toMatchObject({ - object: "mcp_doctor_report", - ok: true, - schema_version: 1, - summary: { - total: 3, - configured: 0, - unconfigured: 3, - misconfigured: 0, - }, - }); - expect(parsed.clients.map((client: { agent: string }) => client.agent)).toEqual( - ["codex", "claude-code", "cursor"], - ); - expect(requests).toHaveLength(0); + const failure = await runCliFailure( + ["--json", "setup", "agent", "--agent", "codex"], + "http://127.0.0.1/v1", + { HOME: homeDir, SUME_API_KEY: "" }, + ); + expect(JSON.parse(failure.stderr ?? "")).toMatchObject({ + error: { + code: "agent_setup_not_launched", + message: + "Sume agent setup is coming soon and is not launched in this CLI release yet.", + hint: expect.stringContaining("No agent or MCP client config was written"), }, + }); + expect(fs.existsSync(path.join(homeDir, ".codex", "config.toml"))).toBe( + false, ); } finally { fs.rmSync(homeDir, { recursive: true, force: true }); } }); - it("reports unsafe MCP client config without printing persisted secrets", async () => { - const homeDir = fs.mkdtempSync(path.join(os.tmpdir(), "sume-cli-mcp-bad-")); - try { - const configPath = path.join(homeDir, ".cursor", "mcp.json"); - fs.mkdirSync(path.dirname(configPath), { recursive: true }); - fs.writeFileSync( - configPath, - `${JSON.stringify( - { - mcpServers: { - sume: { - command: "sume", - args: ["mcp", "--allow-write"], - env: { SUME_API_KEY: "persisted-secret" }, - }, - }, - }, - null, - 2, - )}\n`, - ); - - await withMockApi( - () => ({ data: { ok: true } }), - async (baseUrl, requests) => { - const { stdout } = await runCli( - ["mcp", "doctor", "--agent", "cursor", "--json"], - baseUrl, - { HOME: homeDir }, - ); - const parsed = JSON.parse(stdout); - expect(parsed).toMatchObject({ - object: "mcp_doctor_report", - ok: false, - summary: { - total: 1, - configured: 0, - unconfigured: 0, - misconfigured: 1, - }, - clients: [ - expect.objectContaining({ - agent: "cursor", - status: "misconfigured", - safety: expect.objectContaining({ - write_tools_enabled: true, - paid_tools_enabled: false, - }), - }), - ], - }); - expect(stdout).not.toContain("persisted-secret"); - expect(stdout).not.toContain("SUME_API_KEY"); - expect(stdout).not.toContain("--allow-write"); - expect(requests).toHaveLength(0); - }, - ); - } finally { - fs.rmSync(homeDir, { recursive: true, force: true }); - } + it("reports MCP start as coming soon", async () => { + const failure = await runCliFailure(["--json", "mcp"], "http://127.0.0.1/v1"); + expect(JSON.parse(failure.stderr ?? "")).toMatchObject({ + error: { + code: "mcp_not_launched", + message: "Sume MCP is coming soon and is not launched in this CLI release yet.", + hint: expect.stringContaining("Use direct Sume CLI commands today"), + }, + }); }); - it("prints MCP install dry-run snippets for supported agents", async () => { - for (const agent of ["claude-code", "cursor"]) { - const { stdout } = await runCli( + it("reports MCP install as coming soon before agent validation", async () => { + for (const agent of ["claude-code", "cursor", "windsurf"]) { + const failure = await runCliFailure( ["--json", "mcp", "install", "--agent", agent, "--dry-run"], "http://127.0.0.1/v1", ); - const parsed = JSON.parse(stdout); - expect(parsed).toMatchObject({ - object: "mcp_install_dry_run", - agent, - command: ["sume", "mcp"], - format: "json", - writes_config: false, - }); - expect(parsed.snippet).toContain('"mcpServers"'); - expect(parsed.snippet).not.toContain("allow-write"); - expect(parsed.snippet).not.toContain("allow-paid"); - } - }); - - it("installs MCP client config without enabling write or paid tools", async () => { - const homeDir = fs.mkdtempSync(path.join(os.tmpdir(), "sume-cli-mcp-home-")); - try { - await withMockApi( - () => ({ data: { ok: true } }), - async (baseUrl, requests) => { - const { stdout } = await runCli( - ["--json", "mcp", "install", "--agent", "cursor"], - baseUrl, - { HOME: homeDir }, - ); - const parsed = JSON.parse(stdout); - expect(parsed).toMatchObject({ - object: "mcp_install", - agent: "cursor", - command: ["sume", "mcp"], - dry_run: false, - status: "configured", - writes_config: true, - safety: { - read_only_default: true, - write_tools_enabled: false, - paid_tools_enabled: false, - }, - }); - - const configPath = path.join(homeDir, ".cursor", "mcp.json"); - const written = fs.readFileSync(configPath, "utf8"); - const config = JSON.parse(written); - expect(config).toMatchObject({ - mcpServers: { - sume: { command: "sume", args: ["mcp"] }, - }, - }); - expect(written).not.toContain("allow-write"); - expect(written).not.toContain("allow-paid"); - expect(written).not.toContain("test-key"); - expect(requests).toHaveLength(0); - }, - ); - } finally { - fs.rmSync(homeDir, { recursive: true, force: true }); - } - }); - - it("sets up an agent by installing read-only MCP config without API calls", async () => { - const homeDir = fs.mkdtempSync(path.join(os.tmpdir(), "sume-cli-setup-agent-")); - try { - await withMockApi( - () => ({ data: { ok: true } }), - async (baseUrl, requests) => { - const first = await runCli( - ["--json", "setup", "agent", "--agent", "codex"], - baseUrl, - { HOME: homeDir, SUME_API_KEY: "" }, - ); - const parsed = JSON.parse(first.stdout); - expect(parsed).toMatchObject({ - object: "agent_setup", - ok: true, - dry_run: false, - agent: "codex", - auth: { - configured: false, - source: "none", - }, - mcp_install: { - object: "mcp_install", - command: ["sume", "mcp"], - writes_config: true, - }, - mcp_readiness: { - status: "configured", - safety: { - read_only_default: true, - write_tools_enabled: false, - paid_tools_enabled: false, - }, - }, - safety: { - write_tools_enabled: false, - paid_tools_enabled: false, - secrets_written: false, - }, - }); - - const configPath = path.join(homeDir, ".codex", "config.toml"); - const firstWrite = fs.readFileSync(configPath, "utf8"); - const second = await runCli( - ["--json", "setup", "agent", "--agent", "codex"], - baseUrl, - { HOME: homeDir, SUME_API_KEY: "" }, - ); - const secondWrite = fs.readFileSync(configPath, "utf8"); - - expect(JSON.parse(second.stdout)).toMatchObject({ - object: "agent_setup", - mcp_readiness: { status: "configured" }, - }); - expect(secondWrite).toBe(firstWrite); - expect(secondWrite).toContain('[mcp_servers.sume]'); - expect(secondWrite).toContain('command = "sume"'); - expect(secondWrite).toContain('args = ["mcp"]'); - expect(secondWrite).not.toContain("allow-write"); - expect(secondWrite).not.toContain("allow-paid"); - expect(first.stdout).not.toContain("test-key"); - expect(second.stdout).not.toContain("test-key"); - expect(requests).toHaveLength(0); - }, - ); - } finally { - fs.rmSync(homeDir, { recursive: true, force: true }); - } - }); - - it("previews setup agent without writing client config", async () => { - const homeDir = fs.mkdtempSync(path.join(os.tmpdir(), "sume-cli-setup-dry-")); - try { - await withMockApi( - () => ({ data: { ok: true } }), - async (baseUrl, requests) => { - const { stdout } = await runCli( - ["setup", "agent", "--agent", "cursor", "--dry-run", "--json"], - baseUrl, - { HOME: homeDir }, - ); - const parsed = JSON.parse(stdout); - expect(parsed).toMatchObject({ - object: "agent_setup", - dry_run: true, - mcp_install: { - object: "mcp_install_dry_run", - writes_config: false, - }, - mcp_readiness: { - status: "unconfigured", - }, - }); - expect(fs.existsSync(path.join(homeDir, ".cursor", "mcp.json"))).toBe( - false, - ); - expect(stdout).not.toContain("test-key"); - expect(requests).toHaveLength(0); + expect(JSON.parse(failure.stderr ?? "")).toMatchObject({ + error: { + code: "mcp_not_launched", + message: + "Sume MCP client setup is coming soon and is not launched in this CLI release yet.", }, - ); - } finally { - fs.rmSync(homeDir, { recursive: true, force: true }); + }); } }); - it("rejects unsupported MCP install agents", async () => { - const failure = await runCliFailure( - ["--json", "mcp", "install", "--agent", "windsurf", "--dry-run"], - "http://127.0.0.1/v1", - ); - expect(JSON.parse(failure.stderr ?? "")).toMatchObject({ - error: { - code: "invalid_argument", - message: "Unsupported MCP agent: windsurf", - hint: "Use one of: codex, claude-code, cursor", - }, - }); - }); - it("surfaces normalized production API base URL diagnostics", async () => { const doctor = await runCli( ["--json", "doctor", "--agent"], @@ -801,15 +601,15 @@ describe("CLI", () => { expect(parsedList.tools.map((tool: { name: string }) => tool.name)).toContain( "jobs.watch", ); - expect(parsedList.tools.map((tool: { name: string }) => tool.name)).toContain( - "jobs.wait", - ); expect(parsedList.tools.map((tool: { name: string }) => tool.name)).toContain( "tools.schema", ); - expect(parsedList.tools.map((tool: { name: string }) => tool.name)).toContain( - "assets.upload_file", - ); + expect( + parsedList.tools.map((tool: { name: string }) => tool.name), + ).not.toContain("jobs.wait"); + expect( + parsedList.tools.map((tool: { name: string }) => tool.name), + ).not.toContain("assets.upload_file"); for (const name of [ "assets.download", "avatar-videos.batch.plan", @@ -869,32 +669,22 @@ describe("CLI", () => { }, required: ["job_id"], }, - mcp_input_schema: expect.objectContaining({ - properties: expect.objectContaining({ - job_id: expect.objectContaining({ type: "string" }), - }), + mcp_input_schema: null, + execution: expect.objectContaining({ + mcp_tool: null, }), + mcp: { + status: "coming_soon", + launched: false, + }, safety: { read_only: true }, }); - const waitSchema = await runCli( + const waitSchema = await runCliFailure( ["--json", "tools", "schema", "jobs.wait"], baseUrl, ); - expect(JSON.parse(waitSchema.stdout)).toMatchObject({ - name: "jobs.wait", - command: "MCP jobs.wait", - mcp_input_schema: { - required: ["job_id"], - properties: { - job_id: expect.objectContaining({ type: "string" }), - timeout_seconds: expect.objectContaining({ maximum: 600 }), - }, - }, - safety: { - read_only: true, - mutating: false, - returns_sensitive_url: true, - }, + expect(JSON.parse(waitSchema.stderr ?? "")).toMatchObject({ + error: { code: "tool_schema_not_found" }, }); const watchSchema = await runCli( ["--json", "tools", "schema", "jobs.watch"], @@ -934,7 +724,6 @@ describe("CLI", () => { }, confirmation: { required: true, - mcp_session_gates: ["allowWrite", "allowPaid"], }, }); const assetGetSchema = await runCli( @@ -951,11 +740,10 @@ describe("CLI", () => { agent: expect.objectContaining({ type: "boolean" }), }, }, - mcp_input_schema: { - required: ["asset_id"], - properties: { - asset_id: expect.objectContaining({ type: "string" }), - }, + mcp_input_schema: null, + mcp: { + status: "coming_soon", + launched: false, }, safety: expect.objectContaining({ read_only: true, @@ -973,7 +761,6 @@ describe("CLI", () => { "sume assets create --confirm-submit --source-url --agent --json", confirmation: { accepted_flags: ["confirm_submit"], - mcp_session_gates: ["allowWrite"], required: true, }, input_schema: { @@ -995,21 +782,7 @@ describe("CLI", () => { confirm_submit: expect.objectContaining({ type: "boolean" }), }, }, - mcp_input_schema: { - required: ["payload"], - properties: { - idempotency_key: expect.objectContaining({ type: "string" }), - payload: expect.objectContaining({ - required: ["source_url"], - properties: expect.objectContaining({ - source_url: expect.objectContaining({ type: "string" }), - media_type: expect.objectContaining({ - enum: ["image", "video", "audio", "file"], - }), - }), - }), - }, - }, + mcp_input_schema: null, safety: expect.objectContaining({ mutating: true, paid_generation_call: false, @@ -1017,32 +790,12 @@ describe("CLI", () => { returns_sensitive_url: true, }), }); - const assetUploadFileSchema = await runCli( + const assetUploadFileSchema = await runCliFailure( ["--json", "tools", "schema", "assets.upload_file"], baseUrl, ); - expect(JSON.parse(assetUploadFileSchema.stdout)).toMatchObject({ - name: "assets.upload_file", - command: "MCP assets.upload_file", - confirmation: { - accepted_flags: ["confirm_submit"], - mcp_session_gates: ["allowWrite"], - required: true, - }, - mcp_input_schema: { - required: ["path", "content_type"], - properties: { - path: expect.objectContaining({ type: "string" }), - content_type: expect.objectContaining({ type: "string" }), - }, - }, - safety: { - mutating: true, - paid_generation_call: false, - read_only: false, - requires_confirmation: true, - returns_sensitive_url: true, - }, + expect(JSON.parse(assetUploadFileSchema.stderr ?? "")).toMatchObject({ + error: { code: "tool_schema_not_found" }, }); const jobCancelSchema = await runCli( ["--json", "tools", "schema", "jobs.cancel"], @@ -1091,7 +844,6 @@ describe("CLI", () => { name: "avatars.create", confirmation: { accepted_flags: ["confirm_submit", "confirm_paid"], - mcp_session_gates: ["allowWrite", "allowPaid"], required: true, }, input_schema: { @@ -1135,20 +887,7 @@ describe("CLI", () => { confirm_submit: expect.objectContaining({ type: "boolean" }), }, }, - mcp_input_schema: { - required: ["idempotency_key", "max_spend_usd", "payload"], - properties: { - idempotency_key: expect.objectContaining({ type: "string" }), - max_spend_usd: expect.objectContaining({ type: "number" }), - model: expect.objectContaining({ - enum: ["sume/avatar/v1.0"], - }), - payload: expect.objectContaining({ - additionalProperties: true, - type: "object", - }), - }, - }, + mcp_input_schema: null, safety: expect.objectContaining({ requires_agent_redaction: true, returns_sensitive_url: true, @@ -1167,7 +906,6 @@ describe("CLI", () => { name: "avatar-videos.create", confirmation: { accepted_flags: ["confirm_submit", "confirm_paid"], - mcp_session_gates: ["allowWrite", "allowPaid"], required: true, }, input_schema: { @@ -1195,33 +933,15 @@ describe("CLI", () => { }), }, }, - mcp_input_schema: { - required: ["idempotency_key", "max_spend_usd"], - anyOf: expect.arrayContaining([ - expect.objectContaining({ required: ["payload"] }), - expect.objectContaining({ required: ["avatar_handle", "script"] }), - ]), - properties: { - avatar_handle: expect.objectContaining({ type: "string" }), - idempotency_key: expect.objectContaining({ type: "string" }), - max_spend_usd: expect.objectContaining({ type: "number" }), - product_image: expect.objectContaining({ type: "string" }), - quality: expect.objectContaining({ - enum: ["standard", "plus", "max"], - type: "string", - }), - scene_image_url: expect.objectContaining({ type: "string" }), - scene_prompt: expect.objectContaining({ type: "string" }), - script: expect.objectContaining({ type: "string" }), - payload: expect.objectContaining({ - additionalProperties: true, - type: "object", - }), - }, - }, + mcp_input_schema: null, execution: { generation_execution: "sume_api", generation_runtime: "sume_api", + mcp_tool: null, + }, + mcp: { + status: "coming_soon", + launched: false, }, }); expect(parsedAvatarVideoSchema.input_schema.required ?? []).not.toContain( @@ -1230,24 +950,12 @@ describe("CLI", () => { expect( parsedAvatarVideoSchema.input_schema.properties.script.description, ).toContain("4-60 seconds"); - expect( - parsedAvatarVideoSchema.mcp_input_schema.properties.payload.description, - ).toContain("Prefer top-level friendly fields"); - expect( - parsedAvatarVideoSchema.mcp_input_schema.properties.scene_prompt.description, - ).toContain("Normalizes to scene"); expect(parsedAvatarVideoSchema.constraints).toContain( "avatar_handle is required for flag-built requests.", ); - expect(parsedAvatarVideoSchema.constraints).toContain( - "For MCP, use either exact payload or top-level friendly fields, not both.", - ); expect( parsedAvatarVideoSchema.input_schema.properties, ).not.toHaveProperty("background"); - expect( - parsedAvatarVideoSchema.mcp_input_schema.properties, - ).not.toHaveProperty("background"); const imageSchema = await runCliFailure( ["--json", "tools", "schema", "images.create"], baseUrl, diff --git a/test/mcp.test.ts b/test/mcp.test.ts index 580227c..10d1bb4 100644 --- a/test/mcp.test.ts +++ b/test/mcp.test.ts @@ -1,6 +1,4 @@ import { describe, expect, it } from "vitest"; -import { Client } from "@modelcontextprotocol/sdk/client/index.js"; -import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js"; import { mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises"; import { tmpdir } from "node:os"; import { join } from "node:path"; @@ -15,7 +13,6 @@ import { import { listToolSchemas } from "../src/lib/tool-registry.js"; import { formatMcpToolResponse } from "../src/mcp/server.js"; import { - DEFAULT_MCP_TOOLSETS, listMcpTools, mcpNextStepsForTool, mcpTools, @@ -309,8 +306,20 @@ describe("MCP tool registry", () => { const schemas = listToolSchemas(); for (const tool of mcpTools) { const schema = schemas.find((candidate) => candidate.name === tool.name); - expect(schema, `missing schema for ${tool.name}`).toBeTruthy(); - expect(schema?.execution.mcp_tool).toBe(tool.name); + if (!schema) { + expect( + tool.name, + `${tool.name} should be an MCP-only prelaunch helper`, + ).toMatch( + /^(assets\.upload_file|jobs\.wait|avatars\.wait|avatars\.create_(prompt|props|photo_url))$/, + ); + continue; + } + expect(schema.execution.mcp_tool).toBeNull(); + expect(schema.mcp).toEqual({ + status: "coming_soon", + launched: false, + }); expect(schema?.safety).toMatchObject({ mutating: !tool.readOnly, paid_generation_call: Boolean(tool.paidProviderCall), @@ -318,12 +327,6 @@ describe("MCP tool registry", () => { requires_confirmation: !tool.readOnly, returns_sensitive_url: Boolean(tool.returnsSensitiveUrl), }); - if (!tool.readOnly) { - expect(schema?.confirmation?.mcp_session_gates).toContain("allowWrite"); - } - if (tool.paidProviderCall) { - expect(schema?.confirmation?.mcp_session_gates).toContain("allowPaid"); - } } }); @@ -349,22 +352,28 @@ describe("MCP tool registry", () => { ?.execute({}, client); const schema = await mcpTools .find((candidate) => candidate.name === "tools.schema") - ?.execute({ name: "assets.upload_file" }, client); + ?.execute({ name: "assets.create" }, client); expect(calls).toEqual([]); expect(list).toMatchObject({ object: "tool_schema_list", count: expect.any(Number), tools: expect.arrayContaining([ - expect.objectContaining({ name: "assets.upload_file" }), + expect.objectContaining({ name: "assets.create" }), ]), }); + expect(JSON.stringify(list)).not.toContain("assets.upload_file"); expect(schema).toMatchObject({ - name: "assets.upload_file", + name: "assets.create", confirmation: { - mcp_session_gates: ["allowWrite"], + accepted_flags: ["confirm_submit"], required: true, }, + mcp_input_schema: null, + mcp: { + status: "coming_soon", + launched: false, + }, safety: { mutating: true, paid_generation_call: false, @@ -373,32 +382,6 @@ describe("MCP tool registry", () => { }); }); - it("starts the actual stdio MCP command with the documented default tools", async () => { - const configDir = await mkdtemp(join(tmpdir(), "sume-mcp-command-")); - const transport = new StdioClientTransport({ - command: "pnpm", - args: ["exec", "tsx", "src/index.ts", "mcp"], - env: { - ...process.env, - SUME_API_BASE_URL: "https://api.sume.com/v1", - SUME_API_KEY: "sume_test_local", - SUME_CONFIG_DIR: configDir, - }, - }); - const client = new Client({ name: "sume-mcp-command-test", version: "1.0.0" }); - - try { - await client.connect(transport); - const result = await client.listTools(); - expect(result.tools.map((tool) => tool.name)).toEqual( - listMcpTools({ toolsets: DEFAULT_MCP_TOOLSETS }).map((tool) => tool.name), - ); - } finally { - await client.close().catch(() => undefined); - await rm(configDir, { recursive: true, force: true }); - } - }, 20000); - it("maps tools to current sume.com API paths", async () => { const calls: Array<{ body?: unknown; From 69637c48030406a9e6cdaff3eded2da1494dd652 Mon Sep 17 00:00:00 2001 From: chaewon-huh Date: Thu, 2 Jul 2026 10:55:27 +0900 Subject: [PATCH 2/2] test: update binary smoke for MCP coming soon --- .github/workflows/ci.yml | 4 ++-- .github/workflows/release.yml | 8 ++------ 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index afbcb37..e0868d5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,9 +35,7 @@ jobs: - run: pnpm run build:binary - run: ./dist/sume --version - run: ./dist/sume --json tools schema jobs.watch > /tmp/jobs-watch-schema.json - - run: ./dist/sume --json tools schema jobs.wait > /tmp/jobs-wait-schema.json - run: ./dist/sume --json tools schema assets.create > /tmp/assets-create-schema.json - - run: ./dist/sume --json tools schema assets.upload_file > /tmp/assets-upload-file-schema.json - run: ./dist/sume --json tools schema assets.get > /tmp/assets-get-schema.json - run: ./dist/sume --json tools schema avatars.create > /tmp/avatars-create-schema.json - run: ./dist/sume --json tools schema avatar-videos.create > /tmp/avatar-videos-create-schema.json @@ -46,6 +44,8 @@ jobs: - run: grep -q '"skills"' /tmp/root-metadata.json - run: grep -q '"balance"' /tmp/root-metadata.json - run: grep -q '"usage"' /tmp/root-metadata.json + - run: grep -q '"coming_soon"' /tmp/root-metadata.json + - run: grep -q '"mcp_status"' /tmp/root-metadata.json - run: ./dist/sume balance --help > /tmp/balance-help.txt - run: ./dist/sume usage get --help > /tmp/usage-help.txt - run: | diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b333b0f..937be62 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -95,9 +95,7 @@ jobs: BIN="./dist/sume.exe" ./dist/sume.exe --version ./dist/sume.exe --json tools schema jobs.watch > jobs-watch-schema.json - ./dist/sume.exe --json tools schema jobs.wait > jobs-wait-schema.json ./dist/sume.exe --json tools schema assets.create > assets-create-schema.json - ./dist/sume.exe --json tools schema assets.upload_file > assets-upload-file-schema.json ./dist/sume.exe --json tools schema assets.get > assets-get-schema.json ./dist/sume.exe --json tools schema avatars.create > avatars-create-schema.json ./dist/sume.exe --json tools schema avatar-videos.create > avatar-videos-create-schema.json @@ -106,9 +104,7 @@ jobs: BIN="./dist/sume" ./dist/sume --version ./dist/sume --json tools schema jobs.watch > jobs-watch-schema.json - ./dist/sume --json tools schema jobs.wait > jobs-wait-schema.json ./dist/sume --json tools schema assets.create > assets-create-schema.json - ./dist/sume --json tools schema assets.upload_file > assets-upload-file-schema.json ./dist/sume --json tools schema assets.get > assets-get-schema.json ./dist/sume --json tools schema avatars.create > avatars-create-schema.json ./dist/sume --json tools schema avatar-videos.create > avatar-videos-create-schema.json @@ -118,6 +114,8 @@ jobs: grep -q '"skills"' root-metadata.json grep -q '"balance"' root-metadata.json grep -q '"usage"' root-metadata.json + grep -q '"coming_soon"' root-metadata.json + grep -q '"mcp_status"' root-metadata.json "$BIN" balance --help > balance-help.txt "$BIN" usage get --help > usage-help.txt if "$BIN" --json catalog > catalog-parent.out 2> catalog-parent.err; then @@ -126,9 +124,7 @@ jobs: fi grep -q "missing_subcommand" catalog-parent.err test -s jobs-watch-schema.json - test -s jobs-wait-schema.json test -s assets-create-schema.json - test -s assets-upload-file-schema.json test -s assets-get-schema.json test -s avatars-create-schema.json test -s avatar-videos-create-schema.json