
Claude를 프로그래밍적으로 사용하려면 보통 Anthropic API Key를 발급받아야 합니다. 사용량만큼 과금되는 종량제 구조죠.
그런데 저는 이미 Claude Pro(또는 Max) 구독을 하고 있습니다. 이미 돈을 내고 있는데, 자동화를 위해 API Key 비용을 또 내야 하나? 라는 생각이 들었습니다.
방법이 있었습니다. Claude Agent SDK는 Anthropic API가 아니라 Claude Code CLI를 내부적으로 실행합니다. 즉, CLI에 로그인된 OAuth 토큰만 있으면 API Key 없이도 Claude를 코드에서 호출할 수 있습니다.
이 글에서는 이 구조를 활용해서 Docker 컨테이너 위에 Claude Agent HTTP 서버를 올리는 과정과, 그 과정에서 만난 삽질들을 공유합니다.
Claude Agent SDK는 Anthropic이 공식으로 제공하는 Python SDK입니다. 핵심은 query() 함수 하나로, Claude에게 프롬프트를 보내고 응답을 비동기 스트림으로 받을 수 있습니다.
from claude_agent_sdk import query, ClaudeAgentOptions
options = ClaudeAgentOptions(
permission_mode="bypassPermissions",
allowed_tools=["Read", "Write", "Edit", "Bash"],
)
async for message in query(prompt="hello.py 만들어줘", options=options):
print(message)
중요한 점은, 이 SDK가 내부적으로 Claude Code CLI를 subprocess로 실행한다는 것입니다. API Key가 아니라 CLI의 인증 체계(OAuth 토큰)를 그대로 사용합니다.
[클라이언트] → HTTP 요청 → [FastAPI 서버] → [Claude Agent SDK] → [Claude Code CLI] → [Claude]
(Docker 컨테이너 내부)
구성 요소는 단순합니다:
| 파일 | 역할 |
|---|---|
main.py | FastAPI 서버 — /query, /query/stream 엔드포인트 |
entrypoint.sh | 컨테이너 시작 시 OAuth 토큰을 .claude.json에 주입 |
Dockerfile | Python 3.12 + Node.js 20 + 비루트 사용자 설정 |
docker-compose.yml | 환경변수, 포트, 볼륨 마운트 구성 |
단순히 pip install claude-agent-sdk만 하면 될 줄 알았지만, Docker 환경에서는 예상치 못한 문제들이 있었습니다.
Claude Agent SDK는 내부적으로 Claude Code CLI를 실행하는데, 이 CLI가 Node.js 기반입니다. Python 이미지에는 Node.js가 없으므로 직접 설치해야 합니다.
RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
&& apt-get install -y --no-install-recommends nodejs
Claude CLI는 처음 실행할 때 대화형 온보딩을 시도합니다. TTY가 없는 Docker 컨테이너에서는 이 과정에서 exit code 1로 종료됩니다.
해결책은 ~/.claude.json에 온보딩 완료 플래그를 미리 심어두는 것입니다:
RUN echo '{"hasCompletedOnboarding": true}' > /home/claude/.claude.json
Claude CLI는 ~/.claude.json 파일에서 인증 정보를 읽습니다. 컨테이너 시작 시 환경변수의 토큰을 이 파일에 주입해야 합니다.
entrypoint.sh에서 jq를 사용해 처리합니다:
echo "$EXISTING" | jq \
--arg token "$CLAUDE_CODE_OAUTH_TOKEN" \
'. + {
"hasCompletedOnboarding": true,
"oauthAccount": (.oauthAccount // {
"emailAddress": "docker@claude-agent.local",
"organizationName": "Docker Agent"
})
}' > "$CLAUDE_JSON"
서버는 두 가지 엔드포인트를 제공합니다.
POST /query전체 결과를 모아서 한 번에 반환합니다. 단순한 요청에 적합합니다.
curl -X POST http://localhost:8000/query \
-H "Content-Type: application/json" \
-d '{"prompt": "피보나치 함수 작성해줘"}'
POST /query/streamSSE(Server-Sent Events)로 메시지를 실시간 전달합니다. Claude가 도구를 사용하는 과정까지 실시간으로 확인할 수 있습니다.
curl -N -X POST http://localhost:8000/query/stream \
-H "Content-Type: application/json" \
-d '{"prompt": "hello.py 만들어줘"}'
스트리밍 응답에서는 텍스트, 도구 사용, 결과를 구분해서 전달합니다:
{"type": "text", "content": "파일을 작성하겠습니다."}
{"type": "tool_use", "tool": "Write", "input": {...}}
{"type": "result", "content": "hello.py를 작성했습니다."}
{
"prompt": "수행할 작업",
"system_prompt": "시스템 프롬프트 (선택)",
"allowed_tools": ["Read", "Write", "Edit", "Bash", "Glob"],
"max_turns": null,
"model": null
}
allowed_tools로 에이전트가 사용할 수 있는 도구를 제어할 수 있고, permission_mode: "bypassPermissions"로 매번 승인 없이 자동 실행됩니다.
호스트에 Claude Code CLI가 설치되어 있어야 합니다.
claude setup-token
출력된 sk-ant-oat01-... 토큰을 복사합니다.
cp .env.example .env
.env 파일에 토큰을 붙여넣습니다:
CLAUDE_CODE_OAUTH_TOKEN=sk-ant-oat01-여기에-토큰-입력
docker compose up --build
서버가 http://localhost:8000에서 시작됩니다.
workspace/ 볼륨 안에서만 이루어짐claude setup-token으로 재발급 필요Claude API Key 없이도 Claude Agent를 프로그래밍적으로 활용할 수 있다는 점이 이 프로젝트의 핵심입니다. 이미 구독 중이라면, 자동화나 개인 프로젝트에 추가 비용 없이 Claude를 연동할 수 있습니다.
전체 소스 코드는 GitHub에서 확인할 수 있습니다:
👉 GitHub 레포지토리 링크