ABAP ADT MCP

Desenvolvimento ABAP a partir do Claude e outros hosts MCP: pesquisar objetos, ler e escrever código-fonte, transports, ativação, ABAP Unit, ATC, short dumps, depurador e consultas SQL via ADT. 173 ferramentas, multi-sistema (S/4HANA Cloud e on-premise), com proteções no lado do servidor (somente leitura, pacotes permitidos, tabelas negadas) e log de auditoria.

Documentação

abap-adt-mcp

Deixe o Claude ler, escrever, testar e verificar código ABAP nos seus sistemas SAP.

npm version CI License: MIT Node.js MCP Registry

Inglês · Português (Brasil) · Deutsch

abap-adt-mcp é um servidor Model Context Protocol. Execute-o ao lado do Claude Desktop, Claude Code ou qualquer outro host MCP, aponte-o para um ou mais sistemas SAP, e o modelo obtém os mesmos endpoints REST do ADT que o Eclipse usa: pesquisar objetos, ler e editar código-fonte, criar transportes, ativar, executar ABAP Unit e ATC, ler dumps curtos, consultar tabelas. Um único servidor expõe 173 ferramentas para quantos sistemas SAP você configurar, tanto S/4HANA Cloud quanto on-prem.

Use-o com cuidado e prefira sistemas de desenvolvimento. Um destino sem um bloco policy é totalmente gravável dentro das suas autorizações SAP. As proteções por destino (somente leitura, pacotes permitidos, tabelas negadas) são aplicadas pelo próprio servidor, independentemente do que o host aprovar, para que um prompt descuidado não alcance o sistema errado.

Sumário

O que há de novo na 2.0.0

Lançada em 2026-09-08. A lista completa está em CHANGELOG.md; o que importa ao atualizar:

  • Node.js 22.12 ou mais recente é obrigatório (quebra). Node 18 e 20 estão além do fim da vida útil e não recebem correções de segurança; um servidor que guarda credenciais SAP não deve rodar neles. Em um Node mais antigo, npm imprime EBADENGINE e o servidor não é testado; instale o LTS atual e reinicie o host. A imagem do contêiner já estava em node:22-alpine.
  • tls.servername em um destino. Para um sistema acessado por endereço IP ou nome de host curto cujo certificado carrega o nome totalmente qualificado: o nome é verificado e enviado como SNI, a verificação permanece ativada, e insecureTls não é mais o único caminho por esse cenário. listSystems mostra servername NAME.
  • Erros de certificado ensinam a correção. Um handshake falho chega ao modelo como kind: "tlsCertificate" com uma dica que nomeia o destino: emissor desconhecido fornece a linha openssl s_client para aquele host e aponta para tls.ca; uma incompatibilidade de nome cita os nomes que o Node relatou e aponta para tls.servername; um certificado expirado diz que apenas a renovação resolve. insecureTls é mencionado por último.
  • insecureTls permanece, por destino, desativado por padrão, anunciado na inicialização; SECURITY.md registra o motivo.
  • Cadeia de suprimentos. puppeteer-core 25 remove o último alerta aberto do Dependabot da árvore de dependências (npm audit relata zero vulnerabilidades); o Dependabot agora aguarda um período de espera antes de propor atualizações e agrupa atualizações de segurança em um único pull request; dotenv é carregado silenciosamente para que o stdout permaneça um canal JSON-RPC limpo.

Atualizar da 1.x não exige mudança de configuração: systems.json, as políticas, os nomes das ferramentas e as variáveis de ambiente permanecem inalterados.

Configuração

Três coisas antes de começar:

  • Node.js 22.12 ou mais recente (22 ou 24 LTS; a 2.0.0 removeu o suporte a Node 18 e 20). Baixe o instalador LTS de nodejs.org; ele inclui npm e npx, que é tudo o que o host precisa. Nenhum terminal é necessário para verificar: se o Node estiver ausente, o log do host diz spawn npx ENOENT ao tentar iniciar o servidor (veja o passo 2).
  • Acesso ao sistema SAP. No S/4HANA Cloud (edição pública) não há nada para configurar no lado SAP para usuários nomeados: seu usuário precisa da função de negócio que permite o ADT do Eclipse no tenant (SAP_BR_DEVELOPER na entrega padrão); se o ADT do Eclipse funciona para você, este servidor também funciona. On-prem, o serviço /sap/bc/adt deve estar ativo na transação SICF (uma tarefa de Basis) e seu usuário precisa das autorizações usuais de desenvolvimento ADT. Apenas clientes oauth não assistidos precisam de um Communication Arrangement, veja Autenticação.
  • Um navegador Chromium (Chrome, Edge ou Brave) na máquina ao usar SSO de navegador.

1. Descreva seus sistemas SAP

Crie uma pasta .abap-adt-mcp no seu diretório inicial e um arquivo systems.json dentro dela, uma entrada por sistema (um "destino"). Sem terminal: no macOS abra o Finder, pressione Shift-Cmd-G, digite ~, crie a pasta (o Finder pede para confirmar um nome começando com ponto; Shift-Cmd-. mostra pastas ocultas), então salve o arquivo lá a partir de qualquer editor de texto. No Windows a pasta é C:\Users\<you>\.abap-adt-mcp, criada no File Explorer como qualquer outra. Um tenant S/4HANA Cloud com SSO de navegador precisa exatamente disto:

{
  "DEV": {
    "url": "https://myXXXXXX.s4hana.cloud.sap",
    "client": "080",
    "authType": "sso",
    "default": true
  }
}

url é obrigatório; client é o client no qual sua sessão SSO aterrissa (nos tenants testados, o sistema de desenvolvimento fez logon em 080 e os sistemas de customizing e teste em 100; a entrada About no menu do usuário do launchpad mostra isso); authType assume o padrão sso e "default": true permite omitir o nome do destino em toda chamada. A chave (DEV) é sua escolha e é o nome que você usará nos chats. Vários sistemas, com proteções, ficam assim (ou copie systems.example.json):

{
  "DEV": {
    "url": "https://myXXXXXX.s4hana.cloud.sap",
    "client": "080",
    "authType": "sso",
    "default": true,
    "policy": { "allowedPackages": ["Z*"] }
  },
  "PRD": {
    "url": "https://myYYYYYY.s4hana.cloud.sap",
    "client": "100",
    "authType": "sso",
    "policy": { "readOnly": true, "deniedTables": ["PA*", "HR*", "USR02"], "allowFreeSql": false }
  },
  "ONPREM": {
    "url": "https://sap.example.com:44300",
    "client": "100",
    "authType": "basic",
    "user": "DEVELOPER",
    "password": "${env:ONPREM_PASSWORD}",
    "policy": { "allowedPackages": ["Z*", "$*"] },
    "tls": { "ca": "/etc/ssl/corp-ca.pem" }
  }
}

O padrão para qualquer sistema produtivo ou de teste é a entrada PRD: adicione "policy": { "readOnly": true } e o servidor recusa toda escrita lá, independentemente do que for pedido ao modelo. sso abre um navegador real uma vez para usuários nomeados do S/4HANA Cloud; basic é para usuários on-prem e Communication Users; oauth é para clientes não assistidos. ${env:VAR} puxa um segredo do ambiente para que ele nunca fique no arquivo, policy é aplicado pelo servidor, e tls.ca adiciona uma CA corporativa com verificação mantida ativada (tls.servername nomeia o certificado quando o sistema é acessado por endereço IP). $* (pacotes locais) é listado apenas na entrada on-prem porque o tenant Public Cloud testado recusa $TMP.

Se você tiver um terminal, restrinja o arquivo ao seu usuário:

chmod 600 ~/.abap-adt-mcp/systems.json

Você pode pular esta etapa quando o arquivo não contiver senhas inline (um arquivo somente SSO, ou segredos referenciados como ${env:VAR}): o servidor então apenas imprime um aviso se o arquivo for legível por outros. Ele recusa iniciar apenas quando um arquivo legível por outros contém senhas inline, segredos de client ou senhas de git. O Windows não tem modos de arquivo; a verificação é ignorada lá.

2. Registre o servidor no seu host

O pacote está no npm como abap-adt-mcp (publicado por meio de trusted publishing com proveniência), então npx é tudo o que você precisa.

Claude Code, uma linha:

claude mcp add abap-adt-mcp -e SAP_SYSTEMS_FILE=$HOME/.abap-adt-mcp/systems.json -- npx -y abap-adt-mcp

Claude Desktop (Settings > Developer > Edit Config, depois saia e reabra o aplicativo). Substitua me pelo seu próprio nome de usuário; no Windows escreva o caminho como C:/Users/<you>/.abap-adt-mcp/systems.json:

