MCP 서버 참조
EmDash는 /_emdash/api/mcp에 내장된 Model Context Protocol (MCP) 서버를 포함하며, 콘텐츠 관리 작업을 AI 어시스턴트용 도구로 노출합니다.
이 페이지는 프로토콜 세부 사항: 인증, 전송, 도구 사양, OAuth 검색 및 오류 처리를 다룹니다.
MCP 서버는 세 가지 인증 방법을 지원합니다:
| 방법 | 작동 방식 |
|---|---|
| OAuth 2.1 Authorization Code + PKCE | MCP 클라이언트를 위한 표준 흐름. 사용자가 브라우저에서 범위를 승인합니다. |
| Personal Access Token (PAT) | 관리자 패널에서 생성된 장기 유효 ec_pat_* 토큰. |
| Device Flow | 브라우저에서 코드를 승인하는 CLI 스타일 흐름. emdash login에서 사용됩니다. |
세션 쿠키(관리자 UI에서)도 작동하지만 외부 MCP 클라이언트에는 실용적이지 않습니다.
토큰은 클라이언트가 수행할 수 있는 작업을 제한하기 위해 범위가 지정됩니다. 범위는 OAuth 승인 중에 요청되며 모든 도구 호출 시 적용됩니다.
| 범위 | 접근 권한 부여 |
|---|---|
content:read | 콘텐츠 나열, 가져오기, 비교 및 검색. 분류 용어 및 메뉴 나열. |
content:write | 콘텐츠 생성, 업데이트, 삭제, 게시, 게시 취소, 예약, 복제 및 복원. 분류 용어 생성. |
media:read | 미디어 항목 나열 및 가져오기. |
media:write | 미디어 메타데이터 업데이트 및 삭제. |
schema:read | 컬렉션 나열 및 컬렉션 스키마 가져오기. |
schema:write | 컬렉션 및 필드 생성 및 삭제. |
admin | 모든 작업에 대한 전체 접근 권한. |
admin 범위는 모든 것에 대한 접근 권한을 부여합니다. 세션 기반 인증(토큰 없음)도 사용자의 역할에 따라 전체 접근 권한을 가집니다.
역할 요구사항
섹션 제목: “역할 요구사항”범위 외에도 일부 도구는 최소 RBAC 역할이 필요합니다:
| 작업 | 최소 역할 |
|---|---|
| 콘텐츠 작업 | 최소 없음(범위가 접근 제어) |
| 스키마 읽기 | 편집자 (40) |
| 스키마 쓰기 | 관리자 (50) |
역할 정의는 인증 가이드를 참조하세요.
서버는 무상태 모드에서 Streamable HTTP 전송을 사용합니다. 각 요청은 독립적입니다 — 세션이나 장기 연결이 없습니다.
POST /_emdash/api/mcp— JSON-RPC 도구 호출 전송GET /_emdash/api/mcp— 405 반환 (무상태 모드에서는 SSE 없음)DELETE /_emdash/api/mcp— 405 반환 (닫을 세션 없음)
응답은 JSON-RPC 2.0 형식을 따릅니다. 오류는 표준 JSON-RPC 오류 코드를 사용하며, 범위 및 권한 실패에 대해서는 MCP 특정 코드를 사용합니다.
서버는 7개 도메인에 걸쳐 33개의 도구를 노출합니다. 각 도구는 결과를 JSON 텍스트 콘텐츠로 반환하거나, 실패 시 isError: true와 함께 오류 메시지를 반환합니다.
콘텐츠 도구
섹션 제목: “콘텐츠 도구”content_list
섹션 제목: “content_list”선택적 필터링 및 페이지 매김으로 컬렉션의 콘텐츠 항목을 나열합니다.
| 매개변수 | 유형 | 필수 | 설명 |
|---|---|---|---|
collection | string | 예 | 컬렉션 슬러그 (예: posts, pages) |
status | string | 아니요 | 필터: draft, published 또는 scheduled |
limit | integer | 아니요 | 반환할 최대 항목 수 (1-100, 기본값 50) |
cursor | string | 아니요 | 이전 응답의 페이지 매김 커서 |
orderBy | string | 아니요 | 정렬 기준 필드 (예: created_at, updated_at) |
order | string | 아니요 | 정렬 방향: asc 또는 desc (기본값 desc) |
locale | string | 아니요 | 로케일별 필터 (예: en, fr). i18n과 관련된 경우에만 해당. |
범위: content:read | 읽기 전용: 예
content_get
섹션 제목: “content_get”ID 또는 슬러그로 단일 콘텐츠 항목을 가져옵니다. 모든 필드 값, 메타데이터 및 낙관적 동시성 제어를 위한 _rev 토큰을 반환합니다.
| 매개변수 | 유형 | 필수 | 설명 |
|---|---|---|---|
collection | string | 예 | 컬렉션 슬러그 |
id | string | 예 | 콘텐츠 항목 ID (ULID) 또는 슬러그 |
locale | string | 아니요 | 슬러그 조회용 로케일. ID는 전역적으로 고유합니다. |
범위: content:read | 읽기 전용: 예
content_create
섹션 제목: “content_create”새 콘텐츠 항목을 생성합니다. data 객체는 컬렉션의 스키마와 일치하는 필드 값을 포함해야 합니다 — 사용 가능한 필드를 확인하려면 schema_get_collection을 사용하세요. 항목은 기본적으로 draft 상태로 생성됩니다.
| 매개변수 | 유형 | 필수 | 설명 |
|---|---|---|---|
collection | string | 예 | 컬렉션 슬러그 |
data | object | 예 | 키-값 쌍으로 된 필드 값 |
slug | string | 아니요 | URL 슬러그 (생략 시 제목에서 자동 생성) |
status | string | 아니요 | 초기 상태: draft 또는 published (기본값 draft) |
locale | string | 아니요 | 이 콘텐츠의 로케일 (사이트 기본값으로 기본 설정) |
translationOf | string | 아니요 | 이 항목이 번역된 원본 항목의 ID |
범위: content:write
content_update
섹션 제목: “content_update”기존 콘텐츠 항목을 업데이트합니다. 변경하려는 필드만 포함하세요 — 지정되지 않은 필드는 변경되지 않습니다.
| 매개변수 | 유형 | 필수 | 설명 |
|---|---|---|---|
collection | string | 예 | 컬렉션 슬러그 |
id | string | 예 | 콘텐츠 항목 ID 또는 슬러그 |
data | object | 아니요 | 업데이트할 필드 값 |
slug | string | 아니요 | 새 URL 슬러그 |
status | string | 아니요 | 새 상태: draft 또는 published |
_rev | string | 아니요 | 충돌 감지를 위한 content_get의 리비전 토큰 |
범위: content:write
content_delete
섹션 제목: “content_delete”콘텐츠 항목을 휴지통으로 이동하여 소프트 삭제합니다. 되돌리려면 content_restore를, 영구 삭제하려면 content_permanent_delete를 사용하세요.
| 매개변수 | 유형 | 필수 | 설명 |
|---|---|---|---|
collection | string | 예 | 컬렉션 슬러그 |
id | string | 예 | 콘텐츠 항목 ID 또는 슬러그 |
범위: content:write | 파괴적: 예
content_restore
섹션 제목: “content_restore”휴지통에서 소프트 삭제된 콘텐츠 항목을 복원합니다.
| 매개변수 | 타입 | 필수 | 설명 |
|---|---|---|---|
collection | string | 예 | 컬렉션 슬러그 |
id | string | 예 | 콘텐츠 항목 ID 또는 슬러그 |
범위: content:write
content_permanent_delete
섹션 제목: “content_permanent_delete”휴지통의 콘텐츠 항목을 영구적이고 되돌릴 수 없게 삭제합니다. 항목은 먼저 휴지통에 있어야 합니다.
| 매개변수 | 타입 | 필수 | 설명 |
|---|---|---|---|
collection | string | 예 | 컬렉션 슬러그 |
id | string | 예 | 콘텐츠 항목 ID 또는 슬러그 |
범위: content:write | 파괴적 작업: 예
content_publish
섹션 제목: “content_publish”콘텐츠 항목을 게시하여 사이트에서 라이브 상태로 만듭니다. 현재 초안에서 게시된 리비전을 생성합니다. 이후 편집은 라이브 버전에 영향을 주지 않고 새 초안을 생성하며, 재게시할 때까지 반영되지 않습니다.
| 매개변수 | 타입 | 필수 | 설명 |
|---|---|---|---|
collection | string | 예 | 컬렉션 슬러그 |
id | string | 예 | 콘텐츠 항목 ID 또는 슬러그 |
범위: content:write
content_unpublish
섹션 제목: “content_unpublish”게시된 항목을 초안 상태로 되돌립니다. 라이브 사이트에서는 더 이상 보이지 않지만 콘텐츠는 보존됩니다.
| 매개변수 | 타입 | 필수 | 설명 |
|---|---|---|---|
collection | string | 예 | 컬렉션 슬러그 |
id | string | 예 | 콘텐츠 항목 ID 또는 슬러그 |
범위: content:write
content_schedule
섹션 제목: “content_schedule”콘텐츠 항목을 미래 게시를 위해 예약합니다. 지정된 날짜/시간에 자동으로 게시됩니다.
| 매개변수 | 타입 | 필수 | 설명 |
|---|---|---|---|
collection | string | 예 | 컬렉션 슬러그 |
id | string | 예 | 콘텐츠 항목 ID 또는 슬러그 |
scheduledAt | string | 예 | ISO 8601 날짜/시간 (예: 2026-06-01T09:00:00Z) |
범위: content:write
content_compare
섹션 제목: “content_compare”콘텐츠 항목의 게시된(라이브) 버전과 현재 초안 버전을 비교합니다. 두 버전과 변경 사항 여부를 나타내는 플래그를 반환합니다.
| 매개변수 | 타입 | 필수 | 설명 |
|---|---|---|---|
collection | string | 예 | 컬렉션 슬러그 |
id | string | 예 | 콘텐츠 항목 ID 또는 슬러그 |
범위: content:read | 읽기 전용: 예
content_discard_draft
섹션 제목: “content_discard_draft”현재 초안을 폐기하고 마지막 게시된 버전으로 되돌립니다. 최소 한 번 이상 게시된 항목에서만 작동합니다.
| 매개변수 | 타입 | 필수 | 설명 |
|---|---|---|---|
collection | string | 예 | 컬렉션 슬러그 |
id | string | 예 | 콘텐츠 항목 ID 또는 슬러그 |
범위: content:write | 파괴적 작업: 예
content_list_trashed
섹션 제목: “content_list_trashed”컬렉션의 휴지통에 있는 소프트 삭제된 콘텐츠 항목을 나열합니다.
| 매개변수 | 타입 | 필수 | 설명 |
|---|---|---|---|
collection | string | 예 | 컬렉션 슬러그 |
limit | integer | 아니요 | 최대 항목 수 (1-100, 기본값 50) |
cursor | string | 아니요 | 페이지네이션 커서 |
범위: content:read | 읽기 전용: 예
content_duplicate
섹션 제목: “content_duplicate”기존 콘텐츠 항목의 사본을 생성합니다. 복제본은 제목에 “(복사본)“이 추가되고 자동 생성된 슬러그를 가진 초안으로 생성됩니다.
| 매개변수 | 타입 | 필수 | 설명 |
|---|---|---|---|
collection | string | 예 | 컬렉션 슬러그 |
id | string | 예 | 복제할 콘텐츠 항목 ID 또는 슬러그 |
범위: content:write
content_translations
섹션 제목: “content_translations”콘텐츠 항목의 모든 로케일 변형을 가져옵니다. 번역 그룹과 각 로케일 버전의 요약을 반환합니다. i18n이 활성화된 경우에만 관련이 있습니다.
| 매개변수 | 타입 | 필수 | 설명 |
|---|---|---|---|
collection | string | 예 | 컬렉션 슬러그 |
id | string | 예 | 콘텐츠 항목 ID 또는 슬러그 |
범위: content:read | 읽기 전용: 예
스키마 도구
섹션 제목: “스키마 도구”schema_list_collections
섹션 제목: “schema_list_collections”CMS에 정의된 모든 콘텐츠 컬렉션을 나열합니다. 슬러그, 레이블, 지원 기능 및 타임스탬프를 반환합니다.
매개변수 없음.
범위: schema:read | 최소 역할: 편집자 | 읽기 전용: 예
schema_get_collection
섹션 제목: “schema_get_collection”모든 필드 정의를 포함한 컬렉션에 대한 상세 정보를 가져옵니다. 필드는 콘텐츠 모델(이름, 타입, 제약 조건, 유효성 검사 규칙)을 설명합니다. 이를 통해 content_create 및 content_update가 기대하는 내용을 이해할 수 있습니다.
| 매개변수 | 타입 | 필수 | 설명 |
|---|---|---|---|
slug | string | 예 | 컬렉션 슬러그 (예: posts) |
범위: schema:read | 최소 역할: 편집자 | 읽기 전용: 예
schema_create_collection
섹션 제목: “schema_create_collection”새 콘텐츠 컬렉션을 생성합니다. 이는 데이터베이스 테이블과 스키마 정의를 생성합니다. 슬러그는 소문자 알파벳으로 시작하고 알파벳, 숫자, 밑줄만 포함해야 합니다.
| 매개변수 | 타입 | 필수 | 설명 |
|---|---|---|---|
slug | string | 예 | 고유 식별자 (/^[a-z][a-z0-9_]*$/) |
label | string | 예 | 표시 이름 (복수형, 예: “블로그 게시물”) |
labelSingular | string | 아니요 | 단수형 표시 이름 |
description | string | 아니요 | 이 컬렉션에 대한 설명 |
icon | string | 아니요 | 관리자 UI용 아이콘 이름 |
supports | string[] | 아니요 | 지원 기능: drafts, revisions, preview, scheduling, search (기본값: ['drafts', 'revisions']) |
범위: schema:write | 최소 역할: 관리자
schema_delete_collection
섹션 제목: “schema_delete_collection”컬렉션과 해당 데이터베이스 테이블을 삭제합니다. 이는 되돌릴 수 없으며 컬렉션의 모든 콘텐츠를 삭제합니다.
| 매개변수 | 타입 | 필수 | 설명 |
|---|---|---|---|
slug | string | 예 | 삭제할 컬렉션 슬러그 |
force | boolean | 아니요 | 컬렉션에 콘텐츠가 있어도 강제 삭제 |
범위: schema:write | 최소 역할: 관리자 | 파괴적 작업: 예
schema_create_field
섹션 제목: “schema_create_field”컬렉션 스키마에 새 필드를 추가합니다. 이는 데이터베이스 테이블에 열을 추가합니다.
| 매개변수 | 타입 | 필수 | 설명 |
|---|---|---|---|
collection | string | 예 | 컬렉션 슬러그 |
slug | string | 예 | 필드 식별자 (/^[a-z][a-z0-9_]*$/) |
label | string | 예 | 표시 이름 |
type | string | 예 | 데이터 타입 (아래 참조) |
required | boolean | 아니요 | 필드가 필수인지 여부 |
unique | boolean | 아니요 | 값이 고유해야 하는지 여부 |
defaultValue | any | 아니요 | 새 항목에 대한 기본값 |
validation | object | 아니요 | 제약 조건: min, max, minLength, maxLength, pattern, options |
options | object | 아니요 | 위젯 구성: collection (참조용), rows (텍스트 영역용) |
searchable | boolean | 아니요 | 전체 텍스트 검색 색인에 포함 |
translatable | boolean | 아니요 | 이 필드가 번역 가능한지 여부 (기본값 true) |
필드 타입: string, text, number, integer, boolean, datetime, select, multiSelect, portableText, image, file, reference, json, slug.
select 및 multiSelect 타입의 경우, 허용된 값을 validation.options에 제공하세요.
범위: schema:write | 최소 역할: 관리자
schema_delete_field
섹션 제목: “schema_delete_field”컬렉션에서 필드를 제거합니다. 이 작업은 열을 삭제하고 해당 필드의 모든 데이터를 지웁니다. 되돌릴 수 없습니다.
| 매개변수 | 타입 | 필수 | 설명 |
|---|---|---|---|
collection | string | 예 | 컬렉션 슬러그 |
fieldSlug | string | 예 | 제거할 필드 슬러그 |
범위: schema:write | 최소 역할: 관리자 | 파괴적 작업: 예
미디어 도구
섹션 제목: “미디어 도구”media_list
섹션 제목: “media_list”업로드된 미디어 파일을 MIME 타입 필터링 및 페이지네이션과 함께 나열합니다.
| 매개변수 | 타입 | 필수 | 설명 |
|---|---|---|---|
mimeType | string | 아니요 | MIME 타입 접두사로 필터링 (예: image/, application/pdf) |
limit | integer | 아니요 | 최대 항목 수 (1-100, 기본값 50) |
cursor | string | 아니요 | 페이지네이션 커서 |
범위: media:read | 읽기 전용: 예
media_get
섹션 제목: “media_get”ID로 단일 미디어 파일의 세부 정보를 가져옵니다. 파일명, MIME 타입, 크기, 차원, 대체 텍스트 및 URL을 포함한 메타데이터를 반환합니다.
| 매개변수 | 타입 | 필수 | 설명 |
|---|---|---|---|
id | string | 예 | 미디어 항목 ID |
범위: media:read | 읽기 전용: 예
media_update
섹션 제목: “media_update”업로드된 미디어 파일의 메타데이터를 업데이트합니다. 파일 자체는 변경할 수 없습니다.
| 매개변수 | 타입 | 필수 | 설명 |
|---|---|---|---|
id | string | 예 | 미디어 항목 ID |
alt | string | 아니요 | 접근성을 위한 대체 텍스트 |
caption | string | 아니요 | 캡션 텍스트 |
width | integer | 아니요 | 픽셀 단위 이미지 너비 |
height | integer | 아니요 | 픽셀 단위 이미지 높이 |
범위: media:write
media_delete
섹션 제목: “media_delete”미디어 파일을 영구적으로 삭제합니다. 데이터베이스 레코드와 저장소의 파일을 제거합니다. 이 미디어를 참조하는 콘텐츠는 참조가 끊어집니다.
| 매개변수 | 타입 | 필수 | 설명 |
|---|---|---|---|
id | string | 예 | 미디어 항목 ID |
범위: media:write | 파괴적 작업: 예
검색 도구
섹션 제목: “검색 도구”search
섹션 제목: “search”콘텐츠 컬렉션 전체에서 전체 텍스트 검색을 수행합니다. 컬렉션은 supports 목록에 search가 포함되어야 하며 필드는 searchable로 표시되어야 합니다.
| 매개변수 | 타입 | 필수 | 설명 |
|---|---|---|---|
query | string | 예 | 검색 쿼리 텍스트 |
collections | string[] | 아니요 | 특정 컬렉션 슬러그로 검색 제한 |
locale | string | 아니요 | 로케일별 결과 필터링 |
limit | integer | 아니요 | 최대 결과 수 (1-50, 기본값 20) |
범위: content:read | 읽기 전용: 예
분류 도구
섹션 제목: “분류 도구”taxonomy_list
섹션 제목: “taxonomy_list”모든 분류 정의(예: 카테고리, 태그)를 나열합니다. 이름, 레이블, 계층적 여부 및 연결된 컬렉션을 반환합니다.
매개변수 없음.
범위: content:read | 읽기 전용: 예
taxonomy_list_terms
섹션 제목: “taxonomy_list_terms”페이지네이션과 함께 분류 내 용어를 나열합니다.
| 매개변수 | 타입 | 필수 | 설명 |
|---|---|---|---|
taxonomy | string | 예 | 분류 이름 (예: categories, tags) |
limit | integer | 아니요 | 최대 항목 수 (1-100, 기본값 50) |
cursor | string | 아니요 | 페이지네이션 커서 |
범위: content:read | 읽기 전용: 예
taxonomy_create_term
섹션 제목: “taxonomy_create_term”분류에 새 용어를 생성합니다. 계층적 분류의 경우, 하위 용어를 생성하려면 parentId를 지정하세요.
| 매개변수 | 타입 | 필수 | 설명 |
|---|---|---|---|
taxonomy | string | 예 | 분류 이름 |
slug | string | 예 | URL-안전 식별자 |
label | string | 예 | 표시 이름 |
parentId | string | 아니요 | 상위 용어 ID (계층적 분류용) |
description | string | 아니요 | 용어 설명 |
범위: content:write
메뉴 도구
섹션 제목: “메뉴 도구”menu_list
섹션 제목: “menu_list”모든 탐색 메뉴를 나열합니다. 이름, 레이블 및 타임스탬프를 반환합니다.
매개변수 없음.
범위: content:read | 읽기 전용: 예
menu_get
섹션 제목: “menu_get”이름으로 메뉴를 가져오고 순서대로 모든 항목을 포함합니다. 항목에는 레이블, URL, 타입 및 중첩을 위한 선택적 상위 항목이 있습니다.
| 매개변수 | 타입 | 필수 | 설명 |
|---|---|---|---|
name | string | 예 | 메뉴 이름 (예: main, footer) |
범위: content:read | 읽기 전용: 예
개정 도구
섹션 제목: “개정 도구”revision_list
섹션 제목: “revision_list”콘텐츠 항목에 대한 개정 이력을 최신순으로 나열합니다. 컬렉션이 revisions를 지원해야 합니다.
| 매개변수 | 타입 | 필수 | 설명 |
|---|---|---|---|
collection | string | 예 | 컬렉션 슬러그 |
id | string | 예 | 콘텐츠 항목 ID 또는 슬러그 |
limit | integer | 아니요 | 최대 개정 수 (1-50, 기본값 20) |
범위: content:read | 읽기 전용: 예
revision_restore
섹션 제목: “revision_restore”콘텐츠 항목을 이전 개정으로 복원합니다. 현재 초안을 지정된 개정의 데이터로 대체합니다. 자동으로 게시되지 않습니다 — 필요한 경우 이후에 content_publish를 사용하세요.
| 매개변수 | 타입 | 필수 | 설명 |
|---|---|---|---|
revisionId | string | 예 | 복원할 개정 ID |
범위: content:write
OAuth 검색
섹션 제목: “OAuth 검색”OAuth 2.1을 지원하는 MCP 클라이언트는 인증 방법을 자동으로 발견할 수 있습니다. 서버는 두 가지 메타데이터 문서를 게시합니다:
보호된 리소스 메타데이터
섹션 제목: “보호된 리소스 메타데이터”GET /.well-known/oauth-protected-resource{ "resource": "https://example.com/_emdash/api/mcp", "authorization_servers": ["https://example.com/_emdash"], "scopes_supported": [ "content:read", "content:write", "media:read", "media:write", "schema:read", "schema:write", "admin" ], "bearer_methods_supported": ["header"]}인증 서버 메타데이터
섹션 제목: “인증 서버 메타데이터”GET /_emdash/.well-known/oauth-authorization-server{ "issuer": "https://example.com/_emdash", "authorization_endpoint": "https://example.com/_emdash/oauth/authorize", "token_endpoint": "https://example.com/_emdash/api/oauth/token", "scopes_supported": ["content:read", "content:write", "..."], "response_types_supported": ["code"], "grant_types_supported": [ "authorization_code", "refresh_token", "urn:ietf:params:oauth:grant-type:device_code" ], "code_challenge_methods_supported": ["S256"], "token_endpoint_auth_methods_supported": ["none"], "device_authorization_endpoint": "https://example.com/_emdash/api/oauth/device/code"}인증되지 않은 요청이 MCP 엔드포인트에 도달하면 서버는 다음을 반환합니다:
HTTP/1.1 401 UnauthorizedWWW-Authenticate: Bearer resource_metadata="https://example.com/.well-known/oauth-protected-resource"이것은 표준 MCP 클라이언트 발견 흐름을 트리거합니다.
오류 처리
섹션 제목: “오류 처리”도구 오류는 isError: true와 함께 텍스트 내용으로 반환됩니다:
{ "content": [{ "type": "text", "text": "Collection 'nonexistent' not found" }], "isError": true}범위 및 권한 오류는 MCP 프로토콜 오류를 발생시킵니다:
{ "jsonrpc": "2.0", "error": { "code": -32600, "message": "Insufficient scope: requires content:write" }, "id": 1}전송 수준 오류(서버 구성 오류, 처리되지 않은 예외)는 구현 세부 정보를 누출하지 않고 JSON-RPC 오류 코드 -32603(내부 오류)을 반환합니다.