Files
dap-was-dapms/docs/extension-points.md
koseokmin d64516b50a Tool inputSchema의 문서 밖 참조와 정규식 폭증을 수신 시점에 차단한다
MCP Java SDK 도입으로 들어온 json-schema-validator는 schema의 $ref가 문서
밖을 가리키면 그 주소로 직접 조회하고, pattern 검증을 백트래킹 기반
java.util.regex로 처리한다. inputSchema는 Tool Service 매니페스트에서 오므로
매니페스트가 서버의 outbound 대상과 CPU 소비를 정할 수 있었다. AGENTS.md의
"outbound 주소는 설정에서만 온다"는 불변식이 이 경로에서 뚫려 있었다.

DefaultJsonSchemaValidator는 SchemaRegistry를 생성자 안에서 만들고 private
final로 들고 있어 정책 주입 지점이 없다. 따라서 SDK 밖에서만 막을 수 있다.

검사는 ToolMetadata의 표준 생성자에 둔다. Portal 매니페스트, local 파일,
Redis snapshot 역직렬화가 모두 이 생성자를 지나므로 우회 경로가 생기지 않는다.
위반은 기존 매니페스트 형식 오류와 같게 다뤄 bundle 단위 실패 격리와
"Redis 실패는 언제나 cache miss" 동작을 그대로 유지한다.

정규식 규칙은 JDK 21.0.11 실측으로 정했다. 통념과 달리 (a+)+는 빠르게 끝나고,
중첩이 아닌 a*a*a*a*a*b와 바깥 반복이 유한한 (.*,){11}P가 폭증했다. 겹치는
문자 집합 판정은 결정 불가능하므로 모양 검사만으로는 부족하고, pattern 필드에
maxLength 동반 선언을 요구해 입력 길이를 묶는 것이 실질적인 상한이 된다.
patternProperties는 key에 길이를 선언할 자리가 없어 사용을 금지한다.

format은 단언되지 않아 format:regex 경로가 실행되지 않는다는 사실도 계약
테스트로 고정했다. SDK 업그레이드로 단언이 켜지면 테스트가 실패한다.

Tool Service는 pattern을 쓰는 필드에 maxLength(<=256)를 선언해야 하므로
매니페스트 수용 조건이 바뀐다. Tool Service 파트와 합의가 필요하다.

근거: ADR-0011, ADR-0012

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 14:44:01 +09:00

99 lines
9.4 KiB
Markdown