{
  "mcpServers": {
    "abap-adt-mcp": {
      "command": "npx",
      "args": ["-y", "abap-adt-mcp"],
      "env": { "SAP_SYSTEMS_FILE": "/Users/me/.abap-adt-mcp/systems.json", "MCP_TOOLSETS": "focused" }
    }
  }
}

MCP_TOOLSETS=focused publica as 114 ferramentas de desenvolvimento em vez de todas as 173, o que evita que os esquemas das ferramentas consumam a janela de contexto do chat; remova-o quando precisar dos conjuntos de ferramentas de depurador, traces, abapGit, RAP ou refatoração. O mesmo JSON funciona no Cursor, Cline e outros hosts que leem um mapa mcpServers; o VS Code nomeia o mapa como servers em vez disso, então renomeie a chave de nível superior lá (docs/HOSTS.md tem a forma por host). A chave abap-adt-mcp é o nome que o host mostra para o servidor e o prefixo de toda ferramenta (mcp__abap-adt-mcp__searchObject no Claude Code); skills ABAP públicas escritas para este servidor procuram esse nome, então uma chave diferente apenas impede que essas skills reconheçam o servidor, nada mais quebra.

Após a reinicialização, o Claude Desktop lista abap-adt-mcp com um status em Settings > Developer, e o menu de ferramentas abaixo do campo de chat (o ícone de controles deslizantes) mostra o servidor com suas ferramentas. Se nada aparecer, leia o log do host: no momento em que este texto foi escrito, o Claude Desktop grava mcp.log e mcp-server-abap-adt-mcp.log em ~/Library/Logs/Claude no macOS e %APPDATA%\Claude\logs no Windows, e o Claude Code mostra o estado com /mcp. Tudo o que o servidor imprime (avisos de inicialização, o aviso do arquivo de auditoria, mensagens MCP_PROFILE_GATE=warn) vai para o stderr e cai nesse log. Tanto o Claude Desktop quanto o Claude Code pedem antes de executar uma ferramenta que você não aprovou permanentemente; esse diálogo é comportamento do host e independente da anotação destructiveHint, então trate-o como uma cortesia e o bloco policy como a garantia.

3. Diga olá

Abra um novo chat e digite (substitua DEV pela chave que você escolheu em systems.json):

Liste meus sistemas SAP, faça logon no DEV e mostre-me o código-fonte da classe CL_ABAP_CHAR_UTILITIES.

O modelo chama listSystems, login (uma janela de navegador aparece para destinos SSO; marque "permanecer conectado" e logins futuros serão silenciosos), searchObject e getObjectSource. Quando o código-fonte voltar, você terminou. login é opcional em todos os modos: o dispatcher executa o login do navegador antes da primeira chamada em um destino SSO, e destinos basic e oauth autenticam na primeira solicitação. Chame-o explicitamente apenas para forçar um novo login ou para comprovar as credenciais antes de qualquer outra coisa. Pedir healthcheck retorna a versão do servidor, os nomes dos destinos, o destino padrão, os conjuntos de ferramentas ativos e a contagem de ferramentas; systemProfile informa se um destino é S/4HANA Cloud ou on-prem e quais conjuntos de ferramentas ele não pode atender.

O que pedir ao modelo

O servidor é uma caixa de ferramentas da qual o modelo escolhe: peça em linguagem simples e ele seleciona a sequência. Coisas que funcionam bem desde a primeira sessão:

PerguntaFerramentas que o modelo utiliza
"Explique o que o método GET_DATA de ZCL_ORDER_SERVICE faz."searchObject, getMethodSource
"Onde a tabela ZTABLE ainda é usada, e por quais programas?"whereUsed, sourceTextSearch, grepPackage
"Mostre-me os campos e associações da visão CDS ZI_PRODUCT."cdsViewInfo, objectStructureElements
"Adicione uma verificação de nulo no topo de GET_DATA, ative e execute os testes de unidade."resolveTransport, syntaxCheckCode, editObjectSource (com activate=true), unitTestRun, objectDiff
"Crie a classe ZCL_HELLO no pacote ZDEMO que imprime Hello World, com um teste de unidade."validateNewObject, resolveTransport, createObject, setObjectSource, createTestInclude, unitTestRun
"Execute ATC no pacote ZFIN e aplique todos os quickfixes que forem seguros."createAtcRun, atcWorklists, atcQuickfixProposals, atcApplyQuickfix, atcSummary
"O que mudou no transporte DEVK900123? Revise-o e me diga se é seguro liberar."transportDetails, transportUnifiedDiff
"Por que ocorreu o último short dump do usuário DEVELOPER? Proponha uma correção."dumps, dumpDetails, getObjectSource
"ZCL_ORDER_SERVICE está pronto para ABAP Cloud? Quais objetos SAP o bloqueiam?"apiReleaseState, createAtcRun
"Selecione as dez linhas mais recentes de ZTABLE onde STATUS = 'X'."runQuery (ou tableContents quando a pré-visualização de dados recusar uma tabela)
"Tente este trecho de código e mostre-me a saída."runSnippet
"Quais conjuntos de ferramentas o DEV suporta? O depurador está disponível lá?"systemProfile

Em um sistema on-prem comum, o exemplo de criação também funciona com $TMP e sem transporte; o tenant S/4HANA Cloud testado recusou $TMP, então lá você nomeia um pacote de cliente e seu transporte (veja S/4HANA Cloud versus on-prem).

Hábitos que o servidor incorpora, para que você não precise explicitá-los: as ferramentas de escrita bloqueiam e desbloqueiam por conta própria; activate=true ativa na mesma chamada; todo erro é JSON com kind, hint e nextTools, então o modelo se recupera em vez de tentar novamente às cegas; sessões expiradas são reautenticadas e a chamada é tentada uma vez mais; resultados grandes são paginados dentro de um orçamento de 40.000 caracteres (MCP_MAX_RESPONSE_CHARS) e relatam hasMore; chamadas longas enviam notificações de progresso MCP para hosts que passam um progressToken (mais um heartbeat a cada 10 segundos). Os fluxos canônicos de criação e edição viajam no campo instructions do MCP, e toda ferramenta carrega anotações readOnlyHint/destructiveHint para que hosts que controlam aprovação por anotação possam perguntar apenas em escritas.

Fluxos de trabalho em detalhe

As sequências completas ferramenta por ferramenta, formatos de argumentos e receitas estão em docs/WORKFLOWS.md; esta seção é a versão resumida.

Toda ferramenta, exceto listSystems e healthcheck, aceita um destination opcional; ele é obrigatório quando vários sistemas estão configurados e nenhum está marcado como default (ou nomeado em SAP_DEFAULT_DESTINATION).

URLs e nomes. searchObject retorna a URL do objeto, por exemplo /sap/bc/adt/oo/classes/zcl_example; a URL da fonte é aquela mais /source/main; includes de classe (implementações, classes de teste) usam as URLs de classIncludes como estão. As ferramentas herdadas de várias gerações upstream nomeiam essa URL de forma diferente (objSourceUrl, objectSourceUrl, objectUrl, classUrl, url, mainUrl), então o dispatcher mapeia os nomes para o esquema de cada ferramenta e remove ou anexa /source/main onde necessário: o valor de searchObject pode ser passado para qualquer uma delas. Ferramentas de nível de classe (getMethodSource, setMethodSource, whereUsed, cdsViewInfo) também aceitam o nome simples.

Encontrar e ler código. searchObject encontra objetos por nome. Por conteúdo, sourceTextSearch usa o índice de texto ADT e grepPackage faz grep nos fontes do pacote no lado do cliente com linhas de contexto (o fallback quando um tenant não tem índice de texto). packageTree, whereUsed, cdsViewInfo, typeHierarchy e classComponents fornecem navegação no estilo IDE. getObjectSource lê uma fonte (paginada com startLine/maxLines, version=inactive para código não ativado), getMethodSource um método, e exportPackageSources escreve uma árvore de pacotes no disco no layout abapGit para ferramentas locais.

