# AI 봇 – 직접 MCP 서버 가져오기

**URL:** https://meta.discourse.org/t/ai-bot-bring-your-own-mcp-server/399667
**Category:** Site Management
**Tags:** ai, ai-bot
**Created:** [3월 31, 2026, 11:40오후 UTC](https://meta.discourse.org/t/ai-bot-bring-your-own-mcp-server/399667 "2026-03-31T23:40:29Z")
**Posts on this page:** 1
**Page:** 1

<div class="post-metadata">

### Author: ![sam](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/sam/32/102149_2.png) [@sam](https://meta.discourse.org/u/sam)
#### Post date: [3월 31, 2026, 11:40오후 UTC](https://meta.discourse.org/t/ai-bot-bring-your-own-mcp-server/399667/1 "2026-03-31T23:40:29Z")

</div>

> 🔖 이 가이드는 외부 **Model Context Protocol (MCP)** 서버를 Discourse AI 에이전트에 연결하는 방법을 설명합니다. 이를 통해 MCP 호환 도구 제공자 중 어떤 것이든 AI 봇 내에서 직접 사용할 수 있습니다.
> 
> 🙋 필요한 사용자 권한: **관리자 (Administrator)**

* * *

## "Bring Your Own MCP"란?

[Model Context Protocol](https://spec.modelcontextprotocol.io/)는 AI 에이전트가 표준 HTTP/JSON-RPC 인터페이스를 통해 외부 도구 서버와 통신할 수 있게 하는 개방형 표준입니다(원래 Anthropic에서 제안). MCP 서버는 LLM이 작업을 수행하기 위해 호출할 수 있는 “도구” 목록을 노출합니다. 여기서 도구는 타입이 지정된 입력을 가진 함수입니다.

Discourse AI는 이제 **MCP 클라이언트** 역할을 수행합니다. 관리자 패널에서 HTTPS MCP 서버를 등록하면, Discourse는 사용 가능한 도구를 발견하고 해당 도구들은 사용자가 선택한 AI 에이전트 내에서 1급 시민(first-class citizens)이 됩니다. JavaScript를 작성할 필요가 없으며, 도구는 원격 서버에 의해 정의됩니다.

이는 Discourse 내에서 실행되는 JavaScript를 작성해야 하는 [커스텀 스크립트 도구](https://meta.discourse.org/t/ai-bot-custom-tools/314103)와 다릅니다. MCP의 경우 이미 실행 중인 외부 서버를 가져오게 됩니다.

* * *

## 요약

- MCP 서버 등록 (URL + 선택적 인증)
- Discourse가 서버의 도구를 자동으로 발견하고 캐시합니다
- 서버를 하나 이상의 AI 에이전트에 할당합니다
- 각 에이전트가 사용할 수 있는 도구를 선택적으로 제한합니다
- 도구는 런타임에 LLM에 의해 호출되며, Discourse를 거쳐 외부 서버로 라우팅됩니다

* * *

## MCP 서버 등록

다음 경로로 이동합니다:

> **Admin → Plugins → Discourse AI → Tools** → **MCP servers** 탭 → **New MCP server**

다음 필드를 입력합니다:

| 필드 | 설명 |
| --- | --- |
| **Name** | 사람이 읽을 수 있는 라벨 (에이전트 에디터 및 로그에 표시됨) |
| **Description** | 이 서버의 용도 (관리자 참고용) |
| **URL** | MCP 서버의 HTTPS 엔드포인트 — 공개된 HTTPS URL이어야 하며, 사설 IP는 허용되지 않습니다 |
| **Authentication** | 다음 중 하나: _No authentication_, _Header credential_, 또는 _OAuth_ |
| **Timeout (seconds)** | 요청당 Discourse가 대기하는 시간 — 기본값 30초, 최대 300초 |
| **Enabled** | 서버를 삭제하지 않고 일시적으로 비활성화하기 위한 토글 |

> ⚠ URL은 HTTPS를 사용해야 합니다. `localhost` 및 RFC-1918 사설 주소는 차단됩니다 (SSRF 보호가 서버 측에서 적용됨).

* * *

## 인증 옵션

### 인증 없음 (No Authentication)

서버는 공개적으로 접근 가능합니다. 자격 증명은 전송되지 않습니다.

### 헤더 자격 증명 (Header Credential)

비밀 값이 모든 요청에 HTTP 헤더로 주입됩니다.

1. 먼저 Admin → AI → Credentials에서 **Credential** 을 생성합니다
2. MCP 서버 폼에서 이를 **Credential** 로 선택합니다
3. **Auth header** 이름을 설정합니다 (기본값: `Authorization`)
4. 선택적 **Auth scheme** 접두사를 설정합니다 (기본값: `Bearer`)

MCP 서버로 전송되는 요청 헤더는 다음과 같습니다:

```plaintext
Authorization: Bearer <your-secret-value>

```

서버가 요구하는 인증 스타일에 맞춰 헤더 이름과 스키마를 모두 변경할 수 있습니다 (예: 스키마를 비워두면 `X-Api-Key: <value>`).

### OAuth

Discourse는 MCP 클라이언트로서 완전한 OAuth 2.0 + PKCE 플로우를 구현합니다. 이는 도구를 OAuth 뒤에 보호하는 MCP 서버를 지원합니다.

**설정 단계:**

1. **Authentication** 을 `OAuth`로 설정합니다
2. **Client registration** 을 선택합니다:
  - **Client metadata document** (기본값) — Discourse는 `https://your-site.com/discourse-ai/mcp/oauth/client-metadata`에 자체 OAuth 클라이언트 메타데이터를 게시합니다. MCP 서버가 [RFC 7591 Dynamic Client Registration](https://www.rfc-editor.org/rfc/rfc7591)을 지원하면 Discourse가 자동으로 등록합니다
  - **Manual client credentials** — 사전에 등록한 **OAuth client ID** 를 입력하고 **OAuth client secret** 자격 증명을 선택합니다

3. 선택적으로 **OAuth scopes** 를 설정합니다 (공백으로 구분)
4. 서버를 저장합니다
5. **Connect** 를 클릭합니다 — Discourse가 제공자의 인증 페이지로 리다이렉트합니다
6. 인증 후 관리자로 돌아오며 상태는 **Connected** 로 표시됩니다

**고급 OAuth 옵션** (“Show advanced options” 토글):

| 옵션 | 목적 |
| --- | --- |
| OAuth authorization params | 인증 요청에 병합되는 JSON 객체 (예: `{"access_type":"offline"}`) |
| OAuth token params | 토큰 교환 요청에 병합되는 JSON 객체 |
| Require refresh token | 제공자가 리프레시 토큰을 반환하지 않으면 연결 실패 |

Discourse는 만료 전에 액세스 토큰을 자동으로 갱신하고, 리프레시 토큰이 사용 가능한 경우 `401` 발생 시 재시도합니다.

* * *

## 연결 테스트

서버를 에이전트에 할당하기 전에 에디터 폼의 **Test connection** 버튼을 사용하십시오. 이는 즉시 MCP 세션을 초기화하고 `tools/list`를 호출하여 다음을 반환합니다:

- 협상된 MCP **프로토콜 버전**
- 발견된 **도구 수**
- **모든 도구의 이름**

테스트가 실패하면 서버의 오류 메시지(또는 타임아웃 표시자)가 인라인으로 표시됩니다.

* * *

## Discourse의 도구 발견 방식

Discourse는 [MCP 스펙 `2025-03-26`](https://spec.modelcontextprotocol.io/)를 따릅니다. 연결 시퀀스는 다음과 같습니다:

```plaintext
Discourse → POST / { method: "initialize", params: { protocolVersion, capabilities, clientInfo } }
Server → { result: { protocolVersion, capabilities } } + Mcp-Session-Id 헤더
Discourse → POST / { method: "notifications/initialized" } (세션 핸드셰이크 완료)
Discourse → POST / { method: "tools/list", session_id: … }
Server → { result: { tools: [{ name, description, inputSchema } …] } }

```

도구 정의는 서버별로 **1시간 동안 캐시** 됩니다. 캐시가 만료되면 백그라운드 작업이 투명하게 이를 새로고침합니다. 캐시 키는 사이트/서버별로 설정되므로 멀티 사이트 설치 환경에서는 격리됩니다.

**Test connection** 을 클릭하여 수동으로 새로고침을 트리거할 수도 있습니다 — 이는 항상 실시간 데이터를 가져옵니다.

서버의 건강 상태(`healthy` / `error`)는 모든 캐시 새로고침 시 업데이트됩니다.

* * *

## AI 에이전트에 MCP 서버 할당

서버가 등록되면 에이전트에 할당합니다:

1. **Admin → Plugins → Discourse AI → Agents** 로 이동하여 에이전트를 편집하거나 생성합니다
2. **MCP servers** 섹션(일반적인 Tools 섹션 아래)으로 스크롤합니다
3. 목록에는 활성화된 모든 MCP 서버와 도구 수 및 예상 토큰 비용이 표시됩니다
4. 서버를 켜면 — 이제 해당 에이전트에서 사용할 수 있게 됩니다

> **팁:** 기본적으로 서버의 _모든_ 도구가 에이전트에 제공됩니다. 로케일 문자열이 잘 설명하고 있습니다: _“선택된 MCP 서버는 기본적으로 모든 도구를 노출합니다. 토큰 사용량을 줄이고 도구 선택에 집중하려면 에이전트별로 범위를 좁히십시오.”_

* * *

## 에이전트별 특정 도구 선택

사용 가능한 도구가 수십 개에 달하면 모든 메시지의 토큰 비용이 증가합니다(각 도구 정의는 시스템 프롬프트에서 모델에 전송됨). 이를 간결하게 유지하기 위해:

1. 에이전트 에디터에서 할당된 MCP 서버 옆의 **Choose tools** 를 클릭합니다
2. 모달이 서버가 현재 노출하는 모든 도구와 그 설명 및 매개변수 목록을 표시합니다
3. 이 에이전트가 필요한 도구만 선택합니다
4. Save를 클릭합니다 — 이제 에이전트는 선택된 부분 집합만 볼 수 있습니다

`ai_agent_mcp_servers` 조인 테이블은 `selected_tool_names`를 JSONB 배열로 저장합니다. 빈 배열은 "모든 도구 활성화"를 의미합니다.

* * *

## 도구 명명 및 충돌 해결

MCP 도구 이름은 단일 에이전트의 도구 목록(에이전트의 내장 및 커스텀 스크립트 도구 포함) 내에서 고유해야 합니다. Discourse는 충돌을 자동으로 처리합니다:

- 두 개의 다른 MCP 서버가 **같은 이름** 의 도구를 노출하는 경우, Discourse는 네임스페이스를 지정합니다: `servername__toolname`
- 내장 Discourse 도구와 MCP 도구가 이름을 공유하는 경우, MCP 도구도 네임스페이스가 지정됩니다
- 네임스페이스 지정 후에도 충돌이 있으면 숫자 접미사가 추가됩니다 (`_2`, `_3`, …)

따라서 LLM 호출에 사용되는 `function_name`은 MCP 서버의 원본 `tool_name`과 다를 수 있습니다. 이는 투명하게 처리됩니다 — MCP 도구 클래스는 항상 원본 `tool_name_value`를 별도로 저장하고 서버 호출 시 이를 사용합니다.

* * *

## 런타임 도구 호출 작동 방식

LLM이 MCP 도구를 사용하기로 결정하면:

1. **세션 재사용** : Discourse는 현재 봇 컨텍스트(`context.mcp_state`)에서 이 서버에 대한 캐시된 MCP 세션 ID를 조회합니다. 세션은 봇 응답 체인별로 생성되며 동일한 서버에 대한 도구 호출 간에 재사용됩니다.
2. **필요 시 초기화** : 세션이 없으면 새로운 `initialize` + `notifications/initialized` 핸드셰이크가 실행됩니다.
3. **호출** : `{ method: "tools/call", params: { name: tool_name, arguments: params } }`와 함께 `POST /`
4. **세션 만료** : 서버가 `404`(만료된 세션)를 반환하면, Discourse는 자동으로 재초기화하고 한 번 재시도합니다.
5. **응답 정규화** : `text` 유형의 MCP 콘텐츠 항목은 연결됩니다. 텍스트가 아닌 항목은 JSON 직렬화됩니다. `structuredContent`는 예쁘게 포맷된 JSON입니다.
6. **오류 결과** : 서버가 `isError: true`를 반환하면, 봇은 결과 대신 오류 메시지를 수신합니다.

서버 응답은 일반 JSON 또는 SSE 스트림일 수 있으며 — Discourse는 둘 다 처리합니다.

* * *

## 토큰 비용 표시

에이전트 에디터에서 각 할당된 MCP 서버는 예상 토큰 수를 표시합니다. 이는 각 도구의 전체 JSON 시그니처(이름 + 설명 + 입력 스키마)에 적용된 OpenAI `cl100k_base` 토크나이저를 사용하여 계산됩니다. 이는 근사치이며, 실제 비용은 LLM의 토크나이저에 따라 달라집니다.

특정 에이전트에 어떤 서버와 도구를 할당할지 정보에 입각한 결정을 내릴 수 있도록 토큰 비용 세부 사항이 표시됩니다.

* * *

## 문제 해결

| 증상 | 확인 사항 |
| --- | --- |
| **Test connection이 타임아웃으로 실패** | \*\*Timeout (seconds)\*\*를 증가시킵니다. 기본값은 30초입니다. 서버 초기화가 느리면 60~120초를 시도해 보세요. |
| **테스트는 성공하지만 에이전트에 도구가 표시되지 않음** | 서버가 **Enabled** 상태인지, 그리고 에이전트의 MCP servers 섹션에서 해당 서버가 켜져 있는지 확인합니다. |
| **OAuth 상태가 "Needs attention"으로 표시** | 마지막 OAuth 오류가 에디터 폼에 표시됩니다. 일반적인 원인: 리프레시 토큰 만료 (Reconnect 클릭), 서버가 예상하지 못한 스코프를 반환, 또는 클라이언트 메타데이터 URL이 서버에서 접근 불가능. |
| **도구 이름이 `myserver__sometool`처럼 보임** | 정상 — 다른 도구(내장 또는 다른 서버에서)가 같은 이름을 가졌습니다. LLM은 이 네임스페이스 지정된 이름을 자동으로 보고 사용합니다. |
| **일정 기간 후 Health가 "error"로 표시** | 백그라운드 새로고침 작업이 서버에 도달하지 못했습니다. 사이트의 `/logs`를 확인하고 MCP 서버가 Discourse 호스트에서 도달 가능한지 검증합니다. |
| **대화 도중 도구가 작동 중단** | 세션 만료. Discourse는 도구 호출당 자동으로 한 번 재시도하지만, 서버가 지속적으로 재시작되고 있다면 세션 TTL을 짧게 하거나 서버 측 로그를 조사해 보세요. |

더 깊은 디버깅을 위해 `ai_bot_debugging_allowed_groups`를 통해 AI 트랜스크립트 접근을 활성화하고 전체 대화 로그를 검사하십시오.

* * *

## 기술 참고 사항

### MCP 프로토콜 세부 사항

| 속성 | 값 |
| --- | --- |
| 프로토콜 버전 | `2025-03-26` |
| 전송 | HTTP POST (JSON-RPC 2.0) |
| SSE 지원 | 예 (`tools/call` 응답 스트리밍을 위해) |
| 세션 관리 | `Mcp-Session-Id` HTTP 헤더 |
| 최대 응답 바디 | 5 MB |
| 클라이언트 User-Agent | `Discourse AI MCP Client / <version>` |

### JSON 스키마 지원

Discourse는 LLM에 전달하기 전에 도구 `inputSchema` 정의에서 다음 JSON 스키마 구성 요소를 해석합니다:

- `$ref` — 루트 스키마의 `$defs` / `definitions`에 대해 해석됨
- `allOf` — 병합됨 (properties 및 required 배열은 유니온 병합됨)
- `anyOf` / `oneOf` — 첫 번째 비-`null` 변형이 사용됨

### 관련 소스 파일

- [`plugins/discourse-ai/lib/mcp/client.rb`](https://github.com/discourse/discourse/blob/main/plugins/discourse-ai/lib/mcp/client.rb) — MCP HTTP 클라이언트 (세션, 호출, OAuth 재시도)
- [`plugins/discourse-ai/lib/mcp/tool_registry.rb`](https://github.com/discourse/discourse/blob/main/plugins/discourse-ai/lib/mcp/tool_registry.rb) — 도구 캐싱, 충돌 해결
- [`plugins/discourse-ai/lib/agents/tools/mcp.rb`](https://github.com/discourse/discourse/blob/main/plugins/discourse-ai/lib/agents/tools/mcp.rb) — 에이전트 런타임을 위한 MCP 호출을 래핑하는 Tool 클래스
- [`plugins/discourse-ai/app/models/ai_mcp_server.rb`](https://github.com/discourse/discourse/blob/main/plugins/discourse-ai/app/models/ai_mcp_server.rb) — 서버 모델, OAuth 토큰 관리
- [`plugins/discourse-ai/app/models/ai_agent_mcp_server.rb`](https://github.com/discourse/discourse/blob/main/plugins/discourse-ai/app/models/ai_agent_mcp_server.rb) — 에이전트별 도구 선택
- [`plugins/discourse-ai/lib/mcp/oauth_flow.rb`](https://github.com/discourse/discourse/blob/main/plugins/discourse-ai/lib/mcp/oauth_flow.rb) — OAuth 2.0 + PKCE 플로우

* * *

## 관련 주제

- [AI Bot – Custom Tools (스크립트 기반)](https://meta.discourse.org/t/ai-bot-custom-tools/314103)
- [Discourse AI 페르소나 / 에이전트 가이드](https://meta.discourse.org/t/discourse-ai-persona-guide/306099)
- [Discourse MCP 출시! (Discourse를 MCP _서버_로)](https://meta.discourse.org/t/discourse-mcp-is-here/386983)

> 💡 Discourse-as-MCP-server 기능([discourse/discourse-mcp](https://github.com/discourse/discourse-mcp))은 이 기능의 보완재입니다: 외부 AI 클라이언트(Claude Code, Cursor 등)가 Discourse 사이트를 읽고 쓸 수 있게 합니다. 이 가이드는 그 반대입니다 — Discourse AI 에이전트가 외부 MCP 서버를 호출할 수 있게 합니다.
