9.4 KiB
DISC-20260827-001 요청 기반 TTL Refresh 설계 메모
- 상태: Open
- 논의 기준일: 2026-08-27
- 보안 등급: 내부용
- 적용 여부: 적용, scheduler polling 제거 후 요청 시점 TTL refresh 사용
이 문서는 MCP가 포털 registry와 Tool Server manifest를 주기적으로 polling하지 않고, Agent 요청 시점에 필요한 경우만 갱신하는 방안을 보존한다. 현재 구현은 이 방향을 적용해 기동 preload 이후 scheduler polling을 수행하지 않는다.
이름
요청 기반 TTL Refresh(Request-driven TTL Refresh)
배경
현재 MCP는 서버 기동 시 포털과 Tool Server를 조회하고, 이후 scheduler를 통해 포털 registry와 Tool Server manifest를 주기적으로 다시 호출한다. 이 방식은 단순하지만 요청이 없어도 외부 호출이 계속 발생한다.
검토 중인 대안은 scheduler와 배치를 사용하지 않고, Agent가 tools/list 또는 tools/call을 요청할 때 마지막 확인 시각을 기준으로 TTL이 만료되었는지 판단한 뒤 필요한 외부 API만 다시 호출하는 방식이다.
목표
- 포털 registry와 Tool Server manifest의 주기 scheduler 호출을 제거하거나 비활성화한다.
- 요청이 없는 route에 대해서는 외부 호출을 발생시키지 않는다.
- TTL 안에서는 기존 in-memory snapshot을 즉시 사용한다.
- TTL이 지난 첫 요청에서 포털과 Tool Server 원천을 best-effort로 재확인한다.
- refresh 실패 시 기존 snapshot을 유지해 요청 경로의 안정성을 보존한다.
비목표
- Redis Stream이나 Pub/Sub 기반 실시간 이벤트 동기화는 이 문서의 직접 구현 대상이 아니다.
- 포털이나 Tool Server에 revision 전용 API를 새로 요구하지 않는다.
- Agent가 Tool을 선택하는 방식이나 Tool Service의 업무 권한 처리는 변경하지 않는다.
- MCP가 Tool을 자동 선택하거나 대체 Tool을 추천하지 않는다.
기본 아이디어
서버 기동 시에는 현재와 같이 최초 원천 조회를 수행한다.
MCP 기동
-> 포털 registry API 호출
-> routeKey별 Tool Server endpoint 목록 확보
-> Tool Server manifest API 호출
-> routeKey별 Tool 목록과 실행 endpoint 확보
-> in-memory snapshot 저장
-> 마지막 확인 시각 저장
이후에는 scheduler가 아니라 Agent 요청이 들어왔을 때 TTL을 확인한다.
Agent 요청: POST /mcp/{routeKey}
-> routeKey 검증
-> 포털 registry 마지막 확인 시각 확인
-> Tool Server manifest 마지막 확인 시각 확인
-> TTL 미만이면 기존 memory snapshot 사용
-> TTL 초과이면 기존 API를 다시 호출해 revision 비교
-> 변경 있으면 snapshot 교체
-> 변경 없으면 마지막 확인 시각만 갱신
-> 요청 처리 계속 진행
포털 처리 방식
포털에는 revision 전용 API가 없다고 가정한다. 따라서 서버 기동 시 호출하던 포털 registry API를 TTL 만료 시 다시 호출하고, 응답 body 안의 registry revision을 비교한다.
포털 TTL 만료
-> 기존 포털 registry API 호출
-> registryRevision 비교
-> 같으면 endpoint snapshot 유지, lastCheckedAt 갱신
-> 다르면 endpoint snapshot 교체
-> 포털 변경이 있었던 route는 Tool Server manifest 강제 재조회 대상이 됨
포털 API 호출 실패 시 정책은 다음과 같다.
기존 endpoint snapshot 있음
-> WARN 로그만 남김
-> 기존 endpoint snapshot 유지
기존 endpoint snapshot 없음
-> Redis portal registry fallback 시도
-> Redis도 없으면 registry unavailable
Tool Server 처리 방식
Tool Server에도 revision 전용 API가 없다고 가정한다. 따라서 서버 기동 시 호출하던 Tool Server manifest API를 TTL 만료 시 다시 호출하고, 응답 body 안의 manifest revision 또는 그에 준하는 값을 비교한다.
Tool manifest TTL 만료
-> 기존 Tool Server manifest API 호출
-> manifest revision 비교
-> 같으면 Tool snapshot 유지, lastCheckedAt 갱신
-> 다르면 Tool snapshot 교체
Tool Server manifest 호출 실패 시 정책은 다음과 같다.
기존 Tool snapshot 있음
-> WARN 로그만 남김
-> 기존 Tool snapshot 유지
기존 Tool snapshot 없음
-> Redis route별 Tool snapshot fallback 시도
-> Redis도 없으면 registry unavailable
포털 변경과 Tool manifest 변경의 관계
포털과 Tool Server는 서로 다른 원천을 가진다.
포털
-> routeKey별 Tool Server serviceDomain, manifestPath, serviceKey 관리
Tool Server manifest
-> Tool name, title, description, inputSchema, 실행 endpoint, manifest revision 관리
포털 revision이 바뀌면 Tool Server endpoint나 manifestPath가 바뀌었을 수 있으므로, Tool manifest TTL이 아직 남아 있어도 영향 route의 manifest는 다시 조회하는 것이 안전하다.
반대로 포털 revision이 같아도 Tool Server 내부 Tool 목록은 바뀔 수 있으므로, Tool manifest TTL이 만료되면 manifest API는 별도로 다시 호출해야 한다.
요청 처리 정책
tools/list와 tools/call 모두 실제 처리 전에 같은 fresh check를 수행하는 방향을 검토한다.
tools/list
-> ensureFreshIfExpired(routeKey)
-> listTools(routeKey)
-> Agent에 Tool 목록 반환
tools/call
-> ensureFreshIfExpired(routeKey)
-> findEnabledTool(routeKey, toolName)
-> inputSchema 검증
-> Tool Server 호출
이렇게 해야 오래된 Tool 목록과 오래된 실행 endpoint를 동시에 줄일 수 있다.
동시 요청 처리
TTL이 지난 시점에 같은 route로 요청이 여러 개 몰리면 외부 API 중복 호출이 발생할 수 있다. route별 single-flight를 적용해 첫 요청 하나만 refresh를 수행하고 나머지 요청은 같은 결과를 기다리거나 기존 snapshot을 사용하도록 정책을 정해야 한다.
우선 검토안은 다음과 같다.
같은 route refresh 진행 중
-> 다른 요청은 진행 중인 refresh 결과를 기다림
-> refresh timeout은 짧게 유지
-> 실패하면 기존 snapshot으로 진행
실패 처리 원칙
TTL refresh는 최신화를 위한 보조 동작이지, 기존 정상 snapshot을 비우는 동작이 아니다.
원천 조회 성공
-> revision 비교
-> 변경 시 memory snapshot 교체
-> Redis 저장은 best-effort
원천 조회 실패 + 기존 memory 있음
-> 기존 memory 유지
-> 요청 처리 계속
원천 조회 실패 + 기존 memory 없음
-> Redis fallback 시도
-> Redis도 실패하면 registry unavailable
stale Tool 보정과의 관계
이미 검토한 404/410 stale Tool refresh는 유지한다.
Tool call 중 upstream 404 또는 410 발생
-> 삭제되었거나 더 이상 제공되지 않는 Tool일 수 있음
-> TTL과 무관하게 해당 route manifest refresh 시도
-> 현재 요청은 Tool 실행 실패로 응답
-> 다음 요청부터 최신 snapshot 사용 가능
이 기능은 삭제된 Tool 호출에 대한 즉시 보정이고, 요청 기반 TTL Refresh는 추가·수정·endpoint 변경까지 포함한 일반 갱신 정책이다.
장점
- 요청이 없는 동안 포털과 Tool Server 호출이 발생하지 않는다.
- scheduler thread와 주기 설정 부담이 줄어든다.
- route별로 실제 사용되는 대상만 갱신할 수 있다.
- 기존 in-memory snapshot, Redis fallback, single-flight 구조를 재사용할 수 있다.
- Redis Stream 이벤트 기반 구조로 가기 전 중간 단계로 적용하기 쉽다.
단점과 주의점
- TTL이 지난 뒤 첫 Agent 요청은 외부 API 확인 때문에 느려질 수 있다.
- 변경 반영은 즉시가 아니라 최대 TTL만큼 지연될 수 있다.
- revision 전용 API가 없으므로 변경 확인만 하려 해도 기존 API 전체 body를 다시 받아야 한다.
- 같은 route 요청이 동시에 들어올 때 중복 refresh 방어가 필요하다.
- scheduler가 사라지면 요청이 전혀 없는 route는 갱신되지 않는다.
설정 후보
mcp:
registry:
refresh-mode: request-ttl
refresh-ttl-seconds: 300
refresh-on-startup: true
portal:
refresh-ttl-seconds: 300
discovery:
manifest-refresh-ttl-seconds: 300
현재 구현 설정 이름은 refresh-ttl-seconds다. scheduler 모드는 유지하지 않는다.
구현 후보
후보 메서드 이름은 다음과 같다.
registryService.ensureFreshIfExpired(routeKey);
예상 호출 위치는 다음과 같다.
ToolsListHandler.handle()
ToolExecutionService.execute()
기존 scheduler는 제거하고 기동 preload만 남긴다.
확정 전 확인할 질문
- TTL 기본값은 5분으로 할지, 운영에서 별도 값으로 둘지.
- TTL 만료 시 refresh를 요청이 기다릴지, 기존 snapshot으로 먼저 응답하고 비동기 refresh할지.
- 포털 registry revision 필드명과 Tool Server manifest revision 필드명이 무엇인지.
- 포털 revision 변경 시 모든 route를 다시 볼지, 변경된 route만 볼 수 있는지.
- scheduler 모드는 제거하는 것으로 확정했다.
- Redis 도입 후 이 방식은 fallback으로 남길지, 이벤트 기반으로 대체할지.
현재 판단
이 방식은 Redis Stream 이벤트 기반 구조가 도입되기 전까지 외부 호출량을 줄이고 route별 최신성을 일정 수준 유지하는 중간 구현이다.