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>
This commit is contained in:
@@ -53,6 +53,8 @@ MCP는 Agent Builder가 `tools/call`에 명시한 단일 Tool을 실행한다. T
|
||||
| `ToolBundleDiscovery` | `registry` | 구현상 N개 Tool Service 매니페스트를 병렬 조회·검증하고 bundle별 last-good 상태를 유지. 최초 원격 조회 실패 시에만 설정된 local manifest fallback을 사용하며, 운영 배포는 1개 Bundle만 사용 |
|
||||
| `ToolBundleRegistryClient` | `registry` | 구현상 모든 bundle의 사용 가능한 성공본을 중복·총량 검증 후 하나의 snapshot으로 병합. 운영 배포에서는 단일 Bundle 결과를 채택 |
|
||||
| `RedisToolRegistryCache` | `registry` | best-effort Redis snapshot, 실제 read/write 실패를 cache miss로 격리 |
|
||||
| `ToolSchemaPatternPolicy` | `registry` | `ToolMetadata` 생성 시점에 `pattern` 정규식의 반복 구조·개수·길이와 대상 필드의 `maxLength`를 검사해 정규식 검증이 요청 스레드를 오래 붙잡지 못하게 한다([ADR-0012](decisions/ADR-0012-tool-input-schema-pattern-budget.md)) |
|
||||
| `ToolSchemaReferencePolicy` | `registry` | `ToolMetadata` 생성 시점에 `inputSchema`가 문서 밖을 참조하지 못하게 차단. 매니페스트가 검증기의 조회 대상을 정하는 통로를 막는다([ADR-0011](decisions/ADR-0011-tool-input-schema-stays-in-document.md)) |
|
||||
| `ToolRegistryRefreshScheduler` | `registry` | 기동 preload와 주기 refresh; 실패 시 애플리케이션 생존 |
|
||||
| `ToolArgumentValidator` | `execute` | 기존 required/type 오류 계약을 보존하고 MCP SDK JSON Schema 2020-12 검증 적용 |
|
||||
| `ToolExecutionService` | `execute` | 이름 기반 metadata 해석, argument validation, 단일 Tool 실행, HTTP 경계 로그와 오류 mapping |
|
||||
|
||||
@@ -179,7 +179,7 @@ MCP는 이 경우 직전 매니페스트를 그대로 유지한다. **선택 기
|
||||
| `name` | 예 | MCP 표준에 맞춘 `[A-Za-z0-9_./-]{1,64}`이며 bundle의 `namePrefix`로 시작해야 한다 |
|
||||
| `title` | 아니오 | 표시용 이름 |
|
||||
| `description` | 예 | 에이전트가 Tool 선택에 사용한다. 언제 쓰는 도구인지 명확히 쓴다 |
|
||||
| `inputSchema` | 예 | JSON Schema 2020-12 |
|
||||
| `inputSchema` | 예 | JSON Schema 2020-12. 아래 **schema 제약**을 만족해야 한다 |
|
||||
| `outputSchema` | 아니오 | `structuredContent` 응답 구조. 현재 MCP는 구조화 출력을 만들지 않으므로 운영에서는 사용하지 않는다 |
|
||||
| `annotations` | 아니오 | `readOnlyHint`, `destructiveHint`, `idempotentHint`, `openWorldHint` |
|
||||
| `_meta.version` | 예 | Tool 버전 |
|
||||
@@ -189,6 +189,24 @@ MCP는 이 경우 직전 매니페스트를 그대로 유지한다. **선택 기
|
||||
`name`, `title`, `description`, `inputSchema`, `outputSchema`, `annotations`는 MCP가 `tools/list`로
|
||||
그대로 공개한다. `_meta`는 공개하지 않는다.
|
||||
|
||||
#### schema 제약
|
||||
|
||||
MCP는 `inputSchema`를 검증기에 넘기기 전에 다음을 확인하고, 어기면 그 Tool이 실린 bundle을 실패로 처리한다.
|
||||
매니페스트 형식 오류와 같은 취급이므로 다른 bundle의 정상 Tool은 영향을 받지 않는다.
|
||||
|
||||
| 제약 | 내용 | 근거 |
|
||||
|---|---|---|
|
||||
| 문서 안 참조만 | `$ref`·`$dynamicRef`는 `#`으로 시작해야 한다. 공통 타입은 같은 문서의 `$defs`에 둔다 | [ADR-0011](../../decisions/ADR-0011-tool-input-schema-stays-in-document.md) |
|
||||
| dialect 고정 | `$schema`를 선언하면 `https://json-schema.org/draft/2020-12/schema`여야 한다 | ADR-0011 |
|
||||
| 정규식 반복 | 무한 수량자(`*`, `+`, `{n,}`)를 품은 그룹을 다시 반복할 수 없다. 바깥 반복 횟수가 유한해도 같다 | [ADR-0012](../../decisions/ADR-0012-tool-input-schema-pattern-budget.md) |
|
||||
| 정규식 수량자 | 무한 수량자는 정규식 하나당 3개까지 | ADR-0012 |
|
||||
| 정규식 길이 | `pattern`은 512자 이하이며 컴파일 가능해야 한다 | ADR-0012 |
|
||||
| 길이 상한 동반 | `pattern`을 선언한 필드는 `maxLength`를 함께 선언해야 하고 값은 256 이하 | ADR-0012 |
|
||||
| `patternProperties` 금지 | 이 keyword는 사용할 수 없다. 고정 key를 `properties`로 선언한다 | ADR-0012 |
|
||||
|
||||
마지막 항목이 가장 자주 걸린다. `{"type":"string","pattern":"^[0-9]{10}$"}`는 거부되고
|
||||
`{"type":"string","maxLength":10,"pattern":"^[0-9]{10}$"}`는 통과한다.
|
||||
|
||||
현재 MCP의 `tools/call`은 `content[0].text`만 반환하고 `structuredContent` 생성·응답 schema 검증은 하지 않는다.
|
||||
MCP 2025-11-25에서 `outputSchema`를 선언한 서버는 이에 맞는 구조화 결과를 제공해야 하므로, Tool Service는
|
||||
구조화 출력 지원이 별도 계약으로 반영되기 전까지 운영 매니페스트에서 `outputSchema`를 생략한다.
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
# ADR-0011 Tool inputSchema는 문서 밖을 참조하지 않는다
|
||||
|
||||
- 상태: Accepted
|
||||
- 결정일: 2026-08-18
|
||||
- 관련 결정: [ADR-0006](ADR-0006-no-authentication-in-mcp.md) · [ADR-0004](ADR-0004-execution-guardrails.md)
|
||||
|
||||
## 배경
|
||||
|
||||
MCP Java SDK를 도입하면서 JSON Schema 2020-12 검증을 `com.networknt:json-schema-validator`에 위임했다
|
||||
([mcp-java-sdk-adoption.md](../mcp-java-sdk-adoption.md)). 그런데 JSON Schema의 `$ref`는 같은 문서 안뿐 아니라
|
||||
**다른 주소의 문서**를 가리킬 수 있고, 검증기는 그런 참조를 만나면 그 주소로 직접 조회를 시도한다.
|
||||
|
||||
`inputSchema`는 Tool Service 매니페스트에서 온다. 즉 매니페스트에 이런 schema가 실리면
|
||||
|
||||
```json
|
||||
{"type":"object","properties":{"q":{"$ref":"http://any-host/whatever.json"}}}
|
||||
```
|
||||
|
||||
MCP가 그 주소로 요청을 보낸다. 이것은 [AGENTS.md §2](../../AGENTS.md)의 불변식과 정면으로 어긋난다.
|
||||
|
||||
> outbound 주소는 설정에서만 온다. 요청 값도 매니페스트도 호출 대상을 바꾸지 못한다.
|
||||
|
||||
매니페스트가 선언한 `endpoint`를 무시하는 규칙은 이미 있고 테스트로 잠겨 있다. `$ref`는 같은 불변식을
|
||||
같은 방식으로 깨는데 통제가 없던 경로였다. SDK 도입이 열어 놓은 구멍이다.
|
||||
|
||||
[ADR-0006](ADR-0006-no-authentication-in-mcp.md)에 따라 MCP는 인증·인가를 하지 않으므로, 이 경로 앞에서
|
||||
호출자를 걸러 주는 계층도 없다.
|
||||
|
||||
## SDK 설정으로는 막을 수 없다
|
||||
|
||||
`DefaultJsonSchemaValidator`는 `SchemaRegistry`를 생성자 안에서 직접 만들고 `private final`로 들고 있다.
|
||||
공개 생성자는 `()`와 `(ObjectMapper)` 둘뿐이라, 참조 해석 정책을 담은 설정을 밖에서 넣을 자리가 없다.
|
||||
검증기 쪽에서 끄는 선택지는 존재하지 않는다.
|
||||
|
||||
## 결정
|
||||
|
||||
**Tool의 `inputSchema`는 문서 밖을 가리키는 참조를 담을 수 없다.** 검증기에 넘기기 전에, schema가 Registry로
|
||||
들어오는 시점에 거부한다.
|
||||
|
||||
| 대상 | 규칙 |
|
||||
|---|---|
|
||||
| `$ref`, `$dynamicRef` | 값이 `#`으로 시작해야 한다. 즉 같은 문서 안의 위치만 가리킨다 |
|
||||
| `$schema` | 선언했다면 `https://json-schema.org/draft/2020-12/schema`여야 한다 |
|
||||
| `$id` | 제한하지 않는다 |
|
||||
|
||||
`$id`를 열어 두는 이유는, 문서 밖 참조가 모두 막히면 base URI가 무엇이든 조회가 일어나지 않기 때문이다.
|
||||
막을 이유가 없는 것까지 막으면 정상 Tool만 거부된다.
|
||||
|
||||
검사 지점은 `ToolMetadata`의 표준 생성자다. Portal 매니페스트 파싱, local 파일 로딩, Redis snapshot 역직렬화가
|
||||
모두 이 생성자를 지나므로 **경로마다 검사를 흩어 놓지 않아도 우회 경로가 생기지 않는다.**
|
||||
|
||||
위반은 기존 매니페스트 형식 오류와 같게 다룬다. 따라서 bundle 단위 실패 격리와 "Redis 실패는 언제나 cache miss"
|
||||
불변식이 그대로 적용되고, 한 Tool의 잘못된 schema가 다른 bundle의 정상 Tool을 지우지 않는다.
|
||||
|
||||
## 검토한 대안
|
||||
|
||||
| 대안 | 채택하지 않은 이유 |
|
||||
|---|---|
|
||||
| 검증기 설정으로 원격 해석 차단 | 위 절대로 주입 지점이 없다 |
|
||||
| `JsonSchemaValidator`를 직접 구현 | SDK에 표준 검증을 위임한다는 도입 전제를 되돌리게 된다. networknt API를 우리가 떠안고, SDK 업그레이드마다 정책이 조용히 어긋날 수 있다 |
|
||||
| egress 방화벽만으로 차단 | 심층 방어로는 유효하지만 단독으로는 부족하다. 플랫폼 설정에 의존하고, 차단되지 않은 내부 주소에는 여전히 도달한다 |
|
||||
|
||||
egress 통제는 이 결정을 대체하지 않고 함께 둔다.
|
||||
|
||||
## 영향
|
||||
|
||||
- Tool Service는 `inputSchema`를 자기 문서 안에서 완결시켜야 한다. 공통 타입은 `$defs`로 같은 문서에 넣고
|
||||
`#/$defs/...`로 참조한다. 이 항목은 합의 대상이 아니라 계약이므로
|
||||
[extension-points.md](../extension-points.md)의 협의 목록에서 뺀다.
|
||||
- `format` 키워드의 검증 강도와 허용 keyword 범위는 여전히 미확정이며 협의 목록에 남는다.
|
||||
- 새 참조 keyword가 JSON Schema에 추가되면 이 결정을 함께 갱신한다. 규칙은
|
||||
`ToolSchemaReferencePolicy`가 소유하고 `ToolSchemaReferencePolicyTest`가 잠근다.
|
||||
88
docs/decisions/ADR-0012-tool-input-schema-pattern-budget.md
Normal file
88
docs/decisions/ADR-0012-tool-input-schema-pattern-budget.md
Normal file
@@ -0,0 +1,88 @@
|
||||
# ADR-0012 Tool inputSchema의 정규식에 예산을 둔다
|
||||
|
||||
- 상태: Accepted
|
||||
- 결정일: 2026-08-18
|
||||
- 관련 결정: [ADR-0011](ADR-0011-tool-input-schema-stays-in-document.md) · [ADR-0006](ADR-0006-no-authentication-in-mcp.md) · [ADR-0004](ADR-0004-execution-guardrails.md)
|
||||
|
||||
## 배경
|
||||
|
||||
`inputSchema`의 `pattern` 검증은 `java.util.regex`로 처리된다. `com.networknt:json-schema-validator`의
|
||||
ECMAScript 엔진은 joni나 graal-js가 있을 때만 쓰이는데 둘 다 해석하지 않으므로
|
||||
([SBOM](../sbom/README.md)), 기본 경로인 `JDKRegularExpression`이 `Pattern.compile` 후 `Matcher.find()`를
|
||||
호출한다. `matches()`가 아니라 `find()`라서 모든 시작 위치를 시도한다.
|
||||
|
||||
이 엔진은 백트래킹 기반이라 정규식과 입력의 조합에 따라 처리 시간이 폭증한다. 정규식은 Tool Service
|
||||
매니페스트에서 오고 입력은 Agent Builder에서 오며, [ADR-0006](ADR-0006-no-authentication-in-mcp.md)에 따라
|
||||
호출자를 걸러 주는 계층이 없다. 한 요청이 스레드를 붙잡으면 그대로 Tomcat 스레드 고갈로 이어진다.
|
||||
|
||||
## 측정
|
||||
|
||||
규칙을 감으로 정하지 않기 위해 JDK 21.0.11에서 직접 재어 보았다. 3초 안에 끝나지 않으면 HANG으로 적었다.
|
||||
|
||||
| 정규식 | n=100 | n=1000 | n=10000 |
|
||||
|---|---|---|---|
|
||||
| `a*a*b` (무한 수량자 2개) | 4ms | 481ms | **HANG** |
|
||||
| `a*a*a*b` (3개) | 17ms | **HANG** | **HANG** |
|
||||
| `a*a*a*a*b` (4개) | 432ms | **HANG** | **HANG** |
|
||||
| `a*a*a*a*a*b` (5개) | **HANG** | **HANG** | **HANG** |
|
||||
| `(.*,){11}P` | **HANG** | **HANG** | **HANG** |
|
||||
| `(x+x+)+y` | 5ms | **HANG** | **HANG** |
|
||||
| `^[^@ ]+@[^@ ]+$` (무한 수량자 2개) | 4ms | 4ms | **4ms** |
|
||||
| `^([A-Z]{3}-)+[0-9]+$` | 1ms | 1ms | 1ms |
|
||||
|
||||
두 가지가 드러났다.
|
||||
|
||||
**첫째, 교과서적인 중첩 수량자는 생각보다 덜 위험하고 다른 형태가 더 위험하다.** `^(a+)+$`는 n=60에서도
|
||||
0ms로 끝났다. 반면 중첩이 아닌 `a*a*a*a*a*b`는 n=100에서 이미 멈췄고, 바깥 반복이 11회로 **묶여 있는**
|
||||
`(.*,){11}P`도 멈췄다. "중첩된 무한 수량자만 막으면 된다"는 통념대로 짰다면 정작 위험한 것을 놓쳤을 것이다.
|
||||
|
||||
**둘째, 개수만으로는 가를 수 없다.** `a*a*b`와 `^[^@ ]+@[^@ ]+$`는 둘 다 무한 수량자가 2개인데 전자는
|
||||
멈추고 후자는 n=10000에서도 4ms다. 차이는 수량자가 **겹치는 문자 집합**에 걸리느냐다. `@`가 경계를 만들면
|
||||
되돌아갈 여지가 없다. 겹침 판정은 정적 분석 대상이고 일반적으로 결정 불가능하다.
|
||||
|
||||
## 결정
|
||||
|
||||
정규식 모양만으로는 안전을 가릴 수 없으므로, **가릴 수 있는 것은 모양으로 막고 나머지는 입력 길이로 묶는다.**
|
||||
검사는 `ToolSchemaPatternPolicy`가 `ToolMetadata` 생성 시점에 수행한다.
|
||||
|
||||
| 규칙 | 내용 | 근거 |
|
||||
|---|---|---|
|
||||
| 그룹 반복 | 무한 수량자를 품은 그룹을 다시 반복하면 거부. 바깥 반복 횟수에 상한이 있어도 거부 | `(x+x+)+y`, `(.*,){11}P` |
|
||||
| 수량자 개수 | 무한 수량자 4개 이상이면 거부 | 4개는 n=1000, 5개는 n=100에서 멈춤 |
|
||||
| 길이 상한 | `pattern`을 선언한 필드는 `maxLength`를 함께 선언해야 하고 256 이하여야 함 | 비용이 입력 길이를 따라 늘어남 |
|
||||
| 정규식 길이 | 512자 이하 | 분석 비용을 함께 묶음 |
|
||||
| 컴파일 | 등록 시점에 `Pattern.compile` | 잘못된 정규식이 요청 시점에 터지지 않게 |
|
||||
| `patternProperties` | 사용 금지 | 아래 참조 |
|
||||
|
||||
`maxLength` 요구가 이 결정의 핵심이다. 나머지 규칙은 겹침을 판정하지 못하므로, 실질적인 상한은 길이 제한이
|
||||
만든다. 상한이 없으면 요청 body 한도(약 1MB)까지 열린다.
|
||||
|
||||
한도 값은 설정으로 열지 않고 상수로 둔다. [ADR-0006](ADR-0006-no-authentication-in-mcp.md)의 NetworkPolicy와
|
||||
같은 이유다. values 한 줄로 사라질 수 있는 통제는 통제가 아니다.
|
||||
|
||||
## 이 결정이 하지 않는 것
|
||||
|
||||
**안전을 증명하지 않는다.** 무한 수량자 3개 이하이면서 문자 집합이 겹치는 정규식은 통과하고, `maxLength`가
|
||||
256이면 그 조합에서 수백 ms가 걸릴 수 있다. 이 결정은 위험을 없애지 않고 **측정된 폭증 구간 밖으로 옮긴다.**
|
||||
|
||||
근본적인 해결은 백트래킹하지 않는 엔진(RE2 계열)으로 바꾸거나 검증에 시간 예산을 두는 것이다. 둘 다 지금
|
||||
채택하지 않았다. 전자는 폐쇄망 반입 대상 의존성이 늘고 networknt가 그 엔진을 지원하는지 확인해야 하며,
|
||||
후자는 `java.util.regex`가 인터럽트에 반응하지 않아 검증기 내부에 우리 `CharSequence`를 넣을 수 없으면
|
||||
스레드를 버리는 방식이 된다. 필요가 생기면 이 ADR을 대체하는 새 ADR을 먼저 쓴다.
|
||||
|
||||
## 영향
|
||||
|
||||
- **Tool Service는 `pattern`을 쓰는 문자열 필드에 `maxLength`(≤256)를 함께 선언해야 한다.** 이는 매니페스트
|
||||
수용 조건의 변경이므로 Tool Service 파트와 합의가 필요하다. 현재 저장소의 schema 중 `pattern`을 쓰는 것은
|
||||
없어 기존 fixture는 영향을 받지 않는다.
|
||||
- **`patternProperties`는 쓸 수 없다.** 이 keyword는 값이 아니라 입력 객체의 **key**에 정규식을 적용하는데,
|
||||
key에는 길이를 선언할 자리가 없어 위의 `maxLength` 방식을 그대로 적용할 수 없다. `propertyNames`로 key 길이를
|
||||
묶는 방법을 검토했으나, JSON Schema는 keyword 평가 순서를 정하지 않으므로 `propertyNames`가 먼저 돈다는
|
||||
보장이 없다. 순서에 기대는 통제는 검증기 구현이 바뀌면 조용히 사라진다.
|
||||
|
||||
현재 어떤 Tool도 이 keyword를 쓰지 않으므로, 묶을 수 없는 위험을 남겨 두는 대신 쓰지 않는 기능을 닫는다.
|
||||
이는 [ADR-0006](ADR-0006-no-authentication-in-mcp.md)이 검증하지 않는 인증 코드를 지운 것과 같은 판단이다.
|
||||
동적 key가 실제로 필요해지면 key 길이를 묶는 방법을 정한 새 ADR을 먼저 쓴다. 부작용으로, `patternProperties`
|
||||
라는 이름의 업무 필드를 가진 schema도 거부된다. 실제로 나타날 가능성이 낮아 감수한다.
|
||||
- 규칙과 한도는 `ToolSchemaPatternPolicy`가 소유하고 `ToolSchemaPatternPolicyTest`가 잠근다. 위 측정을 다시
|
||||
하지 않고 한도를 바꾸지 않는다.
|
||||
@@ -22,3 +22,5 @@
|
||||
| [ADR-0008](ADR-0008-shared-host-path-routing.md) | 공유 host의 path를 독립 MCP 배포로 연결 | Superseded |
|
||||
| [ADR-0009](ADR-0009-container-handles-public-mcp-path.md) | 컨테이너가 공개 MCP path를 직접 처리 | Accepted |
|
||||
| [ADR-0010](ADR-0010-portal-owns-route-and-endpoint-registry.md) | Tool Server endpoint 목록과 route 매핑의 원천은 Portal | Accepted |
|
||||
| [ADR-0011](ADR-0011-tool-input-schema-stays-in-document.md) | Tool inputSchema는 문서 밖을 참조하지 않는다 | Accepted |
|
||||
| [ADR-0012](ADR-0012-tool-input-schema-pattern-budget.md) | Tool inputSchema의 정규식에 예산을 둔다 | Accepted |
|
||||
|
||||
@@ -34,7 +34,13 @@
|
||||
|
||||
1. `GET {manifestUrl}` 제공, 인증 방식과 NetworkPolicy 범위
|
||||
2. Tool name namespace, 변경·폐기 절차와 하위 호환 기간
|
||||
3. 허용할 JSON Schema 2020-12 keyword, 원격 `$ref`와 `format` 정책
|
||||
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 알림의 필요성
|
||||
|
||||
@@ -108,8 +108,23 @@ SDK 검증은 `ToolExecutionService`가 Registry 기반 argument validation을
|
||||
3. 실패하면 Tool Service를 호출하지 않고 기존 `JsonRpcException(INVALID_PARAMS)`으로 종료한다. SDK 원문 오류는
|
||||
입력값을 포함할 수 있으므로 외부에는 `arguments do not match inputSchema`만 반환한다.
|
||||
|
||||
SDK validator는 Spring singleton으로 한 번 생성되며 동일 schema의 컴파일 결과를 재사용한다. Registry가 제공하는
|
||||
schema 자체의 허용 dialect와 `$ref` 원격 해석 정책은 운영 Registry 계약으로 별도 통제해야 한다.
|
||||
SDK validator는 Spring singleton으로 한 번 생성되며 동일 schema의 컴파일 결과를 재사용한다.
|
||||
|
||||
Registry가 제공하는 schema 자체의 허용 dialect와 `$ref` 해석 범위는
|
||||
[ADR-0011](decisions/ADR-0011-tool-input-schema-stays-in-document.md)로 확정했다. `ToolSchemaReferencePolicy`가
|
||||
`ToolMetadata` 생성 시점에 문서 밖 `$ref`·`$dynamicRef`와 2020-12가 아닌 `$schema`를 거부하므로, 검증기가 schema에
|
||||
적힌 주소로 조회를 시도할 수 있는 경로가 남지 않는다. `DefaultJsonSchemaValidator`는 `SchemaRegistry`를 내부에서
|
||||
생성해 정책 주입 지점을 열어 두지 않으므로, 이 통제는 SDK 밖에서만 걸 수 있다. `format` 키워드의 검증 강도는 아직
|
||||
협의 항목이다.
|
||||
|
||||
`pattern` 정규식은 joni·graal-js를 해석하지 않아 `java.util.regex`로 검증된다. 백트래킹 폭증을 막기 위해
|
||||
`ToolSchemaPatternPolicy`가 반복 구조·수량자 개수·정규식 길이를 제한하고 `maxLength` 동반 선언을 요구한다
|
||||
([ADR-0012](decisions/ADR-0012-tool-input-schema-pattern-budget.md)). 측정 근거와 남는 위험은 그 ADR에 있다.
|
||||
|
||||
`format`은 단언하지 않는다. 2020-12에서 format-assertion은 opt-in이고 SDK 검증기가 이를 켜지 않으므로,
|
||||
`format: "date-time"`이나 `format: "ipv4"`에 임의 문자열을 넣어도 통과한다. 덕분에 입력 값을 정규식으로
|
||||
컴파일하는 `format: "regex"` 경로도 실행되지 않는다. 이 동작은 `ToolArgumentValidatorTest`가 고정하므로,
|
||||
SDK 업그레이드로 단언이 켜지면 테스트가 실패해 알 수 있다.
|
||||
|
||||
## 6. 의도적으로 도입하지 않은 SDK 기능
|
||||
|
||||
|
||||
Reference in New Issue
Block a user