- sap/: abap-mcp 의 catalog/sap_client/mcp_server 복사. import 와 .env 탐색만 이 저장소에 맞춤 - ingest/from_sap.py: 패키지명 → GET_PROGRAM_LIST → GET_PROGRAM_SOURCE(+Include) → data/raw/*.txt (normalize 가 읽는 수집 JSON 형식 그대로). 받은 파일은 건너뛰고 --force 로 재수집 - normalize: 응답의 TCODE_LIST 를 tcodes.jsonl 로 (from_dir 와 같은 모양, 로더가 적재) - .env.example 에 SAP_URL/SAP_USER/SAP_PASS, tests/test_from_sap.py Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
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] # 툴 목록 + 실제 호출 점검
접속 정보는 .env 의 SAP_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_list … get_tcode_info, get_object_type (17개, 메서드명 소문자) |
파라미터는 IV_ 를 뗀 소문자 (IV_MAX_ROWS → max_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줄로 돌아온다.
호출 규약 (실측)
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 기준 모두 해결)
-
2026-09-04 해결.GET_VERSION_SOURCE과거 버전 → HTTP 500SVRS_GET_REPS_FROM_OBJECT로 교체 (REPS 만 지원) -
2026-09-04 해결. 함수 Include 를 통째로 읽도록 교체 (출처가GET_FUNCTION_DETAIL의FUNC_SOURCE항상 빈값RETURN.MESSAGE에 찍힘) -
2026-09-04 해결.GET_PROGRAM_SOURCEinclude 목록에 클래스 include 노이즈 혼입=포함 또는 30자 초과 이름 제거 -
2026-09-04 해결. n+1 건을 읽어 초과 시 W (실측 ZFI01 PROG 1,132건)GET_OBJECT_LIST_BY_PACKAGE상한에서 잘려도TYPE=S -
2026-09-04 해결. W + 잘린 엘리먼트 이름, 0건은 빈 RESULT XMLGET_FIELD_LIST_BY_TEXTUSED_TABLES 20건 상한이 조용히 잘림 / 후보 0건이면 응답 본문 0바이트 -
목록 API 기본 상한 200 / 최대 2,0002026-09-04 A안으로 제거. 생략 시 전건(안전 상한 50,000),RETURN.TOTAL_ROWS추가. 실측: 테이블*전건 822,899건 → 50,000건 W, 8.7MB, 8초 -
2026-09-04 제거. 후보 500개씩 청크 조회, 사용 테이블 총량 50,000 넘으면 중단 + W. 실측 '회사코드' 전건 499후보/6,949건 0.8MB, '코드' 14,000후보 → 안전 상한 W 10MB/4초GET_FIELD_LIST_BY_TEXTUSED_TABLES 엘리먼트당 20건 고정 상한
수정 소스는 ~/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 로 읽으면 된다.