Skip to main content
Glama
ethanhan2014

SAP ADT MCP Server

by ethanhan2014

change_interface

Replace the source code of an existing ABAP interface with automatic locking, writing, activation, and unlocking. First retrieve the current source using get_interface.

Instructions

Modify an existing ABAP interface in the SAP system. Locks the object, writes the new source, activates, and unlocks. Use get_interface first to read the current source.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
nameYesInterface name (e.g. ZIF_MY_INTERFACE)
sourceYesComplete new ABAP interface source code including INTERFACE definition.
system_idNoSAP system ID (e.g. DEV). Omit to use default system.

Implementation Reference

  • Input validation schema for the change_interface tool, requiring 'name' and 'source' strings.
    const ChangeInterfaceSchema = z.object({
      name: z.string(),
      source: z.string(),
    });
  • Handler that parses args with ChangeInterfaceSchema and delegates to client.changeInterface().
    case "change_interface": {
      const { name: intfName, source } = ChangeInterfaceSchema.parse(args);
      const log = await client.changeInterface(intfName, source);
      return { content: [{ type: "text", text: log }] };
    }
  • Core implementation: locks the interface, writes source (with auto-transport detection), unlocks, and activates in the SAP system.
      async changeInterface(name: string, source: string, transport?: string): Promise<string> {
        await this.fetchStatefulCsrf();
        const log: string[] = [];
        const nameLower = name.toLowerCase();
        const nameUpper = name.toUpperCase();
    
        try {
          // 1. Lock
          const lockResp = await this.http.post(
            `/sap/bc/adt/oo/interfaces/${nameLower}?_action=LOCK&accessMode=MODIFY`,
            "",
            { headers: this.statefulHeaders(), responseType: "text", validateStatus: () => true }
          );
          const lockData = lockResp.data as string;
          const lockMatch = lockData.match(/<LOCK_HANDLE>([^<]+)<\/LOCK_HANDLE>/);
    
          if (!lockMatch?.[1]) {
            log.push(`Failed to lock interface ${nameUpper} (HTTP ${lockResp.status})`);
            log.push(lockData.substring(0, 500));
            return log.join("\n");
          }
    
          const lockHandle = lockMatch[1];
          log.push(`Locked ${nameUpper} for editing`);
    
          // 2. Write source (auto-detect transport if not provided)
          let corrNr = transport ?? "";
          let writeResp = await this.http.put(
            `/sap/bc/adt/oo/interfaces/${nameLower}/source/main?lockHandle=${encodeURIComponent(lockHandle)}&corrNr=${corrNr}`,
            source,
            {
              headers: this.statefulHeaders({ "Content-Type": "text/plain; charset=utf-8" }),
              responseType: "text",
              validateStatus: () => true,
            }
          );
          if (writeResp.status >= 400 && !transport) {
            const trMatch = (writeResp.data as string).match(/request\s+([A-Z]{3}K\d{6})/);
            if (trMatch) {
              corrNr = trMatch[1];
              log.push(`Auto-detected transport ${corrNr}`);
              writeResp = await this.http.put(
                `/sap/bc/adt/oo/interfaces/${nameLower}/source/main?lockHandle=${encodeURIComponent(lockHandle)}&corrNr=${corrNr}`,
                source,
                {
                  headers: this.statefulHeaders({ "Content-Type": "text/plain; charset=utf-8" }),
                  responseType: "text",
                  validateStatus: () => true,
                }
              );
            }
          }
          if (writeResp.status >= 400) {
            log.push(`Write failed (HTTP ${writeResp.status}): ${(writeResp.data as string).substring(0, 500)}`);
          } else {
            log.push("Source code written");
          }
    
          // 3. Unlock (must unlock before activation)
          await this.http.post(
            `/sap/bc/adt/oo/interfaces/${nameLower}?_action=UNLOCK&lockHandle=${encodeURIComponent(lockHandle)}`,
            "",
            { headers: this.statefulHeaders(), responseType: "text", validateStatus: () => true }
          );
          log.push("Unlocked");
    
          // 4. Activate
          const activateBody = `<?xml version="1.0" encoding="UTF-8"?>
    <adtcore:objectReferences xmlns:adtcore="http://www.sap.com/adt/core">
      <adtcore:objectReference adtcore:uri="/sap/bc/adt/oo/interfaces/${nameLower}" adtcore:name="${nameUpper}"/>
    </adtcore:objectReferences>`;
    
          const actResp = await this.http.post(
            "/sap/bc/adt/activation?method=activate&preauditRequested=true",
            activateBody,
            {
              headers: this.statefulHeaders({
                "Content-Type": "application/xml",
                Accept: "application/xml",
              }),
              responseType: "text",
              validateStatus: () => true,
            }
          );
    
          const actData = actResp.data as string;
          if (actData.includes('activationExecuted="true"')) {
            log.push("Activated successfully");
          } else {
            const msgMatch = actData.match(/<msg:shortText>([\s\S]*?)<\/msg:shortText>/);
            log.push(`Activation: ${msgMatch?.[1] ?? `HTTP ${actResp.status}`}`);
          }
        } finally {
          await this.endStatefulSession();
        }
    
        return log.join("\n");
      }
  • Tool registration in the ListToolsRequestSchema handler, defining name, description, and inputSchema for change_interface.
    {
      name: "change_interface",
      description: "Modify an existing ABAP interface in the SAP system. Locks the object, writes the new source, activates, and unlocks. Use get_interface first to read the current source.",
      inputSchema: {
        type: "object" as const,
        properties: {
          name: { type: "string", description: "Interface name (e.g. ZIF_MY_INTERFACE)" },
          source: { type: "string", description: "Complete new ABAP interface source code including INTERFACE definition." },
          ...SYSTEM_ID_PROP,
        },
        required: ["name", "source"],
      },
    },
Behavior4/5

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

Describes locking, writing, activating, unlocking – discloses side effects beyond 'modify'. However, lacks details on failure handling or prerequisites for locking.

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?

Two concise sentences, no fluff. Critical information front-loaded.

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

Completeness4/5

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

Covers purpose and prerequisite. Missing output/return info (e.g., success indicator or transport number), but adequate for a modification tool with 3 params and no output schema.

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?

Schema covers 100% of parameters. Description adds no extra semantic detail beyond schema definitions.

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?

States 'Modify an existing ABAP interface' – clear verb+resource. Distinguishes from sibling create_interface and get_interface.

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

Usage Guidelines4/5

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

Explicitly advises using get_interface first to read current source. Could mention avoid using for creation or deletion, but still helpful.

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/ethanhan2014/sap-adt-mcp'

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