AppStore MCP Server

Servidor MCP (Rust, rmcp) que expõe a API Apple App Store Connect — apps, compras dentro do app, assinaturas, preços, versões/metadados, TestFlight, provisionamento e uploads de assets, além de ferramentas genéricas JSON:API.

Documentação

appstore-mcp

Um servidor MCP, escrito em Rust, que expõe a API do Apple App Store Connect para agentes de IA. Ele cobre todo o ciclo de vida do produto — apps e metadados, compras dentro do app, assinaturas e suas ofertas, preços e disponibilidade, versões da App Store, envio para análise da App Store, TestFlight, provisionamento e assinatura, uploads de assets, compras promovidas, avaliações de clientes, lançamento faseado, usuários e acesso, eventos no app, Xcode Cloud e relatórios de análise — em 114 ferramentas, e pode alcançar qualquer outro endpoint do App Store Connect por meio de duas ferramentas genéricas JSON:API.

Construído sobre o SDK oficial rmcp via stdio.

📖 Referência completa de ferramentas → docs/TOOLS.md — a finalidade e os parâmetros de cada ferramenta.

Cada ferramenta é rotulada com anotações MCP, para que um cliente possa distinguir list_apps de remove_user. Você pode servir apenas os domínios que precisa (ASC_TOOLS) ou apenas as ferramentas que não podem gravar (ASC_READ_ONLY) — veja Escolhendo quais ferramentas servir.

Design: cobertura híbrida

A API do App Store Connect tem centenas de endpoints, mas é uniformemente JSON:API. Em vez de uma ferramenta por endpoint, este servidor é híbrido:

  • Ferramentas selecionadas (112) para os fluxos de trabalho comuns, de várias etapas ou propensos a erros — apps e metadados, compras dentro do app, assinaturas e ofertas, versões, preços, disponibilidade, envio para análise da App Store, TestFlight, provisionamento, uploads de assets, compras promovidas, avaliações de clientes, lançamento faseado, usuários, eventos no app, Xcode Cloud, relatórios de análise e páginas de produto personalizadas.
  • Duas ferramentas genéricas de escape — appstore_request e appstore_list — que podem chamar qualquer endpoint com documentos JSON:API brutos.

Ferramentas

GrupoFerramentas
Genéricasappstore_request, appstore_list
Apps e metadadoslist_apps, get_app, update_app, list_app_infos, update_app_info, set_age_rating, create_app_info_localization, update_app_info_localization
Compras dentro do app (v2)list_in_app_purchases, create_in_app_purchase, update_in_app_purchase, delete_in_app_purchase, create_iap_localization, set_iap_price_schedule, upload_iap_review_screenshot
Assinaturaslist_subscription_groups, create_subscription_group, create_subscription, update_subscription, create_subscription_localization, set_subscription_price
Versões e metadadoslist_app_store_versions, create_app_store_version, create_version_localization, update_version_localization
Envio para análise da App Storecreate_review_submission, add_review_submission_item, submit_review_submission, list_review_submissions, submit_in_app_purchase, set_app_review_detail, create_app_encryption_declaration, assign_build_encryption_declaration
Preçoslist_territories, list_iap_price_points, list_subscription_price_points
Disponibilidadeset_iap_availability, set_subscription_availability, set_app_availability
TestFlightlist_builds, list_beta_groups, create_beta_group, add_beta_tester, submit_build_for_beta_review, set_build_test_notes, set_build_beta_detail, set_beta_app_review_detail, expire_build, add_build_to_beta_group
Provisionamento e assinaturalist_bundle_ids, create_bundle_id, enable_bundle_id_capability, disable_bundle_id_capability, list_certificates, create_certificate, list_devices, register_device, list_profiles, create_profile
Assetsupload_app_screenshot, upload_app_preview, create_screenshot_set, create_preview_set, delete_screenshot_set, delete_preview_set, reorder_screenshots
Ofertas de assinaturacreate_introductory_offer, create_promotional_offer, create_winback_offer, list_winback_offers
Códigos de ofertacreate_offer_code, generate_one_time_use_codes, create_custom_offer_code, list_offer_codes
Compras promovidascreate_promoted_purchase, update_promoted_purchase, set_promoted_purchase_order, list_promoted_purchases
Avaliações de clienteslist_customer_reviews, respond_to_review, delete_review_response
Lançamento faseadostart_phased_release, update_phased_release
Usuários e acessolist_users, invite_user, update_user, remove_user
Eventos no appcreate_app_event, create_app_event_localization, upload_app_event_screenshot
Xcode Cloudlist_ci_products, list_ci_workflows, start_ci_build, get_ci_build_run, list_ci_build_actions
Relatórios de análiserequest_analytics_report, list_analytics_reports, list_analytics_report_instances, list_analytics_report_segments, download_analytics_segment
Páginas de produto personalizadaslist_custom_product_pages, get_custom_product_page, create_custom_product_page, update_custom_product_page, delete_custom_product_page, list_custom_product_page_versions, create_custom_product_page_version, list_custom_product_page_localizations, create_custom_product_page_localization, update_custom_product_page_localization, create_cpp_screenshot_set, create_cpp_preview_set

