Skip to main content
Glama
monch1962
by monch1962

Calibre MCP

CI Python MCP Calibre Licence: MIT

기존 Calibre 전자책 라이브러리를 위한 읽기 전용 Model Context Protocol 서버입니다.

Calibre MCP를 사용하면 MCP 호환 클라이언트가 도서 메타데이터를 검색하고, Calibre의 전문(full-text) 인덱스를 조회하고, 도서 세부 정보를 확인하고, 라이브러리 카테고리를 탐색하고, 관련 도서를 찾을 수 있습니다. metadata.db를 직접 읽는 대신 Calibre가 지원하는 calibredb 명령줄 인터페이스를 사용합니다.

기능

  • Calibre 검색 언어를 사용한 메타데이터 검색

  • 일치하는 스니펫이 포함된 전문(full-text) 검색

  • 개별 도서의 상세 메타데이터

  • 최근 추가된 도서

  • 저자, 태그, 시리즈, 출판사 및 언어 카테고리

  • 관련 도서 발견

  • 도서, 검색 및 라이브러리 상태에 대한 MCP 리소스

  • 선택적 Calibre Content Server 링크

  • 인메모리 TTL 캐시

  • Streamable HTTP 전송

  • Podman Quadlet 배포

  • 메타데이터를 변경하는 MCP 도구 없음

Related MCP server: calibre-manager

사용 가능한 도구

도구

용도

server_info

서버, Calibre, 캐시 및 라이브러리 구성 표시

library_status

도서 수 및 전문(full-text) 인덱싱 상태 표시

search_books

Calibre 메타데이터 검색

search_fulltext

인덱싱된 전자책 내부를 검색하고 스니펫 반환

get_book_metadata

한 권의 도서에 대해 사용 가능한 모든 메타데이터 반환

list_recent_books

가장 최근에 추가된 도서 나열

list_categories

저자, 태그, 시리즈, 출판사 및 언어 탐색

find_related_books

저자, 시리즈 또는 태그가 겹치는 도서 찾기

clear_cache

인메모리 읽기 캐시 지우기

MCP 리소스

URI

용도

calibre://library/status

라이브러리 및 전문(full-text) 인덱스 상태

calibre://book/{book_id}

도서의 상세 메타데이터

calibre://search/{query}

메타데이터 검색 결과

요구 사항

  • metadata.db가 있는 Calibre 라이브러리

  • Calibre 9.x

  • Python 3.11 이상

  • Streamable HTTP를 지원하는 MCP 클라이언트

  • 포함된 Quadlet 배포를 위한 Podman 및 systemd

전문(full-text) 도구를 사용하려면 Calibre의 전문(full-text) 인덱스가 활성화되고 완료되어 있어야 합니다.

Podman Quadlet 빠른 시작

1. 저장소 클론

git clone https://github.com/monch1962/calibre-mcp.git
cd calibre-mcp

2. Calibre 라이브러리 확인

제공된 Quadlet은 다음을 가정합니다:

/tank/media/Books

라이브러리 데이터베이스가 존재하는지 확인합니다:

test -f /tank/media/Books/metadata.db && echo "Calibre library found"

3. 라이브러리 소유자 확인

stat -c 'uid=%u gid=%g owner=%U:%G' /tank/media/Books

quadlet/calibre-mcp.container를 편집하고 User=를 반환된 숫자 UID 및 GID로 설정합니다:

User=1000:1000

호스트 라이브러리 경로가 다르면 변경합니다:

Volume=/tank/media/Books:/books

4. 이미지 빌드

sudo podman build \
  --build-arg CALIBRE_VERSION=9.11.0 \
  -t localhost/calibre-mcp:1.0.0 .

5. Quadlet 설치

sudo mkdir -p /etc/containers/systemd

sudo cp quadlet/calibre-mcp.container \
  /etc/containers/systemd/calibre-mcp.container

sudo systemctl daemon-reload
sudo systemctl start calibre-mcp.service

systemctl enable calibre-mcp.service를 실행하지 마십시오. 생성된 서비스는 일시적입니다. Quadlet의 [Install] 섹션이 부팅 의존성을 생성합니다.

6. 배포 확인

