Skip to main content
Glama

GetIncludesList

Recursively discover all include files used in an ABAP program or include. Lists nested includes to understand program structure.

Instructions

[read-only] Recursively discover and list ALL include files within an ABAP program or include.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
object_nameYesName of the ABAP program or include
object_typeYes[read-only] ADT object type (e.g. PROG/P, PROG/I, FUGR, CLAS/OC)
detailedNo[read-only] If true, returns structured JSON with metadata and raw XML.
timeoutNo[read-only] Timeout in ms for each ADT request.

Implementation Reference

  • Main handler function for the 'GetIncludesList' tool. Uses ADT client to recursively discover all includes within an ABAP program/include by fetching the root node structure, finding the includes node, and parsing include names from XML responses. Supports both detailed (JSON) and plain text output modes.
    export async function handleGetIncludesList(
      context: HandlerContext,
      args: any,
    ) {
      const { connection, logger } = context;
      try {
        const { object_name, object_type, timeout, detailed } = args;
    
        if (
          !object_name ||
          typeof object_name !== 'string' ||
          object_name.trim() === ''
        ) {
          throw new McpError(
            ErrorCode.InvalidParams,
            'Parameter "object_name" (string) is required and cannot be empty.',
          );
        }
        if (!object_type || typeof object_type !== 'string') {
          throw new McpError(
            ErrorCode.InvalidParams,
            'Parameter "object_type" (string) is required.',
          );
        }
    
        // Default timeout: 30 seconds
        const requestTimeout =
          timeout && typeof timeout === 'number' ? timeout : 30000;
        const isDetailed = detailed === true;
    
        // Pass object_type straight through as parentType
        const parentName = object_name.toUpperCase();
        const parentType = object_type;
    
        logger?.info(
          `Starting includes discovery for ${parentName} (${parentType}), detailed=${isDetailed}`,
        );
    
        // Create AdtClient and get utilities
        const client = createAdtClient(connection, logger);
        const utils = client.getUtils();
    
        // Step 1: Get root node structure to find includes node (with timeout)
        const rootResponse = await Promise.race([
          utils.fetchNodeStructure(
            parentType,
            parentName,
            '000000', // Root node
            true, // with descriptions
          ),
          new Promise<never>((_, reject) =>
            setTimeout(
              () =>
                reject(
                  new Error(
                    `Timeout after ${requestTimeout}ms while fetching root node structure for ${object_name}`,
                  ),
                ),
              requestTimeout,
            ),
          ),
        ]);
    
        // Step 2: Parse response to find includes node ID
        const includesInfo = parseIncludesFromXml(rootResponse.data);
        const includesNode = includesInfo.find((info) => info.name === 'PROG/I');
    
        if (!includesNode) {
          logger?.info(`No includes found in ${object_type} '${object_name}'`);
          // Return empty result if no includes node found
          return {
            isError: false,
            content: [
              {
                type: 'text',
                text: `No includes found in ${object_type} '${object_name}'.`,
              },
            ],
          };
        }
    
        // Step 3: Get includes list using the found node ID (with timeout)
        const includesResponse = await Promise.race([
          utils.fetchNodeStructure(
            parentType,
            parentName,
            includesNode.node_id,
            true, // with descriptions
          ),
          new Promise<never>((_, reject) =>
            setTimeout(
              () =>
                reject(
                  new Error(
                    `Timeout after ${requestTimeout}ms while fetching includes list for ${object_name}`,
                  ),
                ),
              requestTimeout,
            ),
          ),
        ]);
    
        // Step 4: Parse the includes response to extract include names
        const includeNames = parseIncludeNamesFromXml(includesResponse.data);
    
        if (isDetailed) {
          // Return detailed JSON response as text (for compatibility)
          const detailedResponse = {
            object_name: object_name,
            object_type: object_type,
            detailed: true,
            total_includes: includeNames.length,
            includes: includeNames,
            includes_node_info: includesNode,
          };
    
          const result = {
            isError: false,
            content: [
              {
                type: 'text',
                text: JSON.stringify(detailedResponse, null, 2),
              },
            ],
          };
          if (args.filePath) {
            writeResultToFile(JSON.stringify(result, null, 2), args.filePath);
          }
          return result;
        } else {
          // Return minimal text response (original format)
          const responseData =
            includeNames.length > 0 ? includeNames.join('\n') : '';
    
          const plainResult = {
            isError: false,
            content: [
              {
                type: 'text',
                text: responseData,
              },
            ],
          };
          if (args.filePath) {
            writeResultToFile(responseData, args.filePath);
          }
          return plainResult;
        }
      } catch (error) {
        logger?.error(
          `Error getting includes list: ${error instanceof Error ? error.message : String(error)}`,
        );
        return return_error(
          error instanceof Error ? error : new Error(String(error)),
        );
      }
    }
  • Tool definition/schema for 'GetIncludesList'. Defines the tool name, description, availability (onprem/cloud/legacy), and input schema with parameters: object_name (string, required), object_type (enum: PROG/P, PROG/I, FUGR, CLAS/OC, required), detailed (boolean, default false), and timeout (number).
    export const TOOL_DEFINITION = {
      name: 'GetIncludesList',
      available_in: ['onprem', 'cloud', 'legacy'] as const,
      description:
        '[read-only] Recursively discover and list ALL include files within an ABAP program or include.',
      inputSchema: {
        type: 'object',
        properties: {
          object_name: {
            type: 'string',
            description: 'Name of the ABAP program or include',
          },
          object_type: {
            type: 'string',
            enum: ['PROG/P', 'PROG/I', 'FUGR', 'CLAS/OC'],
            description:
              '[read-only] ADT object type (e.g. PROG/P, PROG/I, FUGR, CLAS/OC)',
          },
          detailed: {
            type: 'boolean',
            description:
              '[read-only] If true, returns structured JSON with metadata and raw XML.',
            default: false,
          },
          timeout: {
            type: 'number',
            description: '[read-only] Timeout in ms for each ADT request.',
          },
        },
        required: ['object_name', 'object_type'],
      },
    } as const;
  • Import of GetIncludesList_Tool and handleGetIncludesList from the handler file into the ReadOnlyHandlersGroup.
    import {
      TOOL_DEFINITION as GetIncludesList_Tool,
      handleGetIncludesList,
    } from '../../../handlers/include/readonly/handleGetIncludesList';
  • Registration of the 'GetIncludesList' tool in the ReadOnlyHandlersGroup, binding toolDefinition and handler together.
    {
      toolDefinition: GetIncludesList_Tool,
      handler: (args: any) => handleGetIncludesList(this.context, args),
    },
  • Helper function parseIncludesFromXml - parses XML responses to extract includes node information (name, node_id, label).
    function parseIncludesFromXml(
      xmlData: string,
    ): Array<{ name: string; node_id: string; label: string }> {
      const includes: Array<{ name: string; node_id: string; label: string }> = [];
    
      try {
        // Simple regex-based parsing for XML
        // Look for OBJECT_TYPE entries that contain "PROG/I" (includes)
        const objectTypeRegex =
          /<SEU_ADT_OBJECT_TYPE_INFO>(.*?)<\/SEU_ADT_OBJECT_TYPE_INFO>/gs;
        const matches = xmlData.match(objectTypeRegex);
    
        if (matches) {
          for (const match of matches) {
            // Check if this is an include type
            if (match.includes('<OBJECT_TYPE>PROG/I</OBJECT_TYPE>')) {
              const nodeIdMatch = match.match(/<NODE_ID>(\d+)<\/NODE_ID>/);
              const labelMatch = match.match(
                /<OBJECT_TYPE_LABEL>(.*?)<\/OBJECT_TYPE_LABEL>/,
              );
    
              if (nodeIdMatch && labelMatch) {
                includes.push({
                  name: 'PROG/I',
                  node_id: nodeIdMatch[1],
                  label: labelMatch[1],
                });
              }
            }
          }
        }
      } catch (_error) {
        // console.warn('Error parsing XML for includes:', error);
      }
    
      return includes;
    }
  • Helper function parseIncludeNamesFromXml - parses XML responses to extract actual include names from node structure, with URL decoding and deduplication.
    function parseIncludeNamesFromXml(xmlData: string): string[] {
      const includeNames: string[] = [];
    
      try {
        // Look for SEU_ADT_REPOSITORY_OBJ_NODE entries with OBJECT_TYPE PROG/I
        const nodeRegex =
          /<SEU_ADT_REPOSITORY_OBJ_NODE>(.*?)<\/SEU_ADT_REPOSITORY_OBJ_NODE>/gs;
        const nodeMatches = xmlData.match(nodeRegex);
    
        if (nodeMatches) {
          for (const nodeMatch of nodeMatches) {
            // Check if this node is for includes (PROG/I)
            if (nodeMatch.includes('<OBJECT_TYPE>PROG/I</OBJECT_TYPE>')) {
              // Extract the object name
              const nameMatch = nodeMatch.match(
                /<OBJECT_NAME>([^<]+)<\/OBJECT_NAME>/,
              );
              if (nameMatch?.[1].trim()) {
                const includeName = nameMatch[1].trim();
                // Decode URL-encoded names if needed
                const decodedName = decodeURIComponent(includeName);
                includeNames.push(decodedName);
              }
            }
          }
        }
    
        // If no nodes found, try alternative parsing for OBJECT_NAME tags
        if (includeNames.length === 0) {
          const objectNameRegex = /<OBJECT_NAME>([^<]+)<\/OBJECT_NAME>/g;
          let match: RegExpExecArray | null = objectNameRegex.exec(xmlData);
          while (match !== null) {
            const name = match[1].trim();
            if (name && name.length > 0) {
              const decodedName = decodeURIComponent(name);
              includeNames.push(decodedName);
            }
            match = objectNameRegex.exec(xmlData);
          }
        }
      } catch (_error) {
        // console.warn('Error parsing XML for include names:', error);
      }
    
      return [...new Set(includeNames)]; // Remove duplicates
    }
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description includes '[read-only]' indicating it's a safe read operation, and states it is recursive and lists all includes. Since no annotations are present, the description carries the burden well, though it lacks details on output format or potential side effects.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single sentence with no extraneous words. It is front-loaded with the key information, making it efficient and easy to parse.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema exists, yet the description does not explain what the tool returns (e.g., list of names, objects). The 'detailed' parameter hints at structured JSON, but that is only in the schema. The description lacks completeness for an agent to fully understand the tool's behavior.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema already has 100% coverage with descriptions for all 4 parameters. The tool description does not add any additional meaning to the parameters beyond what the schema provides, so a baseline score of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states it 'Recursively discover and list ALL include files within an ABAP program or include.' The verb 'discover and list' and the resource 'include files' are specific, and it distinguishes itself from the sibling tool 'GetInclude' which likely retrieves a single include.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No explicit guidance on when to use this tool versus alternatives like 'GetInclude'. The description implies it for listing all includes recursively, but does not mention exclusions or contexts. It is adequate but not explicit.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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/fr0ster/mcp-abap-adt'

If you have feedback or need assistance with the MCP directory API, please join our Discord server