메인 콘텐츠로 건너뛰기
사용자 정의 도구는 Claude가 대화 중에 호출할 수 있는 자신의 함수를 정의하도록 하여 Agent SDK를 확장합니다. SDK의 인프로세스 MCP 서버를 사용하면 Claude에 데이터베이스, 외부 API, 도메인별 로직 또는 애플리케이션에 필요한 다른 기능에 대한 액세스 권한을 부여할 수 있습니다. 이 가이드에서는 입력 스키마 및 핸들러를 사용하여 도구를 정의하고, 이를 MCP 서버로 번들링하고, query에 전달하며, Claude가 액세스할 수 있는 도구를 제어하는 방법을 다룹니다. 또한 오류 처리, 도구 주석, 이미지와 같은 비텍스트 콘텐츠 반환에 대해서도 다룹니다.

빠른 참조

사용자 정의 도구 만들기

도구는 TypeScript의 tool() 헬퍼 또는 Python의 @tool 데코레이터에 인수로 전달되는 네 부분으로 정의됩니다:
  • 이름: Claude가 도구를 호출하는 데 사용하는 고유 식별자입니다.
  • 설명: 도구가 수행하는 작업입니다. Claude는 이를 읽고 도구를 호출할 시기를 결정합니다.
  • 입력 스키마: Claude가 제공해야 하는 인수입니다. TypeScript에서는 항상 Zod 스키마이며, 핸들러의 args는 자동으로 입력됩니다. Python에서는 {"latitude": float}와 같이 이름을 유형에 매핑하는 딕셔너리이며, SDK가 JSON Schema로 변환합니다. Python 데코레이터는 열거형, 범위, 선택적 필드 또는 중첩된 객체가 필요할 때 전체 JSON Schema 딕셔너리도 허용합니다.
  • 핸들러: Claude가 도구를 호출할 때 실행되는 비동기 함수입니다. 검증된 인수를 받고 다음을 포함하는 객체를 반환해야 합니다:
    • content (필수): 각각 "text", "image", "audio", "resource" 또는 "resource_link"type을 가진 결과 블록의 배열입니다. 비텍스트 블록은 이미지 및 리소스 반환을 참조하세요.
    • structuredContent (선택사항): 머신 판독 가능한 데이터로 결과를 보유하는 JSON 객체이며, content와 함께 반환됩니다. 구조화된 데이터 반환을 참조하세요.
    • isError (선택사항): Claude가 반응할 수 있도록 도구 실패를 신호하려면 true로 설정합니다. 오류 처리를 참조하세요.
도구를 정의한 후 createSdkMcpServer (TypeScript) 또는 create_sdk_mcp_server (Python)를 사용하여 서버로 래핑합니다. 서버는 별도의 프로세스가 아닌 애플리케이션 내에서 인프로세스로 실행됩니다.

날씨 도구 예제

이 예제는 get_temperature 도구를 정의하고 MCP 서버로 래핑합니다. 도구만 설정합니다. query에 전달하고 실행하려면 아래의 사용자 정의 도구 호출을 참조하세요.
전체 매개변수 세부 정보, JSON Schema 입력 형식 및 반환 값 구조를 포함하여 tool() TypeScript 참조 또는 @tool Python 참조를 참조하세요.
매개변수를 선택사항으로 만들려면: TypeScript에서 Zod 필드에 .default()를 추가합니다. Python에서 딕셔너리 스키마는 모든 키를 필수로 취급하므로 스키마에서 매개변수를 생략하고, 설명 문자열에서 언급하고, 핸들러에서 args.get()으로 읽습니다. 아래의 get_precipitation_chance 도구는 두 패턴을 모두 보여줍니다.

사용자 정의 도구 호출

mcpServers 옵션을 통해 생성한 MCP 서버를 query에 전달합니다. mcpServers의 키는 각 도구의 정규화된 이름에서 {server_name} 세그먼트가 됩니다: mcp__{server_name}__{tool_name}. 도구가 권한 프롬프트 없이 실행되도록 allowedTools에 해당 이름을 나열합니다. 이 스니펫은 위의 예제weatherServer를 재사용하여 Claude에 특정 위치의 날씨를 묻습니다.

더 많은 도구 추가

