npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@mcp-abap-adt/adt-clients

v5.1.0

Published

ADT clients for SAP ABAP systems - AdtClient and AdtRuntimeClient

Readme

@mcp-abap-adt/adt-clients

Stand With Ukraine

TypeScript clients for SAP ABAP Development Tools (ADT).

Features

  • Client API – simplified interface for common operations:
    • AdtClient – high-level CRUD API with automatic operation chains
    • AdtClientBatch – batch mode: multiple read operations in a single HTTP round-trip
    • AdtExecutor – execution API via IExecutor contracts (class/program, with profiling)
    • AdtRuntimeClient – stable runtime operations (ABAP debugger, traces, logs, dumps)
    • AdtRuntimeClientBatch – batch mode for runtime operations
    • AdtRuntimeClientExperimental – runtime APIs in progress (for example AMDP debugger)
    • AdtClientsWS – realtime WebSocket facade for event-driven workflows
  • ABAP Unit test support – run and manage ABAP Unit tests (class and CDS view tests)
  • Stateful session management – maintains sap-adt-connection-id across operations
  • Lock registry – persistent .locks/active-locks.json with CLI tools for recovery
  • TypeScript-first – full type safety with comprehensive interfaces
  • Response headers are normalized – ADT response headers can be non-string; normalize before parsing in contributors’ code
  • Public API is clients + supporting types – internal builders and low-level utilities are not exported from the package root

Responsibilities and Design Principles

Core Development Principle

Interface-Only Communication: This package follows a fundamental development principle: all interactions with external dependencies happen ONLY through interfaces. The code knows NOTHING beyond what is defined in the interfaces.

This means:

  • Does not know about concrete implementation classes from other packages
  • Does not know about internal data structures or methods not defined in interfaces
  • Does not make assumptions about implementation behavior beyond interface contracts
  • Does not access properties or methods not explicitly defined in interfaces

This principle ensures:

  • Loose coupling: Clients are decoupled from concrete implementations in other packages
  • Flexibility: New implementations can be added without modifying clients
  • Testability: Easy to mock dependencies for testing
  • Maintainability: Changes to implementations don't affect clients

Package Responsibilities

This package is responsible for:

  1. ADT operations: Provides high-level and low-level client APIs for interacting with SAP ABAP Development Tools (ADT)
  2. Object management: CRUD operations for ABAP objects (classes, interfaces, programs, etc.)
  3. Session management: Maintains session state across operations using sap-adt-connection-id
  4. Lock management: Handles object locking with persistent registry

What This Package Does

  • Provides ADT clients: AdtClient and specialized clients for ADT operations
  • Manages locks: Lock registry with persistent storage and CLI tools
  • Handles requests: Makes HTTP requests to SAP ADT endpoints through connection interface
  • Manages state: Maintains object state across chained operations

What This Package Does NOT Do

  • Does NOT handle authentication: Authentication is handled by @mcp-abap-adt/connection
  • Does NOT manage connections: Connection management is handled by @mcp-abap-adt/connection
  • Does NOT validate headers: Header validation is handled by @mcp-abap-adt/header-validator
  • Does NOT store tokens: Token storage is handled by @mcp-abap-adt/auth-stores
  • Does NOT orchestrate authentication: Token lifecycle is handled by @mcp-abap-adt/auth-broker

External Dependencies

This package interacts with external packages ONLY through interfaces:

  • @mcp-abap-adt/connection: Uses AbapConnection interface for HTTP requests - does not know about concrete connection implementation
  • No direct dependencies on other packages: All interactions happen through well-defined interfaces

Installation

As npm Package

# Install globally for CLI tools
npm install -g @mcp-abap-adt/adt-clients

# Or install in project
npm install @mcp-abap-adt/adt-clients

Architecture

