n2-qln 3.4.1 → 4.1.0

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 (57) hide show
  1. package/README.ko.md +251 -262
  2. package/README.md +245 -276
  3. package/dist/index.d.ts +3 -0
  4. package/dist/index.js +87 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/lib/config.d.ts +9 -0
  7. package/{lib → dist/lib}/config.js +23 -27
  8. package/dist/lib/config.js.map +1 -0
  9. package/dist/lib/embedding.d.ts +27 -0
  10. package/{lib → dist/lib}/embedding.js +39 -47
  11. package/dist/lib/embedding.js.map +1 -0
  12. package/dist/lib/executor.d.ts +57 -0
  13. package/dist/lib/executor.js +175 -0
  14. package/dist/lib/executor.js.map +1 -0
  15. package/dist/lib/mcp-discovery.d.ts +83 -0
  16. package/dist/lib/mcp-discovery.js +203 -0
  17. package/dist/lib/mcp-discovery.js.map +1 -0
  18. package/dist/lib/provider-loader.d.ts +13 -0
  19. package/dist/lib/provider-loader.js +146 -0
  20. package/dist/lib/provider-loader.js.map +1 -0
  21. package/dist/lib/registry.d.ts +38 -0
  22. package/{lib → dist/lib}/registry.js +82 -92
  23. package/dist/lib/registry.js.map +1 -0
  24. package/dist/lib/router.d.ts +63 -0
  25. package/{lib → dist/lib}/router.js +75 -117
  26. package/dist/lib/router.js.map +1 -0
  27. package/dist/lib/schema.d.ts +20 -0
  28. package/{lib → dist/lib}/schema.js +38 -30
  29. package/dist/lib/schema.js.map +1 -0
  30. package/dist/lib/store.d.ts +37 -0
  31. package/dist/lib/store.js +207 -0
  32. package/dist/lib/store.js.map +1 -0
  33. package/dist/lib/validator.d.ts +37 -0
  34. package/dist/lib/validator.js +114 -0
  35. package/dist/lib/validator.js.map +1 -0
  36. package/dist/lib/vector-index.d.ts +37 -0
  37. package/{lib → dist/lib}/vector-index.js +19 -36
  38. package/dist/lib/vector-index.js.map +1 -0
  39. package/dist/tools/qln-call.d.ts +41 -0
  40. package/dist/tools/qln-call.js +353 -0
  41. package/dist/tools/qln-call.js.map +1 -0
  42. package/dist/tools/qln-helpers.d.ts +55 -0
  43. package/dist/tools/qln-helpers.js +88 -0
  44. package/dist/tools/qln-helpers.js.map +1 -0
  45. package/dist/types.d.ts +243 -0
  46. package/dist/types.js +4 -0
  47. package/dist/types.js.map +1 -0
  48. package/index.js +3 -79
  49. package/package.json +12 -5
  50. package/.github/FUNDING.yml +0 -3
  51. package/docs/README.md +0 -2
  52. package/docs/architecture.png +0 -0
  53. package/lib/executor.js +0 -104
  54. package/lib/provider-loader.js +0 -126
  55. package/lib/store.js +0 -217
  56. package/lib/validator.js +0 -171
  57. package/tools/qln-call.js +0 -257
package/README.ko.md CHANGED
@@ -4,68 +4,105 @@
4
4
 