sudo systemctl status calibre-mcp.service --no-pager
sudo journalctl -u calibre-mcp.service -n 100 --no-pager
sudo podman ps --filter name=calibre-mcp

컨테이너 내부의 Calibre를 확인합니다:

sudo podman exec calibre-mcp \
  calibredb list \
  --with-library /books \
  --for-machine \
  --fields title \
  --limit 1

sudo podman exec calibre-mcp \
  calibredb fts_index status \
  --with-library /books

기본 엔드포인트는 다음과 같습니다:

http://localhost:8008/mcp

MCP Inspector로 테스트

npx @modelcontextprotocol/inspector

Streamable HTTP를 선택하고 다음에 연결합니다:

http://YOUR_SERVER:8008/mcp

메타데이터 검색 예시:

{
  "query": "author:asimov",
  "limit": 10
}

전문(full-text) 검색 예시:

{
  "query": "zero trust architecture",
  "limit": 10
}

제한된 전문(full-text) 검색 예시:

{
  "query": "encryption",
  "limit": 10,
  "restrict_to": "search:tags:security"
}

MCP 클라이언트 연결

서버가 노출하는 Streamable HTTP 엔드포인트를 사용합니다:

http://YOUR_SERVER:8008/mcp

클라이언트 구성 형식은 다양합니다. 클라이언트의 MCP 문서를 참조하고 stdio 또는 레거시 SSE 대신 Streamable HTTP를 선택하십시오.

Calibre 검색 예시

search_books는 Calibre 검색 표현식을 허용합니다:

author:asimov
title:"i robot"
tags:history
series:"Discworld"
publisher:penguin
languages:eng
rating:>=4

빈 쿼리는 결과 제한에 따라 모든 도서를 반환합니다.

선택적 Content Server 링크

Quadlet에서 기존 Calibre Content Server의 URL을 설정합니다:

Environment=CALIBRE_CONTENT_SERVER_URL=http://mini-nas:8083

구성되면 메타데이터 결과에 브라우저 및 형식 다운로드 링크가 포함됩니다.

구성

환경 변수

기본값

설명

CALIBRE_LIBRARY_PATH

/books

컨테이너 내부의 Calibre 라이브러리

CALIBREDB

calibredb

Calibre CLI 경로

CALIBRE_COMMAND_TIMEOUT

120

명령 타임아웃(초)

CALIBRE_MAX_RESULTS

100

도구가 반환하는 최대 결과 수

CALIBRE_CACHE_TTL

300

캐시 수명(초); 0으로 설정하면 비활성화

CALIBRE_CACHE_SIZE

256

최대 캐시 항목 수

CALIBRE_MAX_CONCURRENT_COMMANDS

4

최대 동시 calibredb 하위 프로세스 수

CALIBRE_CONTENT_SERVER_URL

설정되지 않음

선택적 Content Server 기본 URL

MCP_HOST

0.0.0.0

MCP HTTP 바인드 주소

MCP_PORT

8000

컨테이너 내부의 MCP 포트

HOME

/tmp/calibre-home

Calibre 구성을 위한 쓰기 가능한 위치

라이브러리 마운트가 쓰기 가능한 이유

Calibre는 라이브러리 루트에 프로브 파일을 잠시 생성하고 삭제하여 라이브러리 파일 시스템이 대소문자를 구분하는지 확인합니다. 결과적으로 바인드 마운트는 읽기 전용으로 마운트할 수 없습니다.

이 서버는 다음과 같은 Calibre 명령을 호출하는 도구를 노출하지 않으므로 기능적으로 읽기 전용으로 유지됩니다:

  • add

  • remove

  • set_metadata

  • add_format

  • remove_format

라이브러리를 소유한 동일한 권한 없는 UID 및 GID로 컨테이너를 실행하십시오. 환경에서 특별히 요구하지 않는 한 root로 실행하지 마십시오.

보안

  • 포트 8008을 신뢰할 수 있는 LAN 또는 Tailscale 클라이언트로 제한하십시오.

  • 엔드포인트를 공개 인터넷에 직접 노출하지 마십시오.

  • 이 배포에서 Streamable HTTP는 인증을 추가하지 않습니다.

  • 더 넓은 노출 전에 서비스 앞에 인증된 리버스 프록시를 배치하십시오.

  • 변경되는 컨테이너 태그 대신 릴리스 버전을 고정하십시오.

  • 취약점을 보고하기 전에 SECURITY.md를 검토하십시오.