Consulte docs/TOOLS.md para a descrição e os parâmetros de cada ferramenta. As imagens de páginas de produto personalizadas são enviadas com as ferramentas existentes upload_app_screenshot / upload_app_preview.

Instalação

Binários pré-compilados para macOS (universal), Linux (x86-64) e Windows (x86-64) são anexados a cada Release do GitHub. Escolha o canal para o seu cliente; todos precisam de credenciais (veja Credenciais).

Claude Desktop — pacote de um clique

Baixe appstore-mcp.mcpb da versão mais recente e abra-o com o Claude Desktop (Configurações → Extensões → Instalar Extensão…, ou arraste o arquivo para a janela). Ele solicita seu Issuer ID, Key ID e arquivo de chave .p8. O pacote inclui os binários das três plataformas e seleciona o correto automaticamente.

Claude Code — marketplace de plugins

/plugin marketplace add forgeopslabs/appstore-mcp
/plugin install appstore-mcp@forgeopslabs

O plugin executa o binário appstore-mcp do seu PATH, então instale-o primeiro — baixe o binário para o seu sistema operacional na versão mais recente e coloque-o no seu PATH, ou cargo install --git https://github.com/forgeopslabs/appstore-mcp. Defina ASC_ISSUER_ID, ASC_KEY_ID e ASC_PRIVATE_KEY_PATH no ambiente a partir do qual você inicia o Claude Code.

Codex

O Codex configura servidores MCP diretamente (sem marketplace). Com appstore-mcp no seu PATH:

codex mcp add appstore \
  --env ASC_ISSUER_ID=... --env ASC_KEY_ID=... \
  --env ASC_PRIVATE_KEY_PATH=/path/AuthKey_XXXXXX.p8 \
  -- appstore-mcp

ou em ~/.codex/config.toml:

[mcp_servers.appstore]
command = "appstore-mcp"
args = []
env = { ASC_ISSUER_ID = "...", ASC_KEY_ID = "...", ASC_PRIVATE_KEY_PATH = "/path/AuthKey_XXXXXX.p8" }

MCP Registry

Publicado como io.github.forgeopslabs/appstore-mcp (metadados em server.json) para que qualquer cliente compatível com MCP possa descobri-lo.

A partir do código-fonte

cargo build --release    # -> target/release/appstore-mcp

Credenciais

Gere uma Team Key no App Store Connect → Usuários e Acesso → Integrações → API do App Store Connect e baixe o arquivo .p8. Em seguida, defina:

VariávelObrigatóriaDescrição
ASC_ISSUER_ID✅UUID do emissor mostrado acima da tabela de chaves.
ASC_KEY_ID✅O Key ID da chave da API.
ASC_PRIVATE_KEYum deConteúdo PEM inline do .p8.
ASC_PRIVATE_KEY_PATHum deCaminho para o arquivo .p8 baixado.
ASC_BASE_URLopcionalSubstitui a origem da API.
ASC_LOGopcionalFiltro de log (para stderr). Padrão info.

Consulte .env.example. O servidor autentica cada solicitação com um JWT ES256 de curta duração assinado pela sua chave (armazenado em cache e renovado automaticamente).

O servidor inicia mesmo sem credenciais para que um cliente possa listar suas ferramentas; as chamadas de ferramentas então retornam um erro de configuração acionável até que as credenciais sejam definidas.

Escolhendo quais ferramentas servir

Cem definições de ferramentas custam contexto em cada sessão, e um cliente que vê uma lista plana não consegue distinguir uma leitura de uma exclusão. Dois controles resolvem isso:

VariávelPadrãoDescrição
ASC_TOOLStodosGrupos de ferramentas separados por vírgula para servir, ou o preset core.
ASC_READ_ONLY0Serve apenas ferramentas que não podem modificar a conta.
ASC_TOOL_DISCOVERY0Expõe apenas search_tools, get_tool_details e call_discovered_tool; as ferramentas de domínio filtradas permanecem disponíveis por meio da descoberta.
ASC_TOOLS=core                     # 41 tools: generic, apps, versions, assets, testflight, submission
ASC_TOOLS=testflight,provisioning  # just what a build-distribution agent needs
ASC_READ_ONLY=1                    # 35 read-only tools; writes are withheld entirely
ASC_TOOL_DISCOVERY=1               # 3 visible tools; discover domain tools on demand

Grupos: generic, apps, iap, subscriptions, versions, pricing, availability, submission, testflight, provisioning, assets, offers, offer-codes, promotions, reviews, users, events, xcode-cloud, analytics, custom-product-pages — além de all e core. Um nome não reconhecido gera um aviso no stderr e não serve nada, em vez de silenciosamente voltar a servir tudo.

No modo somente leitura, appstore_request é mantido, mas recusa qualquer método diferente de GET, para que a saída de escape ainda alcance endpoints sem uma ferramenta selecionada sem se tornar uma forma de contornar a restrição.

Cada ferramenta servida anuncia anotações MCP (readOnlyHint, destructiveHint, idempotentHint), que os clientes usam para decidir o que precisa de confirmação. Nove ferramentas são marcadas como destrutivas: as sete ferramentas delete_*/remove_*, expire_build, disable_bundle_id_capability e appstore_request (que podem alcançar qualquer endpoint DELETE).

Modo de descoberta. Pesquise por tarefa, inspecione o esquema completo de entrada e as anotações de segurança de uma ferramenta correspondente e, em seguida, passe seu nome e argumentos exatos para call_discovered_tool. ASC_TOOLS e ASC_READ_ONLY filtram o catálogo privado antes da pesquisa ou execução. Chamadas diretas a nomes de ferramentas ocultas falham. Isso é descoberta no lado do servidor: os esquemas inspecionados aparecem nos resultados das ferramentas, não como novas ferramentas MCP de primeira classe injetadas pelo host. A ferramenta de execução genérica é marcada como destrutiva sempre que as gravações estão habilitadas; os hosts não podem aplicar regras de aprovação distintas a cada ferramenta oculta. Inspecione a ferramenta subjacente e aprove as gravações antes de chamá-la. O modo padrão preserva a superfície de ferramentas anotadas individualmente existente.

Ajustes

Os padrões são escolhidos para que uma chamada de ferramenta não trave e uma única resposta não sobrecarregue o contexto de um agente. Todos são opcionais.

VariávelPadrãoDescrição
ASC_TIMEOUT_SECS60Tempo limite de toda a solicitação. 0 desativa.
ASC_CONNECT_TIMEOUT_SECS10Tempo limite de conexão. 0 desativa.
ASC_TRANSFER_TIMEOUT_SECS300Tempo limite para uploads de assets e downloads de relatórios.
ASC_MAX_RETRIES3Tentativas após a primeira tentativa. 0 desativa.
ASC_MAX_RESPONSE_BYTES60000Limite de tamanho do resultado da ferramenta. 0 desativa.
ASC_COMPACT_RESPONSES1Remove links JSON:API redundantes das respostas.

Tentativas. Um 429 é reproduzido para qualquer método, pois a Apple rejeitou a solicitação sem aplicá-la. Um 5xx ou um tempo limite no meio da solicitação é reproduzido apenas para GET/PATCH/PUT/DELETE — nunca POST, que poderia criar um recurso duplicado (e a Apple reserva permanentemente identificadores como um ID de produto). O backoff é exponencial com jitter e respeita Retry-After.

Formatação de resposta. Os resultados são serializados de forma compacta — JSON indentado medido 1,72× os bytes para conteúdo idêntico, então o mesmo orçamento agora carrega cerca de 40% mais dos dados que você solicitou. Links self por recurso e relacionamentos apenas com link são removidos: nenhum conteúdo endereçável é perdido, e links.next sobrevive para paginação. Se uma resposta ainda exceder o orçamento, included é removido primeiro, depois os itens data finais, e o resultado carrega uma chave _truncated informando o que foi omitido e como restringir a consulta. Observe que seguir links.next após um corte pularia os itens removidos — solicite novamente com um limit menor.

Build e execução

cargo build --release
ASC_ISSUER_ID=... ASC_KEY_ID=... ASC_PRIVATE_KEY_PATH=/path/AuthKey_XXX.p8 \
  ./target/release/appstore-mcp

O servidor fala MCP via stdio. Os logs vão para stderr; o stdout é o canal do protocolo.

Uso com um cliente MCP