Public API

  1. AdtClient (High-level, recommended)

    • Simplified CRUD operations with automatic operation chains
    • Factory pattern: client.getClass(), client.getProgram(), etc.
    • Automatic error handling and resource cleanup
    • Utility functions via client.getUtils()
    • Example: await client.getClass().create({...}, { activateOnCreate: true })
  2. AdtRuntimeClient

    • Stable runtime operations for ABAP debugging, traces, dumps, logs, feeds, and more
    • Factory accessors: getProfiler(), getCrossTrace(), getSt05Trace(), getDebugger(), getApplicationLog(), getAtcLog(), getDdicActivation(), getDumps(), getFeeds(), getSystemMessages(), getGatewayErrorLog()
    • Example: await runtimeClient.getDebugger().getAbap().launch()
  3. AdtExecutor

    • Typed execution API based on IExecutor
    • Executors:
      • getClassExecutor() for classrun
      • getProgramExecutor() for programrun (on-premise systems)
    • Methods: run, runWithProfiler, runWithProfiling
  4. AdtRuntimeClientExperimental

    • Runtime APIs in progress that may change without backward-compatibility guarantees
    • Current scope: AMDP data preview (AMDP debugger is now part of AdtRuntimeClient.getDebugger().getAmdp())
    • Example: await experimentalRuntime.startAmdpDataPreview(...)
  5. AdtClientsWS

    • Realtime request/event facade over IWebSocketTransport
    • Includes debugger-session facade: listen, attach, step, stack, variables
    • Example: await wsClient.request('debugger.listen', { timeoutSeconds: 30 })
  6. AdtClientBatch / AdtRuntimeClientBatch

    • Execute multiple independent read operations in a single HTTP round-trip
    • Uses SAP ADT batch endpoint (POST /sap/bc/adt/debugger/batch) with multipart/mixed payloads
    • Same factory API as AdtClient / AdtRuntimeClient — record calls, then batchExecute()
    • Example: const batch = new AdtClientBatch(connection); batch.getClass().readMetadata({...}); await batch.batchExecute();

Supported Object Types

| Object Type | AdtClient | |------------|-----------| | Classes (CLAS) | ✅ | | Behavior Implementations (CLAS) | ✅ | | Behavior Definitions (BDEF) | ✅ | | Interfaces (INTF) | ✅ | | Programs (PROG) | ✅ | | Function Groups (FUGR) | ✅ | | Function Modules (FUGR/FF) | ✅ | | Domains (DOMA) | ✅ | | Data Elements (DTEL) | ✅ | | Structures (TABL/DS) | ✅ | | Tables (TABL/DT) | ✅ | | Views (DDLS) | ✅ | | Metadata Extensions (DDLX) | ✅ | | Packages (DEVC) | ✅ | | Transports (TRNS) | ✅ |

Quick Start

Using AdtClient (Recommended - High-Level CRUD API)

import { createAbapConnection } from '@mcp-abap-adt/connection';
import { AdtClient } from '@mcp-abap-adt/adt-clients';

const connection = createAbapConnection({
  url: 'https://your-sap-system.example.com',
  client: '100',
  authType: 'basic',
  username: process.env.SAP_USERNAME!,
  password: process.env.SAP_PASSWORD!
}, console);

const client = new AdtClient(connection, console);

// Simple CRUD operations with automatic operation chains
await client.getClass().create({
  className: 'ZCL_TEST',
  packageName: 'ZPACKAGE',
  description: 'Test class'
}, { activateOnCreate: true });

// Utility functions
const utils = client.getUtils();
await utils.searchObjects({ query: 'Z*', objectType: 'CLAS' });

// Where-used with parsed results (recommended)
const result = await utils.getWhereUsedList({
  object_name: 'ZCL_TEST',
  object_type: 'class',
  enableAllTypes: true  // Eclipse "select all" behavior
});
console.log(`Found ${result.totalReferences} references`);
for (const ref of result.references) {
  console.log(`${ref.name} (${ref.type}) in ${ref.packageName}`);
}

// Where-used with raw XML (legacy)
await utils.getWhereUsed({ object_name: 'ZCL_TEST', object_type: 'class' });

Using AdtClientsWS (Realtime)

import { AdtClientsWS } from '@mcp-abap-adt/adt-clients';
import type { IWebSocketTransport } from '@mcp-abap-adt/adt-clients';

const transport: IWebSocketTransport = createYourTransport();
const wsClient = new AdtClientsWS(transport, console, {
  requestTimeoutMs: 30000,
});

await wsClient.connect('wss://your-realtime-endpoint');

const debuggerSession = wsClient.getDebuggerSessionClient();
await debuggerSession.listen({ timeoutSeconds: 60 });
await debuggerSession.step({ action: 'step_over' });

Using AdtClientBatch (Batch Read Operations)

AdtClientBatch sends multiple independent read operations in a single HTTP round-trip via multipart/mixed batch requests.

import { AdtClientBatch } from '@mcp-abap-adt/adt-clients';

