mcp-walmart-ads

Servidor MCP para Walmart Connect Ads (Sponsored Search + Display) — assinatura automática RSA-SHA256, configuração multirregional e documentação da API inclusa.

Documentação

APIs Walmart e Sam's Club

CI PyPI Python 3.13+ License: MIT

Servidor MCP para três famílias de APIs da Walmart Inc., atrás de uma única superfície de ferramentas:

PlataformaAPIsAutenticação
walmart:ads — Walmart ConnectSponsored Products, DisplayAssinatura RSA-SHA256 + token bearer
walmart:marketplace — Walmart Marketplace28 domínios (pedidos, itens, feeds, relatórios, …)OAuth2 client_credentials
samsclub:ads — Sam's ClubSponsored ProductsAssinatura RSA-SHA256 + token bearer

Quatro ferramentas sobre 31 APIs e 424 operações — descoberta, um proxy genérico e um download. Um agente encontra endpoints nas especificações OpenAPI incluídas e os chama; o servidor assina, adquire tokens e monta cabeçalhos.

walmart:ads:sponsored-products:SBAProfileUpdateV2
└─ retailer ─┘└ line ┘└─── api name ───┘└── operationId ──┘
   └────────── platform ─────────┘  credentials attach here

Um ID de operação sozinho resolve para um host e um modelo de autenticação. Um sufixo <line>:<name> correspondente significa a mesma superfície para outro varejista — 13 IDs de operação compartilhados de 90.

Requisitos

  • Python 3.13+
  • Credenciais para as plataformas que você usar. Configure apenas essas — uma plataforma ausente simplesmente fica não configurada, e a descoberta funciona sem nenhuma credencial.
    • Walmart Connect / Sam's Club — consumer ID, par de chaves RSA, token bearer
    • Walmart Marketplace — client ID + secret, e os IDs de anunciante (perfil de vendedor) que eles atendem

Início rápido

Configure sua configuração (veja Configuração), depois execute o servidor:

# Run directly with uvx (no clone needed)
npx -y @modelcontextprotocol/inspector@latest uvx mcp-walmart-ads
# Or run from source
git clone https://github.com/alyiox/mcp-walmart-ads.git
cd mcp-walmart-ads
uv sync
npx -y @modelcontextprotocol/inspector@latest uv run mcp-walmart-ads

Configuração

config.json DEVE estar em ~/.config/mcp-walmart-ads/config.json. O servidor o lê uma vez na inicialização, então um arquivo corrigido EXIGE reinicialização.

Windows: ~ mapeia para %USERPROFILE% (normalmente C:\Users\<you>), tornando o caminho completo %USERPROFILE%\.config\mcp-walmart-ads\config.json.

Crie o diretório e copie o exemplo:

# Unix-like (macOS, Linux, WSL, …)
mkdir -p ~/.config/mcp-walmart-ads/keys/walmart-ads
cp config.example.json ~/.config/mcp-walmart-ads/config.json
# Windows (PowerShell)
New-Item -ItemType Directory -Force "$env:USERPROFILE\.config\mcp-walmart-ads\keys\walmart-ads"
Copy-Item config.example.json "$env:USERPROFILE\.config\mcp-walmart-ads\config.json"

Formato

platforms.<platform>.regions.<region>.<environment> = <auth block>

<platform> é o prefixo de dois segmentos com o qual um ID de API começa, então uma chave de configuração é literalmente o valor que você passa como parâmetro da ferramenta platform — nada para traduzir.

O formato do bloco de autenticação segue o modelo de autenticação da plataforma. Existe exatamente um formato por plataforma, então nenhum campo discriminador é necessário.

Plataformas com assinatura (walmart:ads, samsclub:ads):

{
  "platforms": {
    "walmart:ads": {
      "regions": {
        "us": {
          "production": {
            "consumer_id": "your-consumer-id",
            "private_key": "./keys/walmart-ads/us-prod.pem",
            "private_key_version": "1",
            "bearer_token": "your-bearer-token",
            "base_urls": {
              "sponsored-products": "https://developer.api.walmart.com/api-proxy/service/WPA/Api/v1",
              "display": "https://developer.api.walmart.com/api-proxy/service/display/api/v1"
            }
          }
        }
      }
    }
  }
}
CampoObservações
consumer_idConsumer ID da Partner Network
private_keyCaminho para a chave privada RSA (PEM). Caminhos relativos são resolvidos em relação ao diretório de configuração
private_key_versionString de versão da chave (padrão "1")
bearer_tokenToken bearer OAuth
base_urls.<api>Um por API na superfície de descoberta da plataforma. Chaves PODEM ser simples (sponsored-products) ou totalmente qualificadas (walmart:ads:sponsored-products); chaves extras são permitidas para as especificações auxiliares alcançadas por método+caminho brutos

