Anthropic Claude API — Tool Use
Anthropic 의 Messages API 는 tools 파라미터를 통해 임의 도구를 LLM 에 노출한다. ainote OpenAPI 3.1 mirror 의 도구 정의를 그대로 변환해 사용 가능 — Anthropic 진영의 모든 직접 API 호출 시나리오 (자체 봇 / SaaS / agentic app / 사내 운영) 가 ainote 를 백엔드로 사용 가능.
핵심 아이디어
Anthropic tools 형식은 OpenAPI 3.1 paths 와 거의 1:1 매핑된다:
Anthropic tools[].field | OpenAPI paths[/{path}].post.field |
|---|---|
name | path 마지막 segment (예: handoff_save) |
description | summary 또는 description |
input_schema | requestBody.content["application/json"].schema |
Anthropic 이 직접 OpenAPI 를 import 하지는 않으므로 한 번 변환만 하면 된다.
Python 예시
import requests
import anthropic
# 1. ainote OpenAPI spec 가져오기
spec = requests.get("https://api.ainote.dev/api/mcp/openapi.json").json()
# 2. paths -> Anthropic tools 변환
tools = []
for path, ops in spec["paths"].items():
op = ops["post"]
name = path.split("/")[-1] # /api/mcp/tools/handoff_save -> handoff_save
body_schema = op["requestBody"]["content"]["application/json"]["schema"]
tools.append({
"name": name,
"description": op.get("description") or op.get("summary", ""),
"input_schema": body_schema,
})
# 3. Anthropic Messages API 호출
client = anthropic.Anthropic() # ANTHROPIC_API_KEY 환경변수
AINOTE_KEY = "<YOUR_MCP_KEY>"
response = client.messages.create(
model="claude-opus-4-7",
max_tokens=4096,
tools=tools,
messages=[{"role": "user", "content": "오늘 마감 태스크 보여줘"}],
)
# 4. tool_use 응답 시 ainote 에 호출
for block in response.content:
if block.type == "tool_use":
tool_name = block.name # 예: "list_tasks"
tool_input = block.input # 예: {"due_today": True}
r = requests.post(
f"https://api.ainote.dev/api/mcp/tools/{tool_name}",
json=tool_input,
headers={"Authorization": f"McpKey {AINOTE_KEY}"},
)
print(r.json())annotations 활용 — destructive 게이팅
Anthropic API 응답에서 tool_use 가 destructive 한 도구일 때 사용자 confirmation 요구:
DESTRUCTIVE = {
name for path, ops in spec["paths"].items()
if (op := ops["post"])
and (ann := op.get("x-mcp-annotations", {}))
and ann.get("destructiveHint")
for name in [path.split("/")[-1]]
}
for block in response.content:
if block.type == "tool_use":
if block.name in DESTRUCTIVE:
# 사용자에게 확인 후 호출
confirm = input(f"⚠️ {block.name} 호출하시겠습니까? (y/n): ")
if confirm.lower() != "y":
continue
# 호출 진행 ...Anthropic SDK — TypeScript
import Anthropic from "@anthropic-ai/sdk";
const spec = await fetch("https://api.ainote.dev/api/mcp/openapi.json").then(r => r.json());
const tools = Object.entries(spec.paths).map(([path, ops]: [string, any]) => {
const op = ops.post;
return {
name: path.split("/").pop()!,
description: op.description || op.summary || "",
input_schema: op.requestBody.content["application/json"].schema,
};
});
const client = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY! });
const AINOTE_KEY = process.env.AINOTE_API_KEY!;
const msg = await client.messages.create({
model: "claude-opus-4-7",
max_tokens: 4096,
tools,
messages: [{ role: "user", content: "save handoff for this session" }],
});
for (const block of msg.content) {
if (block.type === "tool_use") {
const res = await fetch(`https://api.ainote.dev/api/mcp/tools/${block.name}`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `McpKey ${AINOTE_KEY}`,
},
body: JSON.stringify(block.input),
});
console.log(await res.json());
}
}Tool result feedback (multi-turn)
Anthropic 가 tool 결과를 본 다음 응답을 만들도록 follow-up 메시지를 추가:
# 도구 호출 결과
tool_result = r.json() # ainote 응답
# Anthropic 에 결과 전달 → 다음 응답 생성
followup = client.messages.create(
model="claude-opus-4-7",
max_tokens=4096,
tools=tools,
messages=[
{"role": "user", "content": "오늘 마감 태스크 보여줘"},
{"role": "assistant", "content": response.content},
{"role": "user", "content": [
{
"type": "tool_result",
"tool_use_id": block.id, # 위 tool_use block 의 id
"content": str(tool_result),
}
]},
],
)MCP HTTP transport vs OpenAPI 변환 — 둘 중 어느 것?
| 방식 | 장점 | 단점 |
|---|---|---|
MCP HTTP (api.ainote.dev/api/mcp) | JSON-RPC 표준, tools/list 동적 발견, annotations 그대로 wire | Anthropic API 의 tools 파라미터가 MCP 를 직접 이해 못 함 (2026-05 현재) — 별도 어댑터 필요 |
| OpenAPI 변환 (위 예시) | Anthropic API 의 tools 파라미터에 한 번 변환만 하면 통합 끝. annotations 는 x-mcp-annotations 로 직접 조회 가능 | OpenAPI spec 변경 시 재변환 필요 (캐시 + 주기적 fetch) |
추천: 대부분의 경우 OpenAPI 변환이 단순. MCP HTTP 는 Claude Code / Claude Desktop 같은 MCP-native 클라이언트에만 사용.
자주 묻는 문제
"input_schema validation error" — Anthropic 의 input_schema 는 OpenAPI 의 requestBody.content["application/json"].schema 와 거의 같지만, 일부 OpenAPI-only 필드 (example, examples, x-* extension) 는 dropped. 변환 시 안전.
"Rate limit 429" — Anthropic 측 API rate limit + ainote 측 fair-use 한도 둘 다 체크. Phase 3 후 X-RateLimit-* 헤더로 ainote 측 quota 노출 예정.
"맥OS Keychain 에서 key 어떻게?" — Python keyring 라이브러리 + macOS security find-generic-password -s @ainote/cli.