SAP-MCP
SAP-MCP
Servidor MCP para SAP on-premise a través de ADT: un proceso que ejecuta tanto el endpoint MCP como la administración web, capaz de conectarse a varios sistemas SAP a la vez, con depurador y herramientas de diagnóstico en tiempo de ejecución. Los nombres de las herramientas siguen la convención PascalCase de vibing-steampunk, con el añadido del modelo multisistema y la página de administración.
No hace falta instalar ningún objeto ABAP en SAP para usarlo — la única excepción es RunReport, y el servidor lo instala por ti (ver la sección Grupo D).
Instalación
Windows — haz doble clic en install.bat, o ejecuta en la terminal:
install.batComprueba Python 3.10+, crea .venv, instala las dependencias y genera systems.json a partir de la plantilla. Después abre systems.json, rellena la URL / usuario / contraseña del sistema SAP real y ejecuta run.bat.
Otras plataformas:
python -m venv .venv && . .venv/bin/activate
pip install -e .
cp systems.example.json systems.json # sửa URL, user, password
python -m sap_mcpsystems.json contiene contraseñas y ya está en .gitignore — no lo incluyas en un commit.
Ejecutar el servidor
Windows — haz doble clic en run.bat, o:
run.bat :: cổng 8765, chế độ focused (50 tool)
run.bat 8766 :: đổi cổng
run.bat 8766 expert :: đổi cổng + bật đủ 66 toolrun.bat pone la consola en UTF-8 automáticamente (los logs contienen vietnamita; una consola cp1252 haría que Python muera), genera systems.json desde la plantilla si no existe, e indica claramente qué PID está ocupando el puerto en lugar de dejar que uvicorn lance un error de socket en crudo.
Abre http://127.0.0.1:8765 para añadir/editar/probar sistemas. El endpoint MCP está en /mcp.
Conexión con el cliente MCP
Copia mcp.example.json como .mcp.json en el directorio del proyecto, o fusiona la sección mcpServers en el archivo de configuración existente del cliente:
{
"mcpServers": {
"sap-mcp": {
"type": "http",
"url": "http://127.0.0.1:8765/mcp"
}
}
}Ajusta el puerto para que coincida si ejecutas run.bat con otro puerto. El servidor debe estar en ejecución antes de que el cliente se conecte — es un transporte streamable-http; el cliente no inicia el proceso por sí mismo como en stdio.
Configuración del sistema (systems.json)
Campo | Por defecto | Significado |
| — |
|
|
|
|
|
|
|
| — | Basic auth |
|
| Pon |
| — | Ruta de CA propia (en lugar de |
|
| Tope de HTTP normal, en segundos |
|
| Solo permite escribir si está activado |
|
| Paquetes con permiso de escritura |
| — | Restricción adicional por nombre de objeto |
|
| Los paquetes transportables deben tener TR obligatoriamente |
|
| Solo permite usar el grupo D si está activado (depurador + ejecución de código) |
|
| Cuánto tiempo puede estar detenido en un breakpoint, en segundos |
|
| Espera predeterminada de |
Los objetos del namespace SAP estándar siempre se rechazan; no se puede desactivar mediante configuración.
debug_timeout no es solo un número para quedar bien. El código detenido en un breakpoint retiene la petición HTTP que lo ejecutó, por lo que el timeout normal (30 s) corta mientras estás mirando variables: el hilo en segundo plano muere y el resultado del report se pierde por completo, y DebuggerDetach devuelve The read operation timed out en lugar de los datos. Este tope solo se amplía cuando se está depurando (hay listener o se está detenido en el debuggee); si se ampliara para todas las ejecuciones, un report colgado retendría un work process de SAP durante media hora sin que nadie lo esté mirando.
Variables de entorno
Variable | Por defecto | Significado |
|
| Ruta del archivo de configuración |
|
| Puerto HTTP |
|
|
|
| — | Desactiva áreas de funcionalidad, p. ej. |
Códigos de grupo: C transport request, D depurador, P diagnóstico de runtime (dump, trace) — consulta la sección Herramientas más abajo. Las herramientas principales no pertenecen a ningún grupo y siempre están habilitadas. Desactivar ambos (SAP_MCP_DISABLED_GROUPS=D,P) devuelve focused/expert a 30/45 herramientas.
Herramientas
Administración ListSystems GetConnectionInfo GetSystemInfo
Lectura GetSource GetObjectStructure GetClassInfo GetPackage GetFunctionGroup SyntaxCheck
· experto: GetProgram GetClass GetInterface GetInclude GetFunction GetClassInclude
GetSource puede leer un fragmento en lugar de todo el objeto: around="SELECT" obtiene la ventana alrededor de la primera aparición fuera de comentarios, o from_line/to_line obtiene el rango de líneas exacto. Todo fragmento comienza con una línea de comentario que indica que es un fragmento; solo la versión completa se puede usar con UpdateSource; sobrescribir con una ventana elimina el resto. GetPackage tiene un límite max_objects y avisa cuando ha recortado.
Búsqueda SearchObject GrepObjects GrepPackages
· experto: GrepObject GrepPackage
Datos RunQuery GetTableContents
RunQuery ejecuta Open SQL SELECT y devuelve la tabla de resultados; GetTableContents construye la sentencia SELECT por ti. No se necesita allow_write porque es el propio SAP el que rechaza las órdenes de escritura en este endpoint:
DELETE FROM t001 … → 400 Invalid query string. Only SELECT statement is allowed.La barrera para la LECTURA son los permisos del usuario SAP en systems.json — cualquier tabla que ese usuario pueda leer, el agente también puede leerla, incluidas las tablas de personal. No configures un usuario con acceso total.
Navegación por código fuente FindDefinition FindReferences
FindDefinition(system, 'CLAS', 'ZCL_X', symbol='cl_salv_bs_runtime_info') — el servidor busca el símbolo en el source (ignorando los comentarios) y lo resuelve allí; devuelve el tipo, el nombre y la lista de componentes. No uses navigation/target aunque el nombre suene más apropiado: devuelve la misma uri de entrada cuando no puede resolverlo, es decir, un falso éxito. La ruta que funciona es abapsource/codecompletion/elementinfo, y exige el source completo en el body.
FindReferences devuelve el where-used. SAP devuelve un árbol que mezcla tres tipos de nodos; solo los elementos con gradeDirect son usos reales. gradeComponent son componentes del propio objeto consultado; si se cuentan, una clase a la que nadie llama tendría de pronto 6 usos.
Escritura WriteSource EditSource Activate ActivatePackage CreatePackage GetInactiveObjects LockObject UnlockObject
· experto: CreateObject UpdateSource DeleteObject
Utilidades CompareSource CloneObject PrettyPrint ImportFromFile ExportToFile
Grupo C ListTransports · experto: GetTransport CreateTransport ReleaseTransport DeleteTransport
Grupo D — depurador SetBreakpoint DeleteBreakpoint DebuggerListen DebuggerPoll DebuggerStopListener DebuggerAttach DebuggerDetach DebuggerGetStack DebuggerGetVariables DebuggerStep RunClass RunReport RunUnitTests
Requiere allow_debug: true. Secuencia de uso:
SetBreakpoint— la línea debe ser una sentencia ejecutable, no una declaración. No hace falta contar líneas:statement="SELECT"hace que el servidor la busque (ignora los comentarios, así que no cae en una línea no ejecutable) y devuelve el número de línea.DebuggerListen— devuelve inmediatamente; el listener se ejecuta en segundo planoRunClass/RunReport/RunUnitTests— ejecuta el códigoSi el breakpoint salta, el paso 3 devuelve inmediatamente
Đã dừng ở breakpoint …(no los datos).DebuggerPollindica el estado en cualquier momento.DebuggerAttach→DebuggerGetStack/DebuggerGetVariables/DebuggerStepDebuggerDetach— suelta el debuggee; el código termina de ejecutarse y el resultado del paso 3 se devuelve aquí (o enDebuggerPollsi tarda mucho).
Si no salta ningún breakpoint, el paso 3 devuelve directamente el resultado como una herramienta normal.
Por qué las tres herramientas que ejecutan código lo hacen en segundo plano. Cuando el código se detiene en un breakpoint, SAP retiene la petición HTTP que lo está ejecutando; la llamada solo devuelve después de que se suelte el debuggee. Si se llamara de forma síncrona, esa misma herramienta se colgaría y el agente nunca podría llamar a DebuggerAttach para soltarla: se encerraría a sí mismo. Por eso estas tres herramientas se ejecutan en una sesión propia en un hilo en segundo plano y responden en cuanto el listener detecta el debuggee.
Cada sistema usa tres sesiones HTTP separadas al depurar: una para el listener + la sesión de depuración (stateful, retenida durante decenas de segundos), una para ejecutar código (puede estar bloqueada hasta soltar el debuggee) y una para poner/quitar breakpoints. Si no se separan, se bloquean entre sí: ejecutar código en la sesión del listener solo puede colarse en el hueco entre dos ciclos de long-poll — justo cuando SAP no tiene ningún listener registrado, así que el breakpoint nunca salta.
Depurar un report con pantalla de selección. Un breakpoint externo no captura la sesión de diálogo — si pulsas F8 en SE38, el depurador no ve nada (medido en un sistema real). Usa RunReport en lugar de RunClass en el paso 3: ejecuta el report en una sesión externa, de modo que el breakpoint sí salta.
RunReport bloquea la visualización ALV pero sigue obteniendo los datos (cl_salv_bs_runtime_info), de modo que un report que termina con ALV no hace dump a mitad de camino. Acepta tanto PARAMETERS como SELECT-OPTIONS (los nombres de parámetros que empiezan por S_) y variantes.
RunReport escribe en SAP, por lo que requiere tanto allow_write como allow_debug, no solo allow_debug como el resto de herramientas de depuración. El servidor instala él mismo dos objetos en $TMP, no tienes que hacer nada:
ZCL_MCP_RUNNER— clase intermedia, genérica y que nunca se modifica. HaceSUBMIT (mv_report) WITH SELECTION-TABLE mt_sel, es decir, el nombre del report y toda la pantalla de selección son datos en tiempo de ejecución.ZMCP_RUNNER_ARGS— programa que consiste solo en una línea de comentario, reescrito antes de cada ejecución. La clase lo lee en tiempo de ejecución conREAD REPORT.
*@MCP TOKEN 24b8bff8dfb8477b
*@MCP REPORT ZPG_DEMO
*@MCP MAX 100
*@MCP SEL S_BUKRS S I BT
*@MCP LOW 1000
*@MCP HIGH 2000Por qué hay que escribir de todos modos: IF_OO_ADT_CLASSRUN~MAIN( out ) no acepta parámetros — ni query param, ni body. El source de un objeto es el único canal de paso de parámetros que abre ADT REST.
La consecuencia más importante es la seguridad: ya nada de lo que proporcione el agente se convierte en código ABAP. La versión anterior incrustaba los valores de filtro en literales ABAP, de modo que una comilla que se colara permitía inyectar órdenes arbitrarias en el sistema SAP — ese punto había que escaparlo para estar seguro. Ahora el valor está en una línea de comentario y llega a SAP a través de la tabla RSPARAMS, así que no hay sintaxis que romper. Solo se prohíbe el carácter de salto de línea (crearía una línea de parámetro falsa), y los valores de más de 45 caracteres se rechazan porque RSPARAMS-LOW es CHAR45 — SAP lo truncaría en silencio, es decir, filtraría mal sin que nadie lo sepa.
Cada ejecución lleva un token; la clase devuelve ese token y el servidor lo verifica. Si la escritura de parámetros falla y aun así se continúa ejecutando, el report se ejecutaría con los parámetros antiguos y el resultado se etiquetaría con la petición nueva; el token es lo que impide ese tipo de error silencioso.
En comparación con vibing-steampunk (que exige el plugin ZADT_VSP: 1 interfaz, 3 clases, manejador WebSocket), RunReport necesita menos y no hay que configurar SAPC + SICF manualmente:
vsp ( | SAP-MCP ( | |
Objetos ABAP a instalar | 4 | 2 |
Configuración SAPC + SICF | requiere admin de basis | no |
El servidor lo instala solo | no | sí |
La clase se modifica en cada ejecución | no | no |
SELECT-OPTIONS | no (fija | sí |
Escritura en SAP en cada ejecución | no | sí (un archivo de comentario) |
La última fila es el precio de no necesitar que un admin instale nada: vsp pasa los parámetros por WebSocket y no toca el sistema; RunReport los pasa por el source porque ADT REST no abre ningún otro canal. A cambio, el objeto que se escribe es un archivo que solo contiene un comentario — no tiene sintaxis que pueda romperse, y la clase con la lógica permanece intacta.
Grupo P — diagnóstico de runtime ListDumps GetDump StartTrace ListTraces GetTrace DeleteTrace GetSQLTraceState · experto: DeleteTraceRequest
Short dump (ST22). ListDumps filtra por user/error/program/since,
GetDump devuelve summary (qué ha pasado, análisis del error, punto de
interrupción, pila de llamadas), source (código fuente en el punto de
bloqueo), full o meta.
Medición de rendimiento (SAT/ATRA). StartTrace('ZPG_X', 'report') → ejecutar código →
ListTraces → GetTrace. GetTrace devuelve por defecto el perfil de tiempo por
llamada, ordenado de forma descendente; view='db' devuelve los accesos a la
base de datos por tabla (número de veces, número de veces que se obtiene de la
caché, tiempo). RunReport(..., trace=True) simplifica toda la secuencia: él
mismo establece la solicitud de medición limitada a ese informe concreto.
NET µs % GROSS µs LẦN GỌI TỪ VIỆC
3800 51.2 3800 1 CL_HTTP_SERVER_NET=======C DB: Exec Static
368 5.0 4185 1 SAPLHTTP_RUNTIME Call M. …SEND_RESPONSETres cosas medidas en NW 758, al contrario de lo que asumía vibing-steampunk — cada una de ellas rompe la herramienta silenciosamente si se sigue al pie de la letra:
vsp hace | medido en NW 758 | |
Accept del volcado de feed |
| 406 — debe ser |
Filtrado de volcados | envía | SAP lo ignora, devuelve la lista completa |
ST05 | lo lee como feed de trazas | devuelve una URL de Fiori, sin registros |
Por eso ListDumps filtra en el lado del servidor MCP, y la consulta SQL se
obtiene de dbAccesses del trace ABAP y no de ST05. GetSQLTraceState sigue
siendo útil para detectar un trace olvidado en estado activado — ralentiza todo
el sistema sin que se vea desde fuera.
StartTrace requiere obligatoriamente un nombre de objeto. Una solicitud de
trace sin límite atrapa inmediatamente la propia llamada HTTP que la ha creado:
la medición obtenida es todo ICFSERVICE/HTTP_HEADER_REG — mides el motor de
ADT, no tu código — y aun así parece una tabla de datos muy real. Con límite, la
medición cae justo en la siguiente ejecución (T001, DDFTX, VARID…).
StartTrace, DeleteTrace, DeleteTraceRequest necesitan allow_debug:
cambian el comportamiento del sistema, y una solicitud olvidada mide
subrepticiamente una ejecución posterior. Las tres herramientas de lectura
(ListDumps, GetDump, GetSQLTraceState) no necesitan nada.
Estado
El grupo de herramientas principal, el grupo D (depurador, incluido
RunReport) y el grupo P (volcados + trazas) están completos — 50 herramientas
en modo enfocado / 66 en experto, probadas en NetWeaver 758. La parte de
DDIC/i18n, abapGit y los ayudantes ABAP no están hechos.
Limitaciones conocidas
1. ImportFromFile / ExportToFile no limitan las rutas. Estas dos
herramientas aceptan cualquier ruta que el modelo proporcione.
import_from_file solo comprueba os.path.isfile, export_to_file solo
comprueba os.path.isdir — sin lista blanca, sin restricción a un directorio de
trabajo, sin bloquear .. ni rutas absolutas. Por lo tanto, un agente — incluso
un agente influenciado por el contenido que lee de SAP — puede leer cualquier
archivo que el proceso del servidor pueda leer y enviarlo a SAP, o escribir el
código fuente de SAP en cualquier ruta con permiso de escritura. Mitigación
actual: ejecuta el servidor solo en máquinas que controlas, con una cuenta sin
acceso a archivos más allá de los que quieras que el agente tenga.
2. La ruta REST de administración no tiene autenticación. / y
/api/systems* solo están protegidos vinculándose a 127.0.0.1. Cualquier cosa
que llegue al bucle local en ese puerto puede listar, añadir, modificar y borrar
la configuración del sistema y activar la prueba de conexión. No expongas este
puerto fuera de la máquina local y no lo ejecutes en un host compartido.
3. El depurador lee todas las variables en memoria.
DebuggerGetVariables devuelve los valores reales en el punto de interrupción,
incluidos los datos confidenciales que haya en las variables — contraseñas,
claves, datos personales. Es la naturaleza de la depuración, no un error. Además,
RunClass ejecuta ABAP arbitrario. Por eso allow_debug está desactivado por
defecto y solo debería activarse en sistemas de desarrollo.
4. RunReport comparte un único archivo de parámetros.
ZMCP_RUNNER_ARGS en $TMP se sobrescribe antes de cada ejecución. Dentro de
un servidor, las ejecuciones ya están en cola (un canal de ejecución por
sistema), pero dos servidores o dos personas que usen el mismo sistema se
sobrescribirán los parámetros entre sí. El token en la salida detecta esta
situación y la convierte en un error, en lugar de devolver datos incorrectos.
vibing-steampunk lo evita con un WebSocket APC separado por sesión, a costa de
tener que configurar manualmente SICF.
Arquitectura
transport/ (HTTP, autenticación, CSRF) → adt/ (tipo de objeto, devuelve
datos) → tools/ (formato + registro MCP). La tabla adt/uri.py es la única
fuente para construir URIs. El grupo D usa además tres AdtSession por sistema
(transport/debug_pool.py, divididas por canal) porque el listener se ejecuta en
segundo plano, la sesión de depuración debe mantener el estado continuamente a
través de múltiples llamadas, y el código en ejecución puede estar bloqueado en
un punto de interrupción — ninguna de esas sesiones se puede tomar prestada del
SessionPool compartido.
Las herramientas se ejecutan en un hilo de trabajo, no en el bucle de
eventos. FastMCP llama directamente a la función síncrona en el bucle de
eventos, así que si se dejara así, una llamada a SAP bloquearía todo el
servidor: el agente no podría llamar a DebuggerPoll mientras RunReport está
esperando, dos sistemas diferentes se bloquearían entre sí y la administración
web se congelaría. tools/_registry.py envuelve cada herramienta con
anyio.to_thread.run_sync antes de registrarla. La serialización por sistema se
mantiene y es intencionada — reside en SessionPool, porque el bloqueo del
manejador de SAP solo es válido en una conexión por sistema.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Hosted Amazon Seller and Vendor MCP server for Claude, ChatGPT, Cursor, Codex, Gemini, Copilot.
Official Microsoft MCP Server to query Microsoft Entra data using natural language
GibsonAI MCP server: manage your databases with natural language
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/NhatPD-VNEXT/SAP-MCP'
If you have feedback or need assistance with the MCP directory API, please join our Discord server