> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tiro.ooo/llms.txt
> Use this file to discover all available pages before exploring further.

# 폴더 검색

> 이름으로 개인 및 팀 폴더를 페이지네이션과 함께 검색

## 개요

폴더 검색 도구(`search_private_folders`와 `search_team_folders`)는 개인 또는 팀 폴더 계층 안에서 이름으로 폴더를 찾는 일관된 방법을 제공해요. 두 도구 모두 NFC 정규화와 함께 **대소문자를 구분하지 않는 부분 문자열 매칭**을 사용하므로 한국어를 비롯한 CJK 텍스트도 안정적으로 매칭돼요.

* **`search_private_folders`** — 개인(공유되지 않은) 폴더를 검색해요.
* **`search_team_folders`** — 팀(워크스페이스 공유) 폴더를 검색해요.

두 도구는 시그니처와 동작이 동일하고, 유일한 차이는 개인 폴더를 검색하느냐 팀 공유 폴더를 검색하느냐예요. 둘 다 `mcp:folders:read` scope가 필요하고 기본적으로 API key의 워크스페이스에서 동작해요 — 다른 워크스페이스를 대상으로 하려면 명시적인 `workspaceGuid`(`list_workspaces`에서 확인)를 전달하세요.

**주요 사용 사례:**

* 이름의 일부만 기억날 때 특정 폴더 찾기(예: "general"은 "0.General", "General", "general-things"에 매칭).
* 워크스페이스의 모든 폴더 열거하기(빈 keyword는 전체를 페이지네이션과 함께 반환).
* 한국어 검색: `keyword="네이버"`는 `"네이버 모니터링"`, `"0.네이버"` 등에 매칭.

**핵심 기능:**

* 대소문자를 구분하지 않는 부분 문자열 매칭(CJK 안정성을 위해 NFC 정규화).
* 폴더는 매칭 위치(이름 시작 부분일수록 상위) 기준으로, 그다음 이름 길이(짧을수록 상위) 기준으로 정렬돼요.
* 각 결과에는 폴더의 breadcrumb 경로가 포함돼요(예: `"Engineering > Q1 Planning > Sprint 1"`).
* 빈 keyword는 모든 폴더를 페이지네이션과 함께 반환해요.
* 하위 호환을 위한 이중 응답 필드: `content`(권장)와 `folders`(레거시 별칭).

<Note>
  **v1 구현 참고:** 이 도구들은 호출할 때마다 상위 폴더 트리를 한 번 가져와 서버 측에서 필터링해요. 네이티브 백엔드 폴더 검색 endpoint는 v2 로드맵에 있어요. 추가되더라도 MCP 시그니처는 동일하게 유지돼요. 이는 구현 세부 사항이에요.
</Note>

## 파라미터

`search_private_folders`와 `search_team_folders`는 동일한 파라미터를 받아요:

| Parameter       | Type   | Required | Description                                                                                   |
| --------------- | ------ | -------- | --------------------------------------------------------------------------------------------- |
| `keyword`       | string | Optional | 검색할 폴더 이름 부분 문자열(대소문자 구분 안 함, NFC 정규화). 생략하면 모든 폴더를 열거해요.                                     |
| `cursor`        | string | Optional | 이전 `nextCursor`에서 받은 페이지네이션 cursor. 다음 페이지를 가져오려면 이걸 전달하세요.                                   |
| `size`          | number | Optional | 페이지당 결과 수(기본값 `30`, 최대 `100`).                                                                |
| `workspaceGuid` | string | Optional | 워크스페이스 GUID(`list_workspaces`에서 확인). 생략하면 API key의 워크스페이스를 사용하고, 하나를 전달하면 다른 워크스페이스를 대상으로 해요. |

### keyword (선택)

대소문자를 구분하지 않는 부분 문자열 매칭이에요. 검색은 한국어, 일본어, 중국어를 비롯한 CJK 텍스트를 안정적으로 처리하기 위해 NFC(Canonical Decomposition 후 Canonical Composition)로 정규화돼요.

빈 keyword이거나 생략하면 모든 폴더를 페이지네이션과 함께 반환해요.

**예시:**

* `"general"`은 `"0.General"`, `"General"`, `"general-things"`에 매칭돼요(매칭 위치, 그다음 이름 길이 순으로 정렬).
* `"네이버"`는 `"네이버 모니터링"`, `"0.네이버"`, `"팀별 > 네이버"`에 매칭돼요.

### cursor (선택)

다음 페이지를 가져오려면 이전 응답의 `nextCursor`를 전달하세요. 첫 페이지에서는 생략하세요.

### size (선택)