서버는 tools 배열에 나열한 만큼 많은 도구를 보유합니다. 서버에 둘 이상의 도구가 있으면 allowedTools에서 각각을 개별적으로 나열하거나 와일드카드 mcp__weather__*를 사용하여 서버가 노출하는 모든 도구를 포함할 수 있습니다. 아래 예제는 날씨 도구 예제weatherServer에 두 번째 도구인 get_precipitation_chance를 추가하고 배열의 두 도구로 다시 빌드합니다.
이 배열의 모든 도구는 매 턴마다 컨텍스트 윈도우 공간을 소비합니다. 수십 개의 도구를 정의하는 경우 도구 검색을 참조하여 필요할 때 로드합니다.

도구 주석 추가

도구 주석은 도구의 동작을 설명하는 선택적 메타데이터입니다. TypeScript의 tool() 헬퍼에 다섯 번째 인수로 전달하거나 Python의 @tool 데코레이터에 대해 annotations 키워드 인수를 통해 전달합니다. 모든 힌트 필드는 부울입니다. 주석은 메타데이터이지 강제 사항이 아닙니다. readOnlyHint: true로 표시된 도구도 핸들러가 수행하는 경우 디스크에 쓸 수 있습니다. 주석을 핸들러에 정확하게 유지합니다. 이 예제는 날씨 도구 예제get_temperature 도구에 readOnlyHint를 추가합니다.
TypeScript 또는 Python 참조에서 ToolAnnotations를 참조하세요.

도구 액세스 제어

날씨 도구 예제는 서버를 등록하고 allowedTools에 도구를 나열했습니다. 이 섹션에서는 도구 이름이 구성되는 방식과 여러 도구가 있거나 기본 제공 도구를 제한하려는 경우 액세스 범위를 지정하는 방법을 다룹니다.

도구 이름 형식

MCP 도구가 Claude에 노출될 때 이름은 특정 형식을 따릅니다:
  • 패턴: mcp__{server_name}__{tool_name}
  • 예제: weather 서버의 get_temperature라는 도구는 mcp__weather__get_temperature가 됩니다

허용된 도구 구성

tools 옵션과 허용/거부 목록은 두 가지 계층에 영향을 미칩니다. 가용성은 도구가 Claude의 컨텍스트에 나타나는지 여부를 제어하고, 권한은 Claude가 호출을 시도한 후 호출이 승인되는지 여부를 제어합니다. tools와 단순 이름 disallowedTools 항목은 가용성을 변경합니다. allowedTools와 범위가 지정된 disallowedTools 규칙은 권한만 변경합니다. 기본 제공 도구를 완전히 제거하려면 tools에서 생략하거나 disallowedTools(Python: disallowed_tools)에 단순 이름을 나열합니다. 둘 다 도구를 컨텍스트 밖으로 유지하므로 Claude는 시도하지 않습니다. 범위가 지정된 disallowedTools 규칙은 일치하는 호출을 차단하지만 도구를 표시하므로 Claude는 시도하는 데 턴을 낭비할 수 있습니다. 전체 평가 순서는 권한 구성을 참조하세요.

오류 처리

핸들러 오류는 에이전트 루프를 중지하지 않습니다. SDK의 인프로세스 MCP 서버는 포착되지 않은 예외를 잡아서 오류 결과로 반환하므로, 오류를 보고하는 방식에 따라 Claude가 읽는 내용이 결정되며, 쿼리 실패 여부는 결정되지 않습니다: 두 경우 모두 Claude는 재시도하거나, 다른 도구를 시도하거나, 실패를 설명할 수 있습니다. 원본 예외 메시지가 Claude가 작용하기에 충분하지 않을 때 오류를 직접 포착하세요. 아래 예제는 핸들러 내에서 두 가지 종류의 실패를 포착하고 Claude가 읽는 오류 메시지를 작성합니다. 200이 아닌 HTTP 상태는 응답에서 포착되어 오류 결과로 반환됩니다. 네트워크 오류 또는 잘못된 JSON은 주변 try/except (Python) 또는 try/catch (TypeScript)로 포착되어 오류 결과로도 반환됩니다. 두 경우 모두 Claude는 단순한 예외 문자열 대신 실패를 설명하는 메시지를 받습니다.

이미지 및 리소스 반환

도구 결과의 content 배열은 text, image, audio, resourceresource_link 블록을 허용합니다. 동일한 응답에서 이들을 혼합할 수 있습니다. TypeScript에서 오디오 블록은 디스크에 저장되며 Claude는 저장된 파일 경로가 포함된 텍스트 블록을 받습니다. Python에서 SDK는 도구 결과에서 오디오 블록을 삭제하고 경고를 기록합니다. 리소스 링크 블록은 링크의 이름, URI 및 설명을 포함하는 텍스트 블록으로 변환됩니다.