Nomes de ambiente são de forma livre aqui — a Walmart pode emitir um tenant apenas production, ou production e staging.

Plataforma OAuth2 (walmart:marketplace):

{
  "platforms": {
    "walmart:marketplace": {
      "regions": {
        "us": {
          "production": {
            "credentials": [
              {
                "client_id": "your-client-id",
                "client_secret": "your-client-secret",
                "advertisers": [
                  { "id": 7060158, "partner_id": "10001234" },
                  { "id": 7060159 }
                ]
              }
            ]
          }
        }
      }
    }
  }
}

environment DEVE ser production ou sandbox; URLs base são fixas pelo servidor e ausentes do arquivo. IDs de anunciante ficam aninhados sob a credencial que os atende, então um secret aparece exatamente uma vez e uma referência de anunciante solta é estruturalmente impossível. partner_id é por vendedor porque duas operações payments o exigem como WM_PARTNER_ID; um valor todo-zero é lido como ausente, já que é o que uma configuração gerada escreve para um vendedor sem um, e scripts/backfill_partner_ids.py preenche as lacunas a partir da Walmart.

Regiões são um namespace, não uma rota — toda região walmart:marketplace alcança os mesmos hosts. O nível existe porque IDs de anunciante são únicos apenas dentro de uma região.

Dividindo a configuração

Um bloco walmart:marketplace preenchido chega a dezenas de kilobytes de credenciais, 88% do arquivo aqui, e uma vírgula perdida ao editá-lo derruba todas as plataformas: uma falha de análise precede a validação por plataforma. As plataformas PODEM, portanto, viver em arquivos drop-in sob config.d/, mesclados sobre a base:

~/.config/mcp-walmart-ads/
├── config.json                  # server-wide settings, and any platforms you like
├── config.d/
│   ├── walmart-marketplace.json # only a "platforms" object
│   └── samsclub-ads.json
└── keys/
  • Um drop-in DEVE declarar apenas platforms; configurações de todo o servidor ficam em config.json.
  • Uma plataforma declarada em dois arquivos é um erro nomeando ambos — nunca precedência silenciosa.
  • Apenas *.json diretamente em config.d/ é lido, então .bak e arquivos de troca do editor são ignorados.
  • Um arquivo que falha ao analisar custa apenas suas próprias plataformas; o resto continua funcionando.
  • Caminhos private_key relativos são resolvidos em relação ao diretório de config.json de qualquer forma, então mover uma plataforma para config.d/ não precisa de edições de caminho.
  • Sem diretório config.d/ significa nenhuma mudança de comportamento.

Um bloco malformado para uma plataforma NÃO DEVE impedir o carregamento das outras. Leia wmt://platforms para ver quais carregaram e quais regiões e ambientes elas declaram: uma que falhou não tem regiões, e ler um de seus ambientes retorna a mensagem do próprio carregador — qual arquivo, quais campos, e que uma correção precisa de reinicialização.

Opções de nível superior

CampoPadrãoObservações
response_cache_ttl3600Segundos que um corpo truncado ou download permanece legível em seu URI de recurso
truncate_threshold2048Bytes de resposta retornados inline antes de truncar para uma prévia
spec_refresh{"auto": true, "interval": 7}Atualização de especificação em segundo plano. auto liga ou desliga a varredura; interval é dias entre varreduras, e PODE ser fracionário

Mercado → tenant (wap-tenant-id)

Passe tenant em call_endpoint e download_file para mercados walmart:ads fora dos EUA (WMT_CA, WMT_MX, WBD_OD, …). Omita para os EUA e para walmart:marketplace.

Ferramentas

list_endpoints

Lista operações em todas as APIs, com filtros opcionais.

