Claude Platform Docs
Managed Agents자체 호스팅 샌드박스

자체 호스팅 샌드박스의 사용자 정의 도구

자체 호스팅 샌드박스 워커에서 사용자 정의 도구를 제공하고, 터널을 실행하지 않고도 네트워크 내부의 MCP 서버를 사용자 정의 도구로 래핑합니다.

사용자 정의 도구는 사용자의 코드가 직접 실행하는 도구입니다. 에이전트는 agent.custom_tool_use 이벤트를 내보내고 일치하는 user.custom_tool_result를 기다립니다. 사용자의 워커가 바로 그 코드가 될 수 있습니다. 워커는 샌드박스 내부에서 실행되므로, 도구는 샌드박스에 구성한 내부 서비스, 자격 증명, 네트워크 이그레스에만 접근하며 그 이상에는 접근하지 않습니다.

환경 키가 사용자 정의 도구 결과 게시를 승인하므로, Claude API 키는 워커 호스트에 두지 않아도 됩니다.

사용자 정의 도구 제공하기

  1. 에이전트에 도구 선언하기

    에이전트의 tools에 워커가 등록하는 도구와 name이 일치하는 custom 항목을 추가하세요. 전체 선언 형식은 사용자 정의 도구를 참조하세요.

    {
      "type": "custom",
      "name": "get_order_status",
      "description": "Look up an order in the internal fulfillment system by order ID.",
      "input_schema": {
        "type": "object",
        "properties": {
          "order_id": { "type": "string", "description": "The order ID" }
        },
        "required": ["order_id"]
      }
    }
  2. 워커에 구현 등록하기

    내장 도구 세트와 함께 워커의 tools 팩토리(EnvironmentWorker 참조)를 통해 도구를 전달하세요:

    import asyncio
    import os
    from anthropic import AsyncAnthropic, beta_async_tool
    from anthropic.lib.environments import EnvironmentWorker
    from anthropic.lib.tools.agent_toolset import beta_agent_toolset_20260401
    
    
    @beta_async_tool
    async def get_order_status(order_id: str) -> str:
        """Look up an order in the internal fulfillment system by order ID."""
        # 워커 호스트에서 실행됩니다: 샌드박스가 접근할 수 있는 모든 것을 호출할 수 있습니다.
        return f"Order {order_id}: shipped"
    
    
    async def main() -> None:
        environment_key = os.environ["ANTHROPIC_ENVIRONMENT_KEY"]
        environment_id = os.environ["ANTHROPIC_ENVIRONMENT_ID"]
        async with AsyncAnthropic(auth_token=environment_key) as client:
            await EnvironmentWorker(
                client,
                environment_id=environment_id,
                environment_key=environment_key,
                workdir="/workspace",
                tools=lambda env: [*beta_agent_toolset_20260401(env), get_order_status],
            ).run()
    
    
    asyncio.run(main())

워커는 자신에게 등록된 도구에만 응답합니다. 도구가 에이전트에 선언되어 있지만 이를 제공하는 워커나 클라이언트가 없으면, 세션은 requires_action 중지 사유와 함께 일시 중지됩니다. 무언가가 결과를 게시할 때까지 일시 중지 상태가 유지됩니다. 이벤트 흐름은 사용자 정의 도구 호출 처리를 참조하세요.

MCP 서버를 사용자 정의 도구로 래핑하기

MCP 커넥터는 Anthropic 측에서 MCP 서버에 연결합니다. 따라서 서버는 Anthropic이 직접 또는 MCP 터널을 통해 접근할 수 있는 HTTP 엔드포인트를 노출해야 합니다.

사용자의 네트워크에서만 접근할 수 있는 서버를 사용하려면, 대신 워커를 MCP 클라이언트로 만들고 서버의 도구를 사용자 정의 도구로 선언하세요. MCP 서버는 네트워크 외부로부터의 인바운드 연결이 필요하지 않습니다. Anthropic은 에이전트에 선언한 도구 정의, 각 호출의 입력, 그리고 워커가 다시 게시하는 결과를 받습니다.

런타임에 모델은 래핑된 도구를 다른 사용자 정의 도구와 마찬가지로 호출합니다:

  1. 에이전트가 agent.custom_tool_use 이벤트를 내보냅니다.
  2. 샌드박스 내부의 워커가 열려 있는 MCP 세션을 통해 네트워크상의 서버로 호출을 전달합니다.
  3. 워커가 서버의 응답을 user.custom_tool_result로 게시합니다.