이미지

이미지 블록은 이미지 바이트를 base64로 인코딩하여 인라인으로 전달합니다. URL 필드가 없습니다. URL에 있는 이미지를 반환하려면 핸들러에서 가져오고, 응답 바이트를 읽고, 반환하기 전에 base64로 인코딩합니다. 결과는 시각적 입력으로 처리됩니다.

리소스

리소스 블록은 URI로 식별되는 콘텐츠 조각을 포함합니다. URI는 Claude가 참조할 레이블입니다. 실제 콘텐츠는 블록의 text 또는 blob 필드에 있습니다. 도구가 나중에 이름으로 주소를 지정하는 것이 합리적인 것을 생성할 때 사용합니다. 예를 들어 생성된 파일 또는 외부 시스템의 레코드입니다. 이 예제는 도구 핸들러 내에서 반환된 리소스 블록을 보여줍니다. URI file:///tmp/report.md는 Claude가 나중에 참조할 수 있는 레이블입니다. SDK는 해당 경로에서 읽지 않습니다.
이 블록 모양은 MCP CallToolResult 유형에서 나옵니다. 전체 정의는 MCP 사양을 참조하세요.

구조화된 데이터 반환

structuredContentcontent 배열과 별개인 결과의 선택적 JSON 객체입니다. 이를 사용하여 텍스트 문자열이나 이미지에서 구문 분석하는 대신 Claude가 정확한 필드로 읽을 수 있는 원본 값을 반환합니다. structuredContent가 설정되면 Claude는 JSON과 content의 모든 이미지 또는 리소스 블록을 받습니다. content의 텍스트 블록은 구조화된 데이터를 복제한다고 가정하므로 전달되지 않습니다. 아래 예제는 차트를 이미지 블록으로 렌더링하고 동일한 핸들러에서 structuredContent의 뒤에 있는 데이터 포인트를 반환합니다.
TypeScript
Python @tool 데코레이터는 핸들러의 반환 딕셔너리에서 contentis_error만 전달합니다. Python에서 structuredContent를 반환하려면 인프로세스 SDK 서버 대신 독립형 MCP 서버를 실행합니다.

예제: 단위 변환기

이 도구는 길이, 온도 및 무게 단위 간에 값을 변환합니다. 사용자는 “100킬로미터를 마일로 변환” 또는 “72°F는 섭씨온도로 몇 도인가”라고 물을 수 있으며, Claude는 요청에서 올바른 단위 유형과 단위를 선택합니다. 두 가지 패턴을 보여줍니다:
  • 열거형 스키마: unit_type은 고정된 값 집합으로 제한됩니다. TypeScript에서 z.enum()을 사용합니다. Python에서 딕셔너리 스키마는 열거형을 지원하지 않으므로 전체 JSON Schema 딕셔너리가 필요합니다.
  • 지원되지 않는 입력 처리: 변환 쌍을 찾을 수 없으면 핸들러는 isError: true를 반환하므로 Claude는 실패를 정상 결과로 취급하는 대신 사용자에게 무엇이 잘못되었는지 알릴 수 있습니다.
서버가 정의되면 날씨 예제와 동일한 방식으로 query에 전달합니다. 이 예제는 루프에서 세 가지 다른 프롬프트를 보내 동일한 도구가 다양한 단위 유형을 처리하는 것을 보여줍니다. 각 응답에 대해 AssistantMessage 객체(Claude가 해당 턴 중에 수행한 도구 호출을 포함)를 검사하고 각 ToolUseBlock을 인쇄한 후 최종 ResultMessage 텍스트를 인쇄합니다. 이를 통해 Claude가 도구를 사용하는 시기와 자신의 지식에서 답변하는 시기를 볼 수 있습니다.

다음 단계

사용자 정의 도구는 비동기 함수를 표준 인터페이스로 래핑합니다. 동일한 서버에서 이 페이지의 패턴을 혼합할 수 있습니다: 단일 서버는 데이터베이스 도구, API 게이트웨이 도구 및 이미지 렌더러를 함께 보유할 수 있습니다. 여기서:
  • 서버가 수십 개의 도구로 증가하면 도구 검색을 참조하여 Claude가 필요할 때까지 로드를 연기합니다.
  • 자신의 도구를 빌드하는 대신 외부 MCP 서버(파일 시스템, GitHub, Slack)에 연결하려면 MCP 서버 연결을 참조하세요.
  • 어떤 도구가 자동으로 실행되는지 대 승인이 필요한지 제어하려면 권한 구성을 참조하세요.