@vdpeijl/kb-mcp 0.1.2
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.
- package/README.md +416 -0
- package/dist/scripts/postinstall.d.ts +3 -0
- package/dist/scripts/postinstall.d.ts.map +1 -0
- package/dist/scripts/postinstall.js +110 -0
- package/dist/scripts/postinstall.js.map +1 -0
- package/dist/src/cli.d.ts +3 -0
- package/dist/src/cli.d.ts.map +1 -0
- package/dist/src/cli.js +22 -0
- package/dist/src/cli.js.map +1 -0
- package/dist/src/commands/doctor.d.ts +3 -0
- package/dist/src/commands/doctor.d.ts.map +1 -0
- package/dist/src/commands/doctor.js +93 -0
- package/dist/src/commands/doctor.js.map +1 -0
- package/dist/src/commands/init.d.ts +3 -0
- package/dist/src/commands/init.d.ts.map +1 -0
- package/dist/src/commands/init.js +150 -0
- package/dist/src/commands/init.js.map +1 -0
- package/dist/src/commands/serve.d.ts +3 -0
- package/dist/src/commands/serve.d.ts.map +1 -0
- package/dist/src/commands/serve.js +22 -0
- package/dist/src/commands/serve.js.map +1 -0
- package/dist/src/commands/setup.d.ts +9 -0
- package/dist/src/commands/setup.d.ts.map +1 -0
- package/dist/src/commands/setup.js +115 -0
- package/dist/src/commands/setup.js.map +1 -0
- package/dist/src/commands/sources.d.ts +3 -0
- package/dist/src/commands/sources.d.ts.map +1 -0
- package/dist/src/commands/sources.js +258 -0
- package/dist/src/commands/sources.js.map +1 -0
- package/dist/src/commands/stats.d.ts +3 -0
- package/dist/src/commands/stats.d.ts.map +1 -0
- package/dist/src/commands/stats.js +48 -0
- package/dist/src/commands/stats.js.map +1 -0
- package/dist/src/commands/sync.d.ts +13 -0
- package/dist/src/commands/sync.d.ts.map +1 -0
- package/dist/src/commands/sync.js +106 -0
- package/dist/src/commands/sync.js.map +1 -0
- package/dist/src/config/index.d.ts +18 -0
- package/dist/src/config/index.d.ts.map +1 -0
- package/dist/src/config/index.js +67 -0
- package/dist/src/config/index.js.map +1 -0
- package/dist/src/config/paths.d.ts +21 -0
- package/dist/src/config/paths.d.ts.map +1 -0
- package/dist/src/config/paths.js +38 -0
- package/dist/src/config/paths.js.map +1 -0
- package/dist/src/config/schema.d.ts +133 -0
- package/dist/src/config/schema.d.ts.map +1 -0
- package/dist/src/config/schema.js +34 -0
- package/dist/src/config/schema.js.map +1 -0
- package/dist/src/db/articles.d.ts +39 -0
- package/dist/src/db/articles.d.ts.map +1 -0
- package/dist/src/db/articles.js +103 -0
- package/dist/src/db/articles.js.map +1 -0
- package/dist/src/db/chunks.d.ts +46 -0
- package/dist/src/db/chunks.d.ts.map +1 -0
- package/dist/src/db/chunks.js +129 -0
- package/dist/src/db/chunks.js.map +1 -0
- package/dist/src/db/index.d.ts +19 -0
- package/dist/src/db/index.d.ts.map +1 -0
- package/dist/src/db/index.js +86 -0
- package/dist/src/db/index.js.map +1 -0
- package/dist/src/db/schema.d.ts +10 -0
- package/dist/src/db/schema.d.ts.map +1 -0
- package/dist/src/db/schema.js +80 -0
- package/dist/src/db/schema.js.map +1 -0
- package/dist/src/db/sources.d.ts +48 -0
- package/dist/src/db/sources.d.ts.map +1 -0
- package/dist/src/db/sources.js +110 -0
- package/dist/src/db/sources.js.map +1 -0
- package/dist/src/index.d.ts +8 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +87 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/search/embeddings.d.ts +22 -0
- package/dist/src/search/embeddings.d.ts.map +1 -0
- package/dist/src/search/embeddings.js +122 -0
- package/dist/src/search/embeddings.js.map +1 -0
- package/dist/src/search/index.d.ts +21 -0
- package/dist/src/search/index.d.ts.map +1 -0
- package/dist/src/search/index.js +50 -0
- package/dist/src/search/index.js.map +1 -0
- package/dist/src/sync/chunker.d.ts +15 -0
- package/dist/src/sync/chunker.d.ts.map +1 -0
- package/dist/src/sync/chunker.js +117 -0
- package/dist/src/sync/chunker.js.map +1 -0
- package/dist/src/sync/index.d.ts +24 -0
- package/dist/src/sync/index.d.ts.map +1 -0
- package/dist/src/sync/index.js +180 -0
- package/dist/src/sync/index.js.map +1 -0
- package/dist/src/sync/parser.d.ts +9 -0
- package/dist/src/sync/parser.d.ts.map +1 -0
- package/dist/src/sync/parser.js +91 -0
- package/dist/src/sync/parser.js.map +1 -0
- package/dist/src/sync/zendesk.d.ts +45 -0
- package/dist/src/sync/zendesk.d.ts.map +1 -0
- package/dist/src/sync/zendesk.js +161 -0
- package/dist/src/sync/zendesk.js.map +1 -0
- package/dist/src/utils/errors.d.ts +39 -0
- package/dist/src/utils/errors.d.ts.map +1 -0
- package/dist/src/utils/errors.js +62 -0
- package/dist/src/utils/errors.js.map +1 -0
- package/dist/src/utils/logger.d.ts +21 -0
- package/dist/src/utils/logger.d.ts.map +1 -0
- package/dist/src/utils/logger.js +25 -0
- package/dist/src/utils/logger.js.map +1 -0
- package/package.json +57 -0
package/README.md
ADDED
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
# @vdpeijl/kb-mcp
|
|
2
|
+
|
|
3
|
+
MCP (Model Context Protocol) server that indexes multiple Zendesk Help Center knowledge bases and exposes them as searchable tools for AI coding assistants.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- š **Vector Search**: Semantic search using Ollama embeddings (nomic-embed-text)
|
|
8
|
+
- š **Multiple Sources**: Index and search across multiple Zendesk knowledge bases
|
|
9
|
+
- š **Incremental Sync**: Efficient updates - only process changed articles
|
|
10
|
+
- š **Easy Setup**: Interactive CLI wizard for first-time configuration
|
|
11
|
+
- šÆ **MCP Compatible**: Works with Claude Code, Cursor, Windsurf, Continue.dev, and Zed
|
|
12
|
+
|
|
13
|
+
## Prerequisites
|
|
14
|
+
|
|
15
|
+
### Node.js 20+
|
|
16
|
+
|
|
17
|
+
Check your version:
|
|
18
|
+
```bash
|
|
19
|
+
node --version
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
If you need to install or update Node.js, visit [nodejs.org](https://nodejs.org)
|
|
23
|
+
|
|
24
|
+
### Ollama
|
|
25
|
+
|
|
26
|
+
Ollama is required for generating embeddings.
|
|
27
|
+
|
|
28
|
+
**macOS:**
|
|
29
|
+
```bash
|
|
30
|
+
brew install ollama
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**Linux:**
|
|
34
|
+
```bash
|
|
35
|
+
curl -fsSL https://ollama.com/install.sh | sh
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**Arch Linux:**
|
|
39
|
+
```bash
|
|
40
|
+
pacman -S ollama
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
**Start Ollama and pull the embedding model:**
|
|
44
|
+
```bash
|
|
45
|
+
ollama serve &
|
|
46
|
+
ollama pull nomic-embed-text
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Installation
|
|
50
|
+
|
|
51
|
+
### From npm (once published)
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
npm install -g @vdpeijl/kb-mcp
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### From source (during development)
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
git clone https://github.com/paragin/kb-mcp.git
|
|
61
|
+
cd kb-mcp
|
|
62
|
+
npm install
|
|
63
|
+
npm run build
|
|
64
|
+
npm link
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Quick Start
|
|
68
|
+
|
|
69
|
+
### 1. Run interactive setup
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
kb-mcp init
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
This will:
|
|
76
|
+
- Check if Ollama is running
|
|
77
|
+
- Verify the embedding model is available
|
|
78
|
+
- Help you add your first knowledge base
|
|
79
|
+
- Create the configuration file
|
|
80
|
+
|
|
81
|
+
### 2. Sync your knowledge base
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
kb-mcp sync
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
This will:
|
|
88
|
+
- Fetch all articles from your Zendesk Help Center
|
|
89
|
+
- Parse HTML content
|
|
90
|
+
- Split into chunks (~500 tokens with overlap)
|
|
91
|
+
- Generate embeddings using Ollama
|
|
92
|
+
- Store in a local SQLite database with vector search
|
|
93
|
+
|
|
94
|
+
### 3. Configure your MCP client
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
kb-mcp setup cursor # or: claude-code, windsurf, continue, zed
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Copy the printed configuration to your MCP client's config file.
|
|
101
|
+
|
|
102
|
+
### 4. Restart your MCP client
|
|
103
|
+
|
|
104
|
+
The knowledge base will now be available for search!
|
|
105
|
+
|
|
106
|
+
## Commands
|
|
107
|
+
|
|
108
|
+
### `kb-mcp init`
|
|
109
|
+
|
|
110
|
+
Interactive setup wizard. Creates configuration and helps you add your first knowledge base.
|
|
111
|
+
|
|
112
|
+
### `kb-mcp sync`
|
|
113
|
+
|
|
114
|
+
Sync all enabled knowledge bases. Only processes articles that have changed since the last sync.
|
|
115
|
+
|
|
116
|
+
**Options:**
|
|
117
|
+
- `--source <id>` - Sync specific source only
|
|
118
|
+
- `--full` - Full re-sync (re-embed everything)
|
|
119
|
+
|
|
120
|
+
**Examples:**
|
|
121
|
+
```bash
|
|
122
|
+
kb-mcp sync # Sync all enabled sources
|
|
123
|
+
kb-mcp sync --source myco # Sync specific source
|
|
124
|
+
kb-mcp sync --full # Full re-sync
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### `kb-mcp sources`
|
|
128
|
+
|
|
129
|
+
Manage knowledge base sources.
|
|
130
|
+
|
|
131
|
+
**Subcommands:**
|
|
132
|
+
- `list` - List all sources with stats (default)
|
|
133
|
+
- `add` - Add a new source (interactive or with flags)
|
|
134
|
+
- `remove <id>` - Remove a source and its data
|
|
135
|
+
- `enable <id>` - Enable a disabled source
|
|
136
|
+
- `disable <id>` - Disable without removing data
|
|
137
|
+
|
|
138
|
+
**Examples:**
|
|
139
|
+
```bash
|
|
140
|
+
kb-mcp sources # List all sources
|
|
141
|
+
kb-mcp sources add # Interactive add
|
|
142
|
+
kb-mcp sources add --id myco --name "My Company" --url https://support.myco.com --locale en-us
|
|
143
|
+
kb-mcp sources remove myco # Remove source
|
|
144
|
+
kb-mcp sources disable myco # Disable source
|
|
145
|
+
kb-mcp sources enable myco # Enable source
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### `kb-mcp serve`
|
|
149
|
+
|
|
150
|
+
Start the MCP server (stdio). This is normally called by your MCP client, not manually.
|
|
151
|
+
|
|
152
|
+
### `kb-mcp setup [client]`
|
|
153
|
+
|
|
154
|
+
Print MCP client configuration. Supports: claude-code, cursor, windsurf, continue, zed.
|
|
155
|
+
|
|
156
|
+
**Examples:**
|
|
157
|
+
```bash
|
|
158
|
+
kb-mcp setup # List all clients
|
|
159
|
+
kb-mcp setup cursor # Show config for Cursor
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### `kb-mcp doctor`
|
|
163
|
+
|
|
164
|
+
Run diagnostics to check:
|
|
165
|
+
- Node.js version
|
|
166
|
+
- Configuration validity
|
|
167
|
+
- Ollama connection
|
|
168
|
+
- Embedding model availability
|
|
169
|
+
- Database accessibility
|
|
170
|
+
- sqlite-vec extension
|
|
171
|
+
|
|
172
|
+
### `kb-mcp stats`
|
|
173
|
+
|
|
174
|
+
Show database statistics:
|
|
175
|
+
- Total sources, articles, chunks
|
|
176
|
+
- Database file size
|
|
177
|
+
- Per-source breakdown
|
|
178
|
+
|
|
179
|
+
## MCP Client Configuration
|
|
180
|
+
|
|
181
|
+
### Claude Code
|
|
182
|
+
|
|
183
|
+
Add to `~/.claude/claude_desktop_config.json`:
|
|
184
|
+
|
|
185
|
+
```json
|
|
186
|
+
{
|
|
187
|
+
"mcpServers": {
|
|
188
|
+
"knowledge-base": {
|
|
189
|
+
"command": "kb-mcp",
|
|
190
|
+
"args": ["serve"]
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Cursor
|
|
197
|
+
|
|
198
|
+
Go to **Settings ā Features ā MCP Servers**, then add:
|
|
199
|
+
|
|
200
|
+
```json
|
|
201
|
+
{
|
|
202
|
+
"mcpServers": {
|
|
203
|
+
"knowledge-base": {
|
|
204
|
+
"command": "kb-mcp",
|
|
205
|
+
"args": ["serve"]
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### Windsurf
|
|
212
|
+
|
|
213
|
+
Add to `~/.codeium/windsurf/mcp_config.json`:
|
|
214
|
+
|
|
215
|
+
```json
|
|
216
|
+
{
|
|
217
|
+
"mcpServers": {
|
|
218
|
+
"knowledge-base": {
|
|
219
|
+
"command": "kb-mcp",
|
|
220
|
+
"args": ["serve"]
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### Continue.dev
|
|
227
|
+
|
|
228
|
+
Add to `~/.continue/config.json`:
|
|
229
|
+
|
|
230
|
+
```json
|
|
231
|
+
{
|
|
232
|
+
"experimental": {
|
|
233
|
+
"modelContextProtocolServers": [
|
|
234
|
+
{
|
|
235
|
+
"transport": {
|
|
236
|
+
"type": "stdio",
|
|
237
|
+
"command": "kb-mcp",
|
|
238
|
+
"args": ["serve"]
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
]
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### Zed
|
|
247
|
+
|
|
248
|
+
Add to `~/.config/zed/settings.json`:
|
|
249
|
+
|
|
250
|
+
```json
|
|
251
|
+
{
|
|
252
|
+
"context_servers": {
|
|
253
|
+
"knowledge-base": {
|
|
254
|
+
"command": {
|
|
255
|
+
"path": "kb-mcp",
|
|
256
|
+
"args": ["serve"]
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
## MCP Tools
|
|
264
|
+
|
|
265
|
+
The server exposes two tools to MCP clients:
|
|
266
|
+
|
|
267
|
+
### `search_knowledge_base`
|
|
268
|
+
|
|
269
|
+
Search the knowledge base for documentation, guides, and help articles.
|
|
270
|
+
|
|
271
|
+
**Parameters:**
|
|
272
|
+
- `query` (required): Natural language search query
|
|
273
|
+
- `sources` (optional): Filter by source IDs (array of strings)
|
|
274
|
+
- `limit` (optional): Maximum results (default: 5, max: 20)
|
|
275
|
+
|
|
276
|
+
**Example usage in Claude Code:**
|
|
277
|
+
> "Search the knowledge base for how to create a new user account"
|
|
278
|
+
|
|
279
|
+
### `list_sources`
|
|
280
|
+
|
|
281
|
+
List all configured knowledge base sources and their sync status.
|
|
282
|
+
|
|
283
|
+
**Example usage in Claude Code:**
|
|
284
|
+
> "List available knowledge bases"
|
|
285
|
+
|
|
286
|
+
## Configuration
|
|
287
|
+
|
|
288
|
+
Configuration is stored in XDG-compliant locations:
|
|
289
|
+
|
|
290
|
+
- **Config**: `~/.config/kb-mcp/config.json`
|
|
291
|
+
- **Data**: `~/.local/share/kb-mcp/kb.sqlite`
|
|
292
|
+
- **Logs**: `~/.local/share/kb-mcp/logs/`
|
|
293
|
+
|
|
294
|
+
On Windows, these paths use `%APPDATA%` and `%LOCALAPPDATA%` instead.
|
|
295
|
+
|
|
296
|
+
### Config file structure
|
|
297
|
+
|
|
298
|
+
```json
|
|
299
|
+
{
|
|
300
|
+
"ollama": {
|
|
301
|
+
"baseUrl": "http://localhost:11434",
|
|
302
|
+
"model": "nomic-embed-text"
|
|
303
|
+
},
|
|
304
|
+
"sync": {
|
|
305
|
+
"chunkSize": 500,
|
|
306
|
+
"chunkOverlap": 50
|
|
307
|
+
},
|
|
308
|
+
"sources": [
|
|
309
|
+
{
|
|
310
|
+
"id": "myco",
|
|
311
|
+
"name": "My Company",
|
|
312
|
+
"baseUrl": "https://support.myco.com",
|
|
313
|
+
"locale": "en-us",
|
|
314
|
+
"enabled": true
|
|
315
|
+
}
|
|
316
|
+
]
|
|
317
|
+
}
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
## Debug Logging
|
|
321
|
+
|
|
322
|
+
Enable debug logging with the `DEBUG` environment variable:
|
|
323
|
+
|
|
324
|
+
```bash
|
|
325
|
+
DEBUG=kb-mcp:* kb-mcp sync
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
Available namespaces:
|
|
329
|
+
- `kb-mcp:sync` - Sync operations
|
|
330
|
+
- `kb-mcp:embed` - Embedding generation
|
|
331
|
+
- `kb-mcp:search` - Search operations
|
|
332
|
+
- `kb-mcp:mcp` - MCP server
|
|
333
|
+
- `kb-mcp:db` - Database operations
|
|
334
|
+
- `kb-mcp:cli` - CLI commands
|
|
335
|
+
|
|
336
|
+
## Troubleshooting
|
|
337
|
+
|
|
338
|
+
### Cannot connect to Ollama
|
|
339
|
+
|
|
340
|
+
Make sure Ollama is running:
|
|
341
|
+
```bash
|
|
342
|
+
ollama serve
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
Check if it's accessible:
|
|
346
|
+
```bash
|
|
347
|
+
curl http://localhost:11434/api/tags
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
### Model not found
|
|
351
|
+
|
|
352
|
+
Pull the embedding model:
|
|
353
|
+
```bash
|
|
354
|
+
ollama pull nomic-embed-text
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
### sqlite-vec extension not loaded
|
|
358
|
+
|
|
359
|
+
Try reinstalling:
|
|
360
|
+
```bash
|
|
361
|
+
npm install -g @vdpeijl/kb-mcp --force
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
Or manually download from: https://github.com/asg017/sqlite-vec/releases
|
|
365
|
+
|
|
366
|
+
### Rate limited by Zendesk
|
|
367
|
+
|
|
368
|
+
The sync process includes exponential backoff for rate limiting. If you're still hitting limits, try:
|
|
369
|
+
- Syncing one source at a time: `kb-mcp sync --source <id>`
|
|
370
|
+
- Waiting a few minutes between syncs
|
|
371
|
+
|
|
372
|
+
## Testing
|
|
373
|
+
|
|
374
|
+
### Test MCP server with Inspector
|
|
375
|
+
|
|
376
|
+
```bash
|
|
377
|
+
npx @modelcontextprotocol/inspector kb-mcp serve
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
This opens a web interface where you can:
|
|
381
|
+
- See available tools
|
|
382
|
+
- Call tools with test queries
|
|
383
|
+
- Inspect responses
|
|
384
|
+
|
|
385
|
+
## Development
|
|
386
|
+
|
|
387
|
+
### Publishing a new version
|
|
388
|
+
|
|
389
|
+
This project uses GitHub Actions to automatically publish to npm when the version changes in `package.json`.
|
|
390
|
+
|
|
391
|
+
To release a new version:
|
|
392
|
+
|
|
393
|
+
```bash
|
|
394
|
+
# Bump version (choose one)
|
|
395
|
+
npm version patch # Bug fixes (0.1.0 ā 0.1.1)
|
|
396
|
+
npm version minor # New features (0.1.0 ā 0.2.0)
|
|
397
|
+
npm version major # Breaking changes (0.1.0 ā 1.0.0)
|
|
398
|
+
|
|
399
|
+
# Push to GitHub (this triggers the publish workflow)
|
|
400
|
+
git push origin main --follow-tags
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
The GitHub Action will automatically:
|
|
404
|
+
- Build the project
|
|
405
|
+
- Publish to npm
|
|
406
|
+
- Create a GitHub release
|
|
407
|
+
|
|
408
|
+
See [.github/workflows/README.md](.github/workflows/README.md) for setup instructions.
|
|
409
|
+
|
|
410
|
+
## License
|
|
411
|
+
|
|
412
|
+
MIT
|
|
413
|
+
|
|
414
|
+
## Author
|
|
415
|
+
|
|
416
|
+
vdpeijl
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postinstall.d.ts","sourceRoot":"","sources":["../../scripts/postinstall.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { mkdir, chmod } from 'node:fs/promises';
|
|
3
|
+
import { get } from 'node:https';
|
|
4
|
+
import { join, dirname } from 'node:path';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
import { createGunzip } from 'node:zlib';
|
|
7
|
+
import { extract } from 'tar';
|
|
8
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
const SQLITE_VEC_VERSION = '0.1.6';
|
|
10
|
+
// Map platform to archive name and extracted file
|
|
11
|
+
const PLATFORM_MAP = {
|
|
12
|
+
'darwin-arm64': {
|
|
13
|
+
archive: 'sqlite-vec-0.1.6-loadable-macos-aarch64.tar.gz',
|
|
14
|
+
file: 'vec0.dylib',
|
|
15
|
+
},
|
|
16
|
+
'darwin-x64': {
|
|
17
|
+
archive: 'sqlite-vec-0.1.6-loadable-macos-x86_64.tar.gz',
|
|
18
|
+
file: 'vec0.dylib',
|
|
19
|
+
},
|
|
20
|
+
'linux-x64': {
|
|
21
|
+
archive: 'sqlite-vec-0.1.6-loadable-linux-x86_64.tar.gz',
|
|
22
|
+
file: 'vec0.so',
|
|
23
|
+
},
|
|
24
|
+
'win32-x64': {
|
|
25
|
+
archive: 'sqlite-vec-0.1.6-loadable-windows-x86_64.tar.gz',
|
|
26
|
+
file: 'vec0.dll',
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
function getPlatformKey() {
|
|
30
|
+
const platform = process.platform;
|
|
31
|
+
const arch = process.arch;
|
|
32
|
+
return `${platform}-${arch}`;
|
|
33
|
+
}
|
|
34
|
+
function downloadAndExtract(url, dest) {
|
|
35
|
+
return new Promise((resolve, reject) => {
|
|
36
|
+
get(url, (response) => {
|
|
37
|
+
// Handle redirects
|
|
38
|
+
if (response.statusCode === 302 || response.statusCode === 301) {
|
|
39
|
+
const redirectUrl = response.headers.location;
|
|
40
|
+
if (!redirectUrl) {
|
|
41
|
+
reject(new Error('Redirect without location header'));
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
// Recursively handle redirect
|
|
45
|
+
downloadAndExtract(redirectUrl, dest).then(resolve).catch(reject);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
if (response.statusCode !== 200) {
|
|
49
|
+
reject(new Error(`Failed to download: HTTP ${response.statusCode}`));
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
// Create gunzip stream
|
|
53
|
+
const gunzip = createGunzip();
|
|
54
|
+
// Create tar extract stream
|
|
55
|
+
const extractor = extract({
|
|
56
|
+
cwd: dest,
|
|
57
|
+
strip: 0, // Don't strip directories
|
|
58
|
+
});
|
|
59
|
+
// Pipe the response through gunzip and tar extract
|
|
60
|
+
response
|
|
61
|
+
.pipe(gunzip)
|
|
62
|
+
.pipe(extractor)
|
|
63
|
+
.on('finish', () => resolve())
|
|
64
|
+
.on('error', (err) => reject(err));
|
|
65
|
+
}).on('error', (err) => {
|
|
66
|
+
reject(err);
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
async function main() {
|
|
71
|
+
try {
|
|
72
|
+
const platformKey = getPlatformKey();
|
|
73
|
+
const platformInfo = PLATFORM_MAP[platformKey];
|
|
74
|
+
if (!platformInfo) {
|
|
75
|
+
throw new Error(`Unsupported platform: ${platformKey}. ` +
|
|
76
|
+
`Supported platforms: ${Object.keys(PLATFORM_MAP).join(', ')}`);
|
|
77
|
+
}
|
|
78
|
+
const { archive, file } = platformInfo;
|
|
79
|
+
const url = `https://github.com/asg017/sqlite-vec/releases/download/v${SQLITE_VEC_VERSION}/${archive}`;
|
|
80
|
+
const nativeDir = join(__dirname, '..', 'native');
|
|
81
|
+
console.log(`Downloading sqlite-vec for ${platformKey}...`);
|
|
82
|
+
console.log(`URL: ${url}`);
|
|
83
|
+
// Ensure native directory exists
|
|
84
|
+
await mkdir(nativeDir, { recursive: true });
|
|
85
|
+
// Download and extract
|
|
86
|
+
await downloadAndExtract(url, nativeDir);
|
|
87
|
+
// Verify the file exists
|
|
88
|
+
const extractedFile = join(nativeDir, file);
|
|
89
|
+
console.log(`ā sqlite-vec extracted to ${extractedFile}`);
|
|
90
|
+
// Make executable on Unix-like systems
|
|
91
|
+
if (process.platform !== 'win32') {
|
|
92
|
+
await chmod(extractedFile, 0o755);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
if (error instanceof Error) {
|
|
97
|
+
console.error(`ā Failed to download sqlite-vec: ${error.message}`);
|
|
98
|
+
// Don't fail installation, just warn
|
|
99
|
+
console.warn('ā sqlite-vec extension not installed. You may need to manually download it.');
|
|
100
|
+
console.warn(` Visit: https://github.com/asg017/sqlite-vec/releases/tag/v${SQLITE_VEC_VERSION}`);
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
console.error('ā Unknown error during postinstall');
|
|
104
|
+
}
|
|
105
|
+
// Exit with 0 to not break npm install
|
|
106
|
+
process.exit(0);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
main();
|
|
110
|
+
//# sourceMappingURL=postinstall.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postinstall.js","sourceRoot":"","sources":["../../scripts/postinstall.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/src/cli.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { defineCommand, runMain } from 'citty';
|
|
3
|
+
import { exitWithError } from './utils/errors.js';
|
|
4
|
+
const main = defineCommand({
|
|
5
|
+
meta: {
|
|
6
|
+
name: 'kb-mcp',
|
|
7
|
+
version: '0.1.0',
|
|
8
|
+
description: 'MCP server for searching Zendesk knowledge bases',
|
|
9
|
+
},
|
|
10
|
+
subCommands: {
|
|
11
|
+
serve: () => import('./commands/serve.js').then(m => m.default),
|
|
12
|
+
init: () => import('./commands/init.js').then(m => m.default),
|
|
13
|
+
sync: () => import('./commands/sync.js').then(m => m.default),
|
|
14
|
+
sources: () => import('./commands/sources.js').then(m => m.default),
|
|
15
|
+
setup: () => import('./commands/setup.js').then(m => m.default),
|
|
16
|
+
doctor: () => import('./commands/doctor.js').then(m => m.default),
|
|
17
|
+
stats: () => import('./commands/stats.js').then(m => m.default),
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
// Run CLI
|
|
21
|
+
runMain(main).catch(exitWithError);
|
|
22
|
+
//# sourceMappingURL=cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAElD,MAAM,IAAI,GAAG,aAAa,CAAC;IACzB,IAAI,EAAE;QACJ,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE,OAAO;QAChB,WAAW,EAAE,kDAAkD;KAChE;IACD,WAAW,EAAE;QACX,KAAK,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;QAC/D,IAAI,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;QAC7D,IAAI,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;QAC7D,OAAO,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,uBAAuB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;QACnE,KAAK,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;QAC/D,MAAM,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,sBAAsB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;QACjE,KAAK,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;KAChE;CACF,CAAC,CAAC;AAEH,UAAU;AACV,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../../src/commands/doctor.ts"],"names":[],"mappings":";AAMA,wBA2FG"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { defineCommand } from 'citty';
|
|
2
|
+
import { getDatabase } from '../db/index.js';
|
|
3
|
+
import { checkOllamaConnection, checkModelAvailable } from '../search/embeddings.js';
|
|
4
|
+
import { configExists, loadConfig } from '../config/index.js';
|
|
5
|
+
import { exitWithError } from '../utils/errors.js';
|
|
6
|
+
export default defineCommand({
|
|
7
|
+
meta: {
|
|
8
|
+
name: 'doctor',
|
|
9
|
+
description: 'Check system requirements and configuration',
|
|
10
|
+
},
|
|
11
|
+
async run() {
|
|
12
|
+
try {
|
|
13
|
+
console.log('\nš„ Running diagnostics...\n');
|
|
14
|
+
let allGood = true;
|
|
15
|
+
// Check Node.js version
|
|
16
|
+
const nodeVersion = process.version;
|
|
17
|
+
const majorVersion = parseInt(nodeVersion.slice(1).split('.')[0]);
|
|
18
|
+
if (majorVersion >= 20) {
|
|
19
|
+
console.log(`ā Node.js ${nodeVersion} (>= 20.0.0)`);
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
console.log(`ā Node.js ${nodeVersion} (requires >= 20.0.0)`);
|
|
23
|
+
allGood = false;
|
|
24
|
+
}
|
|
25
|
+
// Check config exists
|
|
26
|
+
if (configExists()) {
|
|
27
|
+
console.log('ā Configuration file exists');
|
|
28
|
+
try {
|
|
29
|
+
const config = await loadConfig();
|
|
30
|
+
console.log('ā Configuration is valid');
|
|
31
|
+
// Check Ollama connection
|
|
32
|
+
const ollamaConnected = await checkOllamaConnection(config.ollama);
|
|
33
|
+
if (ollamaConnected) {
|
|
34
|
+
console.log(`ā Ollama running at ${config.ollama.baseUrl}`);
|
|
35
|
+
// Check model available
|
|
36
|
+
const modelAvailable = await checkModelAvailable(config.ollama);
|
|
37
|
+
if (modelAvailable) {
|
|
38
|
+
console.log(`ā Model '${config.ollama.model}' available`);
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
console.log(`ā Model '${config.ollama.model}' not found`);
|
|
42
|
+
console.log(`\n Pull it with:`);
|
|
43
|
+
console.log(` ollama pull ${config.ollama.model}\n`);
|
|
44
|
+
allGood = false;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
console.log(`ā Cannot connect to Ollama at ${config.ollama.baseUrl}`);
|
|
49
|
+
console.log(`\n Make sure Ollama is running:`);
|
|
50
|
+
console.log(` ollama serve\n`);
|
|
51
|
+
allGood = false;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
console.log(`ā Configuration error: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
56
|
+
allGood = false;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
console.log('ā Configuration file not found');
|
|
61
|
+
console.log(`\n Run 'kb-mcp init' to create configuration\n`);
|
|
62
|
+
allGood = false;
|
|
63
|
+
}
|
|
64
|
+
// Check database
|
|
65
|
+
try {
|
|
66
|
+
const db = await getDatabase();
|
|
67
|
+
console.log('ā Database accessible');
|
|
68
|
+
// Check sqlite-vec extension
|
|
69
|
+
const versionQuery = db.prepare('SELECT vec_version() as version');
|
|
70
|
+
const result = versionQuery.get();
|
|
71
|
+
console.log(`ā sqlite-vec extension loaded (v${result.version})`);
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
console.log('ā Database error');
|
|
75
|
+
console.log(`\n ${error instanceof Error ? error.message : 'Unknown error'}\n`);
|
|
76
|
+
allGood = false;
|
|
77
|
+
}
|
|
78
|
+
console.log();
|
|
79
|
+
if (allGood) {
|
|
80
|
+
console.log('ā
All checks passed!\n');
|
|
81
|
+
process.exit(0);
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
console.log('ā ļø Some checks failed. Please fix the issues above.\n');
|
|
85
|
+
process.exit(1);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
exitWithError(error);
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
//# sourceMappingURL=doctor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../../src/commands/doctor.ts"],"names":[],"mappings":"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"}
|