@sunub/obsidian-mcp-server 0.3.29 → 0.3.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/README.md +214 -72
  2. package/build/index.js +28 -10
  3. package/build/index.js.map +1 -1
  4. package/build/server.d.ts +2 -1
  5. package/build/server.js +7 -1
  6. package/build/server.js.map +1 -1
  7. package/build/tools/index.d.ts +1 -1
  8. package/build/tools/vault/index.d.ts +1 -1
  9. package/build/tools/vault/params.d.ts +4 -4
  10. package/build/tools/vault/params.js +3 -3
  11. package/build/tools/vault/params.js.map +1 -1
  12. package/build/tools/vault/types/collect_context.d.ts +15 -15
  13. package/build/tools/vault/types/read_specific.d.ts +46 -46
  14. package/build/tools/vault/types/read_specific.js +4 -4
  15. package/build/tools/vault/types/read_specific.js.map +1 -1
  16. package/build/tools/vault/utils/actions/collect_context.js +15 -10
  17. package/build/tools/vault/utils/actions/collect_context.js.map +1 -1
  18. package/build/tools/vault/utils/actions/read.js +48 -12
  19. package/build/tools/vault/utils/actions/read.js.map +1 -1
  20. package/build/tools/vault/utils/actions/search.js +7 -3
  21. package/build/tools/vault/utils/actions/search.js.map +1 -1
  22. package/build/tools/vault/utils/shared.d.ts +1 -1
  23. package/build/tools/vault/utils/shared.js +9 -1
  24. package/build/tools/vault/utils/shared.js.map +1 -1
  25. package/build/utils/BackgroundTaskRegistry.d.ts +7 -0
  26. package/build/utils/BackgroundTaskRegistry.js +39 -0
  27. package/build/utils/BackgroundTaskRegistry.js.map +1 -0
  28. package/build/utils/Embedder.d.ts +4 -3
  29. package/build/utils/Embedder.js +20 -8
  30. package/build/utils/Embedder.js.map +1 -1
  31. package/build/utils/LocalModelManager.d.ts +45 -0
  32. package/build/utils/LocalModelManager.js +196 -0
  33. package/build/utils/LocalModelManager.js.map +1 -0
  34. package/build/utils/LocalReranker.d.ts +4 -3
  35. package/build/utils/LocalReranker.js +20 -8
  36. package/build/utils/LocalReranker.js.map +1 -1
  37. package/build/utils/RAGIndexer.d.ts +8 -3
  38. package/build/utils/RAGIndexer.js +61 -34
  39. package/build/utils/RAGIndexer.js.map +1 -1
  40. package/build/utils/ServerLifecycle.d.ts +23 -0
  41. package/build/utils/ServerLifecycle.js +50 -0
  42. package/build/utils/ServerLifecycle.js.map +1 -0
  43. package/build/utils/VaultManger/VaultManager.d.ts +2 -1
  44. package/build/utils/VaultManger/VaultManager.js +81 -59
  45. package/build/utils/VaultManger/VaultManager.js.map +1 -1
  46. package/build/utils/VaultWatcher.d.ts +2 -1
  47. package/build/utils/VaultWatcher.js +3 -6
  48. package/build/utils/VaultWatcher.js.map +1 -1
  49. package/build/utils/abort.d.ts +5 -0
  50. package/build/utils/abort.js +51 -0
  51. package/build/utils/abort.js.map +1 -0
  52. package/build/utils/worker/WorkerPool.d.ts +7 -2
  53. package/build/utils/worker/WorkerPool.js +22 -7
  54. package/build/utils/worker/WorkerPool.js.map +1 -1
  55. package/package.json +3 -1
