122 lines
9.3 KiB
Markdown
122 lines
9.3 KiB
Markdown
# MCP server and the desktop machine interface
|
|
|
|
`storebound mcp` speaks MCP over stdio, tools only: spec revision **2026-07-28** (stateless: `server/discover`,
|
|
per-request `_meta`, `resultType`, cacheable `tools/list`) and, on the same process, clients that still open with
|
|
`initialize` (2025-11-25, 2025-06-18, 2025-03-26, 2024-11-05). It runs each tool as a CLI call in the project directory
|
|
(the server's working directory, or `STOREBOUND_PROJECT`) and returns the output.
|
|
|
|
- One tool per command. Read-only: `scan`, `check`, `check_aso`, `aso_competitors` (no snapshot saved), `aso_suggest` (never writes), `aso_audit`, `validate`, `report` (writes only the report page in .storebound/reports/ and returns its path and both stores' verdicts), `catalog_diff`, `health`, `reviews_list`, `prices_diff`,
|
|
`analytics_compare`, `apple_status`, `apple_next_build`, `apple_testflight_status`, `apple_ppo_status`,
|
|
`play_status`, `play_next_version_code`, `privacy_manifest`, `shots_check`, `workspace_list`, `workspace_status`,
|
|
`release_status`, `release_plan`, `flow_list`, `flow_run` (dry mode only), `listing_check`, `api_get` (any App Store
|
|
Connect or Google Play GET operation by id). Local writes: `import_fastlane`, `whats_new`, `listing_translate`, `icons`,
|
|
`health_report`, `reviews_draft`, `prices_export`, `analytics_snapshot`, `shots_capture`, `shots_render`,
|
|
`shots_gallery`, `shots_record`, `shots_video`. Store writes: `play_listing`, `play_images`, `play_products`,
|
|
`play_data_safety`, `play_subscriptions`, `play_release_testing`, `apple_bundle`, `apple_iap`, `apple_iap_review`,
|
|
`apple_subscriptions`, `apple_listing`,
|
|
`apple_screenshots`, `apple_previews`, `apple_appinfo`, `apple_review_details`, `apple_encryption`,
|
|
`apple_phased_release`, `apple_testflight_groups`, `apple_testflight_what_to_test`, `apple_testflight_info`,
|
|
`apple_testflight_distribute` (internal groups only), `apple_ppo_create`, `apple_ppo_upload`, `analytics_setup`.
|
|
- Annotations say what is read-only, destructive (replaces data), idempotent and network-bound.
|
|
- No MCP SDK: a small newline-delimited JSON-RPC server (server/discover, initialize, ping, tools/list, tools/call,
|
|
cancellation), so storebound keeps zero runtime dependencies.
|
|
|
|
Manual config for a tool that `install` does not know: command `bunx` with args `["storebound", "mcp"]` (or the
|
|
absolute path of `bin/storebound` plus `mcp`).
|
|
|
|
## One shared server over HTTP
|
|
|
|
`storebound mcp --http` serves the same tools over Streamable HTTP (MCP 2025-06-18 and later) at `/mcp`, so every
|
|
agent session of a machine shares one process instead of starting its own. POST carries one JSON-RPC message and gets
|
|
one JSON answer; there is no server-initiated stream and no session state. A browser Origin other than localhost is
|
|
refused unless `--allow-origin` names it.
|
|
|
|
- Every tool gets a `project` argument: the absolute path of the app folder to run in. It must be inside `--roots`
|
|
(comma-separated, default the home folder). `--project <dir>` sets a default for calls without one.
|
|
- `--auth token` (default): the server makes `~/.storebound/mcp-token` (mode 600) on first start and requires it as a
|
|
bearer token. Only localhost hosts are allowed with it.
|
|
|
|
```bash
|
|
storebound mcp --http --port 7787
|
|
claude mcp add --transport http storebound http://127.0.0.1:7787/mcp --header "Authorization: Bearer $(cat ~/.storebound/mcp-token)"
|
|
```
|
|
- `--auth introspect`: for a server shared over the network behind TLS. Bearer tokens are OAuth 2.0 access tokens from
|
|
your authorization server, checked through its introspection endpoint (RFC 7662; this server authenticates with the
|
|
key in `--introspect-key-file`). A token must be active, carry the `mcp` scope and list `--resource` in `aud`
|
|
(RFC 8707). Without one the answer is 401 with `WWW-Authenticate: Bearer resource_metadata=...`, and
|
|
`/.well-known/oauth-protected-resource/mcp` names `--issuer` (RFC 9728).
|
|
|
|
```bash
|
|
storebound mcp --http --host 0.0.0.0 --auth introspect --introspect-url https://auth.example.com/introspect \
|
|
--introspect-key-file ~/.storebound/introspect.key --resource https://mcp.example.com/mcp --issuer https://auth.example.com
|
|
```
|
|
- `--read-only`: only the tools that change nothing are listed and callable.
|
|
- `--broker-profiles a,b`: a host that keeps no key files takes these credential profiles from the credential broker's
|
|
vault (`GET /api/store-credentials/<profile>/asc-api-key | play-service-account`, a key with the `store-credentials`
|
|
scope; docs/credential-broker.md). They reach each tool call as `STOREBOUND_PROFILE_<NAME>_*` env, held in memory for
|
|
10 minutes and never written. A project picks its profile as usual (the config's `account`).
|
|
- `project` may also be a folder name under the roots (a shared server keeps its checkouts there).
|
|
- Long calls: a `tools/call` whose request accepts `text/event-stream` is answered as SSE, with a comment line every
|
|
20 s until the result arrives as one `message` event, so a proxy that cuts silent responses (Cloudflare: 100 s)
|
|
keeps the connection. Other requests get plain JSON.
|
|
- `/health` answers `{ ok, version }` without auth.
|
|
|
|
|
|
## Public key-less server
|
|
|
|
`storebound mcp --http --public [--port 7788] [--host 127.0.0.1] [--rate 60] [--trust-proxy]` is a separate mode for a
|
|
server anyone may connect to (for example behind a public HTTPS address). No sign-in, no token, no project: it never
|
|
reads store credentials, project folders or the working directory, never starts a child process and never runs the CLI.
|
|
It is read-only and keeps no state. The only network call it makes is the public iTunes Search API (`aso_search`).
|
|
It cannot be combined with `--auth`, `--token-file`, `--roots`, `--project`, `--broker-profiles`, `--allow-origin`
|
|
or `--read-only`.
|
|
|
|
Tools (and only these; the CLI tools of the normal server do not exist here, a call gets "Unknown tool"):
|
|
|
|
- `skills_list`: name and one-line description of every skill in the package.
|
|
- `skill_get {name}`: the full SKILL.md of one skill (`^[a-z0-9-]+$`, must be in the list).
|
|
- `pitfalls_search {query, store?}`: the sections of the store-pitfalls skill that match the query words, best first (at
|
|
most 8, each clipped). `store` is `apple` or `play`.
|
|
- `store_limits {store?}`: listing field character limits, the App Store keyword field rules, screenshot and app
|
|
preview sizes per device class, Play feature graphic and icon sizes.
|
|
- `listing_lint {store, fields, locale?}`: storebound's listing and ASO checks on the text you send (limits, keyword
|
|
field rules, repeated name words, other platforms or apps named, placeholder text, keyword stuffing). Apple fields:
|
|
`name`, `subtitle`, `keywords`, `promotionalText`, `description`, `whatsNew`. Play fields: `title`,
|
|
`shortDescription`, `fullDescription`, `whatsNew`. Only the fields you send are judged; nothing is stored.
|
|
- `aso_search {term, country?, limit?}`: top apps for a term in one storefront from the iTunes Search API (name,
|
|
developer, id, rating, rating count, genre; 1-25 results, 10 s timeout).
|
|
|
|
Limits: `--rate N` requests per minute per client (default 60; over the limit the answer is 429 with `Retry-After`),
|
|
bodies over 64 KB get 413, every tool input is validated against a closed schema, and output is bounded. Behind a
|
|
reverse proxy add `--trust-proxy` so the first `X-Forwarded-For` entry is the client; without it that header is
|
|
ignored. Any browser origin may call it (there is no ambient credential), and CORS preflight is answered. `/health`
|
|
works as before. Request bodies are not logged.
|
|
|
|
```bash
|
|
storebound mcp --http --public --port 7788 --trust-proxy
|
|
claude mcp add --transport http storebound-public https://mcp.example.com/mcp
|
|
```
|
|
|
|
For real store work (builds, uploads, listings, releases) use `npx storebound` and its own MCP server.
|
|
|
|
## Desktop machine interface
|
|
|
|
`storebound serve --stdio` is what the desktop app (`apps/desktop`, in progress) runs as its sidecar: newline-delimited
|
|
JSON-RPC on the same core as the MCP server (tool list, validation, forbidden flags, child-process runner), with typed
|
|
methods (`check`, `validate`, `apple.status`, `play.listing`, ... plus `project.inspect` and `portfolio.status` over
|
|
many project folders), structured results (the commands' `--json` output), progress notifications and cancellation.
|
|
The first request is `session.hello` with a per-session secret only the host knows. Write methods are dry runs unless
|
|
the call carries a single-use confirm token (HMAC over method, arguments and expiry) that the host mints after the
|
|
owner confirmed a native dialog showing that dry run. Sending for review is there only as **owner actions**
|
|
(`owner.apple_submit`, `owner.apple_resubmit`, `owner.apple_iap_submit`, `owner.play_production`, next to the rollout,
|
|
phased release, price and reply owner actions): the window shows the plan (dry run) with the build or versionCode the
|
|
owner picked by number, then a native dialog, and only the host's token after that dialog runs it. Nothing publishes,
|
|
releases an approved version or cancels a submission, and the MCP server (AI tools) has none of the owner actions.
|
|
Play's "Send changes for review" has no API: the Releases tab shows its console plan and a deep link. Types:
|
|
`cli/lib/desktop-protocol.ts`.
|
|
`bun tools/build-sidecars.ts` compiles the CLI for macOS, Linux and Windows (`bun build --compile`). Design, safety
|
|
model and the Dependencies screen (tool sources and licenses): [docs/desktop.md](desktop.md).
|
|
|
|
---
|
|
|
|
[All docs](README.md) · [README](../README.md)
|