레드팀 하드닝(1차)

10가지 적대적 공격 벡터가 실패하는 테스트로 입증된 후 수정되었습니다. tests/attack_round1_test.py의 각 TestAttack_* 테스트는 해당 벡터에 대한 영구 회귀 픽스처입니다.

#

공격 벡터

진입점

방어

1

무제한 캐시 키 — 캐시 항목당 수 메가바이트 크기의 쿼리가 메모리에 유지됨

search_books / search_fulltext

512바이트를 초과하는 키는 SHA-256으로 해시됨(_cache_key)

2

무제한 캐시 값 — 항목당 대용량 calibredb 출력(주석, 스니펫)이 유지됨

_run

1MiB를 초과하는 값은 캐시를 우회함(_cache_put)

3

server_info 하위 프로세스 중단 — calibredb --version이 타임아웃 없이 실행됨

server_info

타임아웃 적용; TimeoutExpiredToolError

4

잘못된 calibredb 출력에 대한 처리되지 않은 JSONDecodeError → 원시 내부 오류

_list_books / search_fulltext

_loads_json 래퍼 → ToolError

5

숫자가 아닌 book-id 키에 대한 처리되지 않은 ValueError → 원시 내부 오류

_normalise_books

래핑됨 → ToolError

6

라이브러리 메타데이터를 통한 검색 구문 주입 — 저자, 시리즈 또는 태그의 따옴표/백슬래시가 생성된 쿼리를 벗어남

find_related_books

_exact_match_clause가 절 값에서 "\를 제거함

7

무제한 쿼리 길이 — MB 단위 쿼리가 calibredb와 캐시에 도달함

search_books / search_fulltext

8192자를 초과하는 쿼리는 ToolError로 거부됨

8

동시 플러드 상황에서 무제한 임시 calibredb stdout 캡처

_run

잔여 위험 — CALIBRE_COMMAND_TIMEOUT으로 제한됨; 문서화됨

9

0.0.0.0의 인증되지 않은 엔드포인트

배포

수용된 자세 — SECURITY.md에 문서화됨

10

정보 공개 — 라이브러리 경로, Calibre 버전

server_info / library_status

읽기 전용 지식 서버에 대해 수용됨; 문서화됨

이번 라운드에서 검증된 알려진 안전 표면: 셸 주입(인자 목록 사용, shell=True 없음), 옵션 값 주입(--sort-by/--categories/--restrict-to는 Calibre 파서에서 선행 대시 값을 거부함), 리소스 URI 경로 탐색(숫자가 아닌 id는 거부됨), 결과 제한 클램핑(_limit), 캐시 경쟁 조건(락으로 보호됨).

레드팀 하드닝(2차)

6가지 입력 형태 검증 벡터가 입증되고 수정되었습니다. 픽스처는 tests/attack_round2_test.py에 있습니다.

#

공격 벡터

진입점

방어

11

무제한 book_id 크기 — 내부적으로 생성된 id:{huge} 쿼리가 1차 쿼리 상한을 우회하여 MB 단위 argv 항목으로 calibredb에 도달

get_book_metadata / book_resource / find_related_books

_validate_book_id가 id를 1..2³¹−1로 제한 (_book)

12

무제한 categories 문자열 → MB 단위 argv

list_categories

1024자 상한 → ToolError

13

무제한 restrict_to 문자열 → MB 단위 argv

search_fulltext

2048자 상한 → ToolError

14

무제한 sort_by 문자열 → MB 단위 argv

search_books

128자 상한 → ToolError

15

반복 불가능한 formats 메타데이터 → TypeError → 원시 500

_content_links

리스트/튜플이 아닌 formats는 무시되고 details 링크는 계속 반환됨

16

생성된 다운로드 링크의 형식 확장자 주입 (.., x;rm -rf)

_content_links

확장자 허용 목록 [a-z0-9]{1,10} — 일치하지 않는 형식은 건너뜀

레드팀 강화 (3차)