ParâmetroObservações
querySubstring sem diferenciar maiúsculas/minúsculas no ID da operação, caminho ou resumo
apiLimitar a uma API, ex.: walmart:marketplace:order-management
platformLimitar a uma plataforma — walmart:ads, walmart:marketplace, samsclub:ads (enum do schema)
tagFiltrar por tag OpenAPI
methodFiltrar por verbo HTTP — GET, POST, PUT, PATCH, DELETE (enum do schema)

IDs de operação retornados são qualificados (api:operationId) e passam direto para describe_endpoint ou call_endpoint.

describe_endpoint

Uma operação mais cada entrada components.schemas alcançável a partir dela, para que um corpo de requisição possa ser construído sem a especificação completa. Cabeçalhos de autenticação e QoS gerenciados pelo servidor são omitidos.

ParâmetroObservações
operation_idQualificado (api:operationId), ou simples quando inequívoco
apiAPI para resolver um ID simples, ex.: walmart:ads:sponsored-products

call_endpoint

Executa uma requisição autenticada contra qualquer plataforma configurada. Assinatura, aquisição de token com cache por credencial e atualização single-flight, e uma nova tentativa após um 401 acontecem tudo no lado do servidor.

ParâmetroObservações
region, environmentObrigatórios. Origem: config
operation_idQualificado ou simples. Resolve API, plataforma, método, caminho e cabeçalhos necessários
apiObrigatório com method + path brutos; caso contrário, inferido de operation_id. Aceita as duas especificações walmart:ads auxiliares
method, pathRota bruta, alcançando endpoints alfa/beta/não publicados ausentes das especificações
path_paramsValores para {placeholders} no caminho
params, bodyQuery string e corpo JSON
file_pathEnvia o arquivo como multipart/form-data — uploads de feed do Marketplace. Combine com o parâmetro de query feedType
advertiser_idDEVE ser fornecido em walmart:marketplace, onde seleciona a credencial. Opcional nas plataformas de anúncios, onde é enviado como X-Advertiser-ID
tenantTenant WAP para regiões walmart:ads fora dos EUA

Uma resposta maior que truncate_threshold é pré-visualizada inline, com o corpo completo em wmt://responses/{request_id} e um cURL reproduzível em wmt://curl/{request_id} — tokens bearer, tokens de acesso e assinaturas substituídos por placeholders.

download_file

Baixa um relatório, etiqueta ou snapshot de um endpoint autenticado. Forneça um url completo (a URL details de uma sondagem de snapshot de display, por exemplo), ou operation_id, ou api com method + path. platform é obrigatório apenas para um url simples.

Com dest_path os bytes são gravados lá. Sem ele, são descompactados com gunzip quando compactados e armazenados em cache, e o resultado carrega cached_at — um payload binário sem dest_path pede um. Redirecionamentos são seguidos, mantendo cabeçalhos de autenticação em um Location relativo ou do mesmo host e descartando credenciais entre hosts; o resultado inclui urls, o caminho de saltos.

Especificações

33 documentos OpenAPI acompanham a wheel. Uma atualização grava cópias atualizadas em ~/.cache/mcp-walmart-ads/specs/, que tem precedência sobre o pacote na leitura. O pacote nunca é gravado em tempo de execução, então permanece como o piso ao qual um cache danificado ou ausente recorre.

De onde vêm

A Walmart não publica arquivos OpenAPI, mas cada página de referência do ReadMe hidrata seu HTML com os UUIDs de registro de seus documentos, e https://dash.readme.com/api/v1/api-registry/<uuid> serve a especificação completa sem autenticação. Isso cobre Walmart Connect e todos os 28 domínios do Marketplace. A Sam's Club não publica nenhum, então sua especificação é escrita manualmente a partir da documentação para desenvolvedores: scripts/build_samsclub_spec.py regenera um candidato desses documentos, e o fluxo de trabalho agendado spec drift abre um PR quando eles mudam, como um portão de revisão humana. O candidato nunca é enviado e nunca é carregado em tempo de execução.

Os documentos são armazenados literalmente como o upstream os serviu, então um diff de atualização mostra exatamente o que mudou. Exemplos inline superdimensionados e metadados x-readme são removidos no carregamento em vez de no disco, o que mantém essa redução reajustável sem baixar nada novamente.

Mantendo-os atualizados