Exemplo de configuração de cliente (por exemplo, o mcpServers do Claude Desktop):

{
  "mcpServers": {
    "appstore": {
      "command": "/absolute/path/to/appstore-mcp/target/release/appstore-mcp",
      "env": {
        "ASC_ISSUER_ID": "00000000-0000-0000-0000-000000000000",
        "ASC_KEY_ID": "ABCD123456",
        "ASC_PRIVATE_KEY_PATH": "/absolute/path/to/AuthKey_ABCD123456.p8"
      }
    }
  }
}

Inspecionar com o MCP Inspector

npx @modelcontextprotocol/inspector ./target/release/appstore-mcp

Notas de uso

  • IDs são opacos. Liste/obtenha primeiro para resolver IDs de app, IAP, assinatura, conjunto e ponto de preço, depois passe-os para as ferramentas de criação/atualização.
  • Precificação exige um ponto de preço. Use list_iap_price_points / list_subscription_price_points para obter o id para set_iap_price_schedule / set_subscription_price.
  • Uploads de assets (upload_*) usam um caminho de arquivo local e executam o fluxo completo de reserva → upload em partes → commit MD5 em uma única chamada. O arquivo é transmitido em fluxo, então o pico de memória é uma parte, não o tamanho do asset, e uma parte que falha é tentada novamente isoladamente. Capturas de tela/prévias exigem um appScreenshotSet / appPreviewSet existente; crie-os com as ferramentas genéricas se necessário.
  • Paginação. appstore_list retorna uma página por padrão. Passe max_pages (até 20) para seguir links.next e mesclar as páginas em um único resultado — meta.hasMore informa se ainda há algo restante.
  • Dados de análise. request_analytics_report → list_analytics_reports → list_analytics_report_instances → list_analytics_report_segments fornece uma URL de segmento pré-assinada; download_analytics_segment a busca, descompacta com gunzip e retorna as linhas como JSON. A Apple pode levar até 48 horas para gerar o primeiro relatório para uma nova solicitação.
  • Qualquer coisa não listada é acessível via appstore_request (método bruto + caminho + corpo JSON:API) ou appstore_list (GET paginado). Exemplo: appstore_request { "method": "GET", "path": "/v1/apps/123/customerReviews" }.
  • Não coberto: endpoints de relatórios de vendas/financeiro retornam TSV compactado com gzip (não JSON:API) e estão fora do escopo dessas ferramentas.

Limitações (impostas pela Apple)

  • Você não pode criar um app via API. O recurso apps permite apenas GET e UPDATE — POST /v1/apps retorna 403 FORBIDDEN_ERROR. Crie o registro do app no site do App Store Connect (Apps → ➕ → Novo App); você pode pré-criar seu bundle ID com create_bundle_id. Todas as outras ferramentas operam em um app existente.
  • O productId de uma compra dentro do app excluída é permanentemente reservado pela Apple e não pode ser reutilizado.

Desenvolvimento

cargo test                              # 200+ tests, no network or credentials needed
cargo clippy --all-targets -- -D warnings
cargo fmt --check

Os testes vêm em três camadas: testes unitários puros para construtores de corpo de solicitação, decisões de repetição e modelagem de resposta; testes wiremock que dirigem o cliente HTTP real contra uma API simulada (repetições, timeouts, paginação, o protocolo de upload em três etapas, downloads de segmento); e tests/tool_surface.rs, que afirma as invariantes do que um cliente realmente vê — nomes únicos, descrições reais, esquemas de objetos, anotações corretas e que ASC_TOOLS/ASC_READ_ONLY retêm exatamente o que afirmam.

A versão mínima suportada do Rust é 1.88, verificada por seu próprio job de CI.

Regenere a referência de ferramentas após adicionar/alterar ferramentas (precisa do binário de lançamento; nenhuma credencial necessária):

cargo build --release && python3 scripts/gen_tools_doc.py   # rewrites docs/TOOLS.md

Testes de integração ao vivo

scripts/integration_test.py dirige o servidor compilado contra a API real. Somente leitura por padrão; --write adiciona um ciclo de vida de IAP autolimpante.

cargo build --release
# Credentials via env (ASC_ISSUER_ID/ASC_KEY_ID/ASC_PRIVATE_KEY_PATH) or local
# appstore-connect.txt + AuthKey_*.p8 in the repo root (both gitignored).
python3 scripts/integration_test.py --app <APP_ID>          # read-only sweep
python3 scripts/integration_test.py --app <APP_ID> --write  # + write lifecycle

Licença

MIT