Skip to main content
Glama

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.bat

Comprueba 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_mcp

systems.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 tool

run.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

url

https://host:port del sistema SAP

client

100

sap-client

language

EN

sap-language

username / password

Basic auth

verify_ssl

true

Pon false para certificados autofirmados

ca_bundle

Ruta de CA propia (en lugar de verify_ssl)

timeout

30

Tope de HTTP normal, en segundos

allow_write

false

Solo permite escribir si está activado

write_packages

["Z*","Y*","$TMP"]

Paquetes con permiso de escritura

write_objects

Restricción adicional por nombre de objeto

require_transport

true

Los paquetes transportables deben tener TR obligatoriamente

allow_debug

false

Solo permite usar el grupo D si está activado (depurador + ejecución de código)

debug_timeout

1800

Cuánto tiempo puede estar detenido en un breakpoint, en segundos

debug_listen_seconds

300

Espera predeterminada de DebuggerListen, en segundos

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

SAP_MCP_SYSTEMS

./systems.json

Ruta del archivo de configuración

SAP_MCP_PORT

8765

Puerto HTTP

SAP_MCP_MODE

focused

focused (50 herramientas) o expert (66 herramientas)

SAP_MCP_DISABLED_GROUPS

Desactiva áreas de funcionalidad, p. ej. C o C,D

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:

  1. 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.

  2. DebuggerListen — devuelve inmediatamente; el listener se ejecuta en segundo plano

  3. RunClass / RunReport / RunUnitTests — ejecuta el código

  4. Si el breakpoint salta, el paso 3 devuelve inmediatamente Đã dừng ở breakpoint … (no los datos). DebuggerPoll indica el estado en cualquier momento.

  5. DebuggerAttachDebuggerGetStack / DebuggerGetVariables / DebuggerStep

  6. DebuggerDetach — suelta el debuggee; el código termina de ejecutarse y el resultado del paso 3 se devuelve aquí (o en DebuggerPoll si 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. Hace SUBMIT (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 con READ REPORT.

*@MCP TOKEN 24b8bff8dfb8477b
*@MCP REPORT ZPG_DEMO
*@MCP MAX 100
*@MCP SEL S_BUKRS S I BT
*@MCP LOW 1000
*@MCP HIGH 2000

Por 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 (ZADT_VSP)

SAP-MCP (RunReport)

Objetos ABAP a instalar

4

2

Configuración SAPC + SICF

requiere admin de basis

no

El servidor lo instala solo

no

La clase se modifica en cada ejecución

no

no

SELECT-OPTIONS

no (fija kind='P' en el código)

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 → ListTracesGetTrace. 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_RESPONSE

Tres 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

application/atom+xml

406 — debe ser …;type=feed

Filtrado de volcados

envía $filter FQL

SAP lo ignora, devuelve la lista completa

ST05 trace/directory

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.

-
license - not tested
-
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

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

View all MCP Connectors

Latest Blog Posts

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