As especificações são atualizadas em segundo plano: uma vez na inicialização, depois a cada spec_refresh.interval dias (7 por padrão). Defina auto para false para parar a varredura — o intervalo é lembrado para quando você o religar, e a atualização manual ainda funciona.

Para atualizar agora, tendo atingido um endpoint que a especificação incluída não tem:

# Installed with uvx (no clone)
uvx mcp-walmart-ads --refresh

# Or from a source checkout
uv run mcp-walmart-ads --refresh

Qualquer forma varre todas as especificações independentemente do intervalo e grava o mesmo cache de usuário, imprimindo uma linha por documento: written, unchanged, ou error.

Não há deliberadamente nenhuma ferramenta para isso. Uma especificação desatualizada é indistinguível de uma atual de dentro de uma sessão — ela simplesmente não tem um endpoint — então um agente solicitado a decidir ou nunca atualizaria ou atualizaria supersticiosamente após uma falha não relacionada. O gatilho pertence fora da sessão.

Um documento DEVE produzir pelo menos uma operação antes de ser instalado, então um upstream respondendo 200 com um corpo de erro não pode envenenar o cache, e um documento byte-idêntico é deixado em paz. Um arquivo em cache que não carrega é descartado e a leitura recorre ao pacote. Servidores coordenam através de spec-state.json na raiz do cache, que registra quando cada especificação foi tentada pela última vez e mantém uma concessão para que um processo varra por vez — cada sessão de cliente executa seu próprio processo de servidor, e sem ele cada um rebaixaria todos os 33.

Reconstruindo o pacote

Uma etapa de mantenedor, e não a mesma coisa que --refresh: isso atualiza seu cache, isso atualiza as cópias que acompanham a wheel.

# Registry-sourced specs only, by default
uv run python scripts/fetch_specs.py
uv run python scripts/fetch_specs.py walmart:ads:sponsored-products walmart:marketplace:order-management

# Regenerate the Sam's Club candidate spec for review
uv run --group spec-build python scripts/build_samsclub_spec.py

Recursos MCP

URI do recursoDescrição
wmt://platformsCada plataforma, seu modelo de autenticação, e as regiões e ambientes que ela declara
wmt://platforms/{platform}/apisOs ids de api dessa plataforma
wmt://platforms/{platform}/apis/{name}Uma api: título, versão, contagem de operações, e suas tags com uma contagem cada — os valores legais de list_endpoints(tag=…)
wmt://platforms/walmart:marketplace/regions/{region}/{environment}/advertisersIds de anunciante mapeados para seu Walmart Partner ID (null quando não definido)
wmt://platforms/{platform}/regions/{region}/{environment}/hostsIds de api mapeados para a URL base que uma chamada alcança, ou * para cada api cujo host o servidor possui
wmt://responses/{request_id}Corpo completo de uma resposta truncada ou de um download em cache (em memória, TTL a partir da configuração)
wmt://curl/{request_id}cURL reproduzível para uma solicitação anterior, com credenciais substituídas por placeholders

Exemplos de hosts MCP

Cursor

Adicione ao .cursor/mcp.json:

{
  "mcpServers": {
    "walmart": {
      "command": "uvx",
      "args": ["mcp-walmart-ads"]
    }
  }
}
Claude Code

Adicione à configuração MCP do seu Claude Code:

{
  "mcpServers": {
    "walmart": {
      "command": "uvx",
      "args": ["mcp-walmart-ads"]
    }
  }
}
Codex
[mcp_servers.walmart]
command = "uvx"
args = ["mcp-walmart-ads"]
OpenCode
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "walmart": {
      "type": "local",
      "enabled": true,
      "command": ["uvx", "mcp-walmart-ads"]
    }
  }
}
GitHub Copilot
{
  "inputs": [],
  "servers": {
    "walmart": {
      "type": "stdio",
      "command": "uvx",
      "args": ["mcp-walmart-ads"]
    }
  }
}

Desenvolvimento

uv sync --group dev
uv run ruff check src/ tests/ scripts/
uv run ruff format --check src/ tests/ scripts/
uv run pyright
uv run pytest tests/ -v

Contribuindo

Issues e pull requests são bem-vindos. Mantenha as mudanças focadas; ruff check, ruff format --check, pyright, e pytest devem passar todos.

Licença

LICENSE.