MCP SDK 설치하기

SDK의 클라이언트 측 MCP 헬퍼는 서버의 도구를 워커가 받아들이는 실행 가능한 도구로 변환합니다. Anthropic SDK와 함께 MCP SDK를 설치하세요: pip install "anthropic[mcp]" "mcp>=1.24".

예제는 인증 없이 연결합니다. 자격 증명을 보내려면 MCP 전송에 전달하는 http_client를 구성하세요.

도구 선언 및 제공하기

  1. 에이전트에 서버의 도구 선언하기

    MCP 서버의 도구를 나열하고 각각을 custom 도구로 선언하세요. MCP의 name, description, inputSchema는 사용자 정의 도구의 필드에 일대일로 대응됩니다. 서버가 도구 목록을 페이지로 나누어 제공하는 경우 모든 페이지를 선언하세요. 워커도 동일한 페이지를 나열해야 합니다.

    import asyncio
    from typing import Any, cast
    from anthropic import AsyncAnthropic
    from anthropic.types.beta import BetaManagedAgentsCustomToolParams
    from mcp import ClientSession, types
    # mcp >= 1.24가 필요합니다. 이 버전에서 streamablehttp_client가 streamable_http_client로 이름이 변경되었습니다.
    from mcp.client.streamable_http import streamable_http_client
    
    MCP_SERVER_URL = "http://mcp.internal.example.com:8000/mcp"
    
    
    def to_custom_tool(tool: types.Tool) -> BetaManagedAgentsCustomToolParams:
        # MCP 필드는 커스텀 도구 선언에 일대일로 매핑됩니다. 캐스트는
        # 스키마 딕셔너리를 SDK의 타입 지정 매개변수에 그대로 전달합니다.
        return {
            "type": "custom",
            "name": tool.name,
            "description": tool.description or tool.name,
            "input_schema": cast(Any, tool.inputSchema),
        }
    
    
    async def main() -> None:
        # 워커 호스트가 아니라 에이전트를 생성하는 곳에서 실행하세요.
        # Claude API 키(ANTHROPIC_API_KEY)로 인증하기 때문입니다.
        async with (
            streamable_http_client(MCP_SERVER_URL) as (read, write, _),
            ClientSession(read, write) as mcp_session,
            AsyncAnthropic() as client,
        ):
            await mcp_session.initialize()
            listed = await mcp_session.list_tools()
            agent = await client.beta.agents.create(
                name="Internal tools agent",
                model="claude-opus-5-5",
                tools=[
                    {"type": "agent_toolset_20260401"},
                    *[to_custom_tool(tool) for tool in listed.tools],
                ],
            )
            print(agent.id)
    
    
    asyncio.run(main())
  2. 워커에서 도구 제공하기

    시작 시 동일한 MCP 서버에 연결하고, async_mcp_tool로 해당 도구를 변환한 다음, beta_agent_toolset_20260401와 함께 등록하세요. 워커가 실행되는 동안 하나의 MCP 세션을 계속 열어 두세요.

    import asyncio
    import os
    from datetime import timedelta
    from anthropic import AsyncAnthropic
    from anthropic.lib.environments import EnvironmentWorker
    from anthropic.lib.tools.agent_toolset import beta_agent_toolset_20260401
    from anthropic.lib.tools.mcp import async_mcp_tool
    from mcp import ClientSession
    # mcp >= 1.24가 필요합니다. 이 버전에서 streamablehttp_client가 streamable_http_client로 이름이 변경되었습니다.
    from mcp.client.streamable_http import streamable_http_client
    
    MCP_SERVER_URL = "http://mcp.internal.example.com:8000/mcp"
    
    
    async def main() -> None:
        environment_key = os.environ["ANTHROPIC_ENVIRONMENT_KEY"]
        environment_id = os.environ["ANTHROPIC_ENVIRONMENT_ID"]
        # 시작 시 MCP 서버에 한 번 연결하고 워커가 실행되는 동안
        # 세션을 열어 둡니다. 타임아웃은 멈춘 도구 호출을 중단된 호출이 아닌
        # 오류 결과로 바꿉니다.
        async with (
            streamable_http_client(MCP_SERVER_URL) as (read, write, _),
            ClientSession(read, write, read_timeout_seconds=timedelta(seconds=60)) as mcp_session,
            AsyncAnthropic(auth_token=environment_key) as client,
        ):
            await mcp_session.initialize()
            listed = await mcp_session.list_tools()
            mcp_tools = [async_mcp_tool(tool, mcp_session) for tool in listed.tools]
            await EnvironmentWorker(
                client,
                environment_id=environment_id,
                environment_key=environment_key,
                workdir="/workspace",
                tools=lambda env: [*beta_agent_toolset_20260401(env), *mcp_tools],
            ).run()
    
    
    asyncio.run(main())