Editar com segurança. Escritas bloqueiam, escrevem e desbloqueiam por conta própria e ativam quando você passa activate=true:

  1. resolveTransport(objSourceUrl) retorna o transporte que já registra o objeto, o mais recente modificável para seu pacote, ou needsTransport: false para pacotes locais; createIfMissing=true cria um quando nenhum existe.
  2. syntaxCheckCode na fonte pretendida: opcional para uma mudança de uma linha, seguro barato para qualquer coisa maior.
  3. editObjectSource(objectSourceUrl, replacements=[{oldText, newText}], activate=true, transport) para mudanças direcionadas (o servidor relê o SAP primeiro; cada oldText deve corresponder exatamente uma vez, caso contrário a chamada falha com "0 correspondências" ou os números de linha de cada correspondência e nada é escrito), setMethodSource(classUrl, methodName, source, activate=true, transport) para trocar um bloco METHOD ... ENDMETHOD na implementação (passe o bloco completo ou apenas o corpo; a parte de definição permanece como está; include e className selecionam classes locais ou de teste; um método desconhecido é recusado com a lista de métodos presentes), setObjectSource para reescritas completas.
  4. Leia o campo activation do resultado; corrija e escreva novamente, ou activateByName / activatePackage depois.
  5. unitTestRun(url), então objectDiff(objectUrl) para mostrar o que mudou em relação à revisão anterior.

lock/unLock apenas seguram um bloqueio entre várias escritas; listLocks e forceUnlock se recuperam de uma escrita falha. Um bloqueio mantido por outra sessão (uma janela Eclipse aberta, por exemplo) é relatado como estrangeiro: dropSession e forceUnlock não podem liberá-lo, apenas aquela sessão ou SM12 pode.

Criar objetos e transportes. loadTypes (escolha o objtype, por exemplo CLAS/OC), validateNewObject, então resolveTransport(objSourceUrl="/sap/bc/adt/packages/<pkg>", devClass="<pkg>") para o pacote em si, já que o objeto ainda não tem URL (ou createTransport), então createObject(objtype, name, parentName=<pkg>, description, parentPath="/sap/bc/adt/packages/<pkg>", responsible, transport), setObjectSource com activate=true, createTestInclude, unitTestRun. creatableTypeDetails informa quais campos cada tipo exige; pacotes (DEVC/K) precisam de swcomp, e backends em nuvem precisam de responsible.

Testes de unidade e ATC. unitTestRun após cada mudança (paginado com startIndex/maxItems); unitTestEvaluation detalha os resultados. ATC: createAtcRun(mainUrl, variant) em um objeto, pacote ou transporte (um nome de variante como ABAP_CLOUD_DEVELOPMENT_DEFAULT é resolvido para uma worklist para você), então atcWorklists ou atcSummary (totais por prioridade, verificação e objeto), atcQuickfixProposals e atcApplyQuickfix para correções determinísticas, atcDocumentation para verificações desconhecidas; isenções passam por atcExemptProposal e atcRequestExemption.

Revisar um transporte. transportDetails lista objetos, proprietário, tarefas e status; transportUnifiedDiff compara cada objeto de fonte registrado no transporte contra a versão anterior a ele, incluindo includes de classe LIMU e métodos, includes REPS e módulos FUNC (mensagens e DDIC são pulados com um motivo). A comparação é contra a fonte atual, então em um transporte já liberado, mudanças posteriores nos mesmos objetos também aparecem. Ela roda em tenants S/4HANA Cloud (a cobertura LIMU veio de uma sessão RAP lá, veja docs/FIELD-NOTES.md). objectDiff cobre objetos com várias revisões. userTransports, transportRelease, transportSetOwner e transportAddUser completam o quadro.

Dados. runQuery(sqlQuery) executa um SELECT SQL ABAP através da pré-visualização de dados ADT sobre tabelas e visões CDS (por nome de entidade, visões de API liberadas incluídas), por exemplo SELECT carrid, connid, fldate FROM sflight WHERE carrid = 'LH' ORDER BY fldate DESCENDING. rowNumber limita quantas linhas o SAP retorna (padrão 100) e startRow/maxRows paginam o resultado. Declarações são quebradas no limite de 255 caracteres por linha da pré-visualização antes do envio (um literal único mais longo que isso ainda falha). Tabelas cujo dataMaintenance DDIC é restrito são recusadas pela pré-visualização: tableContents(ddicEntityName) as lê (S_TABU_DIS/S_TABU_NAM ainda se aplicam). Chaves retornam em formato interno, então getDataElementProperties e getDomainProperties informam sobre zeros à esquerda e exits de conversão.

Dumps e depurador. dumps(from, to, user, contains) retorna resumos compactos (erro de runtime, exceção, programa, ponto de término com URL da fonte e linha, topo da pilha) e dumpDetails(dumpId) a análise completa; getObjectSource em torno de terminatedAt.line e whereUsed encontram a causa. Os conjuntos de ferramentas debugger e traces existem apenas onde o backend os expõe (systemProfile informa) e apenas quando o conjunto é publicado (focused deixa ambos de fora). Sem um depurador, os caminhos são: um dump (dumps), reproduzir o bug com runSnippet ou runClass em um sistema de desenvolvimento e ler a saída, e traces onde o backend os serve. Quando o depurador está disponível, debuggerListen precisa de debuggingMode, terminalId, ideId e user, como no Eclipse.

Prontidão para ABAP Cloud. apiReleaseState aceita uma de quatro entradas: names (separado por vírgulas, opcionalmente tipado como TABL:MARA), objectUrl, source (texto ABAP colado) ou sourceUrl (uma URL .../source/main que o servidor lê e escaneia). Ele verifica os objetos SAP contra o repositório oficial de cloudificação da SAP (liberado, depreciado com sucessores, classicAPI, noAPI; edições cloud, btp, pce2023, pce2022) mais a resposta /sap/bc/adt/apireleases do backend, então o modelo nunca lembra estados de liberação da memória.

Executar código. runSnippet(code, packageName) envolve ABAP descartável em uma classe IF_OO_ADT_CLASSRUN temporária, cria, ativa e executa, retorna a saída do console e exclui a classe novamente, também quando a ativação ou a execução falha (uma exclusão falha é relatada como cleanupError; keep=true a mantém). On-prem packageName padrão é $TMP; em S/4HANA Cloud passe um pacote de cliente, seu transport e responsible, e a criação e exclusão são registradas nesse transporte. runClass executa uma classe existente. Ambos precisam de S_DEVELOP, então apenas sistemas de desenvolvimento.

abapGit, gerador RAP, refatoração, serviços. abapGit: gitRepos, gitCreateRepo, gitPullRepo, stageRepo, pushRepo, checkRepo, switchRepoBranch, com gitUser/gitPassword por destino mantendo credenciais remotas fora da conversa. Gerador RAP: rapGenIsAvailable, rapGenGetContent, rapGenValidateContent, rapGenPreview, rapGenGenerate (transporte obrigatório), então activateObjects nos objetos gerados e rapGenPublishService. Refatoração: renameEvaluate, renamePreview, renameExecute; o mesmo trio para extractMethod*; changePackagePreview e changePackageExecute. Serviços de negócios: fetchServiceDetails(name), bindingDetails, publishServiceBinding, unPublishServiceBinding.

Prompts integrados

Seis fluxos de trabalho prontos viajam como prompts MCP. Cada um nomeia as ferramentas exatas a chamar, em ordem, e diz onde deve parar e perguntar:

PromptArgumentosO que fazOnde para
create-objectopcional destination, depois objectType (ID de tipo ADT, como CLAS/OC, INTF/OI, PROG/P, DDLS/DF), name, package, opcional purposeValida, cria, grava, ativa, testa unitariamente e verifica com ATC um novo objeto no pacote e transporte corretos.Cria e ativa; nunca exclui nem libera.
safe-editopcional destination, depois object (nome ou URL), changeLê, altera com substituições ancoradas em texto, ativa, testa e mostra o diff.Nunca alcança deleteObject, transportRelease ou forceUnlock por conta própria; se um lock externo ou uma questão de liberação surgir, para e pergunta.
review-transportopcional destination, depois transport (número de requisição)Gera diff de cada objeto em um transporte e produz uma revisão go/no-go.Nunca chama transportRelease.
fix-atcopcional destination, depois target (URL do objeto, nome do pacote ou transporte), opcional variantExecuta ATC, aplica quickfixes determinísticos, corrige o restante com edições, reexecuta até que prioridades 1 e 2 estejam limpas.Aplica quickfixes e edições; isenções somente com aprovação.
clean-core-checkopcional destination, depois target (nome ou URL do objeto, ou nome do pacote)Avalia prontidão para ABAP Cloud: APIs liberadas, objetos obsoletos, sucessores, verificações ATC de nuvem.Não altera código.
debug-dumpopcional destination, depois opcional filter (usuário, programa, exceção ou janela de tempo)Encontra a causa raiz de um short dump e propõe a correção na linha exata.Propõe substituições; não as aplica sem aprovação.

Como você os invoca depende do host. O Claude Code expõe prompts MCP como comandos de barra nomeados /mcp__<server>__<prompt>, com os argumentos fornecidos posicionalmente na ordem que o prompt declara (destination vem primeiro em todo prompt, como na tabela):