const batch = new AdtClientBatch(connection, console);

// Record operations (not yet executed)
const classPromise = batch.getClass().readMetadata({ className: 'CL_ABAP_TYPEDESCR' });
const domainPromise = batch.getDomain().readMetadata({ domainName: 'MANDT' });
const dePromise = batch.getDataElement().readMetadata({ dataElementName: 'MANDT' });

// Execute all in one HTTP request
await batch.batchExecute();

// Resolve individual results
const classState = await classPromise;
const domainState = await domainPromise;
const deState = await dePromise;

Batch-safe operations (single-step, no chained awaits):

  • read(), readMetadata(), readTransport() — single GET
  • check(), validate(), activate() — single POST

NOT batch-safe (multi-step chains): create(), update(), delete().

ABAP Debugger Step Operations via Batch Endpoint

AdtRuntimeClient executes step operations through debugger batch requests (POST /sap/bc/adt/debugger/batch) using multipart/mixed payloads.

import { AdtRuntimeClient } from '@mcp-abap-adt/adt-clients';

const runtime = new AdtRuntimeClient(connection);
const abapDebugger = runtime.getDebugger().getAbap();

// Executes stepInto + getStack in one batch request
const batchResponse = await abapDebugger.stepIntoBatch();

// Also available:
await abapDebugger.stepOutBatch();
await abapDebugger.stepContinueBatch();

For non-step actions use executeAction(action, value?). Step actions (stepInto, stepOut, stepContinue) are reserved for batch-only execution.

Using AdtExecutor (Execution API)

import { AdtExecutor } from '@mcp-abap-adt/adt-clients';

const executor = new AdtExecutor(connection, console);

// Class execution
await executor.getClassExecutor().run({ className: 'ZCL_MY_CLASSRUN' });

// Program execution (on-premise)
await executor.getProgramExecutor().run({ programName: 'ZMY_EXEC_REPORT' });

// Program execution with profiling
const runWithProfilingResult = await executor.getProgramExecutor().runWithProfiling(
  { programName: 'ZMY_EXEC_REPORT' },
  {
    profilerParameters: {
      allProceduralUnits: true,
      sqlTrace: true,
      allDbEvents: true,
    },
  },
);

console.log(runWithProfilingResult.traceId);

AdtUtils read type safety: readObjectMetadata and readObjectSource accept strict object type unions to prevent invalid inputs like view:ZOBJ.

import type { AdtObjectType, AdtSourceObjectType } from '@mcp-abap-adt/adt-clients';

await utils.readObjectMetadata('DDLS/DF' satisfies AdtObjectType, 'ZOK_I_CDS_TEST');
await utils.readObjectSource('view' satisfies AdtSourceObjectType, 'ZOK_I_CDS_TEST');

Benefits:

  • ✅ Simplified API - no manual lock/unlock management
  • ✅ Automatic operation chains (validate → create → check → lock → update → unlock → activate)
  • ✅ Consistent error handling and resource cleanup
  • ✅ Separation of CRUD operations and utility functions
  • ✅ Long polling support for object readiness

Using Long Polling for Object Readiness

The withLongPolling parameter allows you to wait for objects to become available after create/update/activate operations, replacing fixed timeouts with server-driven waiting:

import { AdtClient } from '@mcp-abap-adt/adt-clients';

const client = new AdtClient(connection);

// Create a class
await client.getClass().create({
  className: 'ZCL_TEST',
  packageName: 'ZPACKAGE',
  description: 'Test class'
});

// Wait for object to be ready using long polling
// The server will hold the connection until the object is available
await client.getClass().read(
  { className: 'ZCL_TEST' },
  'active',
  { withLongPolling: true }
);

// Now the object is guaranteed to be ready for subsequent operations
await client.getClass().update({
  className: 'ZCL_TEST'
}, { sourceCode: updatedCode });

Benefits of Long Polling:

  • No arbitrary timeouts - waits for actual object readiness
  • Faster tests - no unnecessary delays when object is ready quickly
  • More reliable - server-driven waiting ensures object is actually available
  • Automatic in create/update - AdtObject implementations use long polling internally

Note: Long polling is automatically used in create() and update() methods of all AdtObject implementations to ensure objects are ready before proceeding with subsequent operations.

Creating Behavior Implementation Classes

import { AdtClient } from '@mcp-abap-adt/adt-clients';

const client = new AdtClient(connection);