오류 경로 견고성과 관련된 세 가지 벡터가 입증되고 수정되었습니다. 픽스처는 tests/attack_round3_test.py에 있습니다.

#

공격 벡터

진입점

방어

17

128 KiB csv 필드 크기 제한을 초과하는 대형 CSV 필드 → 원시 csv.Error → 500

list_categories

반복이 래핑됨 → ToolError

18

dict가 아닌 항목의 배열로 된 calibredb 목록 출력 → search_books에서 AttributeError → 500

_normalise_books

dict가 아닌 배열 항목 거부 → ToolError

19

예기치 않은 리스트 값 키를 가진 fts_search dict 페이로드가 상한 없이 통과 → 응답 증폭

search_fulltext

모든 리스트 값 키가 결과 상한으로 슬라이스됨

레드팀 강화 (4차)

동시성/프로세스 플러드와 관련된 두 가지 벡터가 입증되고 수정되었습니다. 픽스처는 tests/attack_round4_test.py에 있습니다.

#

공격 벡터

진입점

방어

20

동시 calibredb 프로세스 플러드 — N개의 병렬 도구 호출이 N개의 하위 프로세스를 생성 (CPU/메모리 고갈, Calibre DB 경합)

_run

threading.Semaphore가 실행 중인 명령을 CALIBRE_MAX_CONCURRENT_COMMANDS(기본값 4)로 제한. 초과 호출 → ToolError

21

server_info 버전 하위 프로세스 플러드 — 호출당 캐시되지 않은 하위 프로세스 하나

server_info

버전 호출이 동일한 세마포어를 통해 라우팅됨 (_run_version)

레드팀 강화 (5차 — 최종 검증)

새로운 취약점은 0건입니다. 커버리지 공백 감사를 통해 14차에서 아직 다루지 않은 모든 진입점을 검증하는 테스트 11개 (tests/attack_round5_test.py)가 추가되었습니다 — search_resource, book_resource(비숫자, 경로 탐색형, 범위 내), status_resource, library_status, list_recent_books, clear_cache, search_fulltext 리스트 페이로드, 0/음수 제한, TTL 0 캐시 비활성화, 공백 쿼리. 모든 테스트가 즉시 통과하여 14차 방어가 전체 도구/리소스 표면에 걸쳐 유지됨을 확인했습니다.

배포 자세와 관련된 문서상 발견 사항 두 가지가 SECURITY.md에 기록되었습니다(코드 변경 없음). ContainerfileUSER 지시문이 없고(Quadlet 외부에서 빌드하면 root로 실행되며, Quadlet은 User=1000:1000을 설정), Quadlet이 SecurityLabelDisable=true를 설정합니다 (SELinux 라벨 분리 꺼짐).

로컬 개발

가상 환경을 생성합니다:

python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install -e .
python -m pip install pytest ruff

테스트를 실행합니다:

pytest

린트 검사를 실행합니다:

ruff check .

서버를 로컬에서 시작합니다:

export CALIBRE_LIBRARY_PATH="/path/to/Calibre Library"
python server.py

프로젝트 상태

버전 1.0.0은 개인 및 신뢰할 수 있는 네트워크 배포에 적합합니다. 공개 API는 향후 마이너 릴리스에서 추가 도구와 리소스를 얻을 수 있으며, 기존 도구 이름과 인자 형태는 실용적인 범위에서 안정적으로 유지됩니다.

기여

이슈와 풀 리퀘스트를 환영합니다. CONTRIBUTING.md를 참조하세요.

라이선스

MIT 라이선스에 따라 배포됩니다.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    An MCP server that enables querying and managing Calibre libraries via chat by interacting with the Calibre content server over HTTP. It allows users to search for books, update metadata, manage authors and tags, and handle book file uploads or conversions.
    3
    BSD 3-Clause
  • A
    license
    A
    quality
    D
    maintenance
    An MCP server to manage and organize a Calibre ebook library, enabling metadata editing, search, conversion, and more through AI assistants.
    17
    5
    MIT
  • A
    license
    A
    quality
    D
    maintenance
    A local stdio MCP server that enables AI tools to search a self-hosted Calibre library over SSH, supporting metadata queries, full-text search, and book details.
    7
    MIT