MCP 서버를 Claude 디렉토리에 통합하는 과정과 그 과정에서 발생한 문제점
요약
소셜 미디어 스케줄러 Fuxux의 MCP 서버를 Claude와 같은 LLM 환경에 통합하는 과정에서 발생한 기술적 문제점들을 분석했습니다. 특히, 인증 실패 시 401 Unauthorized 상태 코드와 `WWW-Authenticate` 헤더를 통해 정확한 오류 정보를 제공해야 하며, OAuth 표준 준수 및 다양한 클라이언트(Claude/ChatGPT)의 특성을 고려한 메타데이터 지원이 필수적임을 강조합니다.
핵심 포인트
- 인증 실패 시 단순 연결 실패가 아닌 401 상태 코드와 WWW-Authenticate 헤더를 반환해야 함.
- OAuth 표준에 따라 `/.well-known` 경로의 JSON 파일들을 정확하게 구현해야 함.
- Claude/ChatGPT 등 LLM 환경은 URL 형태의 클라이언트 ID 메타데이터 문서를 사용하므로 이를 지원해야 함.
- 동적 클라이언트 등록(Dynamic registration)과 메타데이터 문서 두 가지 방식을 모두 지원해야 안정적임.
저는 Alex입니다. 제가 직접 Fuxux를 구축했습니다. 이것은 소셜 미디어 스케줄러로, 한 번 게시물을 작성하면 Instagram, TikTok, YouTube, LinkedIn, X, Threads, Bluesky, Pinterest 등 여러 플랫폼에 각각의 캡션과 함께 자동으로 게시됩니다.
제가 원했던 것은 단 하나였습니다. Claude를 열고 '내일 오전 9시에 LinkedIn에 이것을 예약해 줘'라고 입력했을 때 실제로 그 작업이 수행되는 것이었습니다. Fuxux에는 이미 MCP 서버가 있었지만, 이는 사용자가 클라이언트에 붙여넣는 API 키로 작동했습니다. Cursor에게는 괜찮았지만, Claude의 디렉토리나 ChatGPT에게는 쓸모가 없었습니다. 왜냐하면 키를 붙여넣을 곳이 없기 때문입니다. 그들은 여러분의 서버가 로그인 처리를 담당하기를 원합니다.
대부분의 작업은 아무도 알려주지 않는 사소한 것들로 이루어졌습니다. 그래서 제가 발견한 순서대로 여기에 정리했습니다.
1. 제 서버는 잘못된 방식으로 실패하고 있었습니다
자격 증명(credentials) 없이 요청이 들어왔을 때, 저는 내부 오류 메시지를 담아 200 응답 코드를 반환했습니다. 합리적이라고 생각했지만, 그렇지 않았습니다. 로그인 기능을 지원하는 클라이언트는 실제 401 상태 코드와 함께 어디를 봐야 하는지 알려주는 헤더가 도착했을 때만 플로우를 시작합니다:
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer resource_metadata="https://www.fuxux.com/.well-known/oauth-protected-resource", scope="mcp"
이 헤더가 없으면 클라이언트는 단순히 연결 실패라고만 표시할 뿐, 더 이상 참고할 만한 정보를 제공하지 않습니다.
2. 정확해야 하는 두 개의 작은 JSON 파일
/.well-known/oauth-protected-resource는 '여기가 리소스이며, 이 서버가 그것을 보호한다'고 명시합니다.resource값은 사람들이 연결하는 정확한 URL이어야 합니다. 제 경우의 값은https://www.fuxux.com/api/mcp입니다.www를 누락하거나 끝에 슬래시(/)를 추가하는 것만으로도 작동이 멈추기 충분하며, 왜 문제가 생겼는지 아무도 알려주지 않습니다./.well-known/oauth-authorization-server는 인증(authorize), 토큰(token) 및 등록(registration) 엔드포인트를 나열하고,S256을 사용한 PKCE를 지원하며, 공개 클라이언트가 안전하다(`token_endpoint_auth_methods_supported: [
저는 모든 클라이언트가 이전 예시에서 보여주는 것처럼 동적 클라이언트 등록(dynamic client registration)을 통해 자신을 등록할 것이라고 예상했습니다. 그런데 Claude를 연결했는데도 호출하지 않았습니다.
Claude는 URL 형태의 클라이언트 ID를 전송합니다. 이 URL을 가져오면 클라이언트 이름과 사용자를 다시 보낼 위치가 담긴 작은 문서가 제공됩니다. ChatGPT도 자체 문서를 사용하여 동일한 작업을 수행합니다. 따라서 두 가지 방식을 모두 지원해야 합니다:
- 클라이언트 ID 메타데이터 문서(Client ID Metadata Documents): Claude와 ChatGPT용입니다. 메타데이터에
client_id_metadata_document_supported: true를 포함시키세요. - 동적 등록(Dynamic registration): 여전히 이를 사용하는 도구들을 위한 것입니다. 건너뛰지 마세요. 최근 다른 카탈로그에 제출했을 때, 서버가 해당 기능을 갖추지 못한 한 회사가 자체 제출을 철회하는 것을 보았습니다.
ChatGPT는 또 하나의 놀라운 점을 안겨주었습니다. 그 문서에는 token_endpoint_auth_method: "private_key_jwt"라고 되어 있고 지원 목록에 ["none", "private_key_jwt"]가 포함되어 있습니다. 제 코드는 none만 메서드로 허용했기 때문에, ChatGPT 사용자들이
이건 예상치 못한 문제였습니다. 매시간 제 서버를 확인하는 디렉토리가 갑자기 이를 '비정상(unhealthy)'으로 표시했습니다. 아무것도 고장 난 것이 아니었습니다. 그들의 확인 호출은 자격 증명 없이 서버에 요청을 보내는데, 이전에는 200 응답을 받았지만 이제는 401 응답을 받았습니다. 저는 대시보드에 들어가서 테스트 계정을 승인해야 했습니다. 이 사실은 그들이 저에게 이메일을 보냈기 때문에 알게 되었습니다.
만약 당신의 서비스가 어디에 등록되어 있다면, 전환하는 날짜에 등록된 목록들을 확인하세요.
6. 동의 화면(consent screen)이 필수적이다
누군가가 Claude를 Fuxux에 연결할 때, 그 화면은 Claude가 무엇을 할 수 있을지 사용자에게 알려줍니다. 저는 단순히 텍스트뿐만 아니라 코드가 이를 강제하도록 만들었습니다:
- 연결된 어시스턴트는 총 8개의 도구(tools)를 얻습니다: 사용자의 게시물 (목록 보기, 읽기, 생성, 수정, 삭제), 연결된 계정들, 대시보드, 그리고 '나에 대한 정보(who am I)'입니다.
- 이는 사용자의 플랜, 결제 정보, 비밀번호 또는 연결된 계정에 접근할 수 없습니다.
- 사용자는 설정(Settings)에서 이를 제거할 수 있으며, 그러면 즉시 작동을 멈춥니다.
또한 도구들이 반환하는 데이터의 양도 줄였습니다. '나에 대한 정보'는 이메일 주소, 이름, 플랜만 반환합니다. 다른 것은 아무것도 나가지 않습니다.
7. OAuth와 관련 없는 부분
서비스 등록이 완료되고 저는 제 인생 최고의 날을 보냈습니다: 12건의 가입 신청 중 10건이 Claude를 통해 이루어졌습니다. 이는 제가 보통 일주일 동안 얻는 것보다 많은 수치입니다.
이틀 후, 저는 그 사람들이 무엇을 했는지 살펴보았습니다. 12명 중 한 명이 소셜 계정을 연결했습니다. 단 하나였습니다.
왜 그런지 파악하는 데 시간이 걸렸습니다. Claude의 디렉토리에서 Fuxux를 찾아 클릭하고 '연결(connect)'한 후, 제 동의 화면에서 로그인하여 승인하면, 바로 Claude로 리디렉션됩니다. 이제 사용자는 Fuxux 계정을 갖게 되었지만, Fuxux를 본 적은 없습니다. 온보딩 과정이 없었습니다. 아무도 인스타그램을 연결하라고 요청하지 않았습니다. 그래서 사용자가 Claude에게 게시물 일정을 잡으라고 요청하지만, 게시할 대상이 없는 것입니다.
제가 수정한 부분:
- 도구가 호출되었는데 연결된 계정이 없을 경우, 이제 빈 목록을 반환하는 대신 다음에 무엇을 해야 하는지 알려주는 답변을 제공합니다.
- 연결된 것이 아무것도 없는 상태에서 커넥터를 승인한 후 한 번만 전송되는 이메일입니다.
아직 제가 계획 중인 것은 사용자가 승인 직후에 '첫 번째 계정 연결' 단계를 추가하는 것입니다.
만약 이러한 디렉토리 중 하나를 위해 구축하고 있다면: 아무것도 모르는 사람의 입장에서 테스트해 보세요. 그런 사람이 나타납니다.
현재 할 수 있는 것들
연결되면, 다음과 같은 종류의 질문을 할 수 있습니다:
- "이번 주에 무엇이 예약되어 있고, 실패한 것이 있나요?"
- "새로운 가격 페이지에 대한 게시물을 작성해 주세요. LinkedIn용 버전 하나와 Bluesky용 버전 하나를 만들고 둘 다 초안으로 저장해 주세요."
- "내일의 Instagram 게시물을 금요일 오전 9시로 옮겨주세요."
Claude(여기 Claude 디렉토리에 있습니다), Claude Code, ChatGPT, Cursor에서도 작동하며, Codex를 위한 설정 페이지도 있습니다. 각각은 약 1분 정도 걸립니다:
무료 플랜이 있습니다: 3개의 소셜 계정과 월 5개 게시물까지, 카드 필요 없습니다. 이 기능을 어시스턴트를 통해 전체적으로 사용해 보고 자신의 작업 방식에 맞는지 확인할 수 있을 만큼 충분합니다.
만약 자신만의 MCP 서버를 구축하고 위의 단계들 중 어느 곳에서 막히면, 댓글로 질문하세요. 아마 저도 겪었을 겁니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기