package/README.md CHANGED
@@ -2,69 +2,74 @@
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/@sunub/obsidian-mcp-server.svg)](https://www.npmjs.com/package/@sunub/obsidian-mcp-server)
4
4
 
5
- `obsidian-mcp-server`는 Obsidian Vault의 Markdown 문서를 AI 에이전트가 조회하고, 검색하고, 요약할 수 있게 해주는 MCP 서버입니다.
5
+ `obsidian-mcp-server`는 Obsidian Vault의 Markdown 문서를 AI 에이전트가 조회하고, 관련 근거를 선별하고, 컨텍스트로 압축해 활용할 수 있게 해주는 로컬 우선 MCP 서버입니다.
6
6
 
7
- 프로젝트는 단순히 문서를 읽어오는 것을 넘어, **transformers.js를 활용한 로컬 하이브리드 검색** 기능을 제공하며, 터미널에서 즉시 Vault와 대화할 있는 **대화형 CLI AI Agent UI**를 포함하고 있습니다.
7
+ 프로젝트에서 RAG는 특정 벡터 DB나 검색 엔진 선택을 뜻하지 않습니다. RAG는 Vault에서 후보 문서를 찾고, Agent 작업에 맞는 근거를 고르고, 컨텍스트 윈도우에 맞게 압축해 제공하는 **Agent Context Pipeline**입니다.
8
8
 
9
- ## 주요 특징
9
+ ## 핵심 방향
10
10
 
11
- - 🔍 **하이브리드 검색:** 키워드 검색과 시맨틱(벡터) 검색을 결합하고 RRF(Reciprocal Rank Fusion)와 Reranking을 통해 최적의 결과 제공.
12
- - 🚀 **Zero-Dependency 로컬 AI:** `@huggingface/transformers`를 사용하여 임베딩 리랭킹 모델을 Node.js 프로세스 내에서 직접 실행 (외부 API 서버 불필요).
13
- - 💬 **내장 CLI 에이전트:** MCP 도구들을 활용하여 Vault 내용에 대해 질문하고 답변을 받을 있는 터미널 기반 UI 제공. [상세 보기](#대화형-cli-ai-agent-ui)
14
- - 📦 **토큰 최적화:** AI 에이전트의 토큰 사용량을 제어하기 위한 다양한 압축 모드와 출력 제한 기능 제공.
11
+ - **로컬 우선 동작**: 외부 서비스나 별도로 운영해야 하는 검색 엔진 없이 사용자 머신에서 Vault 검색과 컨텍스트 준비를 수행합니다.
12
+ - **컨텍스트 선별**: 키워드 검색과 시맨틱 검색을 결합해 Agent에게 제공할 근거 후보를 찾습니다.
13
+ - **명시적 RAG 통합**: 모든 프롬프트에 백그라운드 검색을 붙이지 않고, Vault 관련 명령이나 도구 참조가 있을 문맥 수집 경로를 엽니다.
14
+ - **토큰 절약**: 원문 전체를 밀어넣기보다 excerpt, evidence snippet, `memory_packet` 형태로 압축합니다.
15
+ - **로컬 모델 기반 검색**: `@huggingface/transformers`, LanceDB, local reranker를 사용해 semantic retrieval을 로컬에서 수행합니다.
15
16
 
16
- ## 무엇을 있나 (MCP Tools)
17
+ Elasticsearch 같은 검색 엔진도 retrieval backend로 사용할 있는 대안입니다. 다만 이 프로젝트의 기본 목표는 외부 서비스나 별도 검색 엔진에 의존하지 않는 로컬 단독 작업이므로, embedded retrieval stack을 기본값으로 선택합니다.
17
18
 
18
- - **통합 검색 (`vault`, `action="search"`)**: 키워드와 의미 기반 검색을 동시에 수행하여 관련성 높은 문서 탐색.
19
- - **문서 열람 (`vault`, `action="read"`)**: 특정 노트의 본문 및 메타데이터 조회.
20
- - **전체 목록 및 상태 (`vault`, `action="list_all"|"stats"`)**: Vault의 전반적인 상태와 파일 목록 확인.
21
- - **컨텍스트 수집 (`vault`, `action="collect_context"`)**: 특정 주제와 연관된 고밀도 지식 패킷 생성.
22
- - **지식 로드 (`vault`, `action="load_memory"`)**: 저장된 메모리 스냅샷 호출.
23
- - **Frontmatter 관리 (`generate_property`|`write_property`)**: AI 기반 메타데이터 생성 및 반영.
24
- - **첨부파일 정리 (`organize_attachments`)**: 문서 내 이미지를 전용 폴더로 자동 이동 및 링크 업데이트.
19
+ ## 제공 기능
25
20
 
26
- ---
21
+ ### MCP Tools
27
22
 
28
- ## 설치 및 설정
23
+ - `vault`
24
+ - `search`: 키워드와 의미 기반 검색을 결합한 하이브리드 후보 탐색
25
+ - `read`: 특정 노트 본문과 메타데이터 조회
26
+ - `list_all`: Vault 문서 목록 조회
27
+ - `stats`: Vault 및 인덱스 상태 조회
28
+ - `collect_context`: 주제와 연관된 문서를 선별해 `memory_packet` 생성
29
+ - `load_memory`: 저장된 컨텍스트 메모리 스냅샷 로드
30
+ - `generate_property`: 문서 내용을 바탕으로 frontmatter 후보 생성
31
+ - `write_property`: frontmatter 쓰기
32
+ - `create_document_with_properties`: 문서 분석 후 속성 생성/쓰기 2단계 워크플로우
33
+ - `organize_attachments`: 문서 내 첨부파일 정리 및 링크 갱신
29
34
 
30
- ### 1. 사전 요구사항
35
+ ### Retrieval Pipeline
31
36
 
32
- - **Node.js**: v22.0.0 이상
33
- - **Obsidian Vault**: 절대 경로를 알고 있어야 합니다.
37
+ 현재 기본 retrieval backend는 다음 순서로 동작합니다.
34
38
 
35
- ### 2. 로컬 AI 모델 설치 (필수)
39
+ 1. **Keyword Search**: 내부 `Indexer`로 정확한 단어 매칭 후보를 찾습니다.
40
+ 2. **Vector Search**: LanceDB와 로컬 embedding model로 의미적으로 유사한 청크를 찾습니다.
41
+ 3. **RRF Fusion**: 키워드 결과와 벡터 결과의 순위를 결합합니다.
42
+ 4. **Local Reranking**: 상위 후보를 reranker로 다시 평가합니다.
43
+ 5. **Compression**: 필요한 excerpt, source ref, memory packet만 Agent context로 제공합니다.
36
44
 
37
- 시맨틱 검색 리랭킹 기능을 활성화하려면 아래 명령어를 통해 필요한 로컬 모델을 다운로드해야 합니다.
45
+ 로컬 embedding/reranking 모델이 설치되지 않은 경우 서버는 키워드 검색으로 폴백합니다.
46
+
47
+ ## 설치
48
+
49
+ ### 요구사항
50
+
51
+ - Node.js 22 이상
52
+ - 접근 가능한 Obsidian Vault 절대 경로
53
+
54
+ ### MCP 서버 설치 및 모델 준비
38
55
 
39
56
  ```bash
40
- # 로컬 임베딩 및 리랭킹 모델 설치
41
57
  npx @sunub/obsidian-mcp-server setup
42
58
  ```
43
59
 
44
- 또는 이미 패키지를 설치했다면:
60
+ 명령은 로컬 semantic search와 reranking에 필요한 모델을 캐시에 설치합니다.
61
+
62
+ 이미 패키지를 설치한 환경에서는 다음처럼 실행할 수도 있습니다.
45
63
 
46
64
  ```bash
47
65
  obsidian-mcp-server setup
48
66
  ```
49
67
 
50
- 명령어는 `Xenova/paraphrase-multilingual-MiniLM-L12-v2`(임베딩)`Xenova/bge-reranker-base`(리랭킹) 모델을 다운로드하여 로컬 캐시에 저장합니다.
51
-
52
- ### 3. 환경 변수 설정
53
-
54
- | 환경변수 | 기본값 | 역할 | 필수 여부 |
55
- |---|---|---|---|
56
- | `VAULT_DIR_PATH` | — | Obsidian Vault 절대 경로 | **필수** |
57
- | `LLM_API_URL` | `http://127.0.0.1:8080` | CLI UI용 채팅 모델 API 엔드포인트 | CLI 사용 시 필수 |
58
- | `LLM_CHAT_MODEL` | `llama3` | 채팅에 사용할 모델명 | CLI 사용 시 필수 |
59
- | `LOGGING_LEVEL` | `info` | 로그 수준 (`debug` / `info` / `warn` / `error`) | 선택 |
60
-
61
- ---
68
+ 모델 설치가 없으면 기본 키워드 검색은 동작하지만, semantic searchreranking 품질은 사용할 없습니다.
62
69
 
63
- ## MCP 클라이언트 설정 예시
70
+ ## MCP 클라이언트 설정
64
71
 
65
- 클라이언트 설정에서 `env.VAULT_DIR_PATH`를 본인의 Vault 경로로 수정하여 사용하세요.
66
-
67
- ### Claude Desktop / Cursor / Copilot
72
+ Claude Desktop, Cursor, Copilot MCP 클라이언트에는 다음처럼 등록합니다.
68
73
 
69
74
  ```json
70
75
  {
@@ -80,50 +85,187 @@ obsidian-mcp-server setup
80
85
  }
81
86
  ```
82
87
 
83
- ---
88
+ `VAULT_DIR_PATH`는 반드시 본인의 Vault 절대 경로로 바꿔야 합니다.
84
89
 
85
- ## 하이브리드 검색 동작 방식
90
+ ## 환경 변수
86
91
 
87
- 기존의 키워드 검색만으로는 찾기 힘든 의미적 연관성을 잡기 위해 다음과 같은 파이프라인을 거칩니다:
92
+ | 환경변수 | 기본값 | 용도 | 필수 |
93
+ | --- | --- | --- | --- |
94
+ | `VAULT_DIR_PATH` | 없음 | Obsidian Vault 절대 경로 | 예 |
95
+ | `LOGGING_LEVEL` | `info` | `debug`, `info`, `warn`, `error` | 아니오 |
96
+ | `LLM_API_URL` | `http://127.0.0.1:8080` | CLI UI가 사용할 OpenAI 호환 로컬 LLM endpoint | CLI 사용 시 |
97
+ | `LLM_CHAT_MODEL` | `llama3` | CLI UI 답변 생성 모델명 | CLI 사용 시 |
88
98
 
89
- 1. **Keyword Search**: 내부 `Indexer`를 통해 정확한 단어 매칭 결과 추출.
90
- 2. **Vector Search**: LanceDB와 `transformers.js` 임베딩을 사용하여 의미적으로 유사한 청크 탐색.
91
- 3. **RRF Fusion**: 두 검색 결과의 순위를 Reciprocal Rank Fusion 알고리즘으로 병합.
92
- 4. **Local Reranking**: 병합된 상위 결과들을 `BGE Reranker` 모델로 다시 평가하여 최종 순위 결정.
99
+ MCP 서버의 Vault 검색/읽기 도구에는 `VAULT_DIR_PATH`가 핵심 설정입니다. `LLM_API_URL`과 `LLM_CHAT_MODEL`은 저장소에 포함된 개발용 CLI UI에서 대화형 스트리밍 답변을 받을 때 필요합니다.
93
100
 
94
- 모델이 설치되지 않은 경우 자동으로 키워드 전용 모드로 동작하며, 터미널에 `npx @sunub/obsidian-mcp-server setup` 실행 권장 메시지를 표시합니다.
101
+ ## 개발용 CLI AI Agent UI
95
102
 
96
- ---
103
+ <img width="2020" height="744" alt="banner" src="https://github.com/user-attachments/assets/16337be2-f728-4761-b8d8-b1ec7425e2e4" />
97
104
 
98
- ## 대화형 CLI AI Agent UI
105
+ 저장소에는 터미널 기반 AI Agent UI가 포함되어 있습니다. 이 CLI는 npm 패키지의 공개 `bin`이 아니라 저장소 개발 환경에서 실행하는 진입점입니다.
99
106
 
100
- 프로젝트에는 Obsidian Vault 최적화된 **터미널 기반 AI 채팅 인터페이스**가 내장되어 있습니다.
107
+ CLI의 목적은 Obsidian Vault 단순히 검색하는 수준을 넘어서, **MCP 도구 호출**, **조건부 RAG 기반 문맥 수집**, **OpenAI 호환 LLM endpoint 스트리밍 응답**을 하나의 대화형 작업 흐름으로 묶는 데 있습니다. 즉, 단순한 "채팅 UI"만 구현하는 곳이 아니라, Vault와 도구, 모델 사이를 연결하는 **오케스트레이션 레이어**입니다.
101
108
 
102
- ### 특징
103
- - **RAG 통합**: 질문 시 자동으로 Vault에서 관련 컨텍스트를 수집하여 LLM에 전달합니다.
104
- - **실시간 스트리밍**: LLM의 답변과 "생각하는 과정(<think>)"을 실시간으로 렌더링합니다.
105
- - **슬래시 커맨드**: `/search`, `/read`, `/index` 등 MCP 도구를 CLI에서 직접 명령어로 호출 가능합니다.
106
- - **멀티 MCP 관리**: 연결된 모든 MCP 서버의 상태와 도구 목록을 모니터링합니다.
109
+ ### 왜 이 CLI가 필요한가
107
110
 
108
- ### 실행 방법
111
+ 프로젝트의 문서와 설계 방향을 기준으로 보면, 이 CLI는 다음 문제를 해결하거나 완화하기 위해 만들어졌습니다.
112
+
113
+ - **외부 AI 서비스 의존성 감소**: 프로젝트가 로컬 Vault와 로컬 도구를 다루는 만큼, 가능한 한 로컬 실행 환경에서 독립적으로 동작하도록 지향합니다.
114
+ - **문맥 손실 감소**: Vault 관련 도구가 트리거된 질문에서는 관련 문서를 수집하고 요약해 LLM에 함께 전달할 수 있습니다.
115
+ - **토큰 낭비 감소**: `collect_context` 기반 압축 요약과 대량 입력 오프로딩을 통해 긴 문서나 대형 paste를 그대로 모델에 밀어넣지 않습니다.
116
+ - **터미널 입력 안정성 개선**: Raw mode 기반 입력 환경에서 발생하는 paste storm, 다중 Enter 트리거, 버퍼 오염 같은 문제를 제어합니다.
117
+ - **장시간 세션 안정성 확보**: 스트리밍 취소, 히스토리 pruning, scrollback 위임 같은 구조를 통해 메모리 사용량과 렌더링 부담을 줄입니다.
118
+
119
+ ### 이 CLI가 하는 일
120
+
121
+ #### 1. 대화형 AI 인터페이스
122
+
123
+ 사용자는 터미널에서 자연어로 질문을 입력하고, CLI는 LLM 서버와 통신해 답변을 스트리밍합니다.
124
+
125
+ - 응답을 실시간으로 출력합니다.
126
+ - 모델의 thinking 영역이 있으면 중간 추론 상태도 별도로 렌더링합니다.
127
+ - 완료된 대화는 히스토리에 반영하고, 진행 중 응답은 별도 `pending` 상태로 관리합니다.
128
+
129
+ #### 2. MCP 도구 실행 인터페이스
130
+
131
+ CLI는 MCP 서버에 연결된 도구를 터미널에서 직접 사용할 수 있게 합니다.
132
+
133
+ - `/search`, `/read`, `/stats`, `/context`, `/tools` 같은 슬래시 커맨드를 제공합니다.
134
+ - 사용자의 명시적 명령뿐 아니라, LLM이 tool call을 생성했을 때도 이를 실행할 수 있는 루프를 제공합니다.
135
+ - 여러 MCP 서버에 연결하고, 각 서버의 도구 목록과 연결 상태를 함께 관리합니다.
136
+
137
+ #### 3. 조건부 RAG 기반 문맥 주입
138
+
139
+ 이 CLI는 모든 일반 질문에 대해 자동으로 RAG를 수행하지는 않습니다. 현재 구현 기준으로는 입력 텍스트에서 `vault` 도구나 관련 서버/도구 이름이 트리거된 경우에만 Vault 문맥 수집을 시도하고, 이를 `<context>` 블록으로 정리해 프롬프트에 주입합니다.
140
+
141
+ - `collect_context` 액션을 활용해 관련 문서를 배치 단위로 수집합니다.
142
+ - `memory_packet`과 고연관 문서 excerpt를 조합해 LLM 입력을 구성합니다.
143
+ - 따라서 이 CLI는 항상 RAG가 붙는 채팅창이라기보다, **필요 시 Vault-aware 동작을 수행하는 agent UI**에 가깝습니다.
144
+
145
+ #### 4. 대용량 입력 최적화
146
+
147
+ 긴 코드, 로그, 문서가 붙여넣기되면 이를 그대로 모델에 보내는 대신 안전하게 축약/오프로딩합니다.
148
+
149
+ - 큰 paste는 임시 파일로 분리해 저장합니다.
150
+ - LLM에는 전체 본문 대신 파일 위치와 미리보기, 처리 지시문을 전달합니다.
151
+ - 이 방식은 토큰 사용량을 줄이고, 필요할 때만 도구를 통해 원문을 읽게 만듭니다.
152
+
153
+ #### 5. 스트리밍 중심 사용자 경험
154
+
155
+ CLI UI는 응답이 끝난 뒤 한 번에 보여주는 구조가 아니라, 생성 중인 상태를 즉시 보여주는 흐름을 중심으로 설계되어 있습니다.
156
+
157
+ - 입력 직후 버퍼를 비워 다음 작업을 준비합니다.
158
+ - 첫 토큰 전에는 thinking/processing 상태를 보여줍니다.
159
+ - 완료된 기록은 정적 영역으로 넘기고, 현재 응답만 동적으로 다시 렌더링합니다.
160
+
161
+ ### 주요 실행 흐름
162
+
163
+ 1. 사용자가 메시지 또는 슬래시 커맨드를 입력합니다.
164
+ 2. 질문 내용에서 Vault 관련 도구가 트리거되면 관련 문맥 수집을 시도합니다.
165
+ 3. LLM 스트리밍 요청을 시작합니다.
166
+ 4. 필요 시 MCP 도구를 호출합니다.
167
+ 5. 응답을 실시간으로 출력합니다.
168
+ 6. 완료된 결과를 히스토리에 반영하고 다음 입력을 기다립니다.
169
+
170
+ ### 아키텍처 관점에서의 역할
171
+
172
+ | 영역 | 역할 | 대표 파일 |
173
+ | --- | --- | --- |
174
+ | 부팅 및 환경 확인 | LLM endpoint 확인, 초기 로더/에러 화면 제어 | `AppContainer.tsx`, `ui/LLMHealthChecker.tsx`, `ui/LLMStatusLoader.tsx` |
175
+ | MCP 연결 관리 | 설정 파일 기반 MCP 서버 연결, 도구 목록 수집, 멀티 서버 상태 관리 | `hooks/useMcpManager.ts`, `services/McpClientService.ts`, `config/mcpServersConfig.ts` |
176
+ | 입력 시스템 | Raw key 처리, paste 버퍼링, 멀티라인 편집, 히스토리 탐색 | `context/KeypressContext.tsx`, `ui/InputPrompt.tsx`, `key/` |
177
+ | 명령 디스패치 | 슬래시 커맨드를 MCP 도구 호출로 변환 | `hooks/useDispatcher.ts` |
178
+ | RAG 컨텍스트 수집 | Vault 관련 도구가 트리거된 질문에서만 문맥을 수집해 프롬프트에 주입 | `hooks/useRagContext.ts` |
179
+ | LLM 스트리밍 루프 | 스트리밍 응답, tool call 실행, thinking 파싱 | `hooks/useLlmStream/useLlmStream.ts` |
180
+ | 렌더링 및 세션 관리 | 히스토리 출력, pending 응답 표시, transient UI 메시지 관리 | `ui/MainContent.tsx`, `hooks/useHistoryManager.ts` |
181
+ | 대량 입력 최적화 | 큰 붙여넣기 입력 오프로딩 및 임시 파일 정리 | `services/InputOffloadService.ts` |
109
182
 
110
- 1. **채팅 모델 서버 구동**: `llama.cpp` 또는 `Ollama`와 같은 서버를 OpenAI 호환 모드로 띄웁니다.
111
- - 예: `llama-server -m models/gemma-2-9b-it.Q4_K_M.gguf --port 8080`
112
- 2. **CLI 실행**:
113
- ```bash
114
- # 환경변수와 함께 실행
115
- VAULT_DIR_PATH="/your/vault" LLM_API_URL="http://localhost:8080" npx @sunub/obsidian-mcp-server
116
- ```
117
-
118
- ### 슬래시 커맨드 도움말
119
- - `/search <keyword>`: 하이브리드 검색 실행
120
- - `/read "filename"`: 특정 문서 읽기
183
+ ### 설계 원칙
184
+
185
+ CLI 다음 원칙을 중심으로 설계됩니다.
186
+
187
+ - **입력과 렌더링의 분리**
188
+ - **스트리밍 우선 UX**
189
+ - **설정 파일 기반 MCP 연결**
190
+ - **도구 호출과 대화 흐름의 통합**
191
+ - **토큰/메모리 효율 최적화**
192
+ - **중단 가능성과 복구 가능성 보장**
193
+
194
+ ### 제공하는 주요 명령
195
+
196
+ 현재 코드 기준으로 기본 제공되는 대표 슬래시 커맨드는 다음과 같습니다.
197
+
198
+ - `/search <keyword>`: Vault 하이브리드 검색
199
+ - `/read "filename"`: 특정 문서 열람
200
+ - `/semantic <query>`: 시맨틱 검색
121
201
  - `/stats`: Vault 상태 확인
122
- - `/index`: 벡터 DB 재색인 강제 실행
123
- - `/tools`: 사용 가능한 모든 MCP 도구 목록 확인
124
- - `/help`: 도움말 보기
202
+ - `/index`: 벡터 인덱스 갱신
203
+ - `/context <topic>`: 토픽 기반 문맥 수집
204
+ - `/organize <keyword>`: 첨부 정리 도구 실행
205
+ - `/genprop <filename>`: frontmatter 생성 도구 호출
206
+ - `/tools`: 연결된 MCP 도구 목록 확인
207
+ - `/help`: 도움말 표시
208
+ - `/clear`: 화면/대화 상태 초기화
209
+ - `/quit`, `/exit`: CLI 종료
210
+
211
+ ### 실행 방법
212
+
213
+ 현재 CLI 진입점은 **저장소 개발 환경용 실행 방식**입니다. 패키지의 `bin` 엔트리는 MCP 서버용이며, CLI UI는 루트에서 별도 스크립트로 실행됩니다.
214
+
215
+ 저장소 루트에서 의존성을 설치하고 서버를 먼저 빌드합니다.
216
+
217
+ ```bash
218
+ npm install
219
+ npm run build
220
+ ```
221
+
222
+ 이 저장소 루트에는 기본 `mcp-servers.json`이 포함되어 있으며, `node ./build/index.js`로 서버를 실행합니다.
223
+
224
+ 그 다음 OpenAI 호환 로컬 LLM 서버를 실행합니다. 예를 들어 `llama.cpp`의 `llama-server`를 `8080` 포트에 띄울 수 있습니다.
225
+
226
+ ```bash
227
+ llama-server -m /path/to/model.gguf --port 8080
228
+ ```
229
+
230
+ CLI는 다음처럼 환경 변수를 주입하여 실행합니다:
231
+
232
+ ```bash
233
+ VAULT_DIR_PATH="/Users/username/Documents/MyVault" \
234
+ LLM_API_URL="http://127.0.0.1:8080" \
235
+ LLM_CHAT_MODEL="llama3" \
236
+ npm run cli
237
+ ```
238
+
239
+ #### MCP 설정 파일
240
+
241
+ CLI는 실행 시 현재 작업 디렉터리에서 다음 파일을 순서대로 찾습니다.
242
+
243
+ 1. `mcp-servers.json`
244
+ 2. `.mcp-servers.json`
245
+
246
+ 설정 파일이 없으면 환경 변수 기반 fallback을 시도하지만, 가장 안전한 실행 방식은 **저장소 루트에서**, `build/index.js`가 준비된 상태로 실행하는 것입니다.
247
+
248
+ #### 실행 시 주의할 점
249
+
250
+ - 이 CLI 실행 방법은 **개발용 CLI UI 진입점** 기준입니다. 배포된 `npx @sunub/obsidian-mcp-server`는 MCP 서버를 띄울 뿐 CLI UI를 실행하지 않습니다.
251
+ - CLI가 MCP 서버에 연결되려면 현재 디렉터리의 `mcp-servers.json` 또는 `.mcp-servers.json`이 유효해야 합니다.
252
+ - `VAULT_DIR_PATH`가 없거나 잘못되면 Vault 관련 도구가 동작하지 않습니다.
253
+ - semantic search와 reranking을 쓰려면 서버 `setup`으로 로컬 모델을 설치해야 합니다.
254
+
255
+ ## 주의 사항
256
+
257
+ - `VAULT_DIR_PATH`가 없거나 잘못되면 Vault 관련 도구가 동작하지 않습니다.
258
+ - semantic search와 reranking을 쓰려면 `setup`으로 로컬 모델을 설치해야 합니다.
259
+ - CLI UI를 쓰려면 별도의 OpenAI 호환 로컬 LLM 서버가 실행 중이어야 합니다.
260
+ - CLI의 명시적 RAG는 `vault` 관련 명령, 서버명, 도구명이 입력에서 트리거될 때만 사전 문맥 수집을 시도합니다.
261
+ - `collect_context`는 긴 주제 정리와 메모리 패킷 생성에 적합하고, 단건 조회는 `search`나 `read`가 더 단순합니다.
262
+ - 쓰기 계열 도구는 Vault 바깥 경로에 쓰지 않도록 차단합니다.
263
+
264
+ ## 참고 문서
125
265
 
126
- ---
266
+ - [Tool Reference](docs/tool-reference.md)
267
+ - [Tool Usage Guide](docs/tools-usage-guide.md)
268
+ - [collect_context Guide](docs/collect-context-guide.md)
127
269
 
128
270
  ## 라이선스
129
271
 
package/build/index.js CHANGED
@@ -5,7 +5,9 @@ import { getOptions, setLocalLLMEnvSetting } from "./config.js";
5
5
  import createMcpServer from "./server.js";
6
6
  import { ensureAppDataDirs } from "./utils/constants.js";
7
7
  import { localEmbedder } from "./utils/Embedder.js";
8
+ import { localModelManager } from "./utils/LocalModelManager.js";
8
9
  import { localReranker } from "./utils/LocalReranker.js";
10
+ import { ServerLifecycle } from "./utils/ServerLifecycle.js";
9
11
  import { vaultWatcher } from "./utils/VaultWatcher.js";
10
12
  async function main() {
11
13
  ensureAppDataDirs();
@@ -36,27 +38,43 @@ async function main() {
36
38
  else {
37
39
  console.error(chalk.yellow("ℹ Basic Keyword Search is active. Run 'npx @sunub/obsidian-mcp-server setup' to enable Hybrid Search.\n"));
38
40
  }
41
+ const lifecycle = new ServerLifecycle();
42
+ const server = createMcpServer(lifecycle);
43
+ const transport = new StdioServerTransport();
44
+ lifecycle.registerCleanup("local-model-manager", () => localModelManager.shutdown());
45
+ lifecycle.registerCleanup("vault-watcher", () => vaultWatcher.stop());
46
+ lifecycle.registerCleanup("mcp-server", () => server.close());
47
+ let exiting = false;
48
+ const shutdownAndExit = async (reason, exitCode = 0) => {
49
+ if (exiting) {
50
+ return;
51
+ }
52
+ exiting = true;
53
+ console.error(chalk.yellow(`\n🛑 Shutting down MCP server (${reason})...`));
54
+ await lifecycle.shutdown(reason);
55
+ process.exit(exitCode);
56
+ };
57
+ process.once("SIGINT", () => void shutdownAndExit("SIGINT"));
58
+ process.once("SIGTERM", () => void shutdownAndExit("SIGTERM"));
59
+ process.once("SIGHUP", () => void shutdownAndExit("SIGHUP"));
60
+ process.stdin.once("end", () => void shutdownAndExit("stdin-end"));
61
+ process.stdin.once("close", () => void shutdownAndExit("stdin-close"));
62
+ process.stdin.once("error", () => void shutdownAndExit("stdin-error", 1));
63
+ transport.onclose = () => void shutdownAndExit("transport-close");
39
64
  try {
40
- await vaultWatcher.start(options.vaultPath);
65
+ await vaultWatcher.start(options.vaultPath, lifecycle);
41
66
  }
42
67
  catch (error) {
43
68
  console.error(chalk.red("[VaultWatcher] Failed to start indexing:"), error);
69
+ await lifecycle.shutdown("startup-failure");
44
70
  process.exit(1);
45
71
  }
46
- const server = createMcpServer();
47
- const transport = new StdioServerTransport();
48
- const cleanup = async () => {
49
- console.error(chalk.yellow("\n🛑 Shutting down MCP server..."));
50
- await vaultWatcher.stop();
51
- process.exit(0);
52
- };
53
- process.on("SIGINT", cleanup);
54
- process.on("SIGTERM", cleanup);
55
72
  try {
56
73
  await server.connect(transport);
57
74
  }
58
75
  catch (error) {
59
76
  console.error(chalk.red("Failed to start MCP server:"), error);
77
+ await lifecycle.shutdown("connect-failure");
60
78
  process.exit(1);
61
79
  }
62
80
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/build/server.d.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
- export default function createMcpServer(): McpServer;
2
+ import type { ServerLifecycle } from "./utils/ServerLifecycle.js";
3
+ export default function createMcpServer(lifecycle: ServerLifecycle): McpServer;
package/build/server.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
2
  import pkg from "../package.json" with { type: "json" };
3
3
  import tools from "./tools/index.js";
4
- export default function createMcpServer() {
4
+ export default function createMcpServer(lifecycle) {
5
5
  const mcpServer = new McpServer({
6
6
  version: pkg.version,
7
7
  name: "obsidian-mcp-server",
@@ -33,6 +33,12 @@ export default function createMcpServer() {
33
33
  - To enable high-performance local hybrid search, run 'npx @sunub/obsidian-mcp-server setup' once.
34
34
  `,
35
35
  });
36
+ const registerTool = mcpServer.registerTool.bind(mcpServer);
37
+ mcpServer.registerTool = ((name, config, callback) => {
38
+ const rawCallback = callback;
39
+ const wrappedCallback = (...args) => lifecycle.runToolCall(name, () => Promise.resolve(rawCallback(...args)));
40
+ return registerTool(name, config, wrappedCallback);
41
+ });
36
42
  for (const tool of Object.values(tools)) {
37
43
  tool.register(mcpServer);
38
44
  }
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,GAAG,MAAM,iBAAiB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AACxD,OAAO,KAAK,MAAM,kBAAkB,CAAC;AAErC,MAAM,CAAC,OAAO,UAAU,eAAe;IACtC,MAAM,SAAS,GAAG,IAAI,SAAS,CAC9B;QACC,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,IAAI,EAAE,qBAAqB;QAC3B,KAAK,EAAE,qBAAqB;KAC5B,EACD;QACC,YAAY,EAAE;YACb,OAAO,EAAE,EAAE;YACX,KAAK,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE;SAC7B;QACD,YAAY,EAAE;;;;;;;;;;;;;;;;;;;;QAoBT;KACL,CACD,CAAC;IAEF,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QACzC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;IAC1B,CAAC;IAED,OAAO,SAAS,CAAC;AAClB,CAAC"}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,GAAG,MAAM,iBAAiB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AACxD,OAAO,KAAK,MAAM,kBAAkB,CAAC;AAkBrC,MAAM,CAAC,OAAO,UAAU,eAAe,CAAC,SAA0B;IACjE,MAAM,SAAS,GAAG,IAAI,SAAS,CAC9B;QACC,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,IAAI,EAAE,qBAAqB;QAC3B,KAAK,EAAE,qBAAqB;KAC5B,EACD;QACC,YAAY,EAAE;YACb,OAAO,EAAE,EAAE;YACX,KAAK,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE;SAC7B;QACD,YAAY,EAAE;;;;;;;;;;;;;;;;;;;;QAoBT;KACL,CACD,CAAC;IAEF,MAAM,YAAY,GAAG,SAAS,CAAC,YAAY,CAAC,IAAI,CAC/C,SAAS,CACqB,CAAC;IAEhC,SAAS,CAAC,YAAY,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE;QACpD,MAAM,WAAW,GAAG,QAA2B,CAAC;QAChD,MAAM,eAAe,GAAoB,CAAC,GAAG,IAAI,EAAE,EAAE,CACpD,SAAS,CAAC,WAAW,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QAE1E,OAAO,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,eAAe,CAAC,CAAC;IACpD,CAAC,CAAkC,CAAC;IAEpC,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QACzC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;IAC1B,CAAC;IAED,OAAO,SAAS,CAAC;AAClB,CAAC"}
@@ -25,7 +25,7 @@ declare const _default: {
25
25
  memoryMode: import("zod").ZodOptional<import("zod").ZodDefault<import("zod").ZodEnum<["response_only", "vault_note", "both"]>>>;
26
26
  continuationToken: import("zod").ZodOptional<import("zod").ZodString>;
27
27
  memoryPath: import("zod").ZodOptional<import("zod").ZodString>;
28
- compressionMode: import("zod").ZodOptional<import("zod").ZodDefault<import("zod").ZodEnum<["aggressive", "balanced", "none"]>>>;
28
+ compressionMode: import("zod").ZodOptional<import("zod").ZodDefault<import("zod").ZodEnum<["summary", "aggressive", "balanced", "none"]>>>;
29
29
  maxOutputChars: import("zod").ZodOptional<import("zod").ZodNumber>;
30
30
  quiet: import("zod").ZodOptional<import("zod").ZodDefault<import("zod").ZodBoolean>>;
31
31
  };
@@ -36,7 +36,7 @@ declare const _default: {
36
36
  memoryMode: import("zod").ZodOptional<import("zod").ZodDefault<import("zod").ZodEnum<["response_only", "vault_note", "both"]>>>;
37
37
  continuationToken: import("zod").ZodOptional<import("zod").ZodString>;
38
38
  memoryPath: import("zod").ZodOptional<import("zod").ZodString>;
39
- compressionMode: import("zod").ZodOptional<import("zod").ZodDefault<import("zod").ZodEnum<["aggressive", "balanced", "none"]>>>;
39
+ compressionMode: import("zod").ZodOptional<import("zod").ZodDefault<import("zod").ZodEnum<["summary", "aggressive", "balanced", "none"]>>>;
40
40
  maxOutputChars: import("zod").ZodOptional<import("zod").ZodNumber>;
41
41
  quiet: import("zod").ZodOptional<import("zod").ZodDefault<import("zod").ZodBoolean>>;
42
42
  };
@@ -1,6 +1,6 @@
1
1
  import { z } from "zod";
2
2
  export declare const responseTypeSchema: z.ZodEnum<["text", "audio", "image", "resource", "resource_link"]>;
3
- export declare const compressionModeSchema: z.ZodDefault<z.ZodEnum<["aggressive", "balanced", "none"]>>;
3
+ export declare const compressionModeSchema: z.ZodDefault<z.ZodEnum<["summary", "aggressive", "balanced", "none"]>>;
4
4
  export declare const obsidianContentActions: z.ZodEnum<["search", "read", "list_all", "stats", "collect_context", "load_memory", "index_vault_to_vectordb"]>;
5
5
  export declare const obsidianContentKeyword: z.ZodString;
6
6
  export declare const obsidianContentQuery: z.ZodString;
@@ -32,7 +32,7 @@ export declare const obsidianContentQueryParamsZod: z.ZodObject<{
32
32
  memoryMode: z.ZodOptional<z.ZodDefault<z.ZodEnum<["response_only", "vault_note", "both"]>>>;
33
33
  continuationToken: z.ZodOptional<z.ZodString>;
34
34
  memoryPath: z.ZodOptional<z.ZodString>;
35
- compressionMode: z.ZodOptional<z.ZodDefault<z.ZodEnum<["aggressive", "balanced", "none"]>>>;
35
+ compressionMode: z.ZodOptional<z.ZodDefault<z.ZodEnum<["summary", "aggressive", "balanced", "none"]>>>;
36
36
  maxOutputChars: z.ZodOptional<z.ZodNumber>;
37
37
  quiet: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
38
38
  }, "strip", z.ZodTypeAny, {
@@ -52,7 +52,7 @@ export declare const obsidianContentQueryParamsZod: z.ZodObject<{
52
52
  memoryMode?: "response_only" | "vault_note" | "both" | undefined;
53
53
  continuationToken?: string | undefined;
54
54
  memoryPath?: string | undefined;
55
- compressionMode?: "none" | "aggressive" | "balanced" | undefined;
55
+ compressionMode?: "none" | "summary" | "aggressive" | "balanced" | undefined;
56
56
  maxOutputChars?: number | undefined;
57
57
  }, {
58
58
  action: "search" | "read" | "list_all" | "stats" | "collect_context" | "load_memory" | "index_vault_to_vectordb";
@@ -71,7 +71,7 @@ export declare const obsidianContentQueryParamsZod: z.ZodObject<{
71
71
  memoryMode?: "response_only" | "vault_note" | "both" | undefined;
72
72
  continuationToken?: string | undefined;
73
73
  memoryPath?: string | undefined;
74
- compressionMode?: "none" | "aggressive" | "balanced" | undefined;
74
+ compressionMode?: "none" | "summary" | "aggressive" | "balanced" | undefined;
75
75
  maxOutputChars?: number | undefined;
76
76
  }>;
77
77
  export type ObsidianContentQueryParams = z.infer<typeof obsidianContentQueryParamsZod>;
@@ -3,9 +3,9 @@ export const responseTypeSchema = z
3
3
  .enum(["text", "audio", "image", "resource", "resource_link"])
4
4
  .describe("The type of content being returned");
5
5
  export const compressionModeSchema = z
6
- .enum(["aggressive", "balanced", "none"])
7
- .default("balanced")
8
- .describe("Compression strategy for tool output. aggressive: smallest output, balanced: default, none: keep as much original content as possible.");
6
+ .enum(["summary", "aggressive", "balanced", "none"])
7
+ .default("summary")
8
+ .describe("Compression strategy for tool output. summary: lightest TOC & document summary only (default), aggressive: smallest output, balanced: moderate size, none: keep as much original content as possible.");
9
9
  const maxOutputCharsSchema = z
10
10
  .number()
11
11
  .min(500)
@@ -1 +1 @@
1
- {"version":3,"file":"params.js","sourceRoot":"","sources":["../../../src/tools/vault/params.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"params.js","sourceRoot":"","sources":["../../../src/tools/vault/params.ts"],"names":[],"mappings":"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"}