“Tauri 앱의 빌드가 실패한 이유를 찾아 주세요.” 에이전트에 로그 읽기 도구를 연결했는데, 수천 줄의 경고와 의존성 메시지가 매번 대화에 들어옵니다. 정작 필요한 것은 실패한 단계, 관련 진단 몇 개, 그 진단의 원문일 수 있습니다.
이때 바꿀 수 있는 것은 모델뿐만이 아닙니다. 도구가 무엇을 반환하고, 다음에 무엇을 읽을 수 있게 하는지부터 설계해 볼 수 있습니다. 공개 구현 사례를 참고해 ‘검색 결과는 작게, 근거는 다시 읽을 수 있게’ 만드는 방법을 살펴보겠습니다. 아래 빌드와 진단 데이터는 모두 가상입니다. 자료 확인 기준은 2026년 10월 19일, Asia/Seoul입니다.
공개 구현에서 가져올 원칙
Anthropic의 도구 설계 글은 전체 목록을 반환하는 도구보다 작업에 맞춘 검색 도구를 만들고, 응답에 필터·페이지 구분·범위 선택을 제공하라고 권합니다. 필요한 경우 간결한 응답과 상세 응답을 선택하게 하는 방법도 설명합니다. 여기서 가져올 원칙은 정보를 삭제하는 것보다 필요한 정보를 선택할 경로를 만드는 것입니다.
Cloudflare는 2025년 Code Mode 구현 소개에서 MCP 도구를 TypeScript API로 바꾸고, 여러 호출의 중간 결과를 실행 환경에서 다룬 뒤 필요한 출력만 모델에 전달하는 구조를 공개했습니다. 이는 공개된 구현 사례이며, 모든 앱에서 같은 효과를 보장하는 비교 실험은 아닙니다.
Anthropic의 MCP 코드 실행 설명도 결과를 코드로 필터링한 뒤 모델에 전달하는 패턴을 보여줍니다. 다만 모델이 만든 코드를 실행하려면 격리·자원 제한·관찰 체계가 추가됩니다. 이 글에서는 더 작은 출발점으로, 개발자가 작성한 고정 함수가 검색과 응답 제한을 담당하는 구조를 제안합니다. 아래 예제가 Code Mode나 MCP 서버를 구현한 것은 아닙니다.
로그 저장소와 모델의 읽기 경로 나누기
가상 빌드 도우미에는 search_diagnostics와 read_diagnostic 두 작업을 둡니다. 검색은 빌드 ID·심각도·검색어로 범위를 줄이고, 짧은 진단 목록을 반환합니다. 원문 조회는 선택한 진단 ID와 줄 범위를 받아 주변 로그를 반환합니다. 두 응답 모두 크기를 제한해야 합니다.
그림은 이 글의 설계안이며 특정 제품의 내부 구조도가 아닙니다. 역할은 다음처럼 나눌 수 있습니다.
- Rust CLI 또는 Python 백엔드는 실행 결과를 파싱하고, 정렬된 진단과 원문을 빌드 스냅샷에 보관합니다. 모델에 보낼 요약에는 ID·제목·심각도처럼 다음 판단에 필요한 필드만 넣습니다.
- 에이전트 실행기는 검색 조건과 허용된 도구 호출을 처리합니다. 원문을 변수에 보관했더라도 그대로 출력하면 다시 모델 컨텍스트에 들어가므로 반환 지점까지 관리합니다.
- React·Tauri 화면은 요약 옆에 ‘원문 보기’와 다음 페이지를 제공합니다. 모델이 읽은 범위와 사용자가 펼쳐 본 범위를 구분해 표시할 수 있습니다. 이것은 적용 제안이며 실제 앱 구현·실험 결과는 아닙니다.
페이지의 total_matches는 이번 검색 조건에 맞는 진단 수입니다. 원본 로그의 모든 문제를 발견했다는 뜻은 아닙니다. next_cursor가 남아 있는데 “다른 오류는 없다”고 결론 내리지 않도록 도구 설명에도 이 차이를 적습니다.
작은 TypeScript 예제: 응답 전체의 바이트 예산
아래 함수는 이미 검색·정렬된 가상 진단을 받아 페이지를 만듭니다. 전체 JSON을 잘라 유효하지 않은 응답을 만드는 대신, 항목을 하나씩 추가하며 메타데이터를 포함한 직렬화 결과가 예산 안에 드는지 확인합니다. 제목에 한글이 들어가므로 문자열 길이 대신 UTF-8 바이트 수를 셉니다.
type Diagnostic = {
id: string;
title: string;
severity: 'error' | 'warning';
detail: string;
};
export function makePager(input: Diagnostic[], maxBytes = 800) {
if (!Number.isSafeInteger(maxBytes) || maxBytes < 1) {
throw new Error('maxBytes must be a positive safe integer');
}
// 검색 결과를 복사해 고정한다. 원문과 불필요한 필드는 내보내지 않는다.
const rows = input.map(({ id, title, severity }) => ({ id, title, severity }));
const snapshot = 'demo-build-v1';
const bytes = (value: unknown) =>
new TextEncoder().encode(JSON.stringify(value)).byteLength;
return (cursor: string | null = null) => {
const match = cursor === null ? null : /^demo-build-v1:(0|[1-9]\d*)$/.exec(cursor);
if (cursor !== null && !match) throw new Error('restart search: invalid snapshot/cursor');
const start = match ? Number(match[1]) : 0;
if (!Number.isSafeInteger(start) || start > rows.length) {
throw new Error('cursor offset out of range');
}
const envelope = (items: typeof rows) => {
const end = start + items.length;
return {
snapshot_id: snapshot,
total_matches: rows.length,
returned: items.length,
items,
next_cursor: end < rows.length ? `${snapshot}:${end}` : null,
};
};
let items: typeof rows = [];
for (const row of rows.slice(start, start + 2)) {
const candidate = [...items, row];
if (bytes(envelope(candidate)) > maxBytes) break;
items = candidate;
}
const result = envelope(items);
if (bytes(result) > maxBytes || (items.length === 0 && start < rows.length)) {
throw new Error('page cannot fit: shorten summary or increase budget');
}
return result;
};
}
const page = makePager(Array.from({ length: 5 }, (_, i) => ({
id: `diag-${i}`, title: `가상 진단 ${i}`,
severity: 'warning', detail: 'x'.repeat(1000),
})));
console.log(page());
1페이지는 최대 두 항목이며 detail을 포함하지 않습니다. 한 항목도 들어가지 않으면 같은 커서를 끝없이 반환하는 대신 명시적으로 실패합니다. 호출자는 오류를 사용자에게 알리고 요약 길이나 예산을 조정해야 합니다. 오류를 빈 검색 결과로 바꾸면 안 됩니다.
800바이트는 설명용 선택이며 토큰 제한이 아닙니다. 토큰 수는 모델과 인코딩에 따라 달라집니다. 실제 모델 입력에는 도구 메시지 포장과 이전 대화도 더해집니다. 이 함수는 한 응답 객체의 바이트 수만 제한하며, 입력 전체의 메모리 사용량이나 전체 대화의 토큰 사용량을 제한하지 않습니다.
예제의 스냅샷 이름은 고정된 데모 값입니다. 운영에서는 서버가 사용자·검색 조건·정렬·빌드 버전에 연결된 고유 스냅샷을 만들고, 만료된 커서는 재검색하게 해야 합니다. ID나 커서를 안다는 사실은 접근 권한이 아닙니다. 원문 조회에서도 같은 사용자 권한을 다시 확인합니다. 위 함수에는 인증, 저장소, 원문 조회, MCP 전송 계층이 없습니다.
MCP 2025-06-18판 Tools 명세는 구조화된 결과와 리소스 링크를 표현할 수 있게 합니다. 다만 명세의 tools/list 페이지 구분은 도구 목록에 대한 것입니다. 이 예제의 검색 결과 커서는 애플리케이션에서 설계한 별도 계약입니다. 일반 JSON을 반환한다고 MCP 응답 구현까지 끝나는 것은 아닙니다.
팀 업무에 적용하는 순서
- 읽기 작업 하나를 고릅니다. 예를 들어 “최근 실패 빌드에서 첫 원인 후보와 근거 줄 찾기”로 좁힙니다. 가상 로그에 알려진 정답 진단과 관련 줄을 표시합니다.
- 서버에서 먼저 줄입니다. 빌드 ID, 단계, 심각도 필터와 안정된 정렬을 적용합니다. 원문 전체를 모델에 보낸 뒤 요약시키는 방식과 구분합니다. 큰 결과는 저장소 쿼리 단계에서도 제한해야 합니다.
- 요약과 재조회를 함께 연결합니다. 제목만 줄이고 ID를 없애면 근거로 돌아갈 수 없습니다. 원문 조회에도 줄 범위와 최대 크기를 두고, 생략된 앞뒤 범위가 있는지 알립니다.
- UI에서 읽은 범위를 보입니다. React 결과 카드에 빌드 버전·일치 건수·다음 페이지·원문 링크를 표시합니다. Tauri에서는 원문 조회를 허용된 백엔드 명령으로 연결하고, 모델이 준 경로를 그대로 파일 읽기에 사용하지 않습니다.
- 기존 방식과 같은 문제로 비교합니다. 전체 로그 전달과 검색 후 재조회를 같은 모델·로그·질문으로 반복합니다. 모델과 도구 설명의 버전, 실제 입력 토큰, 호출 횟수, 총 지연, 정답 진단 발견 여부와 근거 인용의 정확도를 함께 기록합니다.
토큰이 줄어도 검색이 원인을 누락하면 업무 효과는 나빠질 수 있습니다. 반대로 작은 페이지 때문에 호출이 늘면 지연이 커질 수 있습니다. 첫 페이지만 보고 놓친 원인, 여러 진단에 걸친 원인, 빈 결과와 만료된 스냅샷을 평가에 포함해야 합니다. 이 글에서는 모델을 호출한 비교 실험을 하지 않았으므로 비용 절감률·정확도 향상·실제 빌드 진단 성능을 주장하지 않습니다.
실행해 본 것과 남은 한계
본문 TypeScript 코드 블록을 그대로 추출해 Node.js 24.19.0에서 실행했습니다. 별도 검사에서는 다섯 진단의 페이지 순회에 누락·중복이 없는지, 원문 필드가 빠지는지, 한글을 포함한 응답의 바이트 상한이 지켜지는지 확인했습니다. 잘못된 커서·범위 밖 커서·한 항목도 담을 수 없는 예산의 오류도 확인했습니다. 실행 명령은 node --experimental-strip-types /tmp/jubee-19-pager.ts와 node --experimental-strip-types --test /tmp/jubee-19-pager.test.ts입니다.
위 가상 데이터 다섯 건을 그대로 JSON으로 직렬화하면 5,376바이트였습니다. 같은 다섯 건의 요약을 끝까지 읽으면 세 페이지가 각각 230·230·154바이트로, 합계 614바이트였습니다. 이는 TextEncoder와 같은 UTF-8 기준으로 측정한 데이터 표현 크기입니다. 원문을 제외한 효과이며 호출은 세 번 필요합니다. 이후 원문을 읽는 비용, 전송 포장과 이전 대화는 포함하지 않았고 토큰·시간·정확도를 측정한 수치도 아닙니다.
이 검사는 순수 함수의 응답 계약에 대한 것입니다. 실제 Rust 컴파일러 출력 파싱, Python 서비스, React·Tauri 통합, MCP 클라이언트 동작과 LLM의 원인 추론은 실행 검증하지 않았습니다. 원문 안의 지시문은 신뢰할 수 없는 데이터로 취급해야 하며, 작은 응답만으로 프롬프트 인젝션 문제가 해결되지는 않습니다.
영상 접근 범위와 출처
Latent Space의 Context Engineering for Agents — Lance Martin, LangChain 공개 에피소드 페이지는 2025년 9월 11일 게시일, 주제별 목차와 YouTube 영상 링크를 제공합니다. 페이지의 14:48 검색, 24:51 컨텍스트 정리 표시는 주최 측 목차를 확인한 범위입니다. YouTube 페이지에서는 영상 본문·자막을 확보하지 못했고, 주최 측 페이지에서도 전체 전문을 읽지 못했습니다. 영상·음성을 시청했다거나 해당 구간의 발언을 검증했다고 주장하지 않습니다. YouTube 채널명·영상 업로드 날짜도 별도로 확인하지 못해 추정하지 않았습니다. 기술적 주장은 아래 공식 원문으로 확인했습니다.
- Anthropic — Writing effective tools for agents — 발행 2025-09-11, 별도 개정일 미표기, 확인 2026-10-19. 검색 중심 도구, 응답 상세도와 페이지·필터 설계의 근거입니다.
- Cloudflare — Code Mode: the better way to use MCP — 발행 2025-09-26, 별도 개정일 미표기, 확인 2026-10-19. TypeScript API와 실행 환경에서 중간 결과를 처리하는 공개 구현 설명입니다. 당시 소개된 API의 현재 제공 상태나 요금은 이 글의 범위가 아닙니다.
- Anthropic — Code execution with MCP — 발행 2025-11-04, 별도 개정일 미표기, 확인 2026-10-19. 결과 필터링 패턴과 실행 환경의 추가 부담을 확인했습니다.
- Model Context Protocol — Tools, 2025-06-18판 — 명세 버전 날짜 2025-06-18, 페이지 발행·개정일 별도 미표기, 확인 2026-10-19. 최신판이라는 주장이 아니라 이 글에서 확인한 특정 판입니다.
- Latent Space — 공개 에피소드 안내 · YouTube — 안내 페이지 게시 2025-09-11, YouTube 업로드 날짜 미확인, 확인 2026-10-19. 영상 내용의 근거로 사용하지 않았습니다.