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.
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
- Configuração
- O que pedir ao modelo
- Fluxos de trabalho em detalhe
- Prompts integrados
- Outras formas de instalação
- Autenticação
- Mantendo a segurança
- Log de auditoria
- S/4HANA Cloud versus on-prem
- Referência de configuração
- Transporte HTTP (opcional)
- Catálogo de ferramentas (todas as 173 ferramentas, por conjunto)
- Comparação com o servidor ADT MCP oficial da SAP
- Skills e plugin
- Solução de problemas
- Testes e contribuição
- Licença
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,
npmimprimeEBADENGINEe o servidor não é testado; instale o LTS atual e reinicie o host. A imagem do contêiner já estava emnode:22-alpine. tls.servernameem 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, einsecureTlsnão é mais o único caminho por esse cenário.listSystemsmostraservername 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 linhaopenssl s_clientpara aquele host e aponta paratls.ca; uma incompatibilidade de nome cita os nomes que o Node relatou e aponta paratls.servername; um certificado expirado diz que apenas a renovação resolve.insecureTlsé mencionado por último. insecureTlspermanece, por destino, desativado por padrão, anunciado na inicialização; SECURITY.md registra o motivo.- Cadeia de suprimentos.
puppeteer-core25 remove o último alerta aberto do Dependabot da árvore de dependências (npm auditrelata 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
npmenpx, que é tudo o que o host precisa. Nenhum terminal é necessário para verificar: se o Node estiver ausente, o log do host dizspawn npx ENOENTao 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_DEVELOPERna entrega padrão); se o ADT do Eclipse funciona para você, este servidor também funciona. On-prem, o serviço/sap/bc/adtdeve estar ativo na transaçãoSICF(uma tarefa de Basis) e seu usuário precisa das autorizações usuais de desenvolvimento ADT. Apenas clientesoauthnã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:
| Pergunta | Ferramentas 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:
resolveTransport(objSourceUrl)retorna o transporte que já registra o objeto, o mais recente modificável para seu pacote, ouneedsTransport: falsepara pacotes locais;createIfMissing=truecria um quando nenhum existe.syntaxCheckCodena fonte pretendida: opcional para uma mudança de uma linha, seguro barato para qualquer coisa maior.editObjectSource(objectSourceUrl, replacements=[{oldText, newText}], activate=true, transport)para mudanças direcionadas (o servidor relê o SAP primeiro; cadaoldTextdeve 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 blocoMETHOD ... ENDMETHODna implementação (passe o bloco completo ou apenas o corpo; a parte de definição permanece como está;includeeclassNameselecionam classes locais ou de teste; um método desconhecido é recusado com a lista de métodos presentes),setObjectSourcepara reescritas completas.- Leia o campo
activationdo resultado; corrija e escreva novamente, ouactivateByName/activatePackagedepois. unitTestRun(url), entãoobjectDiff(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:
| Prompt | Argumentos | O que faz | Onde para |
|---|---|---|---|
create-object | opcional destination, depois objectType (ID de tipo ADT, como CLAS/OC, INTF/OI, PROG/P, DDLS/DF), name, package, opcional purpose | Valida, 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-edit | opcional destination, depois object (nome ou URL), change | Lê, 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-transport | opcional 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-atc | opcional destination, depois target (URL do objeto, nome do pacote ou transporte), opcional variant | Executa 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-check | opcional 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-dump | opcional 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.
| Modo | Use para | O que você configura | Configuraçã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 |
basic | AS ABAP on-prem, Usuários de Comunicação S/4HANA Cloud | user e password (use ${env:VAR}). Autentica na primeira chamada, login é opcional. | Um usuário com autorizações ADT |
oauth | Clientes não assistidos S/4HANA Cloud | oauth.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
policyde 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 comokind: "policyDenied"nomeando o portão, elistSystemsmostra cada política. Um destino sem blocopolicyé totalmente gravável.Chave Tipo Efeito readOnlybooleano Apenas ferramentas anotadas como somente leitura podem executar, além de login,logout,dropSession,listSystems,healthcheck,systemProfileeexportPackageSources(que grava apenas localmente). Bloqueadas como gravações: toda gravação de fonte,lock,runSnippet,runClass,unitTestRun,createAtcRuneatcSummary. Ainda permitidas:runQueryetableContents(são leituras; negue-as comallowFreeSql: falseoudeniedTools).deniedToolsglobs Ferramentas recusadas diretamente neste destino: um nome, um glob ( rapGen*) outoolset:<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ãogit*sozinho deixa o caminho de push aberto. As ferramentas permanecem listadas.allowFreeSqlbooleano falserecusarunQueryetableContentscomsqlQuery.deniedTablesglobs Aplicado a tableContents, a cada alvoFROM/JOINde umrunQuery, e (melhor esforço, escaneando o texto ABAP) arunSnippet,setObjectSourceesetMethodSource. 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 combineallowFreeSql: falsecomdeniedTools: ["runSnippet"]oureadOnly.allowedPackagesglobs, lista fechada Portõ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,publishServiceBindingeunPublishServiceBindingnão podem derivar um pacote e são recusados sempre que esta chave está definida.allowedTransportsglobs Cada argumento transport/transportNumberdeve corresponder;createTransporteresolveTransport(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 desystems.json(password,oauth.clientSecret,gitPassword,tls.passphrase, atéurl); uma variável ausente falha na inicialização pelo nome, nunca pelo valor. Mantenhasystems.jsonno modo0600: um arquivo legível por grupo ou por todos é avisado e recusado quando contém umpassword,oauth.clientSecretougitPasswordinline. PrefiraSAP_SYSTEMS_FILEem vez deSAP_SYSTEMSinline 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 em0600também.listSystemsehealthchecknão reportam credenciais, mensagens de erro passam por uma etapa de redação que mascara tokens de portador, cookies, senhas e URLsuser:password@host, eexportPackageSourcessó pode escrever dentro deMCP_EXPORT_ROOT(padrão~/.abap-adt-mcp/exports, verificado contra symlinks).reentranceTicketpermanece desabilitado a menos queSAP_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, usetls.canaquele destino; para um certificado emitido para um nome diferente do que está emurl, usetls.servername(a verificação permanece ativa em ambos os casos, sem aviso), ou como último recursoinsecureTls: truesomente naquele destino (anunciado na inicialização, mostrado porlistSystems). Uma falha de handshake retorna comokind: "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.
runQueryetableContentsleem dados de negócios reais, então configure apenas destinos onde isso é aceitável, eexportPackageSourcescopia pacotes inteiros de código-fonte para o disco local mesmo em um destinoreadOnly: adicione-o adeniedToolsonde 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 deraw.githubusercontent.com/SAP/abap-atc-cr-cv-s4hc, timeout de 15 segundos, cache por 24 horas em~/.abap-adt-mcp/cache, realocável comMCP_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 ofetchembutido do Node, que ignoraHTTPS_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.npxem 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ópico | S/4HANA Cloud (edição pública) | On-prem / privado |
|---|---|---|
| Autenticação | Usuá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 ferramentas | Gerador 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 liberadas | apiReleaseState 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ócios | runQuery/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ável | Finalidade | Padrão / observações |
|---|---|---|
SAP_SYSTEMS_FILE | Caminho para o arquivo de destinos | Recomendado; mantenha o modo 0600 |
SAP_SYSTEMS | O mesmo mapa inline | Contém credenciais, prefira o arquivo |
SAP_DEFAULT_DESTINATION | Destino usado quando uma chamada omite destination | Ou marque uma entrada como "default": true |
SAP_AUTH_TYPE | Tipo de autenticação padrão para entradas sem um, e o modo da configuração legada de sistema único | sso; basic ou oauth |
MCP_TOOLSETS | Conjuntos de ferramentas a publicar: predefinição all ou focused, ou uma lista separada por vírgulas | all |
MCP_DISABLED_TOOLSETS | Conjuntos de ferramentas a ocultar, lista separada por vírgulas | core não pode ser desativado |
MCP_READ_ONLY | 1 torna cada destino somente leitura, no lado do servidor | Desativado |
MCP_MAX_RESPONSE_CHARS | Orçamento de caracteres de uma resposta de ferramenta antes de paginação ou truncamento | 40000, mínimo 5000 |
MCP_PROFILE_GATE | Portão para conjuntos de ferramentas que o destino não expõe | enforce; warn registra apenas, off desativa |
MCP_SOURCE_CACHE_TTL_SECONDS | Tempo 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_ROOT | Diretório em que exportPackageSources pode gravar | ~/.abap-adt-mcp/exports |
MCP_AUDIT_FILE | Caminho do trilho de auditoria JSONL | Desativado quando não definido |
SAP_ALLOW_REENTRANCE_TICKET | 1 habilita a ferramenta reentranceTicket | Desativado |
SAP_BROWSER_PATH | SSO: caminho para um binário Chromium, Chrome ou Edge | Detectado automaticamente |
SAP_BROWSER_PROFILE_DIR | SSO: perfil de navegador persistente que mantém a sessão do provedor de identidade | ~/.abap-adt-mcp/sso/<host> |
MCP_HTTP_PORT | Servir Streamable HTTP em http://127.0.0.1:<port>/mcp com autenticação bearer em vez de stdio | Não definido (stdio); aceita 1024 a 65535 |
MCP_HTTP_HOST | Endereço de bind do transporte HTTP | 127.0.0.1; 0.0.0.0 apenas em contêineres |
MCP_HTTP_TOKEN | Token bearer para o transporte HTTP | Gerado em ~/.abap-adt-mcp/http-token |
MCP_HTTP_MAX_SESSIONS | Máximo de sessões MCP simultâneas; solicitações initialize adicionais recebem 503 | 16 |
MCP_HTTP_MAX_BODY_BYTES | Maior corpo de solicitação que o transporte HTTP aceita; corpos maiores recebem 413 | 4194304 (4 MB) |
MCP_HTTP_SESSION_TTL_MINUTES | Minutos ociosos após os quais uma sessão HTTP (e suas sessões SAP e bloqueios) é encerrada | 30 |
MCP_HTTP_ALLOWED_ORIGINS | Valores Origin permitidos separados por vírgulas; * permite qualquer | Origens de loopback sempre permitidas em um bind de loopback |
MCP_HTTP_ALLOWED_HOSTS | Valores 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_URL | Modo legado de sistema único: URL base, por exemplo https://host:44300 | |
SAP_CLIENT | Modo legado de sistema único: cliente, por exemplo 100 | |
SAP_LANGUAGE | Modo legado de sistema único: idioma de logon, por exemplo EN | |
SAP_USER | Modo legado de sistema único: usuário SAP | |
SAP_PASSWORD | Modo legado de sistema único: senha SAP | Segredo |
SAP_TLS_INSECURE | Modo legado de sistema único: 1 ignora a verificação de certificado apenas para esse sistema | Apenas sandboxes |
SAP_OAUTH_TOKEN_URL | Modo legado de sistema único com SAP_AUTH_TYPE=oauth: endpoint de token | |
SAP_OAUTH_CLIENT_ID | Modo legado de sistema único: ID do cliente OAuth2 | |
SAP_OAUTH_CLIENT_SECRET | Modo legado de sistema único: segredo do cliente OAuth2 | Segredo |
SAP_OAUTH_SCOPE | Modo 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
HosteOriginde loopback passam, extensíveis comMCP_HTTP_ALLOWED_HOSTSeMCP_HTTP_ALLOWED_ORIGINS(*permite qualquer). Em um bind não loopback, todo cabeçalhoHostpassa (a verificação de Host protege apenas binds de loopback), enquanto um cabeçalhoOriginainda precisa estar listado emMCP_HTTP_ALLOWED_ORIGINS(chamadores de navegador); solicitações sem cabeçalhoOrigin(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 deMCP_HTTP_MAX_SESSIONS(padrão 16), novas solicitaçõesinitializerecebem503comRetry-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 envieDELETE /mcpdos clientes antes de parar uma instância compartilhada. Cada corpo de solicitação é limitado aMCP_HTTP_MAX_BODY_BYTES(padrão 4 MB); corpos maiores são recusados com413e 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 ferramentas | Em focused | Ferramentas |
|---|---|---|
core · Destinos, saúde e sessão (6) | sim | login, logout, dropSession, listSystems, healthcheck, systemProfile |
source · Código-fonte (16) | sim | lock, unLock, listLocks, forceUnlock, getObjectSource, setObjectSource, editObjectSource, getMethodSource, setMethodSource, prettyPrinterSetting, setPrettyPrinterSetting, prettyPrinter, revisions, objectDiff, getTextElements, setTextElements |
objects · Objetos e navegação (27) | sim | objectStructure, 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) | sim | transportDetails, 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) | sim | syntaxCheckCode, syntaxCheckCdsUrl, codeCompletion, findDefinition, usageReferences, syntaxCheckTypes, codeCompletionFull, runClass, codeCompletionElement, usageReferenceSnippets, fixProposals, fixEdits, fragmentMappings, abapDocumentation, apiReleaseState, runSnippet |
tests · Testes de unidade (4) | sim | unitTestRun, unitTestEvaluation, unitTestOccurrenceMarkers, createTestInclude |
atc · ATC (14) | sim | atcCustomizing, atcQuickfixProposals, atcApplyQuickfix, atcCheckVariant, atcSummary, createAtcRun, atcWorklists, atcUsers, atcExemptProposal, atcRequestExemption, isProposalMessage, atcContactUri, atcChangeContact, atcDocumentation |
data · Acesso a dados e DDIC (10) | sim | annotationDefinitions, ddicElement, ddicRepositoryAccess, packageSearchHelp, getDomainProperties, setDomainProperties, getDataElementProperties, setDataElementProperties, tableContents, runQuery |
discovery · Descoberta e metadados (7) | não | featureDetails, collectionFeatureDetails, findCollectionByUrl, loadTypes, adtDiscovery, adtCoreDiscovery, adtCompatibilityGraph |
runtime · Erros de tempo de execução (3) | sim | feeds, dumps, dumpDetails |
refactoring · Refatoração (8) | não | renameEvaluate, renamePreview, renameExecute, extractMethodEvaluate, extractMethodPreview, extractMethodExecute, changePackagePreview, changePackageExecute |
rap · Geração RAP (8) | não | rapGenIsAvailable, rapGenGetSchema, rapGenGetContent, rapGenValidateInitial, rapGenValidateContent, rapGenPreview, rapGenGenerate, rapGenPublishService |
services · Serviços de negócios (4) | não | publishServiceBinding, unPublishServiceBinding, fetchServiceDetails, bindingDetails |
git · abapGit (10) | não | gitRepos, gitExternalRepoInfo, gitCreateRepo, gitPullRepo, gitUnlinkRepo, stageRepo, pushRepo, checkRepo, remoteRepoInfo, switchRepoBranch |
debugger · Depurador (13) | não | debuggerListeners, debuggerListen, debuggerDeleteListener, debuggerSetBreakpoints, debuggerDeleteBreakpoints, debuggerAttach, debuggerSaveSettings, debuggerStackTrace, debuggerVariables, debuggerChildVariables, debuggerStep, debuggerGoToStack, debuggerSetVariableValue |
traces · Rastreamentos (9) | não | tracesList, 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 SAP | Ferramenta(s) abap-adt-mcp |
|---|---|
abap_lists_destinations | listSystems, systemProfile |
SAPRead / abap_get_source | getObjectSource (version=inactive para código não ativado) |
SAPSearch / abap_search_objects | searchObject; por conteúdo sourceTextSearch, grepPackage |
abap_write_source / SAPWrite | setObjectSource (activate=true), editObjectSource direcionado |
abap_activate_objects / ActivatePackage | activateByName, activateObjects, inactiveObjects |
abap_run_unit_tests | unitTestRun, unitTestEvaluation |
abap_atc_run / abap_atc_findings | createAtcRun, atcWorklists, atcQuickfixProposals, atcApplyQuickfix, atcDocumentation |
abap_transport-unifiedDifference | transportUnifiedDiff, transportDetails |
abap_generators-* | rapGenIsAvailable, rapGenGetSchema, rapGenValidateContent, rapGenPreview, rapGenGenerate, rapGenPublishService |
abap_lock / abap_unlock | Não necessário para gravações únicas (bloqueio automático); lock, unLock, listLocks, forceUnlock |
abap_dumps | dumps, dumpDetails |
| verificação de API liberada / Clean Core | apiReleaseState |
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 paranpxemcommand(/usr/local/bin/npxpara o instalador macOS,/opt/homebrew/bin/npxpara Homebrew).EBADENGINEno log: o Node que o host encontrou é mais antigo que 22.12; instale o LTS atual.No ABAP systems configured:SAP_SYSTEMS_FILEaponta 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_PATHaponta para ele quando a detecção automática falha. O perfil padrão do navegador é rejeitado de propósito;SAP_BROWSER_PROFILE_DIRnomeia 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
clientdiz: definaclientpara 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 chamarloginpara esse destino. Handles de bloqueio da sessão antiga são inválidos (kind: "staleLockHandle"): bloqueie novamente.kind: "locked"por outra sessão.listLocksmostra 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 ouSM12o libera.editObjectSourcerelata 0 correspondências, ou várias. Nada foi gravado. A âncora deve ser o texto atual exato na SAP, incluindo indentação: releia comgetObjectSourcee 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=warnapenas registra,offdesativa a barreira). "Pertence ao conjunto de ferramentas ... que não está habilitado": o conjunto de ferramentas está ausente deMCP_TOOLSETS(o presetfocusednão temdebuggeroutraces); adicione-o ou useMCP_TOOLSETS=all. Sem um depurador,dumpsedumpDetailssão o caminho de causa raiz. kind: "policyDenied". Opolicydo destino (ouMCP_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 600ou 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 comtls.ca(a dica carrega a linhaopenssl s_client). Incompatibilidade de nome (o sistema é acessado por endereço IP ou hostname curto): definatls.servernamepara o nomeDNS:que a mensagem cita. Expirado: apenas a renovação emSTRUSTcorrige.insecureTls: true(ouSAP_TLS_INSECURE=1no modo legado) desativa a verificação apenas para esse destino.NODE_TLS_REJECT_UNAUTHORIZED=0não ajudará: o servidor o remove. - Erros de conexão. Verifique URL e cliente, autorizações ADT e, on-prem, que
/sap/bc/adtestá ativo emSICF. runQueryfalha em uma tabela que o usuário pode exibir. A pré-visualização de dados recusa tabelas comdataMaintenancerestrito; usetableContents. 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.