/mcp__abap-adt-mcp__safe-edit DEV ZCL_ORDER_SERVICE "return early when the input table is empty"

O Claude Desktop os oferece no menu de anexo (mais) do chat sob o nome do servidor no momento da escrita; hosts sem suporte a prompts simplesmente não os exibem, e os mesmos fluxos ainda alcançam o modelo através do campo instructions do servidor.

Outras formas de instalar

Fixar a versão. npx -y abap-adt-mcp busca a versão mais recente a cada início. Para um rollout controlado, fixe-a (npx -y abap-adt-mcp@X.Y.Z, ou a tag de contêiner vX.Y.Z) e verifique a atestação de proveniência que a publicação confiável anexa com npm audit signatures em um diretório onde o pacote está instalado.

Plugin do Claude Code. O repositório é seu próprio marketplace de plugins (.claude-plugin/marketplace.json ao lado de plugin.json), então dois comandos no Claude Code registram o servidor e carregam ambas as skills, sem claude mcp add:

/plugin marketplace add williansaez/abap-adt-mcp
/plugin install abap-adt-mcp@abap-adt-mcp

O manifesto inicia o servidor como npx -y abap-adt-mcp@<version>, fixado na versão que acompanha (a fixação se move com cada versão e o CI a verifica contra package.json), então um host de plugin mantém a versão que instalou em vez de pegar o que o npm serve como mais recente no próximo início; define SAP_SYSTEMS_FILE=${HOME}/.abap-adt-mcp/systems.json e nenhum MCP_TOOLSETS, então publica todas as 173 ferramentas; systems.json do passo 1 ainda é seu para escrever. As skills sozinhas instalam, no momento da escrita, com npx skills add williansaez/abap-adt-mcp (um instalador de terceiros, não parte deste repositório) ou copiando os dois diretórios sob skills/ para ~/.claude/skills/.

Contêiner. Imagens são construídas a partir de node:22-alpine, executadas como o usuário não privilegiado node (uid 1000) e publicadas no GHCR a cada versão (tags latest e vX.Y.Z). Monte seu systems.json somente leitura e passe segredos referenciados através:

docker run -i --rm \
  -v "$PWD/systems.json:/config/systems.json:ro" \
  -e SAP_SYSTEMS_FILE=/config/systems.json \
  -e ONPREM_PASSWORD \
  ghcr.io/williansaez/abap-adt-mcp:latest

A verificação de modo de arquivo também roda dentro do contêiner: um arquivo montado com modo 0600 pertencente a outro uid não pode ser lido pelo usuário node (o início falha com is not valid JSON: EACCES, já que a leitura e o parse compartilham um caminho de erro), e um arquivo legível por outros apenas avisa, a menos que contenha segredos inline. Ou possua o arquivo pelo uid 1000 e mantenha 0600, ou referencie cada segredo como ${env:VAR} e aceite o aviso. Segredos passados com -e são visíveis para docker inspect; não há alternativa baseada em arquivo para MCP_HTTP_TOKEN, então trate o ambiente do contêiner como confidencial. Para Streamable HTTP dentro do contêiner, adicione -e MCP_HTTP_PORT=2236 -e MCP_HTTP_HOST=0.0.0.0 -e MCP_HTTP_TOKEN=<token> -p 127.0.0.1:2236:2236. SSO de navegador precisa de um navegador local, então execute destinos SSO do npm na estação de trabalho; destinos basic e oauth funcionam dentro do contêiner.

Registro MCP. Listado como io.github.williansaez/abap-adt-mcp para hosts que navegam no registro; server.json é o manifesto do registro.

A partir do código-fonte.

git clone https://github.com/williansaez/abap-adt-mcp.git
cd abap-adt-mcp
npm ci
npm run build

Depois aponte o host para node /absolute/path/abap-adt-mcp/dist/index.js. Um systems.json ao lado do checkout é detectado automaticamente; .env (veja .env.example) funciona para configurações de sistema único. Ambos são ignorados pelo git.

Autenticação

Cada destino escolhe seu próprio authType (sso a menos que SAP_AUTH_TYPE diga o contrário). Detalhes e passos do lado SAP estão em docs/AUTH.md.

ModoUse paraO que você configuraConfiguração do lado SAP
sso (padrão)Usuários nomeados S/4HANA Cloud, exatamente como Eclipse ADT (SAML2/OIDC via IAS)Um navegador Chromium (Chrome, Edge, Brave) abre uma vez por host; os cookies de sessão são lidos pelo protocolo DevTools e mantidos em memória, com sap-client fixado em cada requisição. A sessão do provedor de identidade vive em um perfil dedicado sob ~/.abap-adt-mcp/sso/<host> (modo 0700). SAP_BROWSER_PATH substitui o navegador, SAP_BROWSER_PROFILE_DIR reutiliza um perfil personalizado com passkeys salvos (o perfil padrão do navegador é rejeitado de propósito).Nenhum além do papel de negócio de desenvolvedor que seu usuário já precisa para Eclipse ADT
basicAS ABAP on-prem, Usuários de Comunicação S/4HANA Clouduser e password (use ${env:VAR}). Autentica na primeira chamada, login é opcional.Um usuário com autorizações ADT
oauthClientes não assistidos S/4HANA Cloudoauth.tokenUrl, oauth.clientId, oauth.clientSecret, opcional oauth.scope (concessão de credenciais de cliente; o token é armazenado em cache até pouco antes da expiração e invalidado em um 401).Um Usuário de Comunicação, um Sistema de Comunicação com OAuth 2.0 e um Acordo de Comunicação para o cenário que expõe ADT no seu tenant (varia por tenant e não está listado aqui; o acordo fornece o endpoint de token). As ferramentas então executam com as autorizações do Usuário de Comunicação.

Usuários de negócio nomeados no S/4HANA Cloud não podem usar autenticação básica; eles fazem login através de sso ou você cria um Usuário de Comunicação. A sessão SSO é criada para o cliente de logon do tenant, que pode diferir do esperado (100 em vez de 080, por exemplo): defina client para o que a sessão realmente usa. Um cliente errado aparece como erros de autorização ou não encontrado em objetos que você pode abrir no Eclipse, após um login que em si foi bem-sucedido. O diretório de perfil SSO é um diretório comum de dados de usuário do Chromium: contém cookies e armazenamento local que o provedor de identidade define quando você marca "permanecer conectado", nada que o servidor adiciona, e é protegido por permissões de arquivo e pelo que o Chromium faz no seu SO, não criptografado pelo servidor; quanto tempo a sessão permanece válida é política do provedor de identidade, e excluir o diretório é a única maneira de encerrá-la cedo (o cookie de sessão SAP coletado nunca é gravado em disco). tls por destino adiciona uma CA corporativa (ca), o nome para verificar o certificado quando url contém um endereço IP ou hostname curto (servername, também enviado como SNI), ou um certificado de cliente X.509 (cert + key, ou pfx + passphrase), com verificação mantida ativa; a janela do navegador SSO gerencia seu próprio armazenamento de confiança. Opcional gitUser/gitPassword fornece credenciais abapGit para que nunca passem pelo modelo. Sessões expiradas em qualquer modo são restabelecidas uma vez e a chamada é repetida; se isso falhar, o erro diz kind: "sessionExpired".

Mantendo seguro