# 미합의 항목과 확장 포인트
이 문서는 **아직 결정되지 않았거나 운영 적용 전에 보완할 내용만** 관리한다. 현재 동작 설명은 [architecture.md](architecture.md), Agent Builder wire 계약은 [v0.3](contracts/agent-builder-mcp/protocol-v0.3-streaming-policy.md), Tool Service wire 계약은 [bundle 조회 v0.2](contracts/tool-service-mcp/protocol-v0.2-bundle-discovery.md)가 정본이다.
결정이 끝난 항목은 ADR 또는 현재 계약으로 옮기고 이 목록에서 제거한다. 목표안인 [Agent Builder-MCP v1 기준선](contracts/agent-builder-mcp/protocol-v1-agreement-baseline.md)은 전체 payload가 승인되기 전까지 구현 근거가 아니다.
## Agent Builder와 합의할 항목
1. 여러 MCP protocol version 공존 시 fallback·upgrade와 공지 정책
2. Tool name 변경·폐기 시 구·신 이름의 rolling 호환 기간과 Agent 재등록 정책
3. Agent Builder가 `tools/list`를 다시 읽는 **주기**. 주기적으로 읽는다는 것까지는 확인됐고 값은 미정이다.
Agent Builder는 MCP 등록 시점에 Tool 정보를 자기 DB에 저장해 계속 사용하므로, Tool 변경이 실제로 반영되기까지
걸리는 시간은 **MCP의 매니페스트 갱신 주기 + Agent Builder의 조회 주기**다. 두 값을 각자 정하면 합이 얼마인지
아무도 모르게 되므로 함께 정한다
4. Agent Builder 내부 UID와 표준 MCP `name`의 lifecycle. UID는 MCP wire 계약에 포함하지 않음
5. Agent별 최대 50개 Tool 선별 로직과 권한 거부 시 Agent Builder가 사용자에게 보일 응답
6. client disconnect 시 downstream cancellation 계약. 현재 MCP는 이미 시작한 Tool 호출을 취소하지 않는다
(계층별 budget 배분은 [architecture.md의 요청 시간 예산](architecture.md#요청-시간-예산)에서 확정)
7. Tool 원본 오류·업무 코드·PII를 Agent Builder에 노출하거나 마스킹하는 기준
8. response 크기, pagination/continuation과 대용량 결과 정책
9. retry가 같은 업무 요청인지 판별하는 규칙과 `guid` 재사용 여부. 같은 `guid`를 재사용하기로 합의한 뒤에만 Tool Service의 멱등성 키로 사용
10. `employee-no`·`virtual-employee-no`가 둘 다 없는 요청을 Agent Builder가 보낼 수 있는지, 언젠가 필수로 승격할지
11. **주기 `tools/list`가 실패했을 때 DB의 Tool 정보를 어떻게 처리하는가.** 직전 목록을 유지하는지, 비우는지에 따라
MCP 재기동·배포 중 수십 초 공백이 Agent에 그대로 드러날 수 있다. 중요 등급 MCP의 replica 하한과 PodDisruptionBudget은
이 답과 무관하게 [ADR-0007](decisions/ADR-0007-one-mcp-per-tool-service.md)에서 이미 강제하지만,
답에 따라 비중요 등급의 배포 방식도 달라진다
12. 같은 환경 host의 여러 공개 path를 Agent Builder에 등록·변경·폐기하는 절차와 주체. path 처리는
[ADR-0009](decisions/ADR-0009-container-handles-public-mcp-path.md)로 확정했지만, 배포 수가 Tool Service 수와 같아
10~20개 이상일 때의 등록 자동화는 미정이다
인증 주체는 [ADR-0006](decisions/ADR-0006-no-authentication-in-mcp.md)에서 확정했다. MCP는 인증·인가를 하지 않는다.
## Tool Service와 합의할 항목
1. `GET {manifestUrl}` 제공, 인증 방식과 NetworkPolicy 범위
2. Tool name namespace, 변경·폐기 절차와 하위 호환 기간
3. 허용할 JSON Schema 2020-12 keyword와 `format` 정책. **현재 SDK 검증기는 `format`을 단언하지 않는다.**
`format: "date-time"`에 아무 문자열이나 넣어도 통과하므로, Tool Service가 이를 입력 검증 수단으로
기대하면 안 된다. 단언을 켤지, 아니면 `pattern`으로 대체할지 정해야 한다. 현재 동작은
`ToolArgumentValidatorTest`가 고정한다. 문서 밖 `$ref`
[ADR-0011](decisions/ADR-0011-tool-input-schema-stays-in-document.md)로, `pattern`의 반복 예산과
`maxLength` 동반 선언 요구는 [ADR-0012](decisions/ADR-0012-tool-input-schema-pattern-budget.md)로
확정했다. **ADR-0012는 매니페스트 수용 조건을 바꾸므로 Tool Service 파트와 합의가 필요하다**
4. Tool별 timeout, 권한 scope, write Tool의 idempotency 보장
5. `outputSchema`/`structuredContent` 도입 여부와 응답 검증 실패 의미
6. 매니페스트 revision·ETag/304 및 즉시 refresh 알림의 필요성
7. 사원 식별자 검증 방식: KMS 키 배포 범위(위조 방지 가능 여부), 동일 암호문 재사용 허용 여부, 만료·nonce 도입 여부.
[ADR-0006](decisions/ADR-0006-no-authentication-in-mcp.md) 전제 2가 이 항목에 의존한다
8. Tool 이름의 **전역 유일성 보장 방법**. 등급으로 나뉜 두 Tool Service가 같은 업무 `namePrefix`를 공유하므로
(`처리계-중요``처리계-비중요`가 모두 `processing.`), 그 안에서 이름이 겹치지 않게 하는 것은 Tool Service 책임이다.
MCP는 자기 bundle의 prefix만 검증하며 다른 MCP의 이름을 알지 못한다([ADR-0007](decisions/ADR-0007-one-mcp-per-tool-service.md))
9. Tool의 **가용성 등급 분류 기준과 변경 절차**. 이 문서에서 위험도는 보안 정책이 아니라 중단 시 업무
영향도를 뜻한다. 등급이 바뀌면 그 Tool을 제공하는 MCP endpoint가 바뀌므로 Agent Builder 반영이
필요하다. 자주 바뀌지 않는 값으로 다룰 수 있는지 확인한다
MCP와 Tool Service를 1:1로 묶는 결정은 [ADR-0007](decisions/ADR-0007-one-mcp-per-tool-service.md)에서 확정했다.
현재 서버는 `tools/call` 결과를 `content[0].text`로만 반환한다. `structuredContent`를 지원하기 전까지 운영 매니페스트에는 `outputSchema`를 사용하지 않는다.
## 플랫폼·DevOps와 확인할 항목
배포 정의를 이 저장소가 어디까지 소유하는지 확정되지 않았다.
현재는 [Helm Chart](../deploy/helm/mcp-server/)만 두고 있으며, 빌드·배포 실행 방식은 정의하지 않는다.
1. **Helm Chart를 어디에 두는가.** 앱 저장소인가 배포 전용 저장소인가
2. 환경별 namespace 명명 규칙과 Agent Builder namespace.
후자는 Route를 우회한 Pod 직접 접근의 허용 출처이므로 [ADR-0006](decisions/ADR-0006-no-authentication-in-mcp.md)의 전제와 직결된다
3. 사내 Nexus에 `io.modelcontextprotocol.sdk:mcp-json-jackson2:2.0.0`과 Spring Boot 3.5.11가 있는가.
없으면 라이브러리 반입이 선행되어야 한다
4. 사내 registry의 JDK 21 빌드·실행 이미지 이름. 현재 `Dockerfile`은 외부 이미지를 쓴다
5. 소스 개행 표준(CRLF)과 `gradlew`의 관계.
shell script가 CRLF이면 Linux 컨테이너에서 실행되지 않으므로 예외 또는 우회 방식이 필요하다
6. 환경별 실제 `global.mcpHost`, 인증서와 TLS termination 책임
7. Agent Builder의 실제 고정 egress CIDR과 Route `ip_allowlist`
8. 대상 OpenShift의 ingress namespace label과 IngressController endpoint publishing 방식이 Chart의 NetworkPolicy 전제와 맞는지
## 운영 적용 전 필수 보완
| 영역 | 현재 상태 | 필요한 결정·구현 |
|---|---|---|
| egress | 절대 HTTP(S) 여부만 검증 | host allowlist, redirect·DNS rebinding 방어, mTLS/NetworkPolicy |
| 장애 격리 | timeout과 last-good 제공 | 측정 후 bulkhead·circuit breaker·제한적 retry 결정 |
| 관측성 | 경계 로그와 bundle Actuator 제공 | Micrometer/OpenTelemetry/SIEM 지표와 경보 기준 |
| 감사 | 일반 애플리케이션 로그만 제공 | 보존 대상·기간·암호화·위변조 방지·유실 정책 확정 후 durable sink |
| 용량 | request body 1 MiB 제한 | response 크기, JSON depth, 동시 실행 수, connection pool 부하 기준 |
| Redis | 요청 경로 밖의 선택 cache. Tool snapshot cache는 route별 key(`key-prefix:identity:v2:route:{routeToken}`)로 분리하고, Portal registry fallback key와도 분리한다. Portal registry fallback key 기본값은 `axhub:mcp:portal-registry`이며 운영에서는 `mcp.redis.portal-registry-key`로 포털 저장 key와 반드시 맞춘다. | Redis 사용 여부, key namespace·schema version·TTL·공유 범위, TLS/ACL, Sentinel/Cluster, rolling upgrade 정책 |
| 종료 | Spring graceful shutdown | 신규 요청 차단과 진행 중 Tool 호출 drain 검증 |
| 가용성 | test·prod critical의 replica·PDB·노드 분산 values를 정적 테스트가 검사하고 usable snapshot으로 readiness 판정. 공개 Route도 배포마다 분리 | `helm lint/template`, 노드 분산 실제 확인, 배포 창 분리, 쿼터 산정. 공유 ingress·DNS 장애는 path 분할로 막히지 않는다 |
## 코드 확장 경계
- 새 MCP method: `McpMethodHandlerRegistry.Handler` 구현 하나를 추가하고 SDK method 상수를 사용한다.
- Tool metadata: 새 원천을 만들지 말고 local fixture 또는 Tool Service 매니페스트 계약을 확장한다.
- Tool protocol: 실제 두 번째 protocol이 필요할 때만 `ToolClient` 구현을 추가한다.
- 인증: 추가하지 않는다. 필요가 생기면 [ADR-0006](decisions/ADR-0006-no-authentication-in-mcp.md)을 대체하는 ADR을 먼저 쓴다.
- 규제 감사: 저장·전달 보장이 합의된 뒤 HTTP/Tool 경계에 durable sink를 연결한다.
새 interface, mapper, DTO, cache 계층은 현재 경계로 해결할 수 없는 요구가 확인되기 전에는 추가하지 않는다.