await client.getBehaviorImplementation().create(
  {
    className: 'ZBP_OK_I_CDS_TEST',
    packageName: 'ZOK_TEST_PKG_01',
    behaviorDefinition: 'ZOK_I_CDS_TEST',
    description: 'Behavior Implementation for ZOK_I_CDS_TEST',
    transportRequest: 'E19K900001'
  },
  { activateOnCreate: true }
);

Developer Tools

ADT Discovery Script

The package includes a tool for generating documentation from the ADT discovery endpoint, which lists all available ADT API endpoints.

Purpose: Explore available ADT API endpoints and generate markdown documentation.

Usage:

# Generate discovery documentation (default output: docs/architecture/discovery.md)
npm run discovery:markdown

# Custom output file
npm run discovery:markdown -- --output custom-discovery.md

# Custom SAP system URL
npm run discovery:markdown -- --url https://your-system.com

# Custom .env file
npm run discovery:markdown -- --env /path/to/.env

What it does:

  1. Connects to the SAP system using credentials from .env file
  2. Fetches the discovery endpoint: GET /sap/bc/adt/discovery (via AdtUtils.discovery())
  3. Parses the XML response
  4. Converts it to readable markdown with endpoint categories, HTTP methods, URLs, content types, and descriptions
  5. Saves the pretty-printed discovery XML next to the markdown output

Output:

  • Default: docs/architecture/discovery.md and docs/architecture/discovery.xml
  • Custom: Path specified via --output option, plus discovery.xml in the same directory

Environment Variables: The script uses the same environment variables as the main package:

  • SAP_URL - SAP system URL (required)
  • SAP_AUTH_TYPE - Authentication type: 'basic' or 'jwt' (default: 'basic')
  • SAP_USERNAME - Username for basic auth
  • SAP_PASSWORD - Password for basic auth
  • SAP_JWT_TOKEN - JWT token for JWT auth
  • SAP_CLIENT - Client number (optional)

When to use:

  • To explore available ADT API endpoints on your SAP system
  • To generate up-to-date documentation for ADT API
  • To understand the structure of ADT discovery responses
  • To verify endpoint availability on a specific SAP system

See Tools Documentation for complete details and options.

API Reference

AdtClient Overview

  • Factory accessors for ADT objects: client.getClass(), client.getProgram(), client.getView(), client.getTable(), client.getRequest(), client.getUtils(), etc.
  • Each accessor returns an Adt* object implementing IAdtObject operations.
  • See src/index.ts for the full type exports and object configs.

AdtObject Methods (with Long Polling Support)

All AdtObject implementations support the withLongPolling parameter for read operations:

// Read with long polling - waits for object to be ready
await adtObject.read(config, 'active', { withLongPolling: true });

// Read metadata with long polling
await adtObject.readMetadata(config, { withLongPolling: true });

// Read metadata with explicit version
await adtObject.readMetadata(config, { version: 'active' });

// Read transport info with long polling
await adtObject.readTransport(config, { withLongPolling: true });

When to use long polling:

  • After create() operations - wait for object to be available
  • After update() operations - wait for changes to be persisted
  • After activate() operations - wait for object to be available in active version
  • In tests - replace fixed setTimeout delays with long polling for better reliability

Operation results are stored on the returned state (createResult, updateResult, checkResult, etc.):

const createState = await client.getFunctionModule().create({
  functionGroupName: 'ZFGROUP',
  functionModuleName: 'ZFM_TEST',
  description: 'Test FM',
});

console.log(createState.createResult?.status);

Accept Negotiation (Optional)

Some ADT endpoints return 406 when the Accept header does not match the system’s supported media types. The client can optionally auto-correct Accept by retrying with supported values returned in the 406 response.

Enable globally:

import { AdtClient } from '@mcp-abap-adt/adt-clients';

const client = new AdtClient(connection, console, {
  enableAcceptCorrection: true,
});

Enable via environment:

ADT_ACCEPT_CORRECTION=true npm test

Override per read call:

await client.getClass().read(
  { className: 'ZCL_TEST' },
  'active',
  { accept: 'text/plain' }
);

await client.getClass().readMetadata(
  { className: 'ZCL_TEST' },
  { accept: 'application/vnd.sap.adt.oo.classes.v4+xml', version: 'active' }
);

// Read source without version (initial post-create state)
await client.getClass().read({ className: 'ZCL_TEST' }, undefined);