Este servidor dá a um modelo de linguagem acesso de leitura e escrita ao SAP. Algumas regras tornam isso confortável:

  • As proteções vivem no servidor, não no host. O bloco policy de um destino é avaliado no servidor antes da chamada SAP da própria ferramenta, seja o que o host aprovar; allowedPackages é o único portão que pode precisar de uma consulta (transportInfo, em cache) para aprender o pacote de um objeto existente primeiro. Recusas voltam como kind: "policyDenied" nomeando o portão, e listSystems mostra cada política. Um destino sem bloco policy é totalmente gravável.

    ChaveTipoEfeito
    readOnlybooleanoApenas ferramentas anotadas como somente leitura podem executar, além de login, logout, dropSession, listSystems, healthcheck, systemProfile e exportPackageSources (que grava apenas localmente). Bloqueadas como gravações: toda gravação de fonte, lock, runSnippet, runClass, unitTestRun, createAtcRun e atcSummary. Ainda permitidas: runQuery e tableContents (são leituras; negue-as com allowFreeSql: false ou deniedTools).
    deniedToolsglobsFerramentas recusadas diretamente neste destino: um nome, um glob (rapGen*) ou toolset:<name> para cada ferramenta de um conjunto, por exemplo ["transportRelease", "toolset:git"]. Cinco ferramentas abapGit não têm prefixo git (pushRepo, stageRepo, checkRepo, remoteRepoInfo, switchRepoBranch), então git* sozinho deixa o caminho de push aberto. As ferramentas permanecem listadas.
    allowFreeSqlbooleanofalse recusa runQuery e tableContents com sqlQuery.
    deniedTablesglobsAplicado a tableContents, a cada alvo FROM/JOIN de um runQuery, e (melhor esforço, escaneando o texto ABAP) a runSnippet, setObjectSource e setMethodSource. SQL dinâmico e visões sobre a tabela não são detectados: para dados que não devem sair do SAP, confie nas autorizações de exibição SAP do usuário conectado e combine allowFreeSql: false com deniedTools: ["runSnippet"] ou readOnly.
    allowedPackagesglobs, lista fechadaPortões apenas para gravações; leituras e navegação de qualquer objeto (objetos SAP incluídos) nunca são portadas. Argumentos de pacote são verificados diretamente; gravações de objeto resolvem o pacote do objeto através de transportInfo; um pacote irresolvível é recusado. gitPullRepo, rapGenGenerate, rapGenPublishService, publishServiceBinding e unPublishServiceBinding não podem derivar um pacote e são recusados sempre que esta chave está definida.
    allowedTransportsglobsCada argumento transport/transportNumber deve corresponder; createTransport e resolveTransport(createIfMissing=true) são recusados.

Os interruptores globais do servidor são MCP_READ_ONLY=1 (adiciona readOnly a cada destino) e MCP_DISABLED_TOOLSETS (oculta conjuntos de ferramentas inteiros de cada destino); não há deniedTools, deniedTables ou allowedPackages global, esses são repetidos por entrada. Oculto e recusado diferem: um conjunto de ferramentas deixado de fora por MCP_TOOLSETS/MCP_DISABLED_TOOLSETS está ausente da lista de ferramentas e uma chamada pelo nome (de um prompt, de um host que armazenou em cache uma lista mais antiga ou de uma skill) é recusada com o nome do conjunto de ferramentas; deniedTools mantém a ferramenta listada e a recusa naquele destino; ferramentas que um destino não pode atender (detectadas por systemProfile) permanecem listadas e são recusadas antes de chamar o SAP (MCP_PROFILE_GATE=enforce|warn|off).

  • Segredos ficam fora de arquivos e conversas. ${env:VAR} funciona em toda string de systems.json (password, oauth.clientSecret, gitPassword, tls.passphrase, até url); uma variável ausente falha na inicialização pelo nome, nunca pelo valor. Mantenha systems.json no modo 0600: um arquivo legível por grupo ou por todos é avisado e recusado quando contém um password, oauth.clientSecret ou gitPassword inline. Prefira SAP_SYSTEMS_FILE em vez de SAP_SYSTEMS inline nas configurações do host. MCP_HTTP_TOKEN é uma variável de ambiente, não uma entrada de arquivo; o lado do cliente do transporte HTTP tem que carregar o token na configuração do host, então mantenha esse arquivo em 0600 também. listSystems e healthcheck não reportam credenciais, mensagens de erro passam por uma etapa de redação que mascara tokens de portador, cookies, senhas e URLs user:password@host, e exportPackageSources só pode escrever dentro de MCP_EXPORT_ROOT (padrão ~/.abap-adt-mcp/exports, verificado contra symlinks). reentranceTicket permanece desabilitado a menos que SAP_ALLOW_REENTRANCE_TICKET=1, porque retorna uma credencial de logon ao vivo para a conversa.
  • TLS permanece ativo e não pode ser desligado para tudo de uma vez. NODE_TLS_REJECT_UNAUTHORIZED=0 é removido do ambiente antes da primeira conexão, e o servidor informa isso na inicialização: o problema de um destino nunca silencia a verificação para os outros, para a solicitação de token OAuth ou para o download de cloudificação. Para um certificado corporativo ou autoassinado, use tls.ca naquele destino; para um certificado emitido para um nome diferente do que está em url, use tls.servername (a verificação permanece ativa em ambos os casos, sem aviso), ou como último recurso insecureTls: true somente naquele destino (anunciado na inicialização, mostrado por listSystems). Uma falha de handshake retorna como kind: "tlsCertificate" com a correção para aquele destino explicitada.
  • Conteúdo do SAP é entrada não confiável. Comentários, linhas de tabelas e feeds podem conter texto que tenta direcionar o modelo. Use um host que pergunte antes de chamadas de ferramentas e revise as destrutivas (deleteObject, transportRelease, transportDelete, setObjectSource, editObjectSource, setMethodSource, pushRepo, forceUnlock) antes de aprová-las.
  • Menor privilégio, e o que "somente leitura" ainda lê. Conecte-se com usuários que tenham apenas as autorizações que a tarefa precisa. runQuery e tableContents leem dados de negócios reais, então configure apenas destinos onde isso é aceitável, e exportPackageSources copia pacotes inteiros de código-fonte para o disco local mesmo em um destino readOnly: adicione-o a deniedTools onde o código-fonte não deve sair do SAP.
  • O que sai da máquina. O servidor fala com os hosts SAP configurados, com o provedor de identidade durante o SSO do navegador e com o GitHub para o repositório de cloudificação do SAP quando apiReleaseState é executado (um arquivo JSON por edição de raw.githubusercontent.com/SAP/abap-atc-cr-cv-s4hc, timeout de 15 segundos, cache por 24 horas em ~/.abap-adt-mcp/cache, realocável com MCP_CACHE_DIR; uma cópia em cache é usada quando o download falha). Não há switch offline, URL de espelho ou suporte a proxy para esse download (usa o fetch embutido do Node, que ignora HTTPS_PROXY): em um host isolado, popule o diretório de cache uma vez ou deixe essa única ferramenta falhar. Nada mais é enviado a lugar nenhum: sem telemetria, sem verificações de atualização. npx em si contata o registro npm.

Log de auditoria

Defina MCP_AUDIT_FILE=/var/log/abap-adt-mcp/audit.jsonl para anexar uma linha JSON por chamada de ferramenta. O diretório é criado com modo 0700 e o arquivo com 0600; uma falha de escrita é reportada uma vez no stderr e nunca interrompe uma chamada. Cada registro é anexado por caminho, então rotacionar o arquivo renomeando-o é seguro (a próxima chamada cria um novo); o servidor não mantém retenção própria. docs/FIELD-NOTES.md explica como transformar o arquivo em um relatório de sessão útil.

{"ts":"2026-09-03T10:15:42.117Z","requestId":42,"tool":"editObjectSource","destination":"DEV","durationMs":1834,"outcome":"ok","args":{"objectSourceUrl":"/sap/bc/adt/oo/classes/zcl_example/source/main","replacements":"[array 312 chars]","activate":true,"transport":"DEVK900123"}}
{"ts":"2026-09-03T10:16:03.902Z","requestId":43,"tool":"runQuery","destination":"QAS","durationMs":2,"outcome":"denied","args":{"sqlQuery":"SELECT * FROM ztable"},"errorKind":"policyDenied","gate":"allowFreeSql","message":"MCP error -32600: Policy: runQuery blocked on destination QAS (allowFreeSql): free SQL (runQuery) is disabled; use tableContents on an allowed table. Configured in systems.json policy; retrying will not help."}

Campos: ts, requestId, tool, destination, durationMs, outcome (ok, error, denied para recusas de política, unavailable para portões de conjunto de ferramentas ou plataforma), errorKind, gate (a chave de política), message (o texto do erro, primeiros 300 caracteres), args e retried (definidos quando a chamada foi reautenticada e repetida). O que args mantém: chaves de argumento contendo pass (então password e passphrase), secret, token, authorization, cookie ou lockHandle tornam-se [REDACTED]; valores de string de até 200 caracteres são armazenados literalmente após a mesma redação das mensagens de erro (então uma instrução SQL ou um trecho curto com literais de negócios está no arquivo), strings mais longas são truncadas, e arrays ou objetos com mais de 200 caracteres colapsam para [array N chars] ou [object N chars]. Trate o arquivo como sensível. Não há identidade do chamador em um registro (sem endereço remoto, ID de sessão MCP ou ID de token): no stdio, o processo pertence a uma pessoa, e em uma instância HTTP compartilhada, a atribuição tem que vir de executar uma instância por pessoa ou do log de acesso do proxy reverso na frente.

S/4HANA Cloud versus on-prem

systemProfile(destination) reporta se um destino é cloud ou on-prem (domínio do host, informações do sistema e documento de descoberta) e quais conjuntos de ferramentas o backend não possui; essas ferramentas são recusadas antes de chamar o SAP. Se você só tem um tenant S/4HANA Cloud, a coluna do meio é sua. O que docs/TESTPLAN.md e docs/FIELD-NOTES.md registraram em um tenant Public Cloud:

TópicoS/4HANA Cloud (edição pública)On-prem / privado
AutenticaçãoUsuários nomeados: somente SSO do navegador. Não assistido: OAuth2 de um Communication Arrangement, ou autenticação básica com um Communication User.Autenticação básica; certificados de cliente através de tls.
Objetos locais$TMP foi recusado no tenant testado (objeto de autorização S_ABPLNGVS: objetos em $TMP recebem a versão de idioma Standard); use um pacote de cliente com ABAP for Cloud Development e seu transporte, resolveTransport o seleciona. runSnippet precisa de packageName, transport e responsible lá.$TMP disponível, sem necessidade de transporte; runSnippet padrão para $TMP.
Conjuntos de ferramentasGerador RAP ausente no tenant testado; depurador, traces e abapGit dependem do tenant e das autorizações. dumps/dumpDetails são o caminho de causa raiz quando o depurador está ausente. sourceTextSearch recai para grepPackage quando o tenant responde "Source Search is not supported".Conjunto completo de coleções ADT em uma versão atual.
APIs liberadasapiReleaseState verifica nomes, uma URL de objeto ou um código-fonte inteiro; variante ATC ABAP_CLOUD_DEVELOPMENT_DEFAULT. createObject precisa de responsible.Opcional.
Dados de negóciosrunQuery/tableContents respeitam autorizações de exibição; negam tabelas por política. runSnippet precisa de S_DEVELOP, então somente sistemas de desenvolvimento.Igual.

Lições que se aplicam em todos os lugares: instruções runQuery são quebradas no limite de 255 caracteres por linha da pré-visualização de dados; tabelas com dataMaintenance restrito são lidas com tableContents; um bloqueio mantido por uma sessão Eclipse aberta é estrangeiro e somente SM12 ou essa sessão pode liberá-lo; escrever uma classe de mensagem através de setObjectSource reescreve a classe inteira e redefine masterLanguage para o idioma de logon.

Referência de configuração

Cada opção com seu padrão, os portões de política ferramenta por ferramenta, trechos de host e notas operacionais estão em docs/CONFIGURATION.md; esta seção é o resumo.

Fontes de configuração, em ordem de precedência: SAP_SYSTEMS (JSON inline), SAP_SYSTEMS_FILE, um systems.json ao lado da instalação, então as variáveis legadas de sistema único (SAP_URL, SAP_CLIENT, SAP_USER, SAP_PASSWORD, SAP_LANGUAGE, SAP_TLS_INSECURE, SAP_OAUTH_TOKEN_URL, SAP_OAUTH_CLIENT_ID, SAP_OAUTH_CLIENT_SECRET, SAP_OAUTH_SCOPE, veja .env.example).

Chaves por destino em systems.json: url, client, language, authType, default, user/password (básico), oauth (tokenUrl, clientId, clientSecret, scope), insecureTls, gitUser/gitPassword, policy e tls (ca, servername, cert + key, pfx + passphrase). Qualquer valor de string pode ser ${env:VAR}. Chaves começando com _ são ignoradas, então entradas _comment são aceitáveis. Toda saída operacional (avisos de inicialização, mensagens de portão, o aviso do arquivo de auditoria) vai para o stderr, que os hosts MCP capturam em seus logs.

Toda variável declarada em server.json:

VariávelFinalidadePadrão / observações
SAP_SYSTEMS_FILECaminho para o arquivo de destinosRecomendado; mantenha o modo 0600
SAP_SYSTEMSO mesmo mapa inlineContém credenciais, prefira o arquivo
SAP_DEFAULT_DESTINATIONDestino usado quando uma chamada omite destinationOu marque uma entrada como "default": true
SAP_AUTH_TYPETipo de autenticação padrão para entradas sem um, e o modo da configuração legada de sistema únicosso; basic ou oauth
MCP_TOOLSETSConjuntos de ferramentas a publicar: predefinição all ou focused, ou uma lista separada por vírgulasall
MCP_DISABLED_TOOLSETSConjuntos de ferramentas a ocultar, lista separada por vírgulascore não pode ser desativado
MCP_READ_ONLY1 torna cada destino somente leitura, no lado do servidorDesativado
MCP_MAX_RESPONSE_CHARSOrçamento de caracteres de uma resposta de ferramenta antes de paginação ou truncamento40000, mínimo 5000
MCP_PROFILE_GATEPortão para conjuntos de ferramentas que o destino não expõeenforce; warn registra apenas, off desativa
MCP_SOURCE_CACHE_TTL_SECONDSTempo de vida do cache de código-fonte por sessão usado por syntaxCheckCode, grepPackage, cdsViewInfo, typeHierarchy, abapDocumentation e apiReleaseState(sourceUrl)300; 0 mantém entradas até o logout
MCP_EXPORT_ROOTDiretório em que exportPackageSources pode gravar~/.abap-adt-mcp/exports
MCP_AUDIT_FILECaminho do trilho de auditoria JSONLDesativado quando não definido
SAP_ALLOW_REENTRANCE_TICKET1 habilita a ferramenta reentranceTicketDesativado
SAP_BROWSER_PATHSSO: caminho para um binário Chromium, Chrome ou EdgeDetectado automaticamente
SAP_BROWSER_PROFILE_DIRSSO: perfil de navegador persistente que mantém a sessão do provedor de identidade~/.abap-adt-mcp/sso/<host>
MCP_HTTP_PORTServir Streamable HTTP em http://127.0.0.1:<port>/mcp com autenticação bearer em vez de stdioNão definido (stdio); aceita 1024 a 65535
MCP_HTTP_HOSTEndereço de bind do transporte HTTP127.0.0.1; 0.0.0.0 apenas em contêineres
MCP_HTTP_TOKENToken bearer para o transporte HTTPGerado em ~/.abap-adt-mcp/http-token
MCP_HTTP_MAX_SESSIONSMáximo de sessões MCP simultâneas; solicitações initialize adicionais recebem 50316
MCP_HTTP_MAX_BODY_BYTESMaior corpo de solicitação que o transporte HTTP aceita; corpos maiores recebem 4134194304 (4 MB)
MCP_HTTP_SESSION_TTL_MINUTESMinutos ociosos após os quais uma sessão HTTP (e suas sessões SAP e bloqueios) é encerrada30
MCP_HTTP_ALLOWED_ORIGINSValores Origin permitidos separados por vírgulas; * permite qualquerOrigens de loopback sempre permitidas em um bind de loopback
MCP_HTTP_ALLOWED_HOSTSValores de cabeçalho Host permitidos separados por vírgulas (proteção contra rebinding de DNS)Hosts de loopback sempre permitidos em um bind de loopback; qualquer host em um bind não loopback
SAP_URLModo legado de sistema único: URL base, por exemplo https://host:44300
SAP_CLIENTModo legado de sistema único: cliente, por exemplo 100
SAP_LANGUAGEModo legado de sistema único: idioma de logon, por exemplo EN
SAP_USERModo legado de sistema único: usuário SAP
SAP_PASSWORDModo legado de sistema único: senha SAPSegredo
SAP_TLS_INSECUREModo legado de sistema único: 1 ignora a verificação de certificado apenas para esse sistemaApenas sandboxes
SAP_OAUTH_TOKEN_URLModo legado de sistema único com SAP_AUTH_TYPE=oauth: endpoint de token
SAP_OAUTH_CLIENT_IDModo legado de sistema único: ID do cliente OAuth2
SAP_OAUTH_CLIENT_SECRETModo legado de sistema único: segredo do cliente OAuth2Segredo
SAP_OAUTH_SCOPEModo legado de sistema único: escopo OAuth2 opcional

Lido em tempo de execução, mas não faz parte do manifesto do registro: MCP_CACHE_DIR realoca o cache do repositório de cloudificação (padrão ~/.abap-adt-mcp/cache), e NODE_TLS_REJECT_UNAUTHORIZED=0 é removido na inicialização para que não possa desativar a verificação de certificado para todo o processo.

Transporte HTTP (opcional)

Por padrão, o servidor fala stdio: um processo por usuário, nada escutando na rede. Para hosts que esperam um endpoint HTTP (Eclipse, outra máquina, um contêiner, uma instância compartilhada de equipe), inicie-o com uma porta:

MCP_HTTP_PORT=2236 npx -y abap-adt-mcp

