# 내 클라이언트

> Streamable HTTP로 어떤 MCP 클라이언트든 Nodaro에 연결하세요. OAuth 서버를 탐색하고, 클라이언트나 개발자 앱을 등록한 다음, PKCE로 로그인합니다.

Source: https://nodaro.ai/ko/docs/mcp/connect/custom-client

**내 클라이언트**는 Streamable HTTP로 표준 MCP를 사용하고 OAuth로 로그인한다면 Nodaro에 연결할 수 있습니다. 클라이언트가 `https://mcp.nodaro.ai/mcp`를 가리키게 하고, OAuth 서버를 탐색하게 한 다음, 클라이언트를 등록하고 사용자를 동의 화면으로 보내세요. 이 페이지에는 엔드포인트, 등록 규칙, 토큰 수명이 나와 있습니다.

## 클라이언트에 필요한 것
- `https://mcp.nodaro.ai/mcp`의 **Streamable HTTP 기반 MCP**.
- **PKCE를 사용하는 OAuth 2.0 인증 코드 흐름.** `S256` 코드 챌린지 방식만 허용됩니다.
- 보호된 리소스 메타데이터(RFC 9728)와 인증 서버 메타데이터(RFC 8414)를 통한 **OAuth 탐색**.
- 동적 클라이언트 등록(RFC 7591)이나 한 번 등록해 두는 개발자 앱을 통한 **클라이언트 등록**.

## 엔드포인트
| 항목 | 위치 |
| --- | --- |
| MCP 엔드포인트 | `https://mcp.nodaro.ai/mcp` |
| 보호된 리소스 메타데이터 | `https://mcp.nodaro.ai/.well-known/oauth-protected-resource` |
| 인증 서버 메타데이터 | `https://app.nodaro.ai/.well-known/oauth-authorization-server` |
| 동적 클라이언트 등록 | `POST https://app.nodaro.ai/v1/oauth/register` |
| 토큰 교환 | `POST https://app.nodaro.ai/v1/oauth/token` |
| 토큰 해지 | `POST https://app.nodaro.ai/v1/oauth/revoke` |

두 메타데이터 문서 모두 `app.nodaro.ai`와 `mcp.nodaro.ai` 두 호스트에서 제공됩니다. 일부 클라이언트는 `/mcp` 접미사가 붙은 형태를 먼저 확인하므로, 각 문서는 `/.well-known/oauth-protected-resource/mcp`처럼 `/mcp` 접미사가 붙은 경로로도 제공됩니다. 인증 서버 메타데이터는 인증, 토큰, 등록, 해지 엔드포인트, `code` 응답 유형, `authorization_code` 권한 부여 유형, `S256` PKCE, `client_secret_post` 인증, 지원되는 범위를 알립니다.

## 연결 흐름
### 인증 서버 탐색
MCP 호스트에서 보호된 리소스 메타데이터를 읽으세요. 이 메타데이터는 리소스 `https://mcp.nodaro.ai/mcp`를 그 인증 서버 `https://app.nodaro.ai`에 연결합니다. 그런 다음 인증 서버 메타데이터에서 엔드포인트를 읽으세요.

### 클라이언트 등록
`client_name`과 리디렉션 URI를 등록 엔드포인트로 보내세요. Nodaro는 `ndr_dcr_`로 시작하는 `client_id`와 `client_secret`으로 응답합니다. 이 엔드포인트는 IP 주소 하나당 분당 10개의 요청을 받습니다.

### 사용자를 동의 화면으로 보내기
`client_id`, `redirect_uri`, `response_type=code`, `scope` 목록, 무작위 `state`, 그리고 `code_challenge_method=S256`과 함께 PKCE `code_challenge`를 넣어 브라우저에서 인증 엔드포인트를 여세요. 사용자는 로그인하고 권한을 검토한 다음 **허용**을 클릭합니다.

### 코드 교환
Nodaro가 `code`와 내 `state`를 붙여 `redirect_uri`로 리디렉션합니다. `state`를 확인한 다음, `code_verifier`와 함께 토큰 엔드포인트에서 코드를 교환하세요. 코드는 한 번만 작동하며 발급된 지 10분 후에 만료됩니다.

### MCP 엔드포인트 호출
`ndr_app_`으로 시작하는 액세스 토큰을 `https://mcp.nodaro.ai/mcp`로 보내는 모든 요청에 `Authorization: Bearer <token>`으로 넣으세요. `tools/list`로 도구 목록을 가져오세요.

## 등록할 수 있는 클라이언트 이름
기본적으로 동적 클라이언트 등록은 알려진 클라이언트 이름만 받습니다. Claude, Claude Code, Cursor, Cline, Continue, Goose, ChatGPT, OpenAI, Lovable, Gemini, Gemini CLI, Codex, MCP Inspector, mcp-inspector입니다. 다른 이름의 클라이언트는 `403 client_not_allowed`를 받습니다.

내 클라이언트의 이름이 다르다면 대신 개발자 앱으로 한 번 등록하세요.