페이지당 결과 수예요. 기본값 `30`, 최대 `100`이에요. 페이지가 작을수록 응답이 빠르고, 클수록 왕복 횟수가 줄어요.

## 응답 형식

### 성공 응답 (search\_private\_folders)

```json theme={"system"}
{
  "content": [
    {
      "folderId": 12345,
      "name": "General",
      "path": "General"
    },
    {
      "folderId": 12346,
      "name": "Q1 Planning",
      "path": "Engineering > Q1 Planning"
    }
  ],
  "folders": [
    {
      "folderId": 12345,
      "name": "General",
      "path": "General"
    },
    {
      "folderId": 12346,
      "name": "Q1 Planning",
      "path": "Engineering > Q1 Planning"
    }
  ],
  "total": 47,
  "totalSize": 2,
  "nextCursor": "eyJvZmZzZXQiOjMwfQ=="
}
```

**필드 설명:**

| Field                | Type           | Description                                                                                         |
| -------------------- | -------------- | --------------------------------------------------------------------------------------------------- |
| `content[]`          | array          | 검색 결과(권장 필드).                                                                                       |
| `content[].folderId` | number         | 안정적인 폴더 식별자.                                                                                        |
| `content[].name`     | string         | 폴더 이름(예: `"General"`, `"Q1 Planning"`).                                                             |
| `content[].path`     | string         | breadcrumb 경로(예: `"Engineering > Q1 Planning > Sprint 1"`), `>`로 연결돼요. 최상위 폴더는 `path`가 `name`과 같아요. |
| `folders[]`          | array          | `content`의 레거시 별칭. 두 배열은 동일한 데이터를 담아요. 클라이언트가 선호하는 쪽을 고르세요.                                         |
| `total`              | number         | keyword에 매칭되는 폴더의 총 개수(모든 페이지에 걸친 전체 결과 집합).                                                        |
| `totalSize`          | number         | 이 페이지의 결과 수.                                                                                        |
| `nextCursor`         | string \| null | 다음 페이지를 위한 cursor. 더 이상 결과가 없으면 `null`.                                                             |

<Note>
  응답에는 하위 호환을 위해 `content`(권장, 최신 명명)와 `folders`(레거시 별칭)가 모두 포함돼요. 둘은 같은 배열 객체를 참조하므로 코드에서 선호하는 쪽을 고르고 다른 쪽은 무시하세요.
</Note>

## 사용 예시

### 예시 1: search\_private\_folders — 단순 keyword

**요청:**

```json theme={"system"}
{
  "keyword": "general"
}
```

"general"에 매칭되는(대소문자 구분 안 함) 모든 개인 폴더를 페이지네이션과 함께 반환해요.

**응답:**

```json theme={"system"}
{
  "content": [
    {
      "folderId": 100,
      "name": "General",
      "path": "General"
    },
    {
      "folderId": 101,
      "name": "0.General Announcements",
      "path": "General Folder > 0.General Announcements"
    }
  ],
  "total": 2,
  "totalSize": 2,
  "nextCursor": null
}
```

### 예시 2: search\_team\_folders — 한국어 keyword

**요청:**

```json theme={"system"}
{
  "keyword": "네이버"
}
```

이름에 "네이버"가 들어간 모든 팀 폴더를 반환해요(CJK 매칭을 위해 NFC 정규화).

**응답:**

```json theme={"system"}
{
  "content": [
    {
      "folderId": 200,
      "name": "네이버",
      "path": "파트너십 > 네이버"
    },
    {
      "folderId": 201,
      "name": "네이버 API 모니터링",
      "path": "기술 > 파트너 > 네이버 API 모니터링"
    }
  ],
  "total": 2,
  "totalSize": 2,
  "nextCursor": null
}
```

### 예시 3: 모든 폴더 열거 (빈 keyword)

**요청:**

```json theme={"system"}
{
  "keyword": "",
  "size": 50
}
```

처음 50개 폴더(모든 최상위 및 중첩 폴더)를 특정 순서 없이 반환해요.

**응답:**

```json theme={"system"}
{
  "content": [
    { "folderId": 1, "name": "Engineering", "path": "Engineering" },
    { "folderId": 2, "name": "Q1 Planning", "path": "Engineering > Q1 Planning" },
    { "folderId": 3, "name": "General", "path": "General" }
  ],
  "total": 137,
  "totalSize": 3,
  "nextCursor": "eyJvZmZzZXQ6NTB9"
}
```

### 예시 4: 페이지네이션

**첫 페이지 (cursor 생략):**

```json theme={"system"}
{
  "keyword": "sprint",
  "size": 20
}
```

**두 번째 페이지 (첫 응답의 nextCursor 사용):**

```json theme={"system"}
{
  "keyword": "sprint",
  "size": 20,
  "cursor": "eyJvZmZzZXQ6MjB9"
}
```