Ele escuta em http://127.0.0.1:2236/mcp (somente loopback, a menos que MCP_HTTP_HOST diga o contrário) e exige Authorization: Bearer <token> em cada solicitação. O token é gerado na inicialização e gravado em ~/.abap-adt-mcp/http-token (modo 0600); MCP_HTTP_TOKEN define o seu próprio. Configuração do host:

{
  "mcpServers": {
    "abap-adt-mcp": {
      "type": "http",
      "url": "http://127.0.0.1:2236/mcp",
      "headers": { "Authorization": "Bearer <token>" }
    }
  }
}

O que a porta de entrada impõe:

  • Portas abaixo de 1024 são recusadas; o token bearer é comparado em tempo constante; GET /health é a única rota não autenticada e responde com versão, contagem de sessões, o limite de sessões e tempo de atividade (bloqueie-a no proxy se essa divulgação for relevante). Tudo o mais fora de /mcp é 404.
  • Proteção contra rebinding de DNS: em um bind de loopback, apenas valores de Host e Origin de loopback passam, extensíveis com MCP_HTTP_ALLOWED_HOSTS e MCP_HTTP_ALLOWED_ORIGINS (* permite qualquer). Em um bind não loopback, todo cabeçalho Host passa (a verificação de Host protege apenas binds de loopback), enquanto um cabeçalho Origin ainda precisa estar listado em MCP_HTTP_ALLOWED_ORIGINS (chamadores de navegador); solicitações sem cabeçalho Origin (clientes não navegador) passam em qualquer bind.
  • Uma instância de servidor por sessão MCP: sessões SAP separadas, livro de bloqueios e caches por chamador. Sessões ociosas expiram após MCP_HTTP_SESSION_TTL_MINUTES (padrão 30); além de MCP_HTTP_MAX_SESSIONS (padrão 16), novas solicitações initialize recebem 503 com Retry-After; uma sessão encerrada ou expirada libera seus bloqueios e sessões SAP. Em SIGINT/SIGTERM, o processo fecha a instância de escuta e sai sem percorrer as sessões abertas, então envie DELETE /mcp dos clientes antes de parar uma instância compartilhada. Cada corpo de solicitação é limitado a MCP_HTTP_MAX_BODY_BYTES (padrão 4 MB); corpos maiores são recusados com 413 e a conexão é fechada.
  • Avisos na inicialização quando o bind vai além do loopback, e novamente quando um destino SSO é exposto dessa forma: todo chamador remoto compartilharia o login do navegador do usuário que executa o servidor.

O que ele não fornece: TLS (coloque um proxy reverso na frente), limitação de taxa, tokens por usuário ou rotação de token sem reinicialização (uma reinicialização sem MCP_HTTP_TOKEN já gera um novo token e sobrescreve http-token; quando você define a variável manualmente, altere-a e reinicie; sessões abertas terminam com o processo). Uma instância compartilhada significa, portanto, um token e, para cada destino, um conjunto de credenciais SAP para cada chamador. Prefira uma instância por pessoa, ou destinos basic/oauth com uma política readOnly, mantenha o token em segredo e coloque TLS na frente.

Catálogo de ferramentas (todas as 173 ferramentas, por conjunto de ferramentas)

A referência por ferramenta (descrição, parâmetros, anotações somente leitura/destrutivas) está em docs/TOOLS.md, gerada a partir da resposta tools/list ao vivo por npm run tools:docs e verificada por um teste de contrato no CI. Toda ferramenta, exceto listSystems e healthcheck, aceita um destination opcional; sem ele, o destino padrão é usado.

Esquemas de ferramentas custam contexto. Defina MCP_TOOLSETS para uma predefinição (all, o padrão, ou focused = 114 ferramentas de desenvolvimento) ou para uma lista separada por vírgulas dos nomes abaixo; MCP_DISABLED_TOOLSETS remove alguns. core é sempre publicado. Nomes desconhecidos falham na inicialização.

Conjunto de ferramentasEm focusedFerramentas
core · Destinos, saúde e sessão (6)simlogin, logout, dropSession, listSystems, healthcheck, systemProfile
source · Código-fonte (16)simlock, unLock, listLocks, forceUnlock, getObjectSource, setObjectSource, editObjectSource, getMethodSource, setMethodSource, prettyPrinterSetting, setPrettyPrinterSetting, prettyPrinter, revisions, objectDiff, getTextElements, setTextElements
objects · Objetos e navegação (27)simobjectStructure, searchObject, findObjectPath, objectTypes, reentranceTicket, classIncludes, classComponents, deleteObject, activateObjects, activateByName, activatePackage, inactiveObjects, objectRegistrationInfo, creatableTypeDetails, validateNewObject, createObject, nodeContents, mainPrograms, typeHierarchy, objectStructureElements, objectEnhancements, packageTree, exportPackageSources, whereUsed, cdsViewInfo, sourceTextSearch, grepPackage
transports · Transportes (18)simtransportDetails, transportUnifiedDiff, transportInfo, resolveTransport, createTransport, hasTransportConfig, transportConfigurations, getTransportConfiguration, setTransportsConfig, createTransportsConfig, userTransports, transportsByConfig, transportDelete, transportRelease, transportSetOwner, transportAddUser, systemUsers, transportReference
analysis · Sintaxe e análise de código (16)simsyntaxCheckCode, syntaxCheckCdsUrl, codeCompletion, findDefinition, usageReferences, syntaxCheckTypes, codeCompletionFull, runClass, codeCompletionElement, usageReferenceSnippets, fixProposals, fixEdits, fragmentMappings, abapDocumentation, apiReleaseState, runSnippet
tests · Testes de unidade (4)simunitTestRun, unitTestEvaluation, unitTestOccurrenceMarkers, createTestInclude
atc · ATC (14)simatcCustomizing, atcQuickfixProposals, atcApplyQuickfix, atcCheckVariant, atcSummary, createAtcRun, atcWorklists, atcUsers, atcExemptProposal, atcRequestExemption, isProposalMessage, atcContactUri, atcChangeContact, atcDocumentation
data · Acesso a dados e DDIC (10)simannotationDefinitions, ddicElement, ddicRepositoryAccess, packageSearchHelp, getDomainProperties, setDomainProperties, getDataElementProperties, setDataElementProperties, tableContents, runQuery
discovery · Descoberta e metadados (7)nãofeatureDetails, collectionFeatureDetails, findCollectionByUrl, loadTypes, adtDiscovery, adtCoreDiscovery, adtCompatibilityGraph
runtime · Erros de tempo de execução (3)simfeeds, dumps, dumpDetails
refactoring · Refatoração (8)nãorenameEvaluate, renamePreview, renameExecute, extractMethodEvaluate, extractMethodPreview, extractMethodExecute, changePackagePreview, changePackageExecute
rap · Geração RAP (8)nãorapGenIsAvailable, rapGenGetSchema, rapGenGetContent, rapGenValidateInitial, rapGenValidateContent, rapGenPreview, rapGenGenerate, rapGenPublishService
services · Serviços de negócios (4)nãopublishServiceBinding, unPublishServiceBinding, fetchServiceDetails, bindingDetails
git · abapGit (10)nãogitRepos, gitExternalRepoInfo, gitCreateRepo, gitPullRepo, gitUnlinkRepo, stageRepo, pushRepo, checkRepo, remoteRepoInfo, switchRepoBranch
debugger · Depurador (13)nãodebuggerListeners, debuggerListen, debuggerDeleteListener, debuggerSetBreakpoints, debuggerDeleteBreakpoints, debuggerAttach, debuggerSaveSettings, debuggerStackTrace, debuggerVariables, debuggerChildVariables, debuggerStep, debuggerGoToStack, debuggerSetVariableValue
traces · Rastreamentos (9)nãotracesList, tracesListRequests, tracesHitList, tracesDbAccess, tracesStatements, tracesSetParameters, tracesCreateConfiguration, tracesDeleteConfiguration, tracesDelete
Ferramentas destrutivas (deleteObject, transportRelease, transportDelete, setObjectSource, editObjectSource, setMethodSource, atcApplyQuickfix, runClass, runSnippet, pushRepo, forceUnlock e outras) carregam destructiveHint: true para hosts que controlam aprovação por anotação. Uma ferramenta pode estar ausente por dois motivos: seu conjunto de ferramentas não está publicado (o preset focused deixa de fora debugger, traces, git, rap, services, refactoring e discovery; a recusa nomeia o conjunto de ferramentas), ou o destino não pode servi-la (systemProfile informa o que está faltando; a recusa diz "não disponível no destino").

Comparação com o servidor MCP ADT oficial da SAP

