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
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | Interface name (e.g. ZIF_MY_INTERFACE) | |
| source | Yes | Complete new ABAP interface source code including INTERFACE definition. | |
| system_id | No | SAP system ID (e.g. DEV). Omit to use default system. |
Implementation Reference
- src/mcp-server.ts:59-62 (schema)Input validation schema for the change_interface tool, requiring 'name' and 'source' strings.
const ChangeInterfaceSchema = z.object({ name: z.string(), source: z.string(), }); - src/mcp-server.ts:1333-1337 (handler)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 }] }; } - src/adt-client.ts:1140-1237 (handler)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"); } - src/mcp-server.ts:357-369 (registration)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"], }, },