Files
ABAP-Indexing/sap
byeongwook.choiandClaude Fable 5.1 e23140b7af sap_client: ZAA_ICF JSON 규약 대응 (2026-09-14 XML→JSON 전환)
- 요청은 INPUT 래퍼 없이 입력 필드만, 응답은 JSON {"RETURN","RESULT"}. 첫 글자로 asXML 구버전도 자동 판별
- 실측: ZMP_ICF 에서 ZFI01 목록 177건, 프로그램 2본(include 10, T코드 2) 수집 → normalize 정상
- sap/README.md 규약 갱신, tests: JSON/XML 파서·요청 본문 검증

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 14:41:14 +09:00
..

ZAA_ICF MCP 서버 (abap-sap)

SAP ZCL_ZAA_AGENT_API 의 16개 메서드를 LLM 에 붙이는 MCP 서버. 전부 조회만 한다. 브라우저에서 같은 API 를 호출해 보는 웹 테스터와 Bruno 연동은 형제 프로젝트 ../abap-api-tester 에 있다. API 정의(catalog.py)와 SAP 호출 클라이언트(sap_client.py)는 이 폴더가 원본이고, 테스터가 여기서 가져다 쓴다.

실행

cp .env.example .env                 # SAP_USER / SAP_PASS 채우기
pip install -r requirements.txt      # mcp>=2.1 (Python 3.10+)
python mcp_server.py                 # stdio (Claude Code / Claude Desktop)
python mcp_server.py --http 8766     # streamable-http  http://127.0.0.1:8766/mcp
python tools/test_mcp.py [--shrink]  # 툴 목록 + 실제 호출 점검

접속 정보는 .envSAP_URL / SAP_USER / SAP_PASS. .env 는 스크립트 위치 기준으로 읽으므로 작업 디렉터리와 무관하다. 로그는 stderr 로만 나간다 (stdout 은 프로토콜 채널이라 print 금지).

파일

파일 역할
mcp_server.py MCP 서버. catalog.py 의 16개 메서드를 툴로 노출 (stdio / streamable-http)
catalog.py 메서드 설명, 파라미터, 샘플, 필드 사전, 코드값 맵, 셀 링크. 테스터와 공유 (원본)
sap_client.py SAP 호출·응답 정규화(BOM/utf-16 선언/제어문자 제거, asXML→JSON). 테스터와 공유 (원본)
.mcp.json Claude Code 프로젝트 MCP 설정 (이 폴더를 열면 abap-sap 서버가 등록됨)
tools/test_mcp.py MCP 서버 점검 (툴 목록 + 실제 호출 + 잘라내기)

카탈로그를 고치면 툴 정의도, 테스터 화면도, Bruno 컬렉션(테스터가 생성)도 같이 바뀐다.

연결

  • Claude Code: 이 폴더에 .mcp.json 이 있어 프로젝트를 열면 abap-sap 서버가 등록된다 (처음 한 번 승인). 다른 폴더에서도 쓰려면 사용자 범위로 등록한다.
    claude mcp add --transport stdio --scope user abap-sap -- python C:\Users\<me>\EdgeCenter\samsung\abap-mcp\mcp_server.py
    
  • Claude Desktop: %APPDATA%\Claude\claude_desktop_config.json
    {"mcpServers": {"abap-sap": {"type": "stdio", "command": "python",
       "args": ["C:\Users\<me>\EdgeCenter\samsung\abap-mcp\mcp_server.py"]}}}
    
    .env 대신 환경변수로 넘기려면 "env": {"SAP_USER": "...", "SAP_PASS": "..."}.

툴 정의(이름·설명·파라미터·예시)는 catalog.py 에서 자동 생성된다.

비고
get_package_listget_tcode_info, get_object_type (17개, 메서드명 소문자) 파라미터는 IV_ 를 뗀 소문자 (IV_MAX_ROWSmax_rows). 플래그는 boolean, 날짜는 YYYY-MM-DD
explain_fields 응답 필드의 한국어 뜻과 코드값 표 (catalog.py 의 FIELDS / VALUE_MAPS)
sap_connection_info 접속 대상·호출 규약 확인 (비밀번호 제외)

응답은 {"return": {"type", "message", "total_rows"}, …결과, "_meta": {sap_method, sap_params, ms, raw_bytes}}. RETURN.TYPE=E 도 툴 오류가 아니라 정상 응답으로 돌려준다 (LLM 이 메시지를 읽고 판단한다). 네트워크·인증·XML 파싱 실패만 툴 오류. 서버 instructions 에 탐색 흐름(패키지 → 오브젝트 → 소스, T코드 → 프로그램, 용어 → 필드)과 응답 읽는 법이 들어 있다.

LLM 컨텍스트 보호

동작 기본값 환경변수
목록 툴에서 max_rows 생략 시 상한. 잘리면 return.type=W + total_rows. 0 이면 전건(SAP 안전 상한 50,000) 200 ABAP_MCP_DEFAULT_MAX_ROWS
응답 JSON 최대 문자 수. 넘치면 가장 큰 소스/목록부터 절반씩 줄이고 _truncated 에 무엇을 얼마나 잘랐는지 적는다 120,000 ABAP_MCP_MAX_OUTPUT_CHARS
SAP 호출 타임아웃(초) 180 ABAP_MCP_TIMEOUT