## 정렬 순서

결과는 매칭 위치 기준으로, 그다음 폴더 이름 길이 기준(매칭 위치가 같으면 짧은 이름이 상위)으로 정렬돼요:

1. **매칭 위치 오름차순** — `name`이 keyword로 **시작하는** 폴더가 이름 **뒷부분**에서 keyword를 포함하는 폴더보다 상위에 와요.
   * `keyword="general"` → `"General"`(위치 0)이 `"0.General"`(위치 2)보다 상위.

2. **이름 길이 오름차순** — 매칭 위치가 같으면 짧은 이름이 상위에 와요.
   * 둘 다 위치 0에서 "gen"에 매칭: `"General"`(7자)이 `"General Announcements"`(21자)보다 상위.

이렇게 해서 가장 구체적인 매칭이 먼저 나타나요.

## 권장 사례

<AccordionGroup>
  <Accordion title="API key 타입이 아니라 폴더 타입으로 도구를 고르세요">
    `search_private_folders`는 개인(공유되지 않은) 폴더를 검색하고, `search_team_folders`는 팀(워크스페이스 공유) 폴더를 검색해요. 둘 다 `mcp:folders:read` scope가 있는 key면 받아요. 도구는 폴더 타입으로 고르세요. 매칭되는 폴더가 없으면 결과는 오류가 아니라 빈 목록이에요.
  </Accordion>

  <Accordion title="workspaceGuid로 특정 워크스페이스를 대상으로 하기">
    두 도구 모두 기본적으로 API key의 워크스페이스에서 동작해요. 접근 가능한 다른 워크스페이스의 폴더를 검색하려면 `list_workspaces`에서 얻은 명시적인 `workspaceGuid`를 전달하세요.
  </Accordion>

  <Accordion title="CJK 텍스트는 NFC 정규화에 맡기세요">
    한국어, 일본어, 중국어 텍스트는 서버 측에서 자동으로 NFC 정규화돼요. keyword를 미리 전처리할 필요 없이 원본 텍스트를 그대로 전달하면 매칭 엔진이 알아서 처리해요.

    예시: `keyword="네이버"`는 같은 텍스트의 결합형 또는 분해형 폴더에 모두 매칭돼요.
  </Accordion>

  <Accordion title="offset이 아니라 nextCursor로 페이지네이션하세요">
    항상 이전 응답에서 반환된 `nextCursor`를 사용하세요. offset을 직접 계산하려고 하지 마세요. 페이지네이션 동작은 향후 릴리스에서 바뀔 수 있어요.
  </Accordion>

  <Accordion title="모든 폴더를 열거하려면 빈 keyword를 사용하세요">
    필터 없이 폴더의 전체 목록을 가져오려면 `keyword`를 생략하거나 빈 문자열을 전달하세요. `size`와 `nextCursor`로 전체 결과 집합을 페이지네이션하세요.
  </Accordion>
</AccordionGroup>

## 자주 발생하는 오류

### 권한 scope 부족

<Error>
  ```json theme={"system"}
  {
    "error": "FORBIDDEN",
    "message": "Insufficient scope: mcp:folders:read required",
    "statusCode": 403
  }
  ```
</Error>

**해결 방법:** API key에 `mcp:folders:read` scope가 없어요. 올바른 scope로 새 key를 발급하거나 워크스페이스 관리자에게 권한 부여를 요청하세요.

## 토큰 사용량

| Operation            | Tokens    |
| -------------------- | --------- |
| 빈 keyword (모든 폴더 열거) | \~200–500 |
| keyword 검색           | \~200–500 |

폴더 검색은 가벼워요. 결과에는 콘텐츠가 아니라 이름과 경로만 포함돼요.

## scope 요구 사항

`search_private_folders`와 `search_team_folders`는 모두 `mcp:folders:read` scope가 필요해요. API key는 [Tiro Platform API Keys](https://platform.tiro.ooo/dashboard/api-keys)에서 구성하세요.

<Warning>
  **참고:** `mcp:folders:write` scope는 더 이상 존재하지 않아요(2026-05-06 기준). 모든 폴더 쓰기 작업이 제거됐어요. `mcp:folders:write`가 있는 오래된 API key가 있다면 무시돼요. 이 scope는 사용되지 않아요.
</Warning>

## 관련 도구

* **[`list_notes`](./list-notes)** — `filter.folderId`를 사용해 특정 폴더 안의 노트를 찾아요(별도의 "폴더 목록" 도구가 필요 없어요).
* **[`search_notes`](./search-notes)** — `filter.folderId`로 폴더 안의 노트를 검색해요(keyword가 필수인 심층 검색).
