직접 만든 stdio MCP 서버가 /mcp엔 connected로 뜨는데 Claude Code가 도구를 안 부릅니다
내부 사내 API를 Claude Code에서 쓰려고 MCP 서버를 직접 만들었습니다. Python으로 stdio 방식이고요. claude mcp add로 등록은 됐고 /mcp에서 connected로 뜨는데, 정작 대화에서 그 도구를 부르려고 하면 호출이 안 되거나 에이전트가 도구 존재 자체를 모르는 것처럼 굽니다.
서버 자체는 mcp inspector나 별도 클라이언트로 때리면 정상 응답합니다. Claude Code에서만 이래요. 뭘 놓치고 있는 걸까요?
답변 3개
- 채택된 답변에디터 검증
별도 클라이언트는 OK인데 Claude Code에서만 도구를 안 부른다 — 이 증상이면 거의 stdout 오염입니다. 근데 헷갈릴 수 있으니 순서대로 짚을게요.
1순위. stdout 오염 의심. stdio MCP는 stdout으로 JSON-RPC 프레임만 주고받습니다. 서버 코드 어딘가에서
print()가 나가거나,logging이 기본 핸들러로 stdout에 찍히거나, 심지어 import한 라이브러리가 시작 배너를 stdout에 뱉으면 그 순간 프레임이 깨져서 핸드셰이크는 되는데 그 뒤 도구 호출이 망가집니다. inspector로 단독 테스트할 땐 안 걸리고 Claude Code 통합에서만 터지는 게 정확히 이 패턴이에요.import logging, sys logging.basicConfig(stream=sys.stderr, level=logging.INFO) # print() 절대 금지, 디버그는 전부 stderr2순위. description이 빈약해서 모델이 후보로 안 떠올림. tools/list로 노출된 name·description·inputSchema가 모델이 보는 전부입니다. description이 한 줄이거나 모호하면 connected여도 그냥 안 부릅니다. (이건 아래 다른 분이 잘 설명해주심)
3순위. 그래도 안 되면
claude --debug로 띄워서 JSON-RPC 왕복 로그를 직접 보세요. tools/list 응답에 도구가 실제로 들어오는지, 호출이 나갔는데 응답에서 끊기는지가 한눈에 보입니다.님 증상이면 1번부터 보세요. print 하나 stderr로 옮기는 거로 끝나는 경우가 정말 많습니다.
description 쪽도 진짜 무시 못 합니다. 저는 도구 5개 노출했는데 모델이 그중 2개만 줄곧 쓰길래 봤더니, 안 쓰던 도구들 description이 "사내 데이터 조회" 이딴 식으로 추상적이었어요.
"직원 ID로 재직 상태와 부서를 조회한다. 사용자가 특정 직원의 소속/재직 여부를 물을 때 사용"처럼 언제 써야 하는지 트리거 상황을 박아주니 바로 부르기 시작했습니다. 파라미터도 schema description 비워두지 말고 다 채우고요. 모델 입장에선 tool description이 곧 사용설명서라, 여기 들인 만큼 그대로 회수됩니다.
stdout 쪽에 한 표 더. 저도 똑같이 당했는데 의존성 하나가 import 시점에 stdout으로 배너를 찍어서, 핸드셰이크는 되는데 그 뒤 통신이 깨졌었음. 파이썬이면 표준출력으로 나가는 모든 걸 의심하세요. 진짜 빡치는 건 내 코드엔 print 한 줄도 없었다는 거. 라이브러리가 범인이었음.
그리고 별개로 등록 스코프도 확인.
claude mcp add는 local/project/user 스코프가 있어서, 등록한 디렉터리랑 다른 데서claude띄우면 그 서버가 안 잡힐 수 있어요.claude mcp list로 지금 세션에 실제로 붙어있는지부터 보세요. connected라고 떴다니 이건 아닐 확률이 높긴 한데, 혹시 모르니.