Skip to main content
Glama

GetObjectsByType

Retrieves ABAP objects of a specific type within a package or composite object. Enables listing all classes, tables, or programs under a given parent node.

Instructions

[read-only] Retrieves all ABAP objects of a specific type (classes, tables, programs, interfaces, etc.) under a given parent node. Useful for listing all objects of one type within a package or composite object.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
parent_nameYes[read-only] Parent object name
parent_tech_nameYes[read-only] Parent technical name
parent_typeYes[read-only] Parent object type
node_idYes[read-only] Node ID
formatNo[read-only] Output format: 'raw' or 'parsed'
with_short_descriptionsNo[read-only] Include short descriptions

Implementation Reference

  • Main handler function for GetObjectsByType. Validates required params (parent_name, parent_tech_name, parent_type, node_id), creates ADT client, fetches node structure, optionally parses XML to extract objects, formats output grouped by type, and caches results.
    export async function handleGetObjectsByType(
      context: HandlerContext,
      args: any,
    ) {
      const { connection, logger } = context;
      try {
        const {
          parent_name,
          parent_tech_name,
          parent_type,
          node_id,
          format,
          with_short_descriptions,
        } = args;
    
        if (
          !parent_name ||
          typeof parent_name !== 'string' ||
          parent_name.trim() === ''
        ) {
          throw new McpError(
            ErrorCode.InvalidParams,
            'Parameter "parent_name" (string) is required and cannot be empty.',
          );
        }
    
        if (
          !parent_tech_name ||
          typeof parent_tech_name !== 'string' ||
          parent_tech_name.trim() === ''
        ) {
          throw new McpError(
            ErrorCode.InvalidParams,
            'Parameter "parent_tech_name" (string) is required and cannot be empty.',
          );
        }
    
        if (
          !parent_type ||
          typeof parent_type !== 'string' ||
          parent_type.trim() === ''
        ) {
          throw new McpError(
            ErrorCode.InvalidParams,
            'Parameter "parent_type" (string) is required and cannot be empty.',
          );
        }
    
        if (!node_id || typeof node_id !== 'string' || node_id.trim() === '') {
          throw new McpError(
            ErrorCode.InvalidParams,
            'Parameter "node_id" (string) is required and cannot be empty.',
          );
        }
    
        const withDescriptions =
          with_short_descriptions !== undefined
            ? Boolean(with_short_descriptions)
            : true;
        const outputFormat = format || 'parsed'; // 'raw' or 'parsed'
    
        // Create AdtClient and get utilities
        const client = createAdtClient(connection, logger);
        const utils = client.getUtils();
    
        // Get specific node structure
        const response = await utils.fetchNodeStructure(
          parent_type,
          parent_name.toUpperCase(),
          node_id,
          withDescriptions,
        );
    
        if (outputFormat === 'raw') {
          const plainResult = return_response(response);
          objectsListCache.setCache(plainResult);
          return plainResult;
        }
    
        // Parse and format the response
        const objects = parseObjectNamesFromXml(response.data);
    
        if (objects.length === 0) {
          const mockResponse = {
            data: `No objects found for node_id '${node_id}' in ${parent_type} '${parent_name}'.`,
            status: 200,
            statusText: 'OK',
            headers: {},
            config: {},
          } as any;
          const plainResult = return_response(mockResponse);
          objectsListCache.setCache(plainResult);
          return plainResult;
        }
    
        // Create formatted response
        let responseText = '';
        responseText = `Found ${objects.length} objects for node_id '${node_id}' in ${parent_type} '${parent_name}':\n\n`;
    
        // Group by object type if there are multiple types
        const objectTypes = [...new Set(objects.map((obj) => obj.type))];
    
        if (objectTypes.length > 1) {
          for (const objType of objectTypes) {
            const typeObjects = objects.filter((obj) => obj.type === objType);
            responseText += `šŸ“ Type: ${objType} (${typeObjects.length} objects)\n`;
    
            for (const obj of typeObjects) {
              responseText += `   • ${obj.name}`;
              if (obj.tech_name !== obj.name) {
                responseText += ` (${obj.tech_name})`;
              }
              if (obj.uri) {
                responseText += `\n     URI: ${obj.uri}`;
              }
              responseText += '\n';
            }
            responseText += '\n';
          }
        } else {
          // Single type, simpler format
          const objType = objectTypes[0];
          responseText += `šŸ“ Object Type: ${objType}\n\n`;
    
          for (const obj of objects) {
            responseText += `   • ${obj.name}`;
            if (obj.tech_name !== obj.name) {
              responseText += ` (${obj.tech_name})`;
            }
            if (obj.uri) {
              responseText += `\n     URI: ${obj.uri}`;
            }
            responseText += '\n';
          }
        }
    
        // Add summary
        responseText += `\nšŸ“Š Summary: ${objects.length} objects found\n`;
        if (objectTypes.length > 1) {
          for (const objType of objectTypes) {
            const count = objects.filter((obj) => obj.type === objType).length;
            responseText += `   ${objType}: ${count} objects\n`;
          }
        }
    
        const mockResponse = {
          data: responseText,
          status: 200,
          statusText: 'OK',
          headers: {},
          config: {},
        } as any;
    
        const finalResult = return_response(mockResponse);
        objectsListCache.setCache(finalResult);
        return finalResult;
      } catch (error) {
        // MCP-compliant error response: always return content[] with type "text"
        return {
          isError: true,
          content: [
            {
              type: 'text',
              text: `ADT error: ${String(error)}`,
            },
          ],
        };
      }
    }
  • Tool definition (schema) for GetObjectsByType. Defines name, availability, description, and input schema with properties: parent_name, parent_tech_name, parent_type, node_id (required), plus optional format and with_short_descriptions.
    export const TOOL_DEFINITION = {
      name: 'GetObjectsByType',
      available_in: ['onprem', 'cloud'] as const,
      description:
        '[read-only] Retrieves all ABAP objects of a specific type (classes, tables, programs, interfaces, etc.) under a given parent node. Useful for listing all objects of one type within a package or composite object.',
      inputSchema: {
        type: 'object',
        properties: {
          parent_name: {
            type: 'string',
            description: '[read-only] Parent object name',
          },
          parent_tech_name: {
            type: 'string',
            description: '[read-only] Parent technical name',
          },
          parent_type: {
            type: 'string',
            description: '[read-only] Parent object type',
          },
          node_id: { type: 'string', description: '[read-only] Node ID' },
          format: {
            type: 'string',
            description: "[read-only] Output format: 'raw' or 'parsed'",
          },
          with_short_descriptions: {
            type: 'boolean',
            description: '[read-only] Include short descriptions',
          },
        },
        required: ['parent_name', 'parent_tech_name', 'parent_type', 'node_id'],
      },
    } as const;
  • Helper function that parses XML data to extract object names, types, technical names, and URIs from SEU_ADT_REPOSITORY_OBJ_NODE entries using regex.
    function parseObjectNamesFromXml(xmlData: string): Array<{
      name: string;
      type: string;
      tech_name: string;
      uri?: string;
    }> {
      const objects: Array<{
        name: string;
        type: string;
        tech_name: string;
        uri?: string;
      }> = [];
    
      try {
        // Look for SEU_ADT_REPOSITORY_OBJ_NODE entries
        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) {
            const objectTypeMatch = nodeMatch.match(
              /<OBJECT_TYPE>([^<]+)<\/OBJECT_TYPE>/,
            );
            const objectNameMatch = nodeMatch.match(
              /<OBJECT_NAME>([^<]+)<\/OBJECT_NAME>/,
            );
            const techNameMatch = nodeMatch.match(
              /<TECH_NAME>([^<]+)<\/TECH_NAME>/,
            );
            const uriMatch = nodeMatch.match(/<OBJECT_URI>([^<]+)<\/OBJECT_URI>/);
    
            if (objectTypeMatch && objectNameMatch) {
              const objectName = decodeURIComponent(objectNameMatch[1]);
              const techName = techNameMatch
                ? decodeURIComponent(techNameMatch[1])
                : objectName;
              const uri = uriMatch ? decodeURIComponent(uriMatch[1]) : undefined;
    
              objects.push({
                name: objectName,
                type: objectTypeMatch[1],
                tech_name: techName,
                uri: uri,
              });
            }
          }
        }
      } catch (_error) {
        // console.warn('Error parsing XML for object names:', error);
      }
    
      return objects;
    }
  • Registration of GetObjectsByType in the SearchHandlersGroup. Maps the TOOL_DEFINITION (renamed as GetObjectsByType_Tool) to the handleGetObjectsByType handler function. This group is included in both the launcher and EmbeddableMcpServer.
    export class SearchHandlersGroup extends BaseHandlerGroup {
      protected groupName = 'SearchHandlers';
    
      /**
       * Gets all search handler entries
       */
      getHandlers(): HandlerEntry[] {
        return [
          {
            toolDefinition: SearchObject_Tool,
            handler: (args: any) => handleSearchObject(this.context, args),
          },
          // Dynamic import handlers
          {
            toolDefinition: GetObjectsList_Tool,
            handler: (args: any) => {
              return handleGetObjectsList(
                this.context,
                args as { object_type: string },
              );
            },
          },
          {
            toolDefinition: GetObjectsByType_Tool,
            handler: (args: any) => {
              return handleGetObjectsByType(
                this.context,
                args as { object_type: string },
              );
            },
          },
        ];
      }
    }
Behavior4/5

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

Description explicitly starts with '[read-only]' indicating a safe read operation, which is especially important given no annotations are provided. No behavioral contradictions are present.

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?

Description is a single concise sentence with an additional usage note, front-loading the purpose with no extraneous information.

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?

While purpose is clear, the tool has no output schema and the description does not explain the return structure or how parameters like 'format' and 'with_short_descriptions' affect output, leaving usage ambiguous for an agent.

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?

All parameters have descriptions in the schema, so the description adds little beyond the schema. It only loosely references parameters like 'parent node' without adding semantic detail beyond schema coverage.

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

Purpose4/5

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

Description clearly states the tool retrieves all ABAP objects of a specific type under a parent node, with examples like classes, tables, etc. However, it does not explicitly differentiate from sibling tools like GetClass or GetTable, which retrieve specific objects.

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?

Description gives usage context ('useful for listing all objects of one type within a package or composite object') but does not mention when to avoid using it or provide alternatives among sibling tools.

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