# 서비스 검색

> LMSP 클라이언트가 수동 설정, 루프백 탐색, 선택적 mDNS/DNS-SD로 로컬 서비스를 찾는 방법과, well-known 서비스 설명 문서를 읽는 방법을 설명합니다.

Source: https://madeforagent.com/ko/lmsp/1.0/discovery/
Language: ko
Specification: LMSP 1.0 (draft)
Updated: 2026-11-08

## 3.1 검색 방법 {#methods}

클라이언트는 다음 방법을 순서대로 시도하여 서비스를 찾는다.

1. **수동 설정.** 사용자가 서비스 주소를 직접 입력한다.
2. **관례적인 로컬 주소 탐색.** 클라이언트가 후보 주소에 `/.well-known/lmsp.json`을 요청한다. 관례적인 후보는 `http://127.0.0.1:17832`와 `http://[::1]:17832`이다.
3. **LAN 검색.** 클라이언트가 mDNS와 DNS-SD로 `_lmsp._tcp.local.`을 탐색한다.

유효한 서비스 설명([3.3절](https://madeforagent.com/ko/lmsp/1.0/discovery.md#service-description))을 얻으면 그 방법은 성공이다. 사용자가 직접 입력한 주소는 항상 검색된 주소보다 우선한다.

## 3.2 LAN 광고 {#mdns}

DNS-SD는 PTR 레코드로 서비스 인스턴스를 찾고, SRV 레코드로 호스트와 포트를 얻고, TXT 레코드로 소량의 추가 정보를 전달한다. mDNS와 결합하면 로컬 네트워크에서 무구성 검색을 제공한다([RFC 6763](https://www.rfc-editor.org/rfc/rfc6763), [RFC 6762](https://www.rfc-editor.org/rfc/rfc6762)).

광고 예시:

```text
Service type:   _lmsp._tcp.local.
Instance name:  Workstation LMSP._lmsp._tcp.local.

TXT record:
  v=1
  id=svc_01J8M4Y8K6M5E6K6Z7Z0Y8W3M2
  path=/
  auth=pairing
```

| TXT 키 | 의미 |
| --- | --- |
| `v` | 광고 형식의 버전. LMSP 1.0에서는 `1`. |
| `id` | 서비스 id. 서비스 설명의 `service.id`와 같다. |
| `path` | 서비스 루트의 URL 경로. 클라이언트는 `{path}.well-known/lmsp.json`을 요청한다. |
| `auth` | 인증 힌트. `pairing`은 서비스를 쓰기 전에 클라이언트가 페어링해야 함을 뜻한다. |

규칙:

- 서비스는 액세스 토큰, 모델 목록, 파일 경로 등 민감한 정보를 TXT 레코드에 넣**어서는 안 된다**. 이 레코드는 서비스의 위치만 알려 준다. 실제 기능은 서비스 설명에서 읽**어야 한다**.
- 서비스는 mDNS 광고를 기본적으로 비활성화해 두**어야 한다**. 사용자가 LAN 검색을 명시적으로 켠 경우에만 활성화된다. 로컬 컴퓨터에서만 쓰는 서비스는 광고하지 않는다.
- LAN에서 광고하는 서비스는 루프백 밖에서도 수신 대기해야 하는데, 이는 LAN 모드에서만 허용된다([10.5절](https://madeforagent.com/ko/lmsp/1.0/security.md#lan)).
- 클라이언트는 TXT 레코드를 검증되지 않은 힌트로 취급하고, 서비스 설명을 읽어 서비스를 확인**해야 한다**.

## 3.3 서비스 설명 {#service-description}

```http
GET /.well-known/lmsp.json
```

서비스는 이 문서를 인증을 요구하지 않고 `application/json`으로 제공**해야 한다**.

```json
{
  "protocol": "lmsp",
  "versions": ["1.0"],
  "service": {
    "id": "svc_01J8M4Y8K6M5E6K6Z7Z0Y8W3M2",
    "name": "Workstation Local Models",
    "version": "1.0.0"
  },
  "interfaces": [
    {
      "kind": "lmsp",
      "version": "1.0",
      "url": "http://127.0.0.1:17832/lmsp/v1",
      "transport": "http+json"
    },
    {
      "kind": "openai",
      "version": "responses+chat",
      "url": "http://127.0.0.1:17832/v1",
      "transport": "http+json"
    }
  ],
  "capabilities": {
    "streaming": true,
    "tasks": true,
    "event_resume": true,
    "conversations": true,
    "model_management": true
  },
  "authentication": {
    "type": "bearer",
    "pairing_url": "http://127.0.0.1:17832/lmsp/v1/pair"
  },
  "openapi": "http://127.0.0.1:17832/lmsp/v1/openapi.json"
}
```

| 필드 | 의미 |
| --- | --- |
| `protocol` | 항상 `"lmsp"`. |
| `versions` | 서비스가 지원하는 LMSP 버전. `major.minor` 형식의 문자열. |
| `service` | `id`는 안정적인 서비스 식별자, `name`은 표시 이름, `version`은 서비스 소프트웨어의 버전. |
| `interfaces` | 제공하는 인터페이스. 각각 `kind`(`lmsp`, `openai`, `ollama`), `version`, 기본 `url`, `transport`를 가진다. `openai`의 경우 `version`은 제공하는 API 계열을 나타낸다(예: `responses+chat`). |
| `capabilities` | 불리언 기능 플래그. 아래에 나열한다. |
| `authentication` | `type`은 `bearer`. `pairing_url`은 클라이언트가 페어링 코드를 토큰으로 교환하는 위치이다([10.2절](https://madeforagent.com/ko/lmsp/1.0/security.md#pairing)). |
| `openapi` | LMSP 인터페이스를 기술하는 OpenAPI 문서의 URL. |

기능 플래그:

| 플래그 | 의미 |
| --- | --- |
| `streaming` | 응답을 서버 전송 이벤트로 스트리밍할 수 있다. 1.0에서는 `true`여**야 한다**. |
| `tasks` | 비동기 작업을 사용할 수 있다. 1.0에서는 `true`여**야 한다**. |
| `event_resume` | 작업 이벤트 스트림을 구독하고 재개할 수 있다(`GET /lmsp/v1/tasks/{task_id}/events`). |
| `conversations` | 서비스가 응답을 저장하므로 `store`와 `previous_response_id`가 동작하고 `GET /lmsp/v1/responses/{response_id}`를 사용할 수 있다. |
| `model_management` | 모델을 명시적으로 로드하고 언로드할 수 있다. |

## 3.4 클라이언트 동작 {#client-behavior}

클라이언트는 다음과 같이 한다.

- `versions` 중 자신도 지원하는 가장 높은 버전을 선택하는 **것이 좋다**.
- 자신이 사용할 수 있는 방식에 따라 `interfaces`에서 LMSP 인터페이스 또는 OpenAI 인터페이스를 선택하는 **것이 좋다**.
- 서비스 설명이 선언한 기능만 사용**해야 한다**. 플래그가 없으면 `false`를 뜻한다.
- 인식하지 못하는 확장 필드는 무시**해야 한다**.
- 서비스 설명을 영원히 캐시하지 말고, 주기적으로 그리고 요청이 실패했을 때 다시 읽는 **것이 좋다**.
- 선택한 서비스는 주소가 아니라 `service.id`로 기억하는 **것이 좋다**. 주소는 바뀔 수 있기 때문이다.
