MCP search·fetch 설계법: ChatGPT deep research에 인용 가능한 내부 지식 붙이기
OpenAI의 MCP server 문서는 ChatGPT deep research와 company knowledge, API research workflow에 내부 지식을 붙이는 최소 인터페이스를 꽤 구체적으로 제시한다. 핵심은 remote MCP server가 search와 fetch라는 read-only 도구를 제공하고, 결과에 citation 가능한 URL을 포함하는 구조다. 내부 문서 검색을 대충 붙이면 답은 나오지만, 출처와 감사가 무너진다.
검색 의도는 ‘MCP search fetch schema를 어떻게 설계해야 하는가’다. 실무 개발자에게 중요한 건 FastMCP 예제 자체보다 도구의 반환값, citation behavior, approval 정책, prompt injection 방어다. 특히 ChatGPT가 citation metadata를 만들려면 url이 비어 있지 않은 문자열이어야 한다는 점은 운영 품질에 직접 영향을 준다.
search와 fetch를 분리하는 이유
문서 검색 도구를 하나로 만들고 싶어지는 유혹이 있다. query를 받으면 관련 문서 전체를 반환하게 하면 구현은 쉽다. 하지만 deep research나 company knowledge 용도에서는 search와 fetch를 나누는 편이 낫다.
search는 관련 후보 목록을 반환한다. 각 결과에는 id, title, url이 들어간다. 모델은 어떤 문서를 더 읽을지 고른다. fetch는 특정 id의 전문 또는 충분한 본문을 반환한다. 이 구조는 비용과 추적성을 개선한다. 모든 문서를 한 번에 모델에게 던지지 않고, 필요한 후보만 펼친다.
또한 search result와 fetch result의 id가 안정적이어야 한다. 같은 문서가 매번 다른 id로 나오면 citation과 캐시가 깨진다. 내부 문서라면 Notion page id, Confluence page id, Git blob hash, vector store file id 같은 안정 식별자를 쓰는 편이 좋다.
structuredContent와 content를 같이 반환한다
OpenAI 문서는 MCP 응답에서 structuredContent를 반환하고, compatibility를 위해 같은 값을 JSON 문자열로 content 배열에도 넣는 형태를 보여준다. 이중 반환은 귀찮아 보이지만 client 호환성을 위해 중요하다. 어떤 클라이언트는 구조화 필드를 읽고, 어떤 클라이언트는 text content를 본다.
반환 schema도 명시해야 한다. FastMCP에서는 Pydantic 모델로 output schema를 만들 수 있다. schema가 있으면 client가 결과 형태를 검증할 수 있고, 도구가 이상한 데이터를 반환했을 때 빨리 잡을 수 있다.
실무에서는 search result를 너무 풍부하게 만들지 않는 편이 낫다. title, canonical URL, 짧은 snippet, updatedAt 정도면 충분하다. 권한 없는 본문 일부나 민감 metadata를 search 단계에서 흘리면 안 된다. 자세한 내용은 fetch에서 권한을 다시 확인하고 반환한다.
citation 가능한 URL을 설계한다
문서에는 ChatGPT가 citation metadata를 만들려면 url 필드가 non-empty string이어야 한다고 적혀 있다. title만 있고 URL이 없으면 평범한 tool output이 될 뿐 citation으로 취급되지 않는다.
내부 문서에서 이 부분이 자주 막힌다. Notion, Google Drive, Confluence, 사내 wiki가 외부에서 접근 불가능한 URL을 갖고 있거나, 권한에 따라 링크가 달라지기 때문이다. 그래도 canonical URL은 필요하다. 사용자가 클릭했을 때 권한이 있으면 원문으로 이동하고, 권한이 없으면 접근 요청 페이지로 이동하는 구조가 좋다.
파일 기반 지식이라면 https://internal.example.com/docs/{id} 같은 resolver URL을 만들 수 있다. resolver는 사용자의 SSO 권한을 확인하고 원문을 보여준다. MCP server가 임시 presigned URL을 citation으로 넣는 것은 조심해야 한다. 링크가 만료되면 나중에 답변의 출처가 깨진다.
approval 정책은 read-only라도 명시한다
OpenAI 예제는 search와 fetch가 read-only라서 API request에서 approval을 skip할 수 있다고 설명한다. 이 말은 read-only 도구가 무조건 안전하다는 뜻이 아니다. 내부 문서 검색은 개인정보, 고객 계약, 보안 취약점 문서를 노출할 수 있다.
따라서 approval 이전에 권한 검사가 있어야 한다. MCP server는 사용자의 workspace, group, document ACL을 확인해야 한다. 모델이 어떤 query를 보냈든, 서버는 해당 사용자가 볼 수 있는 문서만 search result로 반환해야 한다. fetch에서도 다시 확인해야 한다. Search에서 보였다고 fetch를 무조건 허용하면 race condition이나 권한 변경에 취약하다.
쓰기 도구를 추가할 계획이라면 search/fetch와 같은 서버에 섞지 않는 편이 좋다. 읽기 전용 지식 서버와 쓰기 가능한 업무 서버를 나누면 approval과 감사가 쉬워진다.
prompt injection 방어는 문서 본문에서 시작된다
MCP server가 반환하는 문서 본문은 외부 콘텐츠일 수 있다. 고객 이메일, 웹페이지, 이슈 본문, 로그 파일 안에는 모델에게 지시하는 문장이 들어갈 수 있다. OpenAI 문서도 prompt injection risk를 별도로 경고한다.
방어의 기본은 문서 본문을 ‘명령’이 아니라 ‘데이터’로 취급하게 하는 것이다. system instruction만으로는 부족하다. 도구 권한을 좁히고, search/fetch 서버는 읽기 전용으로 유지하고, fetch 결과 안의 지시문이 tool approval을 바꿀 수 없게 해야 한다.
또한 반환값에 provenance를 붙이는 편이 좋다. source system, document id, updatedAt, author, sensitivity label을 metadata로 넣으면 답변 후 검토가 쉬워진다. 단, 민감 metadata 자체가 유출 정보가 될 수 있으므로 사용자에게 보여줄 값과 audit log에만 남길 값을 구분해야 한다.
vector store를 쓸 때의 운영 기준
OpenAI 예제는 vector store search를 사용한다. 실무에서는 임베딩 색인과 원문 권한을 같이 관리해야 한다. 문서를 삭제했는데 vector store chunk가 남아 있으면 큰 사고다. 문서 권한이 바뀌었는데 색인 결과가 계속 보이는 것도 문제다.
운영 기준은 세 가지다. 첫째, ingestion pipeline은 문서 id와 ACL version을 함께 저장한다. 둘째, search 결과 반환 직전에 현재 권한을 다시 확인한다. 셋째, fetch는 원문 저장소나 최신 승인된 snapshot에서 가져온다. 오래된 vector chunk만으로 fetch를 구성하면 삭제와 수정이 반영되지 않을 수 있다.
검색 품질 평가도 필요하다. query 50개 정도를 만들고, 기대 문서가 search top 5에 들어오는지, fetch 본문이 답변에 충분한지 테스트한다. 내부 지식 MCP는 모델 성능보다 검색 recall과 권한 정확도가 먼저다.
실행 체크리스트
- remote MCP server는 read-only
search와fetch를 먼저 구현한다. - search result에는 안정적인
id, 사람이 읽을title, citation 가능한 canonicalurl을 넣는다. - fetch result에는
id,title,text,url, 필요한 metadata를 반환한다. structuredContent와 compatibility용 JSON text content를 함께 제공한다.- search와 fetch 모두에서 현재 사용자 권한을 다시 확인한다.
- citation URL은 만료 링크보다 SSO가 붙은 canonical resolver를 쓴다.
- 문서 본문은 명령이 아니라 데이터로 취급하고, 쓰기 도구와 읽기 도구를 분리한다.
- vector store 색인은 삭제, 권한 변경, 최신 원문과 동기화되는지 테스트한다.
출처: OpenAI API Docs, Building MCP servers for plugins and API integrations; Model Context Protocol documentation