5
5
  [![npm](https://img.shields.io/npm/v/n2-qln?color=brightgreen)](https://www.npmjs.com/package/n2-qln) [![license](https://img.shields.io/npm/l/n2-qln)](LICENSE) [![node](https://img.shields.io/node/v/n2-qln?color=brightgreen)](https://nodejs.org) [![downloads](https://img.shields.io/npm/dm/n2-qln?color=blue)](https://www.npmjs.com/package/n2-qln)
6
6
 
7
- **QLN** = **Q**uery **L**ayer **N**etwork — AI와 도구 사이에 위치하는 시맨틱 검색 레이어.
7
+ **QLN** = **Q**uery **L**ayer **N**etwork — AI와 도구 사이에 위치하는 시맨틱 도구 라우터.
8
8
 
9
- > **1,000개 이상의 도구를 1개의 MCP 도구로 라우팅합니다.** AI는 라우터 하나만 봅니다 — 1,000개 전체가 아닙니다.
9
+ > **1,000개 이상의 도구를 1개의 MCP 도구로 라우팅합니다.** AI는 라우터만 봅니다 — 1,000개 전체가 아닙니다.
10
10
 
11
11
  ![QLN Architecture — Without vs With](docs/architecture.png)
12
12
 
13
13
  ## 목차
14
14
 
15
- - [기능](#기능)
16
- - [문제점](#문제점)
17
- - [설치](#설치)
18
- - [설정](#설정)
15
+ - [왜 QLN인가](#왜-qln인가)
16
+ - [v4.1 주요 변경사항](#v41-주요-변경사항)
17
+ - [빠른 시작](#빠른-시작)
19
18
  - [작동 방식](#작동-방식)
20
19
  - [API 레퍼런스](#api-레퍼런스)
21
- - [설정 파일](#설정-파일)
22
- - [시맨틱 검색 설정](#시맨틱-검색-설정-선택사항)
20
+ - [MCP 자동 디스커버리](#mcp-자동-디스커버리)
21
+ - [Provider 매니페스트](#provider-매니페스트)
22
+ - [설정](#설정)
23
23
  - [프로젝트 구조](#프로젝트-구조)
24
- - [실전 검증 완료](#실전-검증-완료)
25
24
  - [FAQ](#faq)
26
25
  - [기여하기](#기여하기)
27
26
 
28
- ## 기능
29
-
30
- 🔍 **하나의 도구로 모든 것을** — AI는 `n2_qln_call` (~200 토큰)만 봅니다. 1,000개의 개별 도구가 아닙니다. 99.6% 컨텍스트 절감.
27
+ ## 왜 QLN인가
31
28
 
32
- **5ms 이하 검색** 3단계 검색 엔진 (트리거 + BM25 키워드 + 시맨틱)이 1,000 이상의 도구에서도 5ms 이내에 최적 도구를 찾습니다.
29
+ MCP 도구를 등록할 때마다 컨텍스트 토큰을 소모합니다. 10개? 괜찮습니다. 100개? 느려집니다. **1,000개? 불가능합니다** 대화 시작 전에 컨텍스트가 가득 찹니다.
33
30
 
34
- 🎯 **BM25 키워드 랭킹** *(v3.4)* — Stage 2에 [Okapi BM25](https://en.wikipedia.org/wiki/Okapi_BM25) 알고리즘 적용. 희귀한 단어일수록 높은 점수, 문서 길이 정규화. Google, Elasticsearch, Wikipedia 검색의 핵심 알고리즘.
31
+ QLN이 해결합니다:
35
32
 
36
- 📈 **자동 학습 랭킹** 많이 사용되고 성공률이 높은 도구는 자동으로 상위에 랭크됩니다. 수동 튜닝 불필요.
33
+ 1. 모든 도구를 QLN의 SQLite 엔진에 인덱싱
34
+ 2. AI는 **도구 1개**만 봅니다: `n2_qln_call` (~200 토큰)
35
+ 3. AI가 검색 → 최적 매칭 → 자동 폴백과 함께 실행
37
36
 
38
- 🔄 **런타임 동적 관리** 서버 재시작 없이 도구를 추가, 수정, 삭제할 수 있습니다. Provider 단위 일괄 관리 지원.
37
+ **결과: ~50,000 토큰 대신 ~200 토큰. 99.6% 절감.**
39
38
 
40
- 🛡️ **강제 품질 검증** — 도구 등록 시 엄격한 검증: `verb_target` 네이밍, 최소 설명 길이, 카테고리 제약. 잘못된 도구는 거부됩니다.
39
+ ## 기능
41
40
 
42
- 🧠 **시맨틱 검색 (선택)** — [Ollama](https://ollama.ai) 추가 시 벡터 유사도 검색 활성화. 없어도 Stage 1 + 2만으로 충분한 결과. Ollama가 다운되어도 검색은 정상 작동합니다.
41
+ | 기능 | 설명 |
42
+ |------|------|
43
+ | **1 도구 = 1,000 도구** | AI는 `n2_qln_call` (~200 토큰)만 보고, QLN이 올바른 도구로 라우팅 |
44
+ | **5ms 이하 검색** | 3단계 엔진: 트리거 매칭 → BM25 키워드 → 시맨틱 벡터 |
45
+ | **Auto 모드** | 검색 + 실행 원샷. 신뢰도 게이팅 + 폴백 체인 |
46
+ | **서킷 브레이커** | 실패하는 도구 자동 비활성화, 타임아웃 후 자동 복구 |
47
+ | **MCP 자동 디스커버리** | 외부 MCP 서버 스캔 → 도구 자동 인덱싱 |
48
+ | **부스트 키워드** | 2× BM25 가중치 적용 검색어로 정밀 검색 |
49
+ | **자동 학습 랭킹** | 사용 횟수 + 성공률이 점수에 반영 |
50
+ | **소스 가중치** | 출처별 도구 우선순위 (mcp > plugin > local) |
51
+ | **핫 리로드** | `providers/` 매니페스트 런타임 수정 → 자동 재인덱싱 |
52
+ | **벌크 인젝트** | 한 번의 호출로 수백 개 도구 등록 |
53
+ | **강제 검증** | `verb_target` 네이밍, 최소 설명 길이, 카테고리 제약 |
54
+ | **시맨틱 검색** | 선택적 Ollama 임베딩으로 자연어 매칭 |
55
+ | **네이티브 의존성 제로** | [sql.js](https://github.com/sql-js/sql.js) WASM 기반 — `npm install`이면 끝 |
56
+ | **이중 실행** | 로컬 함수 핸들러 또는 HTTP 프록시 — 혼합 가능 |
57
+ | **TypeScript strict** | v4.0부터 완전 strict 모드 코드베이스 |
58
+
59
+ ## v4.1 주요 변경사항
60
+
61
+ ### 🔍 MCP 자동 디스커버리
62
+
63
+ 연결된 MCP 서버를 스캔하고 도구를 자동 인덱싱 — QLN이 **범용 MCP 허브**가 됩니다.
43
64
 
44
- 📦 **네이티브 의존성 제로** — [sql.js](https://github.com/sql-js/sql.js) (WASM) 기반. `node-gyp` 빌드 없음, 플랫폼별 바이너리 없음. `npm install`이면 끝.
65
+ ```javascript
66
+ n2_qln_call({
67
+ action: "discover",
68
+ servers: [
69
+ { name: "my-server", command: "node", args: ["server.js"] }
70
+ ]
71
+ })
72
+ // → my-server에서 47개 도구 발견 (320ms)
73
+ ```
45
74
 
46
- 🔌 **이중 실행** — 도구를 로컬 함수 또는 HTTP 엔드포인트로 실행. 핸들러를 직접 등록하거나 원격 서비스를 연결. 혼합도 가능.
75
+ ### 서킷 브레이커
47
76
 
48
- 📋 **Provider 자동 인덱싱** *(v3.3)* `providers/`에 JSON 매니페스트를 넣으면 부팅 시 자동 등록. 코드 수정 불필요, 수동 `create` 호출 불필요. 멱등성 보장 및 에러 격리.
77
+ 3 연속 실패 도구 자동 비활성화. 60초 복구 시도. 연쇄 장애 방지.
49
78
 
50
- 🏗️ **10,000개 이상 확장** — 카테고리별 centroid hierarchy 파티셔닝. 100개 ~1ms, 1,000개 ~3ms, 10,000개 ~5ms.
79
+ ```
80
+ closed → 3회 실패 → open (즉시 거부) → 60초 → half-open (재시도) → 성공 → closed
81
+ ```
51
82
 
52
- 🌍 **범용 MCP** — Claude Desktop, Cursor, n2-soul 또는 모든 MCP 호환 클라이언트에서 동작. 표준 stdio 전송.
83
+ ### 🔄 폴백 체인
53
84
 
54
- ## 문제점
85
+ `auto` 모드에서 최대 3개 후보를 순차 시도. 1순위가 실패하면 자동으로 다음 후보 실행.
55
86
 
56
- MCP 도구를 등록할 때마다 AI 컨텍스트 토큰을 소모합니다. 10개는 괜찮습니다. 100개면 느려집니다. **1,000개면 불가능합니다** — 대화가 시작되기도 전에 컨텍스트 윈도우가 가득 찹니다.
87
+ ```
88
+ auto "알림 보내기" → push_notification 시도 ❌ → send_email 시도 ✅
89
+ ```
57
90
 
58
- QLN은 **시맨틱 검색 라우터**로 이 문제를 해결합니다:
91
+ ### 🎯 부스트 키워드
59
92
 
60
- 1. 모든 도구를 QLN의 SQLite 인덱스에 등록
61
- 2. AI는 **하나의 도구**만 봅니다: `n2_qln_call` (~200 토큰)
62
- 3. AI가 도구가 필요하면 **검색** → **최적 매칭** → **실행**
93
+ `boostKeywords` 필드로 검색 최적화. BM25 랭킹에서 2배 가중치 적용.
63
94
 
64
- **결과: ~50,000 토큰 대신 ~200 토큰. 99.6% 절감.**
95
+ ```json
96
+ {
97
+ "name": "send_email",
98
+ "description": "이메일을 수신자에게 전송",
99
+ "boostKeywords": "smtp outbound notification mail"
100
+ }
101
+ ```
65
102
 
66
103
  ---
67
104
 
68
- ## 설치
105
+ ## 빠른 시작
69
106
 
70
107
  ```bash
71
108
  npm install n2-qln
@@ -73,20 +110,12 @@ npm install n2-qln
73
110
 
74
111
  **요구사항:** Node.js ≥ 18
75
112
 
76
- **선택사항:** 시맨틱 벡터 검색(Stage 3)을 위해 [Ollama](https://ollama.ai) 설치. [시맨틱 검색 설정](#시맨틱-검색-설정-선택사항) 참조.
77
-
78
- ---
79
-
80
- ## 설정
81
-
82
- QLN은 MCP 서버입니다. 모든 MCP 호환 AI 클라이언트에 연결할 수 있습니다.
113
+ ### MCP 클라이언트 연결
83
114
 
84
- ### Claude Desktop
115
+ <details>
116
+ <summary><strong>Claude Desktop</strong></summary>
85
117
 
86
- Claude Desktop 설정 파일을 편집합니다:
87
-
88
- - **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
89
- - **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
118
+ `claude_desktop_config.json` 편집:
90
119
 
91
120
  ```json
92
121
  {
@@ -98,12 +127,12 @@ Claude Desktop 설정 파일을 편집합니다:
98
127
  }
99
128
  }
100
129
  ```
130
+ </details>
101
131
 
102
- Claude Desktop을 재시작하면 `n2_qln_call` 도구가 목록에 나타납니다.
103
-
104
- ### Cursor
132
+ <details>
133
+ <summary><strong>Cursor</strong></summary>
105
134
 
106
- **Settings → MCP Servers → Add Server**에서 설정:
135
+ **Settings → MCP Servers → Add Server**:
107
136
 
108
137
  ```json
109
138
  {
@@ -112,303 +141,266 @@ Claude Desktop을 재시작하면 `n2_qln_call` 도구가 목록에 나타납니
112
141
  "args": ["-y", "n2-qln"]
113
142
  }
114
143
  ```
144
+ </details>
115
145
 
116
- ### n2-soul
117
-
118
- Soul `config.local.js`에 추가:
119
-
120
- ```javascript
121
- module.exports = {
122
- mcpServers: {
123
- 'n2-qln': {
124
- command: 'node',
125
- args: ['<path-to-qln>/index.js'],
126
- }
127
- }
128
- };
129
- ```
130
-
131
- npm으로 설치한 경우:
146
+ <details>
147
+ <summary><strong>기타 MCP 클라이언트</strong></summary>
132
148
 
133
- ```javascript
134
- module.exports = {
135
- mcpServers: {
136
- 'n2-qln': {
137
- command: 'npx',
138
- args: ['-y', 'n2-qln'],
139
- }
140
- }
141
- };
142
- ```
143
-
144
- ### 기타 MCP 클라이언트
145
-
146
- QLN은 **stdio 전송** — 표준 MCP 통신 방식을 사용합니다. 모든 MCP 호환 클라이언트에서 연결 가능합니다:
149
+ QLN은 **stdio 전송** — MCP 표준 방식을 사용합니다.
147
150
 
148
151
  ```
149
152
  command: npx
150
153
  args: ["-y", "n2-qln"]
151
154
  ```
152
155
 
153
- 소스를 클론한 경우:
154
-
155
- ```
156
- command: node
157
- args: ["/absolute/path/to/n2-qln/index.js"]
158
- ```
159
-
160
- > **💡 팁:** 가장 쉬운 설정 방법? **그냥 AI 에이전트에게 부탁하세요.** *"n2-qln을 내 MCP 설정에 추가해줘"* — 에이전트가 알아서 설정합니다.
156
+ > **팁:** AI 에이전트에게 *"n2-qln을 MCP 설정에 추가해줘"*라고 말하면 됩니다.
157
+ </details>
161
158
 
162
159
  ---
163
160
 
164
161
  ## 작동 방식
165
162
 
166
- ### 단계별 예시
167
-
168
163
  ```
169
164
  사용자: "이 페이지 스크린샷 찍어"
170
165
 
171
- Step 1 AI 호출: n2_qln_call(action: "search", query: "screenshot page")
172
- QLN 1,000개 이상의 도구를 <5ms 검색
173
- 응답: take_screenshot (score: 8.0)
174
-
175
- Step 2 → AI 호출: n2_qln_call(action: "exec", tool: "take_screenshot", args: {fullPage: true})
176
- QLN이 실제 도구로 라우팅 및 실행
177
- 응답: ✅ 스크린샷 저장됨
166
+ AI → n2_qln_call(action: "auto", query: "screenshot page")
167
+ QLN 3단계 검색 (< 5ms) → take_screenshot (score: 8.0)
168
+ 실행 필요시 폴백 → 결과 반환
178
169
  ```
179
170
 
180
- AI는 `n2_qln_call`만 사용했습니다. 나머지 999개 도구는 전혀 보지 않았습니다.
181
-
182
171
  ### 3단계 검색 엔진
183
172
 
184
- QLN은 단계의 검색으로 적합한 도구를 찾습니다:
185
-
186
- | 단계 | 방식 | 속도 | 작동 원리 |
187
- |:---:|--------|:---:|---------|
188
- | **1** | 트리거 매칭 | <1ms | 도구 이름과 트리거 키워드 정확 매칭 |
189
- | **2** | BM25 키워드 | ⚡ 1-3ms | [Okapi BM25](https://en.wikipedia.org/wiki/Okapi_BM25) 랭킹 검색 — IDF 가중치 + 문서 길이 정규화 *(v3.4)* |
190
- | **3** | 시맨틱 검색 | 🧠 5-15ms | 임베딩 벡터 유사도 검색 *(선택, Ollama 필요)* |
173
+ | 단계 | 방식 | 속도 | 상세 |
174
+ |:---:|--------|:---:|------|
175
+ | **1** | 트리거 매칭 | <1ms | 도구 이름과 트리거의 정확 키워드 매칭 |
176
+ | **2** | BM25 키워드 | 1-3ms | [Okapi BM25](https://en.wikipedia.org/wiki/Okapi_BM25) — IDF 가중치, 길이 정규화, `boostKeywords` 2× 부스트 |
177
+ | **3** | 시맨틱 검색 | 5-15ms | [Ollama](https://ollama.ai) 임베딩 벡터 유사도 *(선택)* |
191
178
 
192
- 모든 단계의 결과를 병합 후 랭킹:
179
+ 결과 병합 후 랭킹:
193
180
 
194
181
  ```
195
- final_score = trigger_score × 3.0
196
- + bm25_keyword_score × 1.0
197
- + semantic_score × 2.0
198
- + log2(usage_count + 1) × 0.5
199
- + success_rate × 1.0
182
+ final_score = trigger × 3.0 + bm25 × 1.0 + semantic × 2.0
183
+ + log₂(usage + 1) × 0.5 + success_rate × 1.0
200
184
  ```
201
185
 
202
- 많이 사용되고 성공률이 높은 도구가 시간이 지날수록 상위에 랭크됩니다.
203
-
204
186
  ---
205
187
 
206
188
  ## API 레퍼런스
207
189
 
208
- QLN은 **하나의 MCP 도구** — `n2_qln_call` — 5개의 액션을 제공합니다.
190
+ QLN은 **하나의 MCP 도구** — `n2_qln_call` — 9개 액션을 제공합니다.
191
+
192
+ ### auto — 검색 + 실행 (원샷)
209
193
 
210
- ### search 자연어로 도구 검색
194
+ 권장 액션. 검색 최적 매칭 → 폴백 체인으로 실행.
195
+
196
+ ```javascript
197
+ n2_qln_call({
198
+ action: "auto",
199
+ query: "스크린샷 찍어", // 자연어 (필수)
200
+ args: { fullPage: true } // 매칭된 도구에 전달 (선택)
201
+ })
202
+ // → [auto] "스크린샷 찍어" → take_screenshot (score: 8.0, 2ms 검색 + 150ms 실행)
203
+ ```
204
+
205
+ **신뢰도 게이트:** 최고 점수가 2.0 미만이면 실행 대신 검색 결과만 반환 — 잘못된 실행 방지.
206
+
207
+ **폴백 체인:** 1순위가 실패하면 자동으로 2, 3순위까지 시도 후 포기.
208
+
209
+ ### search — 도구 검색
211
210
 
212
211
  ```javascript
213
212
  n2_qln_call({
214
213
  action: "search",
215
- query: "take a screenshot", // 자연어 쿼리 (필수)
216
- category: "capture", // 카테고리 필터 (선택)
217
- topK: 5 // 최대 결과 수, 기본: 5 (선택)
214
+ query: "이메일 보내기",
215
+ topK: 5 // 최대 결과 (기본: 5, 최대: 20)
218
216
  })
219
217
  ```
220
218
 
221
- ### exec — 이름으로 도구 실행
219
+ ### exec — 특정 도구 실행
222
220
 
223
221
  ```javascript
224
222
  n2_qln_call({
225
223
  action: "exec",
226
- tool: "take_screenshot", // 도구 이름 (필수)
227
- args: { // 도구 인수 (선택)
228
- fullPage: true,
229
- format: "png"
230
- }
224
+ tool: "take_screenshot",
225
+ args: { fullPage: true, format: "png" }
231
226
  })
232
227
  ```
233
228
 
234
- ### create — 도구 등록
229
+ ### create — 도구 등록
235
230
 
236
231
  ```javascript
237
232
  n2_qln_call({
238
233
  action: "create",
239
- name: "read_pdf", // 필수, verb_target 형식
240
- description: "Read and extract text from PDF files", // 필수, 최소 10자
241
- category: "data", // 필수, 아래 카테고리 참조
242
- provider: "pdf-tools", // 선택, 소스별 도구 그룹화
243
- tags: ["pdf", "read", "extract", "document"], // 선택, 검색 개선
244
- examples: [ // 선택, 키워드 검색에 색인
245
- "read this PDF file",
246
- "extract text from PDF",
247
- "open the PDF"
248
- ],
249
- endpoint: "http://127.0.0.1:3100", // 선택, HTTP 기반 도구용
250
- toolSchema: { filePath: { type: "string" } } // 선택, 입력 스키마
234
+ name: "read_pdf", // verb_target 형식 (필수)
235
+ description: "PDF에서 텍스트를 추출합니다", // 최소 10자 (필수)
236
+ category: "data", // web|data|file|dev|ai|capture|misc
237
+ boostKeywords: "pdf extract parse document", // BM25 부스트 검색어
238
+ tags: ["pdf", "read", "extract"],
239
+ endpoint: "http://127.0.0.1:3100" // HTTP 기반 도구용
251
240
  })
252
241
  ```
253
242
 
254
- **검증 규칙 (강제 위반 시 거부):**
255
-
256
- | 규칙 | 요구사항 | 예시 |
257
- |------|---------|------|
258
- | **이름** | `verb_target` 형식 (소문자 + 밑줄) | `read_pdf`, `take_screenshot` |
259
- | **설명** | 최소 10자 | `"Read and extract text from PDF files"` |
260
- | **카테고리** | 유효한 카테고리 중 하나 | `"data"` |
261
- | **고유성** | 중복 이름 불가 | — |
262
-
263
- **유효 카테고리:** `web` · `data` · `file` · `dev` · `ai` · `capture` · `misc`
264
-
265
- ### update — 기존 도구 수정
243
+ ### inject벌크 등록
266
244
 
267
245
  ```javascript
268
246
  n2_qln_call({
269
- action: "update",
270
- tool: "read_pdf", // 수정할 도구 (필수)
271
- description: "Enhanced PDF text extractor", // 변경할 필드만 제공
272
- examples: ["read this PDF", "parse PDF"],
273
- tags: ["pdf", "read", "parse"]
247
+ action: "inject",
248
+ source: "my-plugin",
249
+ tools: [
250
+ { name: "tool_a", description: "A를 수행합니다", category: "misc" },
251
+ { name: "tool_b", description: "B를 수행합니다", category: "dev" }
252
+ ]
274
253
  })
275
254
  ```
276
255
 
277
- 변경된 필드만 제공하면 됩니다. 미변경 필드는 기존 값 유지. 동일한 검증 규칙 적용.
256
+ ### discover MCP 서버 스캔
257
+
258
+ [MCP 자동 디스커버리](#mcp-자동-디스커버리) 참조.
278
259
 
279
- ### delete 도구 삭제
260
+ ### update / delete / stats
280
261
 
281
262
  ```javascript
282
- // 이름으로 단일 도구 삭제
283
- n2_qln_call({
284
- action: "delete",
285
- tool: "read_pdf"
286
- })
263
+ // 필드 수정
264
+ n2_qln_call({ action: "update", tool: "read_pdf", description: "향상된 PDF 리더" })
287
265
 
288
- // Provider의 모든 도구 일괄 삭제
289
- n2_qln_call({
290
- action: "delete",
291
- provider: "pdf-tools"
292
- })
293
- // Deleted 3 tools from provider: pdf-tools
266
+ // 이름 또는 provider로 삭제
267
+ n2_qln_call({ action: "delete", tool: "read_pdf" })
268
+ n2_qln_call({ action: "delete", provider: "pdf-tools" })
269
+
270
+ // 시스템 통계 (서킷 브레이커 상태 포함)
271
+ n2_qln_call({ action: "stats" })
294
272
  ```
295
273
 
296
274
  ---
297
275
 
298
- ## 설정 파일
276
+ ## MCP 자동 디스커버리
299
277
 
300
- QLN은 설정 없이 바로 동작합니다. 커스터마이즈하려면 QLN 디렉토리에 `config.local.js`를 생성하세요:
278
+ v4.1의 킬러 피처. MCP 서버를 연결하면 QLN 모든 도구를 자동으로 인덱싱합니다.
301
279
 
302
280
  ```javascript
303
- module.exports = {
304
- dataDir: './data', // SQLite DB 저장 위치
305
- embedding: {
306
- enabled: true, // Stage 3 시맨틱 검색 활성화
307
- provider: 'ollama',
308
- model: 'nomic-embed-text',
309
- baseUrl: 'http://127.0.0.1:11434',
310
- },
311
- };
281
+ n2_qln_call({
282
+ action: "discover",
283
+ servers: [
284
+ { name: "n2-soul", command: "node", args: ["path/to/soul/index.js"] },
285
+ { name: "github", command: "npx", args: ["-y", "@modelcontextprotocol/server-github"] }
286
+ ]
287
+ })
312
288
  ```
313
289
 
314
- > **참고:** `config.local.js`는 gitignore 처리됩니다. 로컬 설정은 커밋되지 않습니다.
315
-
316
- ---
290
+ **처리 과정:**
291
+ 1. QLN이 stdio로 각 서버에 연결
292
+ 2. `tools/list`로 모든 도구 조회
293
+ 3. `mcp__서버명__도구명` 형식으로 QLN 인덱스에 등록
294
+ 4. 도구 이름과 설명에서 `boostKeywords` 자동 생성
295
+ 5. 실행을 위해 연결 유지
317
296
 
318
- ## 시맨틱 검색 설정 (선택사항)
297
+ **재디스커버리는 멱등** 다시 실행하면 기존 항목 삭제 후 재등록.
319
298
 
320
- Ollama 없이도 QLN은 Stage 1 (트리거) + Stage 2 (키워드) 매칭을 사용하며, 대부분의 경우 충분한 결과를 제공합니다.
299
+ ---
321
300
 
322
- 최대 정확도를 원한다면 시맨틱 벡터 검색(Stage 3)을 추가하세요:
301
+ ## Provider 매니페스트
323
302
 
324
- ### 1. Ollama 설치
303
+ `providers/`에 JSON 파일을 넣으면 부팅 시 자동 인덱싱. 코드 수정 불필요.
325
304
 
326
- [ollama.ai](https://ollama.ai)에서 다운로드 후 설치.
305
+ ```json
306
+ {
307
+ "provider": "my-tools",
308
+ "version": "1.0.0",
309
+ "tools": [
310
+ {
311
+ "name": "send_email",
312
+ "description": "수신자에게 이메일을 전송합니다",
313
+ "category": "communication",
314
+ "triggers": ["email", "send", "mail"],
315
+ "boostKeywords": "smtp outbound notification"
316
+ }
317
+ ]
318
+ }
319
+ ```
327
320
 
328
- ### 2. 임베딩 모델 다운로드
321
+ 리로드: QLN 실행 중 매니페스트 수정 → 자동 반영.
329
322
 
330
- ```bash
331
- ollama pull nomic-embed-text
332
- ```
323
+ ---
333
324
 
334
- ### 3. 설정 활성화
325
+ ## 설정
335
326
 
336
- `config.local.js` 생성:
327
+ 설정 없이 바로 동작합니다. 커스터마이즈하려면 `config.local.js` 생성:
337
328
 
338
329
  ```javascript
339
330
  module.exports = {
331
+ dataDir: './data',
332
+
333
+ // Stage 3 시맨틱 검색 (선택 — Stage 1+2는 이것 없이 작동)
340
334
  embedding: {
341
335
  enabled: true,
342
336
  provider: 'ollama',
343
- model: 'nomic-embed-text',
337
+ model: 'nomic-embed-text', // 다국어는 'bge-m3'
344
338
  baseUrl: 'http://127.0.0.1:11434',
345
339
  },
346
- };
347
- ```
348
340
 
349
- ### 비교
350
-
351
- | 설정 | 검색 단계 | 정확도 | 의존성 |
352
- |:------|:---:|:---:|:---:|
353
- | **기본** (Ollama 없음) | Stage 1 + 2 | ⭐⭐⭐⭐ 훌륭 | 없음 |
354
- | **Ollama 포함** | Stage 1 + 2 + 3 | ⭐⭐⭐⭐⭐ 완벽 | Ollama 실행 필요 |
355
-
356
- ### 다국어 사용자
357
-
358
- `nomic-embed-text`는 영어에 최적화되어 있습니다. **한국어, 일본어, 중국어** 등 다른 언어를 사용한다면 다국어 모델로 교체하세요:
341
+ // 도구 실행
342
+ executor: {
343
+ timeout: 20000, // 실행 타임아웃 (ms)
344
+ circuitBreaker: {
345
+ failureThreshold: 3, // 연속 실패 횟수 비활성화
346
+ recoveryTimeout: 60000, // 복구 시도까지 대기 시간 (ms)
347
+ },
348
+ },
359
349
 
360
- ```bash
361
- ollama pull bge-m3
362
- ```
350
+ // 소스 가중치 (v4.0)
351
+ // 높은 가중치 = 검색 결과에서 높은 우선순위
352
+ search: {
353
+ sourceWeights: {
354
+ mcp: 1.5, // MCP 디스커버리 도구 최우선
355
+ provider: 1.2, // Provider 매니페스트 도구
356
+ local: 1.0, // 수동 생성 도구 (기본)
357
+ },
358
+ },
363
359
 
364
- ```javascript
365
- // config.local.js
366
- module.exports = {
367
- embedding: {
368
- enabled: true,
369
- model: 'bge-m3', // 다국어 지원 (100개 이상 언어)
360
+ // Provider 자동 인덱싱
361
+ providers: {
362
+ enabled: true, // 부팅 시 providers/*.json 자동 로드
363
+ dir: './providers', // 매니페스트 디렉토리
370
364
  },
371
365
  };
372
366
  ```
373
367
 
374
- 코드 수정 없이 config의 모델명만 바꾸면 됩니다.
368
+ > `config.local.js`는 gitignore 처리. 클라우드 동기화: `dataDir`을 Google Drive / OneDrive / NAS로 지정.
375
369
 
376
- ### 클라우드 동기화
370
+ ### 시맨틱 검색 (선택)
377
371
 
378
- 도구 인덱스를 여러 기기에서 동기화하고 싶다면 `dataDir`을 클라우드 폴더로 지정하세요:
372
+ Ollama 없이도 Stage 1 + 2로 충분한 결과를 제공합니다.
379
373
 
380
- ```javascript
381
- // config.local.js
382
- module.exports = {
383
- dataDir: 'G:/My Drive/n2-qln', // Google Drive, OneDrive, Dropbox, NAS...
384
- };
374
+ ```bash
375
+ ollama pull nomic-embed-text # 영어 최적화
376
+ # 또는
377
+ ollama pull bge-m3 # 다국어 (100개 이상 언어)
385
378
  ```
386
379
 
387
- [n2-soul 클라우드 스토리지](https://github.com/choihyunsus/soul#%EF%B8%8F-cloud-storage--store-your-ai-memory-anywhere)와 동일한 방식입니다. SQLite 파일이 해당 폴더에 저장되고, 동기화 서비스가 나머지를 처리합니다.
388
-
389
380
  ---
390
381
 
391
382
  ## 프로젝트 구조
392
383
 
393
384
  ```
394
385
  n2-qln/
395
- ├── index.js # MCP 서버 진입점
396
- ├── lib/
397
- │ ├── config.js # 설정 로더 (기본 + 로컬 병합)
398
- ├── store.js # SQLite 스토리지 엔진 (sql.js WASM)
399
- ├── schema.js # 도구 스키마 정규화 + 검색 텍스트 빌더
400
- ├── validator.js # 강제 검증 (이름, 설명, 카테고리)
401
- ├── registry.js # 도구 CRUD + 사용량 추적 + 임베딩 캐시
402
- ├── router.js # 3단계 검색 엔진 (BM25 v3.4)
403
- ├── vector-index.js # Float32 벡터 인덱스 (centroid hierarchy)
404
- ├── embedding.js # Ollama 임베딩 클라이언트 (nomic-embed-text)
405
- ├── executor.js # HTTP/함수 도구 실행기
406
- └── provider-loader.js # 부팅 providers/*.json 자동 인덱싱
407
- ├── tools/
408
- └── qln-call.js # 통합 MCP 도구 (search/exec/create/update/delete)
409
- ├── providers/ # 도구 provider 매니페스트 (일괄 등록용)
410
- ├── config.local.js # 로컬 설정 오버라이드 (gitignored)
411
- └── data/ # SQLite 데이터베이스 (gitignored, 자동 생성)
386
+ ├── src/
387
+ ├── index.ts # MCP 서버 진입점
388
+ │ ├── types.ts # 공유 타입 정의
389
+ └── lib/
390
+ ├── config.ts # 설정 로더
391
+ ├── store.ts # SQLite 엔진 (sql.js WASM)
392
+ ├── schema.ts # 도구 정규화 + boostKeywords 빌더
393
+ ├── validator.ts # 강제 검증 (이름, 설명, 카테고리)
394
+ ├── registry.ts # 도구 CRUD + 사용량 추적 + 서킷 브레이커 통계
395
+ ├── router.ts # 3단계 병렬 검색 (BM25)
396
+ ├── vector-index.ts # Float32 centroid hierarchy
397
+ ├── embedding.ts # Ollama 임베딩 클라이언트
398
+ ├── executor.ts # HTTP/함수 실행기 + 서킷 브레이커
399
+ ├── mcp-discovery.ts # MCP 자동 디스커버리 엔진
400
+ │ └── provider-loader.ts
401
+ ├── providers/ # 도구 매니페스트 (부팅 시 자동 인덱싱)
402
+ ├── config.local.js # 로컬 오버라이드 (gitignored)
403
+ └── data/ # SQLite 데이터베이스 (gitignored)
412
404
  ```
413
405
 
414
406
  ## 기술 스택
@@ -416,46 +408,43 @@ n2-qln/
416
408
  | 컴포넌트 | 기술 | 이유 |
417
409
  |-----------|-----------|------|
418
410
  | 런타임 | Node.js ≥ 18 | MCP SDK 호환성 |
419
- | 데이터베이스 | SQLite via [sql.js](https://github.com/sql-js/sql.js) (WASM) | 네이티브 의존성 제로, 크로스 플랫폼, 빌드 불필요 |
420
- | 임베딩 | [Ollama](https://ollama.ai) + nomic-embed-text | 로컬, 빠름, 무료, 선택사항 |
421
- | 프로토콜 | [MCP](https://modelcontextprotocol.io) (Model Context Protocol) | 표준 AI 도구 프로토콜 |
422
- | 검증 | [Zod](https://zod.dev) | 런타임 타입 안전 스키마 검증 |
411
+ | 데이터베이스 | SQLite via [sql.js](https://github.com/sql-js/sql.js) (WASM) | 네이티브 의존성 제로, 크로스 플랫폼 |
412
+ | 임베딩 | [Ollama](https://ollama.ai) | 로컬, 빠름, 무료, 선택사항 |
413
+ | 프로토콜 | [MCP](https://modelcontextprotocol.io) | 표준 AI 도구 프로토콜 |
414
+ | 언어 | TypeScript (strict) | 타입 안전, 유지보수성 |
423
415
 
424
416
  ## 관련 프로젝트
425
417
 
426
418
  | 프로젝트 | 관계 |
427
419
  |---------|------|
428
- | [n2-soul](https://github.com/choihyunsus/soul) | AI 에이전트 오케스트레이터 — QLN은 Soul의 "도구 브레인" 역할 |
420
+ | [n2-soul](https://github.com/choihyunsus/soul) | AI 에이전트 오케스트레이터 — QLN은 Soul의 도구 브레인 |
429
421
 
430
422
  ## 실전 검증 완료
431
423
 
432
- 주말 프로토타입이 아닙니다. QLN은 **2개월 이상 운영 환경에서 검증**되었으며, [n2-soul](https://github.com/choihyunsus/soul)의 핵심 도구 라우터로 매일 실사용되고 있습니다.
424
+ QLN은 [n2-soul](https://github.com/choihyunsus/soul)의 핵심 도구 라우터로 **2개월 이상 운영 환경에서 검증**되었습니다. 프로토타입이 아니라 매일 사용하는 실전 도구입니다.
433
425
 
434
- **Rose** 🌹 제작 — N2의 첫 번째 AI 에이전트. 하루에 수백 번 QLN을 통해 라우팅합니다.
435
-
436
- 문제가 있거나 아이디어가 있다면 이슈를 열어주세요. 여러분의 활용 사례를 듣고 싶습니다.
426
+ **Rose** 제작 — N2의 첫 번째 AI 에이전트.
437
427
 
438
428
  ## FAQ
439
429
 
440
- **"왜 프로젝트를 이렇게 자주 올리나요?"**
430
+ **"왜 도구 1개만 쓰나요?"**
441
431
 
442
- N2 생태계는 4개월 이상 활발히 개발되어 왔습니다. Soul, QLN, Ark 보이는 모든 프로젝트는 공개 전에 실제 업무에서 충분히 테스트되고 검증되었습니다. 앞으로 더 나올 예정이지만, 도배가 아니라 이미 만들어져서 검증 완료된 것들이 많기 때문입니다.
432
+ 컨텍스트 토큰 때문입니다. 도구 정의 하나당 50~200 토큰. 100개 = 대화 시작 10,000 토큰 소모. QLN으로 1,000개 이상의 도구를 ~200 토큰으로 사용합니다.
443
433
 
444
- 혼자서 개발하고 배포하는 프로젝트입니다. 빌드, 테스트, 문서화를 혼자 하다 보니 시간이 많이 걸렸습니다. 관심과 인내에 감사드립니다 🙏
434
+ **"검색이 잘못된 도구를 고르면?"**
445
435
 
446
- ## 기여하기
436
+ 폴백 체인 (v4.1)이 자동으로 다음 후보를 시도합니다. 게다가 자동 학습 — 자주 사용되고 성공률 높은 도구가 상위에 오릅니다.
447
437
 
448
- 기여를 환영합니다! 시작하는 방법:
438
+ **"Ollama가 필요한가요?"**
449
439
 
450
- 1. 저장소를 Fork합니다
451
- 2. 기능 브랜치를 생성합니다 (`git checkout -b feature/amazing-feature`)
452
- 3. 변경사항을 커밋합니다 (`git commit -m 'feat: add amazing feature'`)
453
- 4. 브랜치에 Push합니다 (`git push origin feature/amazing-feature`)
454
- 5. Pull Request를 엽니다
440
+ 아닙니다. Stage 1 (트리거) + Stage 2 (BM25)가 대부분의 경우를 처리합니다. Ollama는 엣지 케이스에 시맨틱 이해를 추가 — 있으면 좋지만 필수는 아닙니다.
455
441
 
456
- ## Star History
442
+ ## 기여하기
457
443
 
458
- QLN이 도움이 되었다면 Star를 눌러주세요! ⭐
444
+ 1. 저장소를 Fork합니다
445
+ 2. 기능 브랜치 생성 (`git checkout -b feature/amazing-feature`)
446
+ 3. 커밋 (`git commit -m 'feat: add amazing feature'`)
447
+ 4. Push 후 PR을 엽니다
459
448
 
460
449
  ## 라이선스
461
450
 
@@ -465,6 +454,6 @@ Apache-2.0
465
454
 
466
455
  > *"1,000개 도구를 200 토큰으로. 이건 최적화가 아니라 패러다임 전환이다."*
467
456
 
468
- 🌐 [nton2.com](https://nton2.com) · 📦 [npm](https://www.npmjs.com/package/n2-qln) · ✉️ lagi0730@gmail.com
457
+ 🔗 [nton2.com](https://nton2.com) · [npm](https://www.npmjs.com/package/n2-qln) · lagi0730@gmail.com
469
458
 
470
- <sub>🌹 Rose가 만들었습니다 — N2의 첫 번째 AI 에이전트. 하루에 수백 번 QLN으로 검색하고, 이 README도 직접 작성했습니다.</sub>
459
+ <sub>Rose가 만들었습니다 — N2의 첫 번째 AI 에이전트. 하루에 수백 번 QLN으로 검색하고, 이 README도 직접 작성했습니다.</sub>