Notes:

  • Disabled by default.
  • Correction retries once and caches the supported Accept per endpoint.

Specialized Clients

  • ManagementClient: batch activation + check operations
  • LockClient: explicit lock/unlock with .locks registry integration
  • ValidationClient: name validation mirroring ADT validation endpoint

Refer to the TypeScript typings (src/index.ts) for the full API surface.

Type System

Centralized Type Definitions

All type definitions are centralized in module-specific types.ts files:

// Import types from module exports
import type {
  IClassConfig,
  IClassState,
  IProgramConfig
} from '@mcp-abap-adt/adt-clients';

Naming Conventions

The package uses dual naming conventions to distinguish API layers:

Low-Level Parameters (snake_case)

Used by internal ADT API functions.

AdtObject Configuration (camelCase)

Used by AdtClient and Adt* object configs:

interface IClassConfig {
  className: string;
  packageName?: string;
  transportRequest?: string;
  description: string;
  sourceCode?: string;
}

This dual convention:

  • Makes low-level/high-level distinction clear
  • Matches SAP ADT XML parameter naming (class_name in ADT requests)
  • Provides familiar camelCase for JavaScript/TypeScript consumers
  • Enables proper type checking at each layer

See Architecture Documentation for details.

Migration Guide

From Timeouts to Long Polling

Migration from fixed timeouts to long polling:

The package now uses long polling (?withLongPolling=true) instead of fixed timeouts for waiting object readiness. This provides better reliability and faster execution.

// ❌ Before - Using fixed timeouts
await client.getClass().create({ className: 'ZCL_TEST', ... });
await new Promise(resolve => setTimeout(resolve, 2000)); // Fixed delay
await client.getClass().update({ className: 'ZCL_TEST' }, { sourceCode });

// ✅ After - Using long polling
await client.getClass().create({ className: 'ZCL_TEST', ... });
// Long polling is automatically used in create/update methods
await client.getClass().update({ className: 'ZCL_TEST' }, { sourceCode });

// Or explicitly use long polling in read operations
await client.getClass().read(
  { className: 'ZCL_TEST' },
  'active',
  { withLongPolling: true }
);

Benefits:

  • No arbitrary delays - waits for actual object readiness
  • Faster execution when objects are ready quickly
  • More reliable - server-driven waiting ensures object is available
  • Automatic in create() and update() methods

Builderless API

  • CrudClient, ReadOnlyClient, and Builder classes are removed in the builderless API.
  • Use AdtClient and the Adt* objects (client.getClass(), client.getView(), etc.).

Documentation

Logging and Debugging

The library uses a 5-tier granular debug flag system for different code layers:

Debug Environment Variables

# Connection package logs (HTTP, sessions, CSRF tokens)
DEBUG_CONNECTORS=true npm test

# Core library logs
DEBUG_ADT_LIBS=true npm test

# Integration test execution logs
DEBUG_ADT_TESTS=true npm test

# E2E integration test logs
DEBUG_ADT_E2E_TESTS=true npm test

# Test helper function logs
DEBUG_ADT_HELPER_TESTS=true npm test

# Enable ALL ADT scopes at once
DEBUG_ADT_TESTS=true npm test

Logger Interface

All clients accept a unified ILogger interface:

import type { ILogger } from '@mcp-abap-adt/adt-clients';
import { AdtClient } from '@mcp-abap-adt/adt-clients';

// Custom logger example
const logger: ILogger = {
  debug: (msg, ...args) => console.debug(msg, ...args),
  info: (msg, ...args) => console.info(msg, ...args),
  warn: (msg, ...args) => console.warn(msg, ...args),
  error: (msg, ...args) => console.error(msg, ...args),
};

const client = new AdtClient(connection, logger);

Note: All logger methods are optional. Lock handles are always logged in full (not truncated).

See docs/DEBUG.md for detailed debugging guide.

Changelog

See CHANGELOG.md for package-specific release notes. Latest (0.3.14): added getWhereUsedList() for parsed where-used results.

Tests

Integration tests use YAML configuration (src/__tests__/helpers/test-config.yaml) and the BaseTester pattern.
Some ADT endpoints are system-specific; 406 is treated as an Accept/header support issue and can be explicitly allowed via test_settings.allow_406 or per-test params.allow_406 (e.g., objectstructure/nodestructure).

License

MIT

Author

Oleksii Kyslytsia [email protected]