소스를 주는 툴(get_program_source, get_version_source, get_function_detail)에는 line_from / line_to 가 추가돼 있어 긴 소스를 나눠 읽는다. 응답에 SOURCE_CODE_LINES(전체 줄 수)와 SOURCE_CODE_RANGE 가 붙는다. Include/화면 안의 소스도 같은 범위로 잘린다.

실측(2026-09-07): SAPMV45A + Include(원문 4.2MB, include 1,822개)를 상한 15,000자로 부르면 14,378자 + 안내 3줄로 돌아온다.

호출 규약 (실측)

2026-09-14 부터 JSON (ZCL_ZAI_API, ICF 노드 /sap/bc/ZMP_ICF). 구버전 asXML 은 아래 그대로이며, sap_client 는 응답 첫 글자({ / <)로 둘을 자동 판별한다.

  • 요청: POST /sap/bc/ZMP_ICF/{METHOD}, 바디는 래퍼 없이 {"IV_PACKAGE":"ZFI01","IV_MAX_ROWS":100} (키 대문자, 숫자는 JSON 숫자, 플래그는 "X", 일자 YYYY-MM-DD 가능)
  • 응답: {"RETURN":{"TYPE","MESSAGE","TOTAL_ROWS"},"RESULT":[...]} — TOTAL_ROWS 는 숫자, 빈 목록은 [], 소스 줄바꿈은
  • 필터 없는 목록 호출은 S+안내가 아니라 E (IV_PACKAGE 또는 IV_PATTERN 중 하나는 필수입니다)
  • 실측 2026-09-21: GET_PROGRAM_LIST ZFI01 177건 / GET_PROGRAM_SOURCE include·T코드 정상

구버전 (asXML, ~2026-09-13)

  • POST /sap/bc/ZAA_ICF/{METHOD}, Content-Type: application/json, 바디 {"INPUT": {"IV_...": ...}}
  • 응답 asXML. XML 선언은 utf-16 이지만 실제 UTF-8 → 선언 제거 후 파싱
  • 소스코드 안 제어문자(0x0C)가 XML 을 깨뜨림 → 파싱 전 제거
  • 날짜는 YYYY-MM-DD
  • 목록 API 의 IV_MAX_ROWS 는 생략하면 전건(안전 상한 50,000). 지정해서 잘리면 RETURN.TYPE=W, 메시지에 (전체 M건), RETURN.TOTAL_ROWS=M (2026-09-04 A안. 그 전엔 기본 200/최대 2,000)

서버측 결함 이력 (2026-09-04 기준 모두 해결)

  • GET_VERSION_SOURCE 과거 버전 → HTTP 500 2026-09-04 해결. SVRS_GET_REPS_FROM_OBJECT 로 교체 (REPS 만 지원)

  • GET_FUNCTION_DETAILFUNC_SOURCE 항상 빈값 2026-09-04 해결. 함수 Include 를 통째로 읽도록 교체 (출처가 RETURN.MESSAGE 에 찍힘)

  • GET_PROGRAM_SOURCE include 목록에 클래스 include 노이즈 혼입 2026-09-04 해결. = 포함 또는 30자 초과 이름 제거

  • GET_OBJECT_LIST_BY_PACKAGE 상한에서 잘려도 TYPE=S 2026-09-04 해결. n+1 건을 읽어 초과 시 W (실측 ZFI01 PROG 1,132건)

  • GET_FIELD_LIST_BY_TEXT USED_TABLES 20건 상한이 조용히 잘림 / 후보 0건이면 응답 본문 0바이트 2026-09-04 해결. W + 잘린 엘리먼트 이름, 0건은 빈 RESULT XML

  • 목록 API 기본 상한 200 / 최대 2,000 2026-09-04 A안으로 제거. 생략 시 전건(안전 상한 50,000), RETURN.TOTAL_ROWS 추가. 실측: 테이블 * 전건 822,899건 → 50,000건 W, 8.7MB, 8초

  • GET_FIELD_LIST_BY_TEXT USED_TABLES 엘리먼트당 20건 고정 상한 2026-09-04 제거. 후보 500개씩 청크 조회, 사용 테이블 총량 50,000 넘으면 중단 + W. 실측 '회사코드' 전건 499후보/6,949건 0.8MB, '코드' 14,000후보 → 안전 상한 W 10MB/4초

수정 소스는 ~/Downloads/CLASS ZCL_ZAA_AGENT_API DEFINITION.txt (전체) 와 METHOD *.txt. API 명세서(메서드당 1시트)는 ~/Downloads/ABAP_API_명세서_ZAA_ICF_v1.4_2026-09-04.xlsx (생성기는 ../abap-api-tester/tools/spec/).

응답 인코딩 (2026-09-04 확인)

응답 HTTP 헤더는 Content-Type: text/html; charset=utf-8 이고 본문은 UTF-8 BOM 으로 시작한다. XML 선언만 encoding="utf-16" 으로 잘못 찍혀 있다. Bruno 는 헤더 charset 으로 디코딩하므로 Bruno 단계에서는 문제없고, 직접 파싱하는 클라이언트만 BOM 과 XML 선언을 떼고 UTF-8 로 읽으면 된다.