Skip to main content
Glama
package_structure.py5.65 kB
import xmltodict import time from requests.exceptions import HTTPError, RequestException from .utils import AdtError, make_session, SAP_URL, SAP_CLIENT, SAP_AUTH_TYPE # JSON schema for Gemini function‐calling get_package_structure_definition = { "name": "get_package_structure", "description": "Retrieve the list of objects in an ABAP package via the ADT repository nodestructure service.", "parameters": { "type": "object", "properties": { "package_name": { "type": "string", "description": "Name of the ABAP package (e.g. 'ZMY_PACKAGE')." } }, "required": ["package_name"] } } def get_package_structure(package_name: str) -> list[dict]: """ Fetches the structure (objects) under an ABAP package via ADT. Working version using requests automatic cookie handling. Fixed the cookie issue: use only cookie values without path, secure, HttpOnly attributes. Args: package_name: Name of the ABAP package (e.g. 'ZMY_PACKAGE') Returns: List of dictionaries with keys: OBJECT_TYPE, OBJECT_NAME, OBJECT_DESCRIPTION, OBJECT_URI Raises: ValueError: If package_name is empty AdtError: On HTTP errors ConnectionError: On network failures """ print(f"Fetching package structure for {package_name}") if not package_name: raise ValueError("package_name is required") session = make_session() base_url = SAP_URL.rstrip('/') endpoint = f"{base_url}/sap/bc/adt/repository/nodestructure" params = { "parent_type": "DEVC/K", "parent_name": package_name, "withShortDescriptions": True } headers = { "Accept": "application/vnd.sap.as+xml; charset=utf-8; dataname=com.sap.adt.RepositoryObjectTreeContent" } print(f"Endpoint: {endpoint}") print(f"Parameters: {params}") try: # Отримуємо CSRF токен csrf_url = f"{base_url}/sap/bc/adt/discovery" csrf_resp = session.get( csrf_url, headers={"x-csrf-token": "fetch", "Accept": "application/atomsvc+xml"}, timeout=10 ) token = csrf_resp.headers.get("x-csrf-token") print(f"CSRF token: {token}") if not token: raise ConnectionError("No CSRF token in response headers") headers_with_csrf = headers.copy() headers_with_csrf["x-csrf-token"] = token # КЛЮЧОВЕ ВИПРАВЛЕННЯ: Використовуємо requests автоматичні cookies # (БЕЗ атрибутів path, secure, HttpOnly) if session.cookies: auto_cookies = "; ".join([f"{cookie.name}={cookie.value}" for cookie in session.cookies]) headers_with_csrf["Cookie"] = auto_cookies print(f"Auto cookies: {len(auto_cookies)} chars") # Add client header if needed if SAP_CLIENT: headers_with_csrf["X-SAP-Client"] = SAP_CLIENT print(f"Headers: {list(headers_with_csrf.keys())}") # POST запит resp = session.post( endpoint, params=params, headers=headers_with_csrf, timeout=30 ) print(f"Response status: {resp.status_code}") print(f"Response content-type: {resp.headers.get('content-type')}") print(f"Response length: {len(resp.text)}") if resp.status_code != 200: if resp.status_code == 404: raise AdtError(404, f"Package '{package_name}' not found") elif resp.status_code == 403: raise AdtError(403, f"Access forbidden: {resp.text}") else: raise AdtError(resp.status_code, f"HTTP {resp.status_code}: {resp.text}") print("Successfully received response!") # Парсимо XML print(f"Parsing XML response...") doc = xmltodict.parse(resp.text) nodes = ( doc.get("asx:abap", {}) .get("asx:values", {}) .get("DATA", {}) .get("TREE_CONTENT", {}) .get("SEU_ADT_REPOSITORY_OBJ_NODE", []) ) # Handle both single node and array of nodes items = nodes if isinstance(nodes, list) else [nodes] if nodes else [] print(f"Found {len(items)} items in package") # Extract and filter result = [] for n in items: name = n.get("OBJECT_NAME") uri = n.get("OBJECT_URI") if not name or not uri: continue result.append({ "OBJECT_TYPE": n.get("OBJECT_TYPE"), "OBJECT_NAME": name, "OBJECT_DESCRIPTION": n.get("DESCRIPTION"), "OBJECT_URI": uri }) print(f"Successfully extracted {len(result)} objects from package {package_name}") return result except HTTPError as e: if e.response.status_code == 404: raise AdtError(404, f"Package '{package_name}' not found") from e elif e.response.status_code == 403: raise AdtError(403, f"Access forbidden: {e.response.text}") from e else: raise AdtError(e.response.status_code, f"HTTP error: {e.response.text}") from e except RequestException as e: raise ConnectionError(f"Network error: {e}") from e except Exception as e: raise AdtError(500, f"Unexpected error: {e}") from e

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

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