1. [app.nodaro.ai/settings/developer-apps](https://app.nodaro.ai/settings/developer-apps)를 열고 **앱 만들기**를 클릭하세요.
2. 이름, 리디렉션 URI, 클라이언트가 요청할 수 있는 범위를 입력하세요.
3. `client_id`와 `client_secret`을 복사하세요. 시크릿은 한 번만 표시됩니다. 시크릿은 만료되지 않으며, 앱 페이지에서 재발급할 수 있습니다.

각 계정은 개발자 앱을 직접 최대 5개까지 등록할 수 있습니다. 스스로 등록한 클라이언트는 같은 목록에 표시되지만 이 한도에는 포함되지 않습니다.

내 Nodaro 인스턴스에서는 운영자가 `MCP_DYNAMIC_REGISTRATION`(기본값인 `allowlist`, `open`, `off` 중 하나)과 `MCP_DCR_ALLOWLIST`로 등록을 제어합니다. `open` 모드에서는 클라이언트 이름과 리디렉션 URI 조합 하나가 24시간 안에 사용되지 않은 등록을 최대 5개까지 가질 수 있으며, 그보다 많으면 `429 too_many_open_registrations`를 반환합니다. `off` 모드에서는 등록이 `403 dcr_disabled`를 반환합니다. [셀프 호스팅 설치의 MCP](https://nodaro.ai/docs/self-hosting/mcp)를 참조하세요.

## 토큰
- **수명.** 액세스 토큰은 90일 동안 유효합니다. 갱신 토큰은 없으므로, 호출이 `401`을 반환하면 사용자를 다시 동의 화면으로 보내세요.
- **해지.** 내 클라이언트는 해지 엔드포인트에서 토큰을 해지할 수 있으며, 이 엔드포인트는 항상 `200`으로 응답합니다. 사용자도 [app.nodaro.ai/settings/connected-apps](https://app.nodaro.ai/settings/connected-apps)의 **설정 › 연결된 앱**에서 내 클라이언트를 해지할 수 있습니다. 그러면 그 사용자에 대해 클라이언트에 발급된 모든 토큰이 한꺼번에 끝나고, 다음 호출은 `401`을 반환합니다.
- **동의 화면.** 동적으로 등록된 클라이언트는 이름을 직접 정했으므로, 동의 화면은 Nodaro가 그 클라이언트를 확인하지 않았다고 사용자에게 경고합니다.

같은 OAuth 서버가 REST API도 담당합니다. [개발자용 OAuth](https://nodaro.ai/docs/developers/oauth)에서 자세히 다룹니다.

## 도구 결과 처리
- **작업.** 생성 도구는 작업을 시작하고 그 ID를 바로 반환합니다. 작업이 `completed` 또는 `failed`가 될 때까지 5~10초마다 `get_job`을 폴링하거나 `wait_for_job`을 호출하세요. [작업 도구](https://nodaro.ai/docs/mcp/tools/jobs)를 참조하세요.
- **구조화된 콘텐츠.** 많은 도구가 텍스트 응답 옆에 `structuredContent`로 데이터를 반환합니다. 예를 들어 `get_job`의 작업 엔벨로프가 그렇습니다. 코드에서는 구조화된 데이터를 읽으세요.
- **카드는 선택 사항입니다.** MCP Apps를 표시하는 호스트는 작업 진행 상황과 업로드 선택기 같은 대화형 카드를 받습니다. 카드가 없는 클라이언트는 같은 결과를 텍스트와 구조화된 데이터로 읽습니다.
- **태스크.** MCP `tasks` API를 지원하는 클라이언트는 이 API로 작업 진행 상황을 받습니다.
- **누락된 도구.** 사용자가 범위를 부여하지 않은 도구는 `tools/list`에서 빠집니다. 누락된 도구를 찾기 전에 부여된 범위를 확인하세요.

## 흔한 실수
- **`https://app.nodaro.ai/mcp` 사용.** 이 주소는 웹 페이지입니다. 이 주소로 `POST`를 보내면 오류 코드 `wrong_mcp_host`와 함께 `405`가 반환되며, 이 오류 코드가 올바른 URL을 알려 줍니다.
- **`https://api.nodaro.ai/mcp` 사용.** 이 도메인은 존재하지 않습니다.
- **끝에 슬래시 추가.** 정확히 `https://mcp.nodaro.ai/mcp`를 사용하세요.

## 참고 자료
- [Model Context Protocol 사양](https://modelcontextprotocol.io/specification)
- [MCP TypeScript SDK](https://github.com/modelcontextprotocol/typescript-sdk)

## 자주 묻는 질문

### Nodaro MCP 서버는 어떤 전송 방식을 사용하나요?

https://mcp.nodaro.ai/mcp에서 Streamable HTTP를 사용합니다. 로그인은 PKCE를 사용하는 OAuth 2.0이며, 클라이언트는 동적 클라이언트 등록으로 스스로 등록할 수 있습니다.

### 등록이 client_not_allowed로 실패하는 이유는 무엇인가요?

동적 등록은 알려진 클라이언트 이름만 받는데, 내 클라이언트의 이름이 목록에 없기 때문입니다. 대신 내 Nodaro 설정에서 개발자 앱을 등록하고, 그 앱의 클라이언트 ID와 시크릿을 사용하세요.

### Nodaro MCP 서버의 액세스 토큰은 얼마 동안 유효한가요?

90일입니다. 갱신 토큰이 없으므로 90일이 지나면 사용자가 다시 로그인합니다. 내 클라이언트는 그 전에 토큰을 해지할 수 있고, 사용자는 설정 › 연결된 앱에서 클라이언트를 해지할 수 있습니다.

### MCP Inspector로 Nodaro MCP 서버를 테스트할 수 있나요?

네. MCP Inspector는 동적으로 등록할 수 있는 클라이언트 이름 중 하나이므로, 연결하고 로그인하고 도구 목록을 볼 수 있습니다.