제한 사항 및 동작

도구는 런타임에 검색되지 않고 선언됩니다

워커는 시작 시 MCP 서버의 도구를 한 번 나열하며, 실행 중인 세션에 도구를 추가할 수 없습니다. 서버의 도구가 변경되면:

  1. 에이전트에서, 또는 에이전트 구성 업데이트를 통해 유휴 세션에서 도구를 다시 선언하세요.
  2. 워커를 다시 시작하세요.

선언은 Managed Agents API에 맞아야 합니다

MCP 헬퍼는 서버의 이름과 설명을 유지하며, 대부분의 스키마는 변경 없이 그대로 전달됩니다. 선언이 다음 규칙 중 하나를 위반하는 경우 이름을 바꾸거나, 줄이거나, 인라인으로 처리하세요:

필드규칙
name에이전트별로 고유해야 합니다. 문자, 숫자, 밑줄, 하이픈으로 구성된 1–128자입니다. bash나 read 같은 내장 에이전트 도구와 일치하거나 예약된 mcp__ 접두사를 사용할 수 없습니다.
description필수이며 비어 있으면 안 됩니다.
input_schemaadditionalProperties 및 title과 같이 MCP 서버가 일반적으로 내보내는 JSON Schema 키워드를 허용합니다. 위치에 관계없이 $ref와 같은 참조 키워드와 최상위 수준의 oneOf, anyOf, allOf는 거부합니다. 속성 이름은 문자, 숫자, 밑줄, 점, 하이픈으로 구성된 1–64자입니다.
에이전트의 tools 배열최대 128개 항목입니다. 래핑된 각 도구가 하나의 항목이며, 내장 도구 세트가 하나의 항목을 더 차지합니다.

다음 두 가지 경우에는 추가 작업이 필요합니다:

  • 두 서버가 동일한 도구 이름을 노출하는 경우: 접두사가 붙은 이름으로 래퍼를 직접 정의하고, 해당 래퍼가 서버의 원래 도구 이름을 호출하도록 하세요.
  • pydantic과 같은 생성기가 스키마를 $defs로 분리하는 경우: 도구를 선언하기 전에 해당 스키마를 인라인으로 처리하세요.

도구 실패는 오류 도구 결과로 나타납니다

MCP 서버가 도구 오류를 보고하면, 워커는 모델이 대응할 수 있는 오류 도구 결과를 게시합니다. 오디오 블록이나 리소스 링크처럼 도구 결과에 대응하는 형식이 없는 MCP 콘텐츠도 오류로 나타납니다.

Python 워커 예제에서 read_timeout_seconds로 하는 것처럼, 더 빠르고 명확하게 실패하도록 MCP 클라이언트에 타임아웃을 설정하세요. 타임아웃이 없을 때 어떤 일이 발생하는지는 래핑된 MCP 도구 호출이 멈춤을 참조하세요.

직접 운영하거나 신뢰하는 서버만 래핑하세요

래핑된 도구의 이름, 설명, 결과는 다른 도구와 마찬가지로 모델의 컨텍스트에 들어갑니다. 이는 에이전트가 워커 호스트의 bash를 포함한 다른 도구로 수행하는 작업에 영향을 줄 수 있는 신뢰할 수 없는 입력입니다. 에이전트가 사용하도록 의도한 도구만 선언하세요.

권한 정책은 적용되지 않습니다

권한 정책은 내장 도구 세트와 MCP 도구 세트를 관리합니다. 워커는 모델이 수행하는 모든 래핑된 도구 호출을 실행하므로, 승인 단계가 필요하다면 직접 작성한 도구 코드에 넣으세요.

Was this page helpful?