O servidor MCP ADT da SAP acompanha o ADT para VS Code e Eclipse e publica sob a chave de servidor abap-adt com seus próprios nomes de ferramentas, pelos quais habilidades públicas como claude-abap-skills roteiam. Este projeto publica sob abap-adt-mcp, atende muitos destinos a partir de um único processo via stdio ou HTTP, aplica políticas no lado do servidor e adiciona composições como resolveTransport, editObjectSource, grepPackage, apiReleaseState, runSnippet e objectDiff. Os dois podem ser registrados lado a lado no mesmo host, pois chaves e nomes de ferramentas não colidem. Este README não cataloga o que o servidor da SAP oferece além deste; docs/ROUTING.md mapeia os nomes da SAP para os nossos onde existe um equivalente. Algumas linhas:

Ferramenta / capacidade oficial da SAPFerramenta(s) abap-adt-mcp
abap_lists_destinationslistSystems, systemProfile
SAPRead / abap_get_sourcegetObjectSource (version=inactive para código não ativado)
SAPSearch / abap_search_objectssearchObject; por conteúdo sourceTextSearch, grepPackage
abap_write_source / SAPWritesetObjectSource (activate=true), editObjectSource direcionado
abap_activate_objects / ActivatePackageactivateByName, activateObjects, inactiveObjects
abap_run_unit_testsunitTestRun, unitTestEvaluation
abap_atc_run / abap_atc_findingscreateAtcRun, atcWorklists, atcQuickfixProposals, atcApplyQuickfix, atcDocumentation
abap_transport-unifiedDifferencetransportUnifiedDiff, transportDetails
abap_generators-*rapGenIsAvailable, rapGenGetSchema, rapGenValidateContent, rapGenPreview, rapGenGenerate, rapGenPublishService
abap_lock / abap_unlockNão necessário para gravações únicas (bloqueio automático); lock, unLock, listLocks, forceUnlock
abap_dumpsdumps, dumpDetails
verificação de API liberada / Clean CoreapiReleaseState

Habilidades e plugin

Duas habilidades de agente são distribuídas sob skills/: abap-adt-mcp ensina o modelo a desenvolver ABAP com estas ferramentas (início de sessão, localização de código, fluxo de alterações, prontidão para nuvem, erros, segurança) e abap-adt-mcp-setup orienta pela instalação, configuração e uma primeira verificação de saúde. Elas chegam ao host pelo plugin do Claude Code (/plugin marketplace add williansaez/abap-adt-mcp, depois /plugin install abap-adt-mcp@abap-adt-mcp, que também registra o servidor), pelo instalador de terceiros npx skills add williansaez/abap-adt-mcp, ou copiando os dois diretórios para ~/.claude/skills/; um registro simples de npx do servidor não instala habilidade alguma, e os fluxos essenciais ainda chegam pelo campo instructions do servidor e pelos prompts integrados.

Este README também existe em Português (Brasil) e Alemão; a versão em inglês é a referência e as contagens geradas são sincronizadas nas três. O que sessões reais ensinaram ao servidor está em docs/FIELD-NOTES.md, o plano de teste ao vivo em docs/TESTPLAN.md, o roteiro em docs/ROADMAP.md e os lançamentos em CHANGELOG.md.

Solução de problemas

  • O servidor nunca aparece no host. Leia o log MCP do host (locais no passo 2). spawn npx ENOENT: Node.js não está instalado ou não está no PATH que o aplicativo vê; instale-o ou coloque o caminho absoluto para npx em command (/usr/local/bin/npx para o instalador macOS, /opt/homebrew/bin/npx para Homebrew). EBADENGINE no log: o Node que o host encontrou é mais antigo que 22.12; instale o LTS atual. No ABAP systems configured: SAP_SYSTEMS_FILE aponta para um arquivo ausente. is not valid JSON: uma vírgula solta ou um caminho do Windows com barras invertidas simples. O Claude Desktop lê a configuração apenas na inicialização, então saia e reabra após cada alteração.
  • Nenhuma janela do navegador, ou SSO falha. Um navegador Chromium deve estar instalado; SAP_BROWSER_PATH aponta para ele quando a detecção automática falha. O perfil padrão do navegador é rejeitado de propósito; SAP_BROWSER_PROFILE_DIR nomeia um dedicado. Exclua ~/.abap-adt-mcp/sso/<host> para sair completamente de um tenant.
  • O login funciona, então tudo fica "não autorizado" ou "não encontrado". A sessão SSO caiu em outro cliente além do que client diz: defina client para o cliente de logon do tenant (a entrada Sobre do menu de usuário do launchpad mostra isso).
  • kind: "sessionExpired" continua voltando. O servidor já reautenticou e tentou novamente uma vez; peça ao modelo para chamar login para esse destino. Handles de bloqueio da sessão antiga são inválidos (kind: "staleLockHandle"): bloqueie novamente.
  • kind: "locked" por outra sessão. listLocks mostra os bloqueios do próprio servidor; se o objeto não estiver lá, o bloqueio pertence a outra sessão (Eclipse ou outro usuário) e apenas essa sessão ou SM12 o libera.
  • editObjectSource relata 0 correspondências, ou várias. Nada foi gravado. A âncora deve ser o texto atual exato na SAP, incluindo indentação: releia com getObjectSource e copie; para várias correspondências, inclua mais linhas ao redor.
  • Ferramenta recusada como não disponível ou não habilitada. "Não disponível no destino": execute systemProfile, o tenant não tem essa coleção ADT (MCP_PROFILE_GATE=warn apenas registra, off desativa a barreira). "Pertence ao conjunto de ferramentas ... que não está habilitado": o conjunto de ferramentas está ausente de MCP_TOOLSETS (o preset focused não tem debugger ou traces); adicione-o ou use MCP_TOOLSETS=all. Sem um depurador, dumps e dumpDetails são o caminho de causa raiz.
  • kind: "policyDenied". O policy do destino (ou MCP_READ_ONLY) proíbe a chamada e a mensagem nomeia a barreira: a proteção está funcionando. Ajuste a política se a chamada foi intencional.
  • A inicialização recusa o arquivo de configuração. Ele é legível por outros usuários e contém senhas inline: chmod 600 ou referencie os segredos como ${env:VAR}.
  • Erros de certificado on-prem (kind: "tlsCertificate"). A dica nomeia o destino e a correção. Emissor desconhecido: dê ao destino seu pacote de CA com tls.ca (a dica carrega a linha openssl s_client). Incompatibilidade de nome (o sistema é acessado por endereço IP ou hostname curto): defina tls.servername para o nome DNS: que a mensagem cita. Expirado: apenas a renovação em STRUST corrige. insecureTls: true (ou SAP_TLS_INSECURE=1 no modo legado) desativa a verificação apenas para esse destino. NODE_TLS_REJECT_UNAUTHORIZED=0 não ajudará: o servidor o remove.
  • Erros de conexão. Verifique URL e cliente, autorizações ADT e, on-prem, que /sap/bc/adt está ativo em SICF.
  • runQuery falha em uma tabela que o usuário pode exibir. A pré-visualização de dados recusa tabelas com dataMaintenance restrito; use tableContents. Uma instrução que ainda falha após o reflow de 255 caracteres tem um literal único mais longo que isso, ou um erro de sintaxe real no token nomeado.
  • Esquemas de ferramentas consomem a janela de contexto. Comece com MCP_TOOLSETS=focused, ou oculte conjuntos de ferramentas (MCP_DISABLED_TOOLSETS=debugger,traces).

Testes e contribuição

git clone https://github.com/williansaez/abap-adt-mcp.git
cd abap-adt-mcp
npm ci
npm run build
npm test

Suites Jest cobrem handlers, dicas de erro, dimensionamento de resposta, conjuntos de ferramentas e o contrato de catálogo contra docs/tools.snapshot.json; CI os executa no Node 22 e 24, constrói a imagem do contêiner e verifica se ela inicia e lista ferramentas. Após alterar uma descrição ou esquema de ferramenta, execute npm run tools:docs e confirme o docs/TOOLS.md regenerado, o snapshot e as contagens do README (incluindo os READMEs traduzidos), ou o CI os sinaliza como desatualizados; npm run docs:check executa a verificação de higiene da documentação (sem identificadores de cliente, sem travessões, sem links mortos, toda variável de ambiente declarada em server.json). Lançamentos são dirigidos por tags: npm via publicação confiável (GitHub OIDC, proveniência anexada) mais a imagem GHCR. Faça fork, crie um branch, abra um pull request. Relatórios de sessão para docs/FIELD-NOTES.md são bem-vindos, sem nomes de clientes, tenants ou números de transporte.

Licença

MIT. Construído sobre abap-adt-api por Marcello Urbani. Se o projeto economizar seu tempo, você pode patrocinar o autor.