sap-abap-mcp
Servidor MCP para SAP ABAP (ADT y JSON RPC)
Un servidor MCP que da a un agente de IA acceso completo de lectura/escritura a un sistema SAP ABAP a través de ADT (ABAP Development Tools), autenticado con inicio de sesión único SPNEGO/Kerberos, un certificado de cliente X.509 o un token de portador OAuth 2.0 — sin contraseña en ningún lugar de la configuración. El usuario y la contraseña siguen estando disponibles como respaldo, ¡pero no se recomienda!
Envuelve abap-adt-api y añade algo que ADT no puede hacer por sí mismo: llamar a módulos de función habilitados para RFC, a través del servicio JSON-RPC 2.0 de SAP Gateway.
128 herramientas — CRUD de objetos, edición de código fuente, bloqueos, transportes, activación, comprobaciones de sintaxis, finalización de código, ABAP Unit, ATC, DDIC, abapGit, refactorización, trazas, el depurador y llamadas RFC.
Cuántas ve realmente un cliente es menor, dos veces. Los perfiles (ABAP_MCP_PROFILE) cambian superficie por contexto: core lista 9 herramientas mientras que all lista 129, es decir, ~2,700 tokens frente a ~17,800 en cada turno para un cliente que no puede obtener los esquemas de herramientas bajo demanda. Además, el servidor pregunta al sistema qué soporta antes de listar nada, así que una versión sin el complemento abapGit nunca recibe las 10 herramientas que responderían con un 400. En DEV eso deja 116.
Este es el fork SSO de
mcp-abap-abap-adt-apide mario-andreschak. Las principales diferencias: Kerberos SSO en lugar de Basic Auth, las herramientas JSON-RPC/RFC, un router derivado de las definiciones de herramientas y una referencia de herramientas documentada.
Documentación
Documento | Qué incluye |
Trabajar en este repositorio: estructura de activos, convenciones, cómo probar. Léelo antes de cambiar el código. | |
Lo que quieres hacer → la herramienta que lo hace. Escrito a mano, con las palabras que la gente usa. Empieza aquí si sabes la tarea pero no la herramienta. | |
Las 128 herramientas con sus argumentos, agrupadas por familia. Generado a partir de las definiciones de las herramientas, así que no puede distanciarse del código. | |
Cómo se comporta el servidor. Los perfiles, los flujos de trabajo de ruta ejemplar, la semántica de ADT URI y de los bloqueos, la autorización de respuesta/error y una matriz de solución de problemas. Escrito para humanos y para agentes que manejan el servidor. | |
Las 20 habilidades de SAP/ABAP y cómo se corresponden con estas herramientas. | |
Las 35 habilidades generales de ingeniería incluidas. | |
Diseño y notas del protocolo para las herramientas JSON-RPC / RFC, leído del código ABAP de | |
Los dos modos de inicio de sesión sin contraseña: Kerberos SSO, y certificados X.509 para usuarios técnicos y de servicio. Lo que debe configurarse en el servidor SAP y por qué esto es TLS mutuo en lugar de SNC. |
Related MCP server: ABAP-ADT-API MCP-Server
Características
Dos modos de inicio de sesión sin contraseña — SPNEGO/Kerberos con el ticket del usuario de Windows, o un certificado de cliente X.509 para un usuario técnico o de servicio que no tiene identidad Kerberos. No se almacena ni envía la contraseña del SAP en ningún de los dos casos, y ambos tipos de solicitud se reponen solos a la expiración de la sesión.
Transporte HTTP streaming para un equipo que comparte un contenedor — ajusta
ABAP_MCP_TRANSPORT=httpy cada cliente MCP que se conecte se autentica con su propio token de portador OAuth 2.0 de la SAP; así cada sesión obtiene su propio inicio de sesión en lugar de que todos compartan un único usuario técnico.stdiose queda como la forma más predeterminada para un único cliente local. Consulta §12 y Ejecución sobre HTTP abajo.Lee cualquier objeto por nombre —
readAbapObjectresuelve un nombre en su código de origen en una sola llamada; no hay que descubrir ni construir una URL de ADT a mano.Describir una tabla —
describeAbapTabledevuelve los campos, los tipos de IV, los indicadores de clave y las tablas de verificación.Gestión de objetos — buscar, leer, crear, modificar, eliminar y activar objetos ABAP.
Examinar una convención de nombres —
searchPackagesencuentra paquetes por patrón (["ZPP_*","Z_PP*"]) explora cada uno en sus objetos agrupados por tipo, en una sola llamada.Flujo de trabajo de código — bloquear → editar → comprobar sintaxis → activar → desbloquear, con manejo de transporte.
Inteligencia de código — finalización, definiciones, referencias de uso, ABAP Doc, impresión bonita, ATC, Unitas ABAP, refactorización (renombrar, método de extracción).
Llamar a módulos de funciones RFC —
callFunctionViaJsonRpcejecuta un módulo de función habilitado por RFC y valida la solicitud contra su firma real, leída del sistema.Llamadas de lote RFC en una sola LUW —
callFunctionsViaJsonRpcen una sola solicitud, que es lo que permite que una BAPI de actualización y suBAPI_TRANSACTION_COMMITcompartan la misma LUW.Acceso a datos — contenidoTable
tableContentsy consultas ad-hocrunQuery.Ver el sistema en ejecución —
listLoggedOnUsersresponde a "quién está conectado" desdeTH_USER_LIST, los datos que hay detrás deSM04;readProfileParameterslee los valores de RZ Z11 en una sola ida y vuelta; ycheckLogonConfigurationdice di qué autenticación acepta realmente el sistema.Habilidades de agente incluidas — 54 habilidades, incluyendo
skills/, para ABAP (Clean ABAP, RAP, CDS, ATC, abapGit…) e ingeniería general (TDD, revisión de código, diagnóstico de errores), presentadas como recursos y recibidas elreadSkill.Autodocumentable — las guías siguientes son dinámicas por el propio servidor, como recursos MCP (
abap-adt://guides/…) y a través de la herramientareadServerGuide, así un agente puede buscar una operación o un argumento a mitad de una tarea sin salir de la sesión.
Requisitos previos
Un sistema SAP ABAP accesible por ADT.
/sap/bc/adtdebe estar activo enSICF. Para las herramientas RFC,/sap/gw/jsonrpcdebe ser también activo (SAP_GWFND), y tu usuario debe tenerS_RFCal grupo de funciones que se llama.Una forma de iniciar sesión sin contraseña, uno de:
Un inicio de sesión Kerberos funcional — el sistema SAP debe aceptar y acercarse a la baja, y debes tener un ticket válido (
klist). Es el modo por defecto y necesita Windows tal como se envía: el script inicial ejecutaC:\Windows\System32\curl.exe --negotiate, que exige el motor Schannel/SSPI de curl. In other platforms para indicarSSO_CURL_PATHa un curl compilado con soporte GSS-API.Un certificado de cliente X.509 — para un usuario del servicio técnico que no tiene identidad Kerberos. Es tan ni siquiera ni curl ni Windows. El servidor SAP se tiene que preparar para ello: el puerto ICM debe solicitar un certificado (
VCLIENTenicm/server_port_<n>, que anulaicm/HTTPS/verify_client), la autoridad de certificación emisora debe estar confirar enSTRUST, y una asignaciónCERTUSERal usuario. Configuración completa, incluido cómo comprobarlo desde este servidor, indocs/Authentication.md.Un cliente OAuth 2.0 — para un entorno ABAP de SAP BTP, en el que no hay una kerberos y no se puede seleccionar ninguna configuración ICM, ni servidor en las instalaciones que publicar ADT a través de
SOAUTH2. Un servicio de clave de BTP ya es uno de estos. Consulta §12.
Node.js (LTS) y npm: verifícalo con
node -vynpm-v.
Instalación
git clone --recurse-submodules https://github.com/Ciltress/sap-abap-mcp.git
cd sap-abap-mcp
npm install
npm run buildEl parámetro
--recurse-submoduleses importante: las habilidades generales de ingeniería ocupan en un submódulo, y sin él, la dirección de ese directorio está vacía y el servidor nos ofrece 35 habilidades menos. ¿Ya lo has clonado? Ejecutagit submodule update --init --recurse--submodules.
El paquete
npx mcp-abap-abap-adt-apien npm es el servidor descendente y no incluye el inicio de sesión SSO ni las herramientas RFC. En su lugar, compila este repositorio desde el código fuente.
Configuración
Copia .env.example a .env y rellena con los datos de tu sistema:
SAP_URL=https://your-sap-server.example.com:44301
SAP_USER=YOUR_SAP_USER
SAP_CLIENT=100
SAP_LANGUAGE=ENSAP_URL y SAP_USER son obligatorias; SAP_CLIENT y SAP_LANGUAGE son opcionales, pero recomendadas.
De los cuatro modos de inicio de sesión en, tres no necesitan **** SAP_PASSWORD en absoluto.
Nunca agregues .env al control de versiones; ya está en .gitignore.
Variable opcional | Efecto |
| El ID del sistema, como en |
| Acepta un certificado de una CA interna o desconocida. Solo para desarrollo. |
| Ruta a un binario de curl con soporte SPNEGO, si no es el del sistema Windows. |
| Sobrescribe la ruta ICF de JSON-RPC cuando el nodo se publica bajo un alias. |
| Qué herramientas enumera este servidor — y, por tanto, a cuáles responderá. Ver más abajo. |
| Tope máximo de una sola respuesta, en bytes. |
|
|
| Arranca incluso cuando SAP niega a este usuario el nodo ADT, conservando las herramientas RFC. Ver docs/Authentication.md. |
| El nodo ICF en el que inicia sesión el modo de respaldo. Solo necesita emitir una cookie de sesión y un token CSRF. |
|
|
| Puerto para el endpoint HTTP streamable. Por defecto |
| Dirección a la que vincularse en modo |
| Orígenes de navegador permitidos para llamar a |
| Valores |
| Peticiones por minuto por sesión MCP en modo |
Dimensionar el servidor para su cliente
Las tres variables ABAP_MCP_* existen por una razón: un cliente que no puede obtener los esquemas de herramientas bajo demanda paga la lista completa de herramientas en cada turno. Claude Code hace esquemas diferidos y debería mantenerse en el valor predeterminado; un modelo de 8B con una ventana de 128k gasta una sexta parte de su contexto antes de que la conversación empiece, y de ahí viene «el prompt que funciona la mitad de las veces».
ABAP_MCP_PROFILE — no definirlo significa all, así que una configuración existente no cambia.
perfil |
| coste por turno | para |
| 9 | ~2.737 tokens | leer un sistema y completar una hoja de edición |
| 18 | ~3.982 tokens | solo lectura: diccionario, datos de tablas, llamadas RFC |
| 10 | ~2.900 tokens | un usuario con derechos RFC pero sin |
| 49 | ~8.034 tokens | el ciclo de flujo de edición: tests, ATC, transportes, refactorización |
| 129 | ~17.759 tokens | el valor predeterminado; adecuado para clientes que obtienen esquemas bajo demanda |
Los conteos incluyen healthcheck, que queda fuera de todos los perfiles porque es la herramienta que responde «¿qué perfil estamos ejecutando?».
Un perfil no es un filtro de conveniencia. Una herramienta fuera del perfil activo no se lista y no se enruta, por lo tanto no se puede llamar — esto es lo que convierte a analyst en una garantía de que nada edita los fuentes y no un menú más predeterminado. Las llamadas fuera del perfil reciben un error que lo dice, en lugar de «tool unknown», así que no tiene sentido reintentar. Un nombre de perfil no reconocido detiene el servidor en el arranque, en lugar de caer a all — servir silenciosamente 129 herramientas a quien pidió 9 es el fallo exacto que los perfiles existen para evitar.
core es pequeño porque una herramienta, editAbapSource, es el ciclo de escritura: bloquear, escribir, activar, desbloquear, liberando el bloqueo incluso si un paso falla. Los cuatro pasos separados permanecen en dev y all.
ABAP_MCP_MAX_RESPONSE_BYTES — la lista de herramientas es un coste fijo que un perfil puede reducir; una respuesta no tiene límite. En core toda la lista de herramientas son ~11KB, mientras que una sola adtDiscovery es ~42 KB. Sin definir sigue el perfil (core 24,000 bytes, analyst 32,000, dev 48,000, all sin techo); without lo elimina.
Una respuesta que excede el presupuesto se retiene y se sustituye por un JSON válido — status:"truncated", los bytes originales, el budget, un preview de 2,000 bytes y un nextStep — nunca por un fragmento cortado, que no se podría analizar y que solo provocaría reintentos idénticos.
ABAP_MCP_GATE — antes de listar varias, el servidor pregunta al sistema qué soporta y retiene las herramientas cuyas colecciones ADT no existen. En DEV se trata de las 10 herramientas de abapGit y las 3 herramientas de unión de servicio, que de otro modo responderían HTTP 400. Cuesta una ida y vuelta de discovery por proceso, solo puede acortar la lista, y cualquier fallo deja listadas todas las herramientanças. ABAP_MCP_GATE=off la omite.
healthcheck informa de las tres cosas: el perfil activo, responseBudgetBytes y cualquier herramienta retenida.
Un certificado en lugar de Kerberos
Para un usuario de servicio o técnico, añade un certificado — solo esto cambia el modo:
SAP_USER=CLAUDEAGENT # the user CERTRULE maps the certificate to
SAP_CERT_FILE=C:\Users\svc_agent\SNC\sec\claudeagent.p12
SAP_CERT_PASSPHRASE=<PKCS#12 password / PSE PIN>Variable opcional | Efecto |
|
|
| La clave privada, cuando no está en |
| Conjunto de CA para verificar el propio certificado de SAP, en lugar de desactivar la verificación TLS. |
Esto es TLS mutuo, no SNC — ADT es HTTPS. Un certificado que ya funcione para RFC/SNC se puede reutilizar y su mapeo
CERTRULEse mantiene, pero la ACLSNC0no participa realmente y el ICM necesitaicm/HTTPS/verify_client.docs/Authentication.mddescribe las diferencias, la trampasapgenpse export_p12/ OpenSSL 3 y cómo leer un certificado rechazado.
Un cliente OAuth 2.0, para BTP y para SOAUTH2
Para un entorno BTP de SAP ABAP, o un sistema on-premise que publica ADT tras un servidor de autorización. Establecer el ID de cliente cambia el modo:
SAP_OAUTH_TOKEN_URL=https://your-tenant.authentication.eu10.hana.ondemand.com/oauth/token
SAP_OAUTH_CLIENT_ID=sb-abap-agent!t1234 # 'clientid' in a BTP service key
SAP_OAUTH_CLIENT_SECRET=<'clientsecret'>En un entorno on-premise, el endpoint está en el propio servidor SAP — https://<host>:<port>/sap/bc/sec/oauth2/token — y el cliente es el registrado en SOAUTH2.
Variable opcional | Efecto |
|
|
| Ámbitos a solicitar. Sin definir pide los ámbitos por defecto del cliente, que es lo habitual. |
| Para el flujo |
| Un token emitido en otro lugar, usado tal cual. Nada puede renovarlo. |
|
|
El token inicia sesión una vez. A partir de ahí la cookie de sesión de SAP transporta cada llamada, como en los demás modos — por tanto no es un problema que un token caduque en cinco minutos. Ten en cuenta que un cliente OAuth 2.0 en AS ABAP es un usuario en
SU01: unSAP_OAUTH_CLIENT_SECRETincorrecto cuenta contralogin/fails_to_user_lockigual que una contraseña, así que una solicitud de token denegada no se reintenta nunca. El flujo de autorización por código (authorization-code) no existe — necesita un navegador que un servidor iniciado por stdio no puede abrir; el flujo se completa a mano y se pasa el refresh token.docs/Authentication.md§11 da detalle, incluido qué fallos se bloquean dejan fijados y por qué.
Una contraseña, cuando no hay nada más
Para un sistema sin Kerberos ni certificados — una sandbox, un trial o cualquier cosa fuera del dominio:
SAP_USER=CLAUDEAGENT
SAP_PASSWORD=<the password>El último recurso, y no intercambiable con los otros dos. Un ticket ausente o un certificado no mapeado de rechaza sin más; una contraseña equivocada cuenta contra
login/fails_to_user_locky bloquea ese usuario para todos los que lo consumen, no solo para este servidor. La implementación rechaza reiterar una contraseña rechazada por esa razón: un intento fallido queda muy marcado, por muchas herramientas que se le llamen. Prefiere un certificado en cualquier uso no atendido.docs/Authentication.md§10 contiene el detalle.
Registrarse con un cliente MCP
Apunta el cliente al punto de entrada compilado mediante rutas absolutas:
{
"mcpServers": {
"sap-abap-dev-100": {
"command": "node",
"args": ["C:/path/to/sap-abap-mcp/dist/index.js"],
"env": {
"SAP_URL": "https://your-sap-server.example.com:44301",
"SAP_USER": "YOUR_SAP_USER",
"SAP_SYSTEM_ID": "DEV",
"SAP_CLIENT": "100",
"SAP_LANGUAGE": "EN"
}
}
}
}El bloque env del cliente tiene preferencia sobre .env. Ejecuta npm run start para lanzar días el servidor manualmente, o npm run dev para dirigirlo a través de MCP Inspector.
Para un cliente que lleva el esquema de todas las herramientas en cada turno, añade un perfil en ese mismo bloque:
"env": { "…": "…", "ABAP_MCP_PROFILE": "core" }En Docker
Por defecto el servidor habla MCP a través de stdio, así que no hay ningún puerto que publicar — el cliente inicia el contenedor y se comunica con él por stdin/stdout. Esta sección trata ese caso predeterminado; para un contenedor result cual por red en vez de esto, ver Funcionamiento por HTTP más abajo.
docker build -t abap-adt-mcp .{
"mcpServers": {
"sap-abap-dev-100": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"--env-file",
"C:/path/to/.env",
"abap-adt-mcp"
]
}
}
}Los cuatro modos de autenticación funcionan aquí, pero una credencial tiene que ser dada a el contenedor, y --env-file no es dotenv — Docker no elimina comillas, no lee export ni descarta un # comment final: así, un valor que dotenv habría despejado llega exactamente igual. Las rutas de Windows en .env deben ser reemplazadas por las montadas. Kerberos es el modo que más exige del contenedor y OAuth el que menos: un token se obtiene a través de la red, por lo que no hay que montar nada en absoluto.
Modo entorno — monta el material de clave en solo lectura, y con él a CA que firma el certificado de SAP:
docker run -i --rm --env-file .env \
-v /host/certs:/certs:ro \
-e SAP_CERT_FILE=/certs/agent.p12 \
-e SAP_CA_FILE=/certs/corporate-root.pem \
abap-adt-mcpModo Kerberos: la imagen incluye un curl compilado contra GSS-API y kinit, así que solo queda un dominio y una credencial:
docker run -i --rm --env-file .env \
-v /etc/krb5.conf:/etc/krb5.conf:ro \
-v /host/agent.keytab:/krb5/agent.keytab:ro \
-e SAP_KRB_KEYTAB=/krb5/agent.keytab \
-e SAP_KRB_PRINCIPAL=SVC_AGENT@CORP.EXAMPLE.COM \
abap-adt-mcpModo OAuth 2.0 — no hay nada que montar; la credencial se obtiene:
docker run -i --rm --env-file .env \
-e SAP_OAUTH_TOKEN_URL=https://your-tenant.authentication.eu10.hana.ondemand.com/oauth/token \
-e SAP_OAUTH_CLIENT_ID='sb-abap-agent!t1234' \
-e SAP_OAUTH_CLIENT_SECRET=<clientsecret> \
abap-adt-mcpModo contraseña — ¡Último recurso!
docker run -i --rm --env-file .env \
-e SAP_USER=YourUser \
-e SAP_PASSWORD=YourPassword \
abap-adt-mcpTres cosas que debes saber antes de recurrir a él:
Un keytab, no por tu ticket. Un contenedor no puede tomar prestada la credencial de la sesión como hace un inicio de sesión interactivo. En un host Linux puedes montar la caché de tickets que ya tengas (
-v /tmp/krb5cc_1000:/krb5/ccache:ro -e KRB5CCNAME=FILE:/krb5/ccache), pero expira con la del host. En un host Windows tampoco ninguna de las dos: el TGT vive en la caché de LSA y no puede escribirse en un archivo; usa el modo certificado, que no requiere nada de esto. El keytab es la única credencial que funciona sin supervisión y la única que sobrevive a la duración del ticket.Verifica el certificado de SAP, o asume que no lo estás haciendo. La imagen confía solo en el bundle público de CA, así que una CA interna en la que el host confía no se conoce aquí y el handshake falla con
UNABLE_TO_GET_ISSUER_CERT_LOCALLY. Monta la CA raíz y apuntaSAP_CA_FILEhacia ella. Copiar un.envde escritorio en bloque oculta esto:NODE_TLS_REJECT_UNAUTHORIZED=0es un ajuste de desarrollo y no tiene lugar en una imagen desplegada.Compila desde un clon con
--recurse-.skills/Developmentes un submódulo; sin él, la imagen incluye 35 skills menos.
La imagen es Debian en lugar de Alpine por una razón: el curl de Alpine se compila sin GSS-API, y ese curl no falla — simplemente nunca envía un token, y SAP responde con el mismo 401 que produciría un ticket vencido. Lo que falta se indica al arranque, en stderr, antes de intentar ninguna sesión. Para preguntar al contenedor con qué credencial se quedó, dale un comando en lugar del servidor:
gxp14
docs/, skills/ y AGENTS.md se copian en la imagen a propósito: el servidor los lee en tiempo de ejecución para servir readServerGuide, readSkill y los recursos abap-adt://. docs/Authentication.md §7 tiene la configuración completa del contenedor, modo a modo.
Ejecución sobre HTTP
Todo lo anterior inicia un servidor para un solo cliente sobre stdio. Establece ABAP_MCP_TRANSPORT=http para ejecutar un contenedor de larga vida con este el cual todo un equipo se conecta through the red, usando el transporte Streamable HTTP del SDK en /mcp.
The HTTP mode cambia quién inicia sesión, no lo que una sesión puede hacer una vez conectada: ninguno de los cuatro modos anteriores (SAP_AUTH_MODE, SAP_CERT_FILE, SAP_OAUTH_CLIENT_ID, SAP_PASSWORD) se aplica aquí, porque no hay un logon compartido que configurar. En su lugar, cada cliente MCP se autentica con su propio token bearer de SAP OAuth 2.0: envía Authorization: Bearer <token> on initialize, and that token becomes the identity of the SAP de E sa session: su propio logon de ADT, sus propios locks, its own audit trail. Dos miembros of the team that connect at once get two independent sessions, never a single technical user.
docker build -t abap-adt-mcp .
docker run --rm -p 3000:3000 \
-e SAP_URL=https://your-sap-server.example.com:44301 \
-e SAP_USER=CLAUDEAGENT \
-e SAP_CLIENT=100 \
-e ABAP_MCP_TRANSPORT=http \
abap-adt-mcpSAP_USER sigue siendo necesario (todos los modos no relacionados neither password require a user name container to build the ADT client), but never transmit and have no relevance to who is the session real: SAP determines it from each one's own token, same as in §11.
Variable | Efecto |
| Cambia de stdio a Streamable HTTP. |
| Puerto en el que escuchar. Predeterminado |
| Dirección al a binding. Predeterminado |
| Orígenes de navegador permitidos to call a |
| Valores |
| Peticiones por minute and session. |
Registra un cliente carefully with any remote Streamable HTTP MCP server, pointing to /mcp and providing your own SAP OAuth token of that user:
gxp16
A a request with no credential is rejected with 401 before having any SAP traffic; a token que SAP itself also rejects also returns 401, with its own message. There is no separate secret to configure for the transport itself: SAP token is the access control.
A client that doesn’t want to be disconnected each time its access token expires can send its own refresh token as X-SAP-Refresh-Token, and in session it renew on the refresh_token grant. That requires SAP_OAUTH_TOKEN_URL and SAP_OAUTH_CLIENT_ID in the container: the client registration against which a refresh token is redeemed is the deployment's, while the refresh token, and therefore the SAP identity, belongs to the caller.
Browser origins are rejected unless ABAP_MCP_HTTP_ALLOWED_ORIGIN paces them: that s the DNS-rebinding guard that the MCP spec asks the server to apply itself, since a rebinding request never passes through the proxy in front. Or allow-listed are worth the CORS headers matching. Clients that do not send an Origin — that is, any MCP client that is not a web page — are unaffected.
The container's docker-entrypoint.sh skips its Kerberos setup automatically when ABAP_MCP_TRANSPORT=http is set, since the resolveAuthMode() choice doesn't describe nothing real once every session logs on with its own token. TLS termination is left to whatever it is in front of the container (a reverse proxy or ingress), as with any other internal HTTP service. Full details, including the OAuth grants mechanics that this reduces to, can be found in `docs/Authentication.md §12.
More more systems
A server is linked to a system and a customer for its entire life: no one can be exchanged at runtime. So register an entry per system/client and give each its SAP_SYSTEM_ID:
GXP17
Then Each server is announce another in the MCP instructions that it returns the time of connection:
This server is linked to SAP system DEV, client 100 (https://…:44301). You cannot switch of system or client at runtime: both are fixed by the environment in which it was started. If a request mentions another system or client, use the MCP server configured for it; If no one is registered, say it instead of acting here.
That is what lets an agent route “please check this in DEV client 200” to the right server without calling anything. healthcheck reports the same identity for a server that needs to be asked directly.
The declaration is checked. SAP names the system and client in the session cookie set during login (SAP_SessionID_DEV_100), so the server knows what it is really connected to. If that contradicts SAP_SYSTEM_ID — for example, an entry that you copied and pasted and points to the wrong host — healthcheck carries a WARNING and it is logged loudly during boot. Worth: because every tool continues to work flawlessly; only it does so on the wrong system.
Quick tour
Read any object to its name — no URL discovery required:
GXP18
Explore an entire naming convention — patterns they normalize for you, so zpp_lab becomes ZPP_LAB*:
GXP19
Call a function — read the signature first and validate the request against it:
GXP20
A BAPI and its commit must travel in a same batch, or the commit puts itself in its own LUW and the BAPI’s changes are lost:
GXP21
The complete write cycle (lock → modify → check → meet → unlock), debugger, ATC and every other working pattern are in docs/MCP-MT.md §4.
Trabajar con objetos ABAP
Three tools cover most of what you need, and each takes a name rather than an ADT URL:
Necesitas | Herramienta |
The source of a class, program, include, function group or module |
|
What does a table, structure or view look like? |
|
Everything that’s behind a naming convention |
|
GXP22
readAbapObject returns metadata and source in a single call. When a name belongs to several objects — ZPP_EXT_LABEL_DATA is both a group of functions and a function block — looks for the most specific one and tells you through ambiguous:true and alternatives; pass objectType to force the choice. Objects without source back with hasSource: false and a pointer to the appropriate tool.
describeAbapTable gives names of fields, DDIC types, lengths, key flags, data elements, domains and check tables — the check table is the target of the foreign key, which is the fastest way to see two tables how do they relate. objectStructure does not return fields for a table, and certificateContents returns lines rather than a definition, so neither answers what this a table looks like.
Rules worth including in your client system prompt
**Prefers the name
tools.** Only falls back tosearchObject→objectStructure→getObjectSourceif you need intermediate results. Never hand-illustrate a/sap/bc/adt/...` route.Select efficiently. SAP tables are big. Always constrain the
SELECTs with aWHEREclause, and useSELECT SINGLE(if all key fields are known) orUP TO n ROWSin one case.
GXP23
SAP is decoupled from your filesystem: reading src returns it as a single tool result, and read you local file doesn’t. change nothing in SAP. Local copies are useful only for diffing, nothing else.
The first READMEs listed
GetTable,GetStructureandGetTypeInfo. They belong to the separate projectmcp-bap-adt, not this server.
Development
GXP24
Tests live in src/__tests__ and run completely offline: the hang suite exercise end-to-end against a node SAP Gateway simulated.
Against a real system (requires a ticket Kerberos), an end-to-end check is:
GXP25
It drives the server built on MCP stdio exactly as a client would, and only calls function modules of read-only.
Adding a tool is a change of a single file: see docs/MCP_Tools.md §10.
Troubleshooting
But above final answer in code block? The user asked "Return only the translated text, with no wrapper and no code fence." So we must output plain text, not inside a code block. The code block in my draft is for illustration only. In the final, I must not wrap with triple backticks. Also I accidentally used a code span with three backticks around the whole translation? No.
I notice in my translation I spelled "GXP" as "gxp114" lower-case? Actually in final draft I see I wrote `gxp14` with backticks (code) but placeholders GXP14 should be not backticks, just plain. Need to ensure code spans: For example, `GXP14` should be plain text, no backticks. So remove backticks around all GXP numbers. Also write them as `GXP14`, not "gxp14". In our final answer we must preserve exactly "GXP14" etc.
Also in the draft "tthe" errors. Need to produce exact final translation, no extra wrapping.
Let me now revise carefully and produce final output with correct formatting, no code fences, no wrappers.
I need to ensure that all GXP signs are uppercase and not in backticks, like the input. The input has them plain: "GXP11", "GXP12", etc. I will place them on their own lines.
Let's rewrite the entire final answer carefully.
I'll also fix where I translated "MRO" etc. Need precise.
Let's generate final output:
---
**Modo Kerber** — la ...
... etc.
Ensure markup: headings with "###", "bold". Lists with "*" spaces. Keep "***" hr.
I'll now prepare final message.
Before final, review in previous draft that I accidentally wrote "MCP-Tools" with a typo. Use exact link from original: `[`docs/MCP-Tools.md` §4](docs/MCP-Tools.md#4-golden-paths)` etc.
For "Desarrollo" heading, include GXP24 after heading.
"troubleshooting" heading is `## Solución de problemas` at end.
Make sure no "gxp" lower.
Let's**Modo Kerberos**** — la imagen incluye un curl compilado contra GSS-API y `kinit`, así que solo queda un dominio y una credencial:
GXP11
**Modo OAuth 2.0** — no hay nada que montar; la credencial se obtiene:
GXP12
**Modo contraseña** — ¡último recurso!
GXP13
Tres cosas que debes saber antes de recurrir a él:
* **Un keytab, no tu propio ticket.** Un contenedor no puede tomar prestada la credencial de la sesión como hace un inicio de sesión interactivo. En un host Linux puedes montar la caché de tickets que ya tengas (`-v /tmp/krb5cc_1000:/krb5/ccache:ro -e KRB5CCNAME=FILE:/krb5/ccache`), pero expira con la del host. **En un host Windows ninguna de las dos funciona**: el TGT vive en la caché de LSA y no puede escribirse en un archivo; usa el modo certificado, que no necesita nada de esto. El keytab es la única credencial que se ejecuta sin supervisión y la única que sobrevive a la vida del ticket.
* **Verifica la certificación de SAP, o sé consciente de que no.** La imagen confía solo en el paquete público de CA, por lo que una CA interna en la que el host confía no se conoce aquí y el protocolo de enlace falla con `UNABLE_TO_GET_ISSUER_CERT_LOCALLY`. Monta la CA raíz y apunta `SAP_CA_FILE` hacia ella. Llevar un `.env` de escritorio en bloque oculta esto: `NODE_TLS_REJECT_UNAUTHORIZED=0` es un ajuste de desarrollo y no tiene cabida en una imagen desplegada.
* **Construye desde un clon con `--recurse-submodules`.** `skills/Development` es un submódulo; sin él la imagen incluye menos 35 habilidades.
La imagen usa Debian en lugar de Alpine por una razón: el curl de Alpine está compilado sin GSS-API, y ese curl no falla, simplemente nunca envía un token, y SAP responde con el mismo 401 que produce un ticket caducado. Lo que falta se indica al arranque, en stderr, antes de intentar ninguna sesión. Para preguntarle al contenedor con qué credencial quedó, pásale un comando en lugar del servidor:
GXP14
`docs/`, `skills/` and `AGENTS.md` se copian en la imagen intencionadamente: el server las lee durante la ejecución para proporcionar `readServerGuide`, `readSkill` y los recursos `abab-adt://`. [`docs/Authentication.md` §7](docs/Authentication.md) contiene la dotación completa del contenedor, modo a modo.
### Ejecución sobre HTTP
Everything above starts one server for one client over stdio. Establece `ABAP_MCP_TRANSPORT=http` para in a contenedor de larga duración al que todo un equipo se conecta a través de la red, usando el transporte transportable HTTP del SDK en `/mcp`.
El modo HTTP cambia*de quién es inicio de sesión*, no lo que una sesión puede hacer una vez inicada: **las cuatro formas** (`SAP_AUTH_MODE`, `SAP_CERT_FILE`, `SAP_OAUTH_CLIENT_ID`, `SAP_PASSWORD`) no se aplican aquí, pues no hay un logon compartido que configurar. Eo contrario, **cada cliente MCP se autentica con su propio token de portador de SAP OAuth 2.0**: envía `Authorization: Bearer <token>` en `iniciar`, y ese token se convierte en la identidad SAP de esa sesión: su propio logon de ADT, sus propias cerraduras, su propia traza de auditoría. Si dos miembros del equipo se conectan a la vez, obtienen sesiones independientes, nunca un único usuario técnico compartido.
GXP15
`SAP_USER` es aún es obligatorio (todo modo que no sea de contraseña necesita un usuario provisional para construir el cliente de ADT), pero no se transmitirá nunca, no influye en who de la sesión es en realidad: SAP determina cada sesión a partir de su propio token, igual que [§11](docs/Authentication.md#11-oauth-20-mode).
| Variable | Efecto |
| ------------------------ | ------------------------------------------------------------------------------------------------------ |
| `ABAP_MCP_TRANSPORT=http` | Cambiar de stdio a Runable HTTP. |
| `ABAP_MCP_HTTP_PORT` | Puerto en el que escucha. Predeterminado `3000`. |
| `ABAP_MCP_HTTP_HOST` | Dirección de escucha. Predeterminado `0.0.0.0`. |
| `ABAP_MCP_HTTP_ALLOWED_ORIGINS` | Orígenes de navegador permitidos para llamar a `/mcp`; comma separated; `*` permite todos. Vacío (el value default) no emt. |
| `ABAP_MCP_HTTP_ALLOWED_HOSTS` | Valores `Host` que se atienden, separados por comand. Vacío acepta cualquier. |
| `ABAP_MCP_HTTP_RATE_LIMIT` | Peticiones por minute y session. `0` (por defecto) off. |
Registra un cliente igual que cualquier otro servidor MCP remoto con Streamable HTTP, pointing at `/mcp` and providing that user's own SAP OAuth token:
GXP16
One petición con no credentials is rejected with `401` before any SAP traffic; token que SAP rejects itself (“una cadena with old”) with the message "401" from SAP. No existe ningún secreto adicional y separado que configurar para el transporte: el token de SAP **es** el control de acceso.
Un cliente that prefiere not be one desconectado cada vez que caduque su token de acceso can send its own token of refresh in the `X-SAP-Refresh-Token" instead, and the session renews automatically using a `refresh_token` grant. This requires `SAP_OAUTH_TOKEN_URL` and `SAP_OAUTH_CLIENT_ID` in the container — the subscription to the client where a refresh takes back is site the implementation, while the refresh token (and thus the SAP identity) remains caller.
Browser origins are refused unless `ABAP_MCP_HTTP_ALLOWED_ORIGIN` bans them: that's an anti-DNS `rebinding` protection that the MCP spec requires the server to apply itself, since a rebind request never crosses the reverse proxy in front. Or have a list of origins with the appropriate CORS headers. Clients that do not send `Origin` — any MCP client that is not web page — no result covers.
The container's `docker-entrypoint.sh` automatically skips its Kerberos configuration when `ABAP_MCP_TRANSPORT=http` is set, since the `resolveAuthMode()`` call does not describe realmente once every session starts with its own token. the TLS termination is left to whatever in in front of the container (reverse proxy or ingress), as with any other HTTP service. The full detail, including the OAuth grant mechanics to which this reduced, can be found in [`docs/Authentication.md` §12](docs/Authentication.md#12-streamable-http-transport-and-per-connection-sessions).
### Multiple systems
A server runs on a system and a client for its lifetime; none can be changed at runtime. So record an entry per client or system and assign it a `SAP_SYSTEM_ID`:
GXP17
Each server then is present in MCP `instructions` it returns at connection time:
> This server has been bound to SAP system **DEV**, client 100 (https\://…:44301).
> It cannot change system or client at runtime — both are fixed by the environment in which it started.
> If a request refers to a different system or client, use the MCP server configured for that one;
> if any is registered, say so instead of acting.
That is what allows an agent to route "please check it in DEV client 200" to the right server without calling **any**. `healthcheck` is reporting the same identity for a server that needs to be asked directly.
**The declaration is checked.** SAP identifies the system and the client in the session cookie it sends at logon (`SAP_SESSIONID_DEV_`), so the server knows what it is actually talking to. If this does not match with `SAP_SYSTEM_ID` — e.g., a copied entry pointing to the wrong host — `healthcheck` shows a `WARNING` and it is logged meaningfully. Beattentive, because every tool continues to work perfectly; only not in the right system.
***
## Quick tour
Read any object of the name — no need to discover URL:
GXP18
Explore all naming conventions — patterns are normalized for you, so `zpp_lab` becomes `ZPP_LAB*`:
GXP19
Review a function module — first read the signature, and then validate the request:
GXP20
A BAPI and its commit in **one** batch must travel; or commit will fall in its own LUW and changes to the BAPI are lost:
GXP21
The full cycle of writing (**blocked → modify → check → activate → unlock**), debugger, ATC and all other workflows can be found in [`docs/MCP-Tools.md` §4](docs/MCP-Tools.md#4-golden-at) **.
***
## Working with ABAP objects
Three tools cover most of what they need, and each takes a **name** instead of a URL ADT:
| What we need | Tool |
| -------------------------------------------------------------------- | ----------------------- |
| The French, program, Include, function group or module | `的社会` |
| The shape of a table, structure or view | `readAbapObject` |
| Everything behind a naming convention | `searchPackages` |
GXP22
`readAbapObject` returns metadata **and** source in a single call. When a name belongs to multiple objects — `ZPP_EXT_LABEL_DATA` is both a function group and a function — it takes the most specific one and tells you via `ambiguous:true` and `alternatives`; pass `objectType` to sp force. Objects with no source come back with `hasSource:false` and a note on the right tool.
`describeAbapTable` gives field names, DDIC types, lengths, key flags, data elements, domains and **check tables** — the check table is the target of the foreign key, which is the fastest way to see how two tables are related. `objectStructure` doesn't return fields for a table, and `tableContents` returns lines, not definitions, so neither answers “*What does a table look like*?”.”
### Rules to put in your client’s system
* **Opt for tools by name.** Use the `searchObject` → `objectStructure` → `getObjectSource` fallback only if you need intermediate results. **In full rute `/sap/bc/adt/...` never build by hand**.
* **Select efficiently.** SAP tables are large. Always limit `SELECT` with a `WHERE` class, and use `SELECT SINGLE` (all keys are known) or `UP TO n ROWS` otherwise.
`GXP23`
SAP is disconnected from your file system: reading your source just returns it as a result of a tool; writing a local file doesn't change anything in SAP. Local copies are useful only for diff. They are nothing more.
> Earlier with `GetTable`, `GetStructure` and `GetTypeInfo` in the README. Are scattered in the different project [`img`](https://github.com/yoshi) not this server.
***
## Development
`GXP24`
Tests live in [`src/__tests__`](src/__tests__) and run completely offline: the `JSON` "ROM suite exercises` the handler end-to-end against a **simulated dummy SAP Gateway** node.
For a **real** system (requires a Kerberos ticket), the end-to-end check is:
GXP25
It drives the built server off MCP stdio exactly like a client, and only calls read-only function blocks.
Adding a tool is one-file change — see [`docs/MCP-Tools.md` §10](docs/MCP-Tools.md#10-extending-the-server).
## Troubleshooting
| Síntoma | Causa / solución |
| ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `HTTP 401` en cada llamada | Modo Kerberos: no hay un ticket válido, o el sistema no acepta SPNEGO: comprueba `klist` y tu conexión VPN/dominio. Modo con certificado: consulta [`docs/Authentication.md` §6](docs/Authentication.md). |
| `curl nicht gefunden` | El arranque de SSO no pudo encontrar `curl`; define `SSO_CURL_PATH`. |
| `SAP rejected the client certificate` | El mapeo `CERTRULE`, `icm/HTTPS/verify_client` o la confianza en la CA en `STRUST`. El error indica el sujeto presentado: compáralo con `CERTRULE`. |
| `unable to get local issuer certificate` | CA interna. Define `NODE_TLS_REJECT_UNAUTHORIZED=0` (solo en desarrollo). |
| Las herramientas RFC devuelven `reachable:false` | Ejecuta `checkJsonRpcEndpoint`. Esto separa un nodo `/sap/ge/jsonrpc` SICF inactivo de un problema de CSRF o de autorización. |
| `-32601` de un módulo de funciones | No existe, no está habilitado para RFC, o `S_RFC` deniega su grupo de funciones. |
| El cliente no muestra herramientas | Verifica la ruta absoluta hacia `dist/index.js` y que se haya ejecutado `npm run build`. |
Más en uno de los elementos: [`docs/MCPTools.md` §8](docs/MCP-Tools.md#8-troubleshooting-matrix).
## Contribución
1. Haz un fork del repositorio
2. `git checkout -b feature/nombre-de-tu-funcion`
3. Realiza tu cambio y deja `npm test` y `npx tsc -- noEmit` en verde
4. `git commit -m "Add some feature"` y `git push origin feature/your-feature-name`
5. Abre una pull request
## Licencia
[MIT](LICENSE). Proyecto upstream y autor original: [mario-andreschak](https://github.com/mario-andreschak/mcp-abap-abap-adt-api).This server cannot be installed
Maintenance
Related MCP Servers
- AlicenseCqualityNot gradedmaintenanceAn MCP server that facilitates seamless interaction with SAP ABAP systems to manage development objects, transport requests, and source code. It provides a comprehensive suite of tools for performing syntax checks, object searches, and code modifications via the ADT API.100
- AlicenseCqualityDmaintenanceAn MCP server that enables seamless communication between ABAP systems and MCP clients using the ABAP Development Tools (ADT) API. It provides tools for managing ABAP objects, handling transport requests, and performing code analysis directly through MCP-compatible interfaces.100MIT
- AlicenseNot gradedqualityBmaintenanceA standalone MCP server for SAP ABAP development and customizing that connects directly to your SAP system via ADT REST API, enabling AI assistants to search, read, write, activate, transport, debug, and run quality checks on ABAP code, as well as manage customizing/IMG configurations with governed transport recording.MIT
- AlicenseBqualityCmaintenanceMCP server for SAP ABAP development that enables AI assistants and code editors to interact with SAP systems via ABAP Developer Toolkit (ADT) APIs, supporting read, create, update, and delete of ABAP objects.1001,664MIT
Related MCP Connectors
2,000+ MCP servers read at source level. Know what one does before you connect. Free, no key.
A MCP server built for developers enabling Git based project management with project and personal…
MCP Server for JFrog, providing tools for development and artifact management.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/Ciltress/sap-abap-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server