공식 Deploy Claude Desktop with an LLM gateway 가이드를 기반으로 합니다 — Claude Desktop에서 연결할 게이트웨이가 바로 shunt입니다. shunt는 Anthropic Messages API(스트리밍과 도구 사용을 지원하는 POST /v1/messages)와 선택 사항인 GET /v1/models를 구현하며, 이는 Claude Desktop의 서드 파티 추론이 기대하는 게이트웨이 계약과 정확히 일치합니다.
1. Claude Desktop을 shunt로 향하게 하기
Developer → Configure Third-Party Inference…에서 Inference provider를 Gateway로 설정하고, Gateway base URL을 실행 중인 shunt(기본 bind 127.0.0.1:3001)로 설정하세요:
| Claude Desktop 키 | 값 |
|---|---|
inferenceProvider |
gateway |
inferenceGatewayBaseUrl |
http://127.0.0.1:3001 (또는 공개 shunt URL) |
shunt는 평문 HTTP를 제공합니다. 루프백을 벗어난 배포에서는 게이트웨이 공유와 마찬가지로 앞단에서 TLS를 종료하거나 터널을 사용하세요.
2. 인증 방식 선택
Claude Desktop은 여러 방식을 제공합니다. shunt는 정적 키(및 자격 증명 헬퍼 변형)와, shunt 자체가 디바이스 코드 인가 서버가 되는 bootstrap 로그인에 자연스럽게 대응합니다. 외부 IdP의 JWT를 쓰는 SSO는 게이트웨이 측 기능이며 shunt는 인바운드에서 이를 구현하지 않습니다.
| Claude Desktop 방식 | shunt 측 | 참고 |
|---|---|---|
정적 API 키 (inferenceGatewayApiKey) |
[server.auth] 클라이언트 토큰 |
권장. |
자격 증명 헬퍼 (inferenceCredentialHelper) |
[server.auth] 클라이언트 토큰을 출력하는 실행 파일 |
이미 게이트웨이 자격 증명을 발급하는 조직용. |
Bootstrap 로그인 (bootstrapUrl + 디바이스 코드, inferenceCredentialKind: interactive) |
[server.gateway] 로그인과 [server.gateway.desktop_bootstrap] |
사용자당 shunt 로그인 한 번, 디바이스에 CLI 불필요 — Bootstrap 로그인을 참고하세요. |
대화형 SSO (inferenceGatewayOidc + inferenceCredentialKind: interactive) |
인바운드에서 지원하지 않음 | shunt는 외부 IdP JWT를 검증하지 않습니다 — 아래를 참고하세요. |
정적 API 키(권장)
shunt에서 [server.auth]를 활성화하고 각 사용자에게 클라이언트 토큰을 발급하세요:
[server.auth]
header = "x-shunt-token" # 기본값
tokens_env = "SHUNT_CLIENT_TOKENS"그 토큰을 Claude Desktop의 inferenceGatewayApiKey에 입력하세요. shunt는 Authorization: Bearer 또는 x-api-key로 클라이언트 토큰을 받으므로, 어느 Gateway auth scheme이든 사용할 수 있습니다:
| Claude Desktop 키 | 값 |
|---|---|
inferenceGatewayApiKey |
shunt 클라이언트 토큰 |
inferenceGatewayAuthScheme |
bearer (기본값) 또는 x-api-key |
[server.auth]가 없으면 shunt는 인바운드 자격 증명을 요구하지 않습니다(개인 루프백 게이트웨이에는 괜찮습니다). 그래도 Claude Desktop은 이 필드가 채워져 있기를 요구하므로 아무 플레이스홀더나 입력하세요.
이 토큰은 GET /v1/models와 자격 증명이 주입되는(매핑된/풀) 모델을 게이팅합니다. 패스스루 모델은 열린 채로 유지되며 운영자 자체의 프로바이더 자격 증명을 전달합니다.
Bootstrap 로그인 (디바이스 코드)
Claude Desktop은 bootstrap URL에서 구성을 가져오고, 같은 서버를 상대로 OAuth 디바이스 코드 grant로 사용자를 로그인시킬 수 있습니다(Anthropic의 bootstrap 가이드, “Bootstrap server as authorization server (device code)” 모드). shunt는 이 모드를 제공합니다. 사용자는 shunt의 /device 페이지에서 비밀번호 또는 OIDC IdP로 한 번 로그인하고, Desktop은 그 bearer를 추론에도 재사용합니다. 디바이스에는 Claude Desktop 외에 설치할 것이 없고, 기기마다 맞춰야 하는 헬퍼 스크립트 경로도 없습니다.
1. 게이트웨이 로그인 활성화. public_url, 서명 시크릿, 정적 사용자 또는 OIDC IdP와 함께 [server.gateway]를 구성하세요. 이 모드에는 shunt 앞단에 TLS가 적용된 실제 호스트명이 필요합니다. Anthropic 가이드는 bootstrap 엔드포인트를 HTTPS로 설명하고, 패키지된 Desktop 앱은 응답 키에서 루프백 URL(127.0.0.1, localhost, [::1])을 버립니다.
2. shunt에 템플릿 지정.
[server.gateway.desktop_bootstrap]
template = "/etc/shunt/claude-desktop-bootstrap.json" # 파일 경로만 가능파일은 존재하는 JSON 객체여야 하며, 그렇지 않으면 설정 로드(및 shunt check)가 실패합니다. shunt는 요청마다 파일을 읽으므로 수정 내용은 재시작 없이 적용됩니다. Desktop의 JSON 내보내기가 만드는 중첩 v2 형식 또는 평면 v1 형식으로 작성하세요. shunt는 그대로 전달합니다:
{
"$schemaVersion": 2,
"inference": {
"provider": "gateway",
"baseUrl": "https://shunt.example.corp",
"credential": { "kind": "interactive" }
},
"otlp": {
"resourceAttributes": { "user.email": "${user.email}" }
}
}평면 v1 형식은 {"inferenceProvider":"gateway","inferenceGatewayBaseUrl":"https://shunt.example.corp","inferenceCredentialKind":"interactive","otlpResourceAttributes":{"user.email":"${user.email}"}}입니다.
- 게이트웨이 base URL은 shunt의
public_url이어야 합니다.bootstrapOidc가 없으면 Desktop은bootstrapUrl과 origin이 같지 않은 게이트웨이 base URL을 버립니다. origin이 같고interactive자격 증명을 쓸 때 Desktop이 bootstrap bearer를 추론에 재사용하고(1.34493.0부터는 refresh grant로 갱신도 합니다), 사용자는 한 번만 로그인하면 됩니다. - 플레이스홀더. 문자열 값 안의
${user.email},${user.sub},${user.name}은 로그인한 사용자의 값으로 바뀝니다. 알 수 없는${...}토큰은 그대로 두고, 객체 키는 치환하지 않습니다. - 적용할 키는 모두 반환하세요. 응답 키가 곧 유효 구성입니다. 템플릿에서 생략한 키는 MDM에서 상속되지 않고 설정 해제됩니다.
3. 시드 파일 배포. 각 사용자는 Developer → Configure Third-Party Inference… → Import configuration으로 가져옵니다:
{
"bootstrapUrl": "https://shunt.example.corp/user/bootstrap",
"trustBootstrapDelivery": true
}bootstrapUrl의 origin은 public_url의 origin과 같아야 합니다. Desktop은 끝의 /user/bootstrap을 떼어 shunt의 OAuth 디스커버리 문서를 찾고, 디바이스 코드 로그인을 실행한 뒤, 발급된 bearer로 GET /user/bootstrap을 호출합니다. trustBootstrapDelivery는 로컬 파일로 구성된 디바이스에 bootstrap 응답이 base URL, 헬퍼, 마켓플레이스 값을 전달할 때 Desktop이 띄우는 “Apply settings from your organization?” 대화상자를 건너뜁니다. Desktop은 이 키를 MDM 또는 로컬 파일에서만 받아들이며 bootstrap 응답에서는 받아들이지 않습니다.
누가 구성을 받는가. 권한 판단은 [[server.gateway.policies]]를 재사용합니다. policy가 없으면 로그인한 모든 사용자가 대상이고, policy가 있으면 policy의 match.emails에 포함되거나 catch-all policy(match 없음)가 있을 때 대상이 됩니다. 그 외에는 403을 받습니다. desktop_bootstrap이 없으면 라우트는 404로 응답합니다. 응답에는 ETag가 있어 Desktop의 백그라운드 재확인(기본 10분마다)은 대개 304로 끝납니다.
Desktop은 응답을 메모리에만 보관합니다. 시작할 때 shunt에 도달할 수 없으면 Desktop은 저하된 로그인 상태로 시작하며, 이는 추론이 이미 갖고 있는 의존성과 같습니다. Desktop 로그아웃은 로컬에서만 처리됩니다. shunt는 revocation 엔드포인트를 광고하지 않습니다. 모든 상태 코드는 엔드포인트 레퍼런스를 참고하세요.
3. 모델 선택
shunt는 GET /v1/models를 제공하므로 Claude Desktop은 시작할 때 모델 선택기를 자동으로 디스커버리합니다. 무엇이 나타나는지는 두 가지 요소가 결정합니다.
디스커버리 필터. Claude Desktop의 자동 디스커버리는 Claude로 인식할 수 있는 id, 즉 tier 이름 id(claude-sonnet-*, claude-opus-*, claude-haiku-*, claude-fable-*)만 표시합니다. shunt의 내장 카탈로그는 Anthropic API와 레퍼런스 Claude apps gateway가 제공하는 목록의 상위집합이며, 14개 id가 모두 tier 이름이므로 Claude Desktop에 전부 표시됩니다. 이것은 폴백 스냅샷입니다. shunt가 Anthropic 업스트림에 도달할 수 있으면 해당 호출자의 실제 목록을 대신 제공합니다(모델 디스커버리 참고).
// GET /v1/models — 내장 카탈로그(auto_include_builtin_models), 모두 tier 이름 id
// (각 항목에는 "type": "model", "display_name", "created_at",
// "max_input_tokens", "max_tokens"도 포함됨)
{ "data": [
{ "id": "claude-sonnet-5-5" }, { "id": "claude-opus-5-5" },
{ "id": "claude-fable-5-1" }, { "id": "claude-opus-5" },
{ "id": "claude-sonnet-5" }, { "id": "claude-fable-5" },
{ "id": "claude-opus-4-8" }, { "id": "claude-opus-4-7" },
{ "id": "claude-sonnet-4-6" }, { "id": "claude-opus-4-6" },
{ "id": "claude-opus-4-5-20251101" }, { "id": "claude-haiku-4-5-20251001" },
{ "id": "claude-sonnet-4-5-20250929" }, { "id": "claude-opus-4-1-20250805" }
], "has_more": false,
"first_id": "claude-sonnet-5-5", "last_id": "claude-opus-4-1-20250805" }선별된 claude-<slug>-via-<provider> 별칭(Claude Code에서 동작하는 패턴)은 Claude Desktop에서 버려집니다. 모델 디스커버리 → Claude Desktop은 tier 이름 id만 인식합니다를 참고하세요.
비-Anthropic 백엔드 노출. 두 가지 방법이 있습니다:
-
[[routes]]의upstream_model로 tier 이름 id를 매핑하면 Desktop에서 이를 선택할 때 해당 백엔드로 해석됩니다:[[routes]] model = "claude-sonnet-5" # Claude Desktop이 인식하는 tier 이름 id provider = "codex" upstream_model = "gpt-5.6-sol" # 실제 백엔드 슬러그 -
shunt가 라우팅하는 정확한 id의 명시적
inferenceModels목록으로 Desktop 측 디스커버리를 오버라이드하세요. 모든 항목이 전체 id이면 Claude Desktop은/v1/models호출을 건너뜁니다.
4. 검증
클라이언트 토큰으로 shunt가 디스커버리와 추론에 응답하는지 확인하세요:
# 디스커버리 — [server.auth]가 설정되어 있으면 토큰으로 게이팅됨
curl -s "$SHUNT_URL/v1/models" -H "Authorization: Bearer $SHUNT_CLIENT_TOKEN" | jq '.data[].id'
# 매핑한 tier 이름 id -> 백엔드로 우회
curl -s -X POST "$SHUNT_URL/v1/messages" \
-H "Authorization: Bearer $SHUNT_CLIENT_TOKEN" \
-H "anthropic-version: 2023-06-01" -H "content-type: application/json" \
-d '{"model":"claude-sonnet-5","max_tokens":16,"messages":[{"role":"user","content":"hi"}]}'그런 다음 Claude Desktop을 여세요. 모델 선택기에 tier 이름 항목이 표시되어야 합니다. 비어 있다면 디스커버리에서 필터링되었거나(tier 이름이 아닌 id) /v1/models에 접근할 수 없는 것입니다. 폴백으로 inferenceModels를 명시적으로 설정하세요.