Claude와 ChatGPT가 MCP를 통해 라이브 웹사이트를 편집하게 하면서 배운 점
요약
Claude와 ChatGPT 같은 LLM을 활용하여 라이브 웹사이트를 직접 편집하는 시스템 구축 경험과 교훈을 공유합니다. 특히, 단순 검색/읽기(read)가 아닌 '쓰기(write)' 작업에 초점을 맞추어 낙관적 동시성 제어 및 스키마 분리 등 실질적인 개발 방안을 제시했습니다.
핵심 포인트
- 전체 페이지를 대체하는 단일 도구(`put_page`) 사용이 안정적입니다.
- 낙관적 동시성 제어를 통해 오래된 버전의 쓰기를 명확히 실패 처리해야 합니다.
- 모든 블록 카탈로그는 MCP 리소스로 분리하여 모델에게 제공하세요.
- 외부 URL 이미지 대신, 모든 이미지를 다운로드하여 자체 저장하는 것이 안전합니다.
저희는 크리에이터와 소규모 비즈니스를 위한 링크 인 바이오 및 웹사이트 빌더인 Keepp을 운영하고 있습니다. 이 서비스는 웹사이트, 판매 기능, 예약 기능, 양식, 채팅 등을 하나의 페이지에 담고 있습니다. 몇 주 전 저희는 MCP 서버를 출시하여 Claude와 ChatGPT가 해당 페이지들을 직접 구축하고 편집할 수 있게 했습니다. 사용자가 채팅창에 "제 새로운 수업 시간과 예약 버튼을 추가해 주세요"라고 말하면, 어시스턴트가 실제 공개된 페이지를 변경합니다.
이는 데이터를 읽거나 검색을 실행하는 대부분의 MCP 서버와는 다른 작업입니다. 저희의 서버는 남들이 볼 수 있는 무언가를 '쓰기(write)'로 만듭니다. 여기서 얻은 교훈은 다음과 같습니다.
1. 모델이 전체 문서를 작성하게 하되, 오래된 쓰기는 실패하도록 처리하기
저희의 첫 번째 생각은 작은 도구들을 수십 개 만드는 것이었습니다: 블록 추가, 블록 이동, 색상 변경 등. 하지만 모델들은 이 작업에 취약했습니다. 순서 추적을 놓치거나, 부분적으로 적용된 변경 사항이 생기거나, 페이지가 일관되지 않게 되었습니다.
작동했던 것은 put_page라는 단 하나의 도구였습니다. 이 도구는 전체 페이지 문서를 대체합니다. 모델은 get_page를 호출하여 받은 내용을 편집하고, 완성된 블록 목록을 전송합니다. 빠진 내용은 모두 삭제되며, 도구 설명에 그 내용이 명확히 나와 있습니다.
위험 요소는 분명합니다: 소유자가 어시스턴트가 변경하는 중간에 에디터에서 페이지를 수정하면, 어시스턴트가 이를 덮어쓰게 됩니다. 따라서 모든 get_page 호출은 version을 반환하고, put_page는 이 버전을 요구하며, 오래된 버전으로의 쓰기는 조용히 성공하는 대신 명확한 오류와 함께 실패하도록 했습니다. 낙관적 동시성 제어(Optimistic concurrency)가 서버 전체에서 가장 중요한 방어 장치임이 밝혀졌습니다.
2. 스키마를 모든 도구 목록에서 분리하기
페이지는 여러 블록 유형을 가지고 있으며, 각 유형은 고유한 필드를 가집니다. 이 모든 것을 put_page의 입력 스키마에 넣으면, 호스트가 모델에게 보내는 모든 도구 목록이 매 턴마다 부풀어 올랐습니다.
저희는 전체 블록 카탈로그를 MCP 리소스로 옮겼습니다. 도구 설명은 이 리소를 가리키고, 따라서 모델은 필요할 때 한 번 읽게 되며, 매 요청에 모든 내용을 담지 않아도 됩니다. 도구 목록은 간결하게 유지되었지만, 페이지를 구축하는 데 필요한 모든 필드는 여전히 모델에게 제공되었습니다.
3. 모델이 제공하는 URL을 절대 신뢰하지 않기
모델들은 자신이 발견한 곳 어디에서든 이미지 URL을 페이지에 바로 넣는 것을 좋아합니다. 이로 인해 공개된 페이지가 다른 사람의 서버에 의존하게 되며, 그 이미지들 중 일부는 하루 뒤 사라지기도 합니다.
이제 작성(write)에 포함된 모든 이미지 URL은 다운로드되어 저희 측에 저장되며, 이는 작성의 일부가 됩니다. 만약 이미지를 가져올 수 없다면 전체 작성이 실패하고 해당 블록을 명시합니다. 모델은 정확히 무엇이 잘못되었는지 통보받고 보통 다음 시도에서 이를 수정합니다.
4. 모든 경로에서 구조화된 결과 반환하기
호스트들은 도구 결과를 다르게 처리합니다. 어떤 것은 모델에게 텍스트 콘텐츠만 보여주고, 어떤 것은 structuredContent를 읽습니다. 저희는 모든 도구에 대해 outputSchema를 선언하고, 가독성 있는 문장과 함께 모든 성공 경로에서 구조화된 콘텐츠를 반환합니다. 만약 어떤 도구가 이 중 하나라도 누락되면 빌드가 실패합니다.
안전 관련 힌트도 마찬가지입니다. 각 도구는 코드베이스의 한 테이블을 통해 읽기 전용인지, 파괴적인지, 또는 외부 세계에 영향을 미치는지 선언하므로, 호스트가 사용자에게 먼저 물어볼 시점을 결정할 수 있습니다.
5. 네이티브 클라이언트용 OAuth는 모든 포트에서 루프백(loopback) 필요
OAuth를 통한 원격 MCP는 브라우저 호스트에서는 처음에는 작동했습니다. 하지만 Claude Code와 같은 네이티브 클라이언트는 임의의 포트를 가진 localhost에서의 콜백을 통해 로그인하는 과정에서 문제가 발생했습니다. 저희 리디렉션 확인 기능은 정확한 일치를 요구했기 때문입니다.
수정 사항은 네이티브 앱 사양에 있습니다: 루프백 리디렉트 URI는 모든 포트에서 허용됩니다. 이 점을 수용한 후, 어디서든 로그인이 작동했습니다. 또한 클라이언트 ID 메타데이터 문서 덕분에 저희가 신경 쓰는 호스트들에 대해 동적 클라이언트 등록이 필요하지 않게 되었습니다.
6. 다른 호스트는 다른 도구 세트가 필요함
모든 호스트가 모든 도구를 원하는 것은 아닙니다. 일부 앱 디렉토리는 어시스턴트 내에서 구독 판매를 허용하지 않기 때문에, 그러한 클라이언트의 경우 실패하게 두는 대신 계획(plan) 도구를 완전히 숨깁니다. 목록 표시 시점에 클라이언트로 필터링하는 것이 호출 시점에 거부하는 것보다 더 깔끔합니다.
실제 작동 예시
그 결과, 크리에이터는 Claude나 ChatGPT를 열고 Keepp에 한 번 연결한 다음 원하는 것을 말할 수 있습니다: 제품 3개가 있는 상점, 세션 예약 페이지, 문의 양식 및 채팅 기능이 있는 페이지입니다. 어시스턴트는 카탈로그를 읽고 페이지를 작성하며, 라이브 URL과 각 부분이 개별 페이지로 열리는 링크들을 돌려줍니다.
만약 공개적인 곳에 쓰는 MCP 서버를 구축하고 있다면, 요점은 다음과 같습니다: 모델에게 버전 확인이 가능한 전체 문서를 제공하고, 큰 스키마는 리소스에 보관하며, 모델이 건네주는 모든 에셋을 소유하고, 어디서든 구조화된 결과를 반환해야 합니다.
MCP 서버 연결 방법 등을 포함한 저희 개발자 문서(developer docs)는 keepp.link/developers에서 확인하실 수 있습니다. Keepp 자체는 keepp.link에 있습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기