@nacho-labs/mcp-semantic-search 0.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.
- package/LICENSE +21 -0
- package/README.md +174 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +241 -0
- package/dist/index.js.map +1 -0
- package/package.json +68 -0
- package/server.json +44 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Nacho Labs LLC
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# @nacho-labs/mcp-semantic-search
|
|
2
|
+
|
|
3
|
+
MCP server that gives AI coding tools persistent semantic memory. Index
|
|
4
|
+
decisions, patterns, and project context — recall them by meaning, not keywords.
|
|
5
|
+
|
|
6
|
+
Powered by [@nacho-labs/nachos-embeddings](https://github.com/nacho-labs-llc/nachos-embeddings).
|
|
7
|
+
Runs entirely locally with [Transformers.js](https://huggingface.co/docs/transformers.js) —
|
|
8
|
+
no API keys, no cloud, no costs.
|
|
9
|
+
|
|
10
|
+
## Prerequisites
|
|
11
|
+
|
|
12
|
+
- **Node.js 18+**
|
|
13
|
+
- **Internet on first run** to download the embedding model (~25MB, cached permanently)
|
|
14
|
+
|
|
15
|
+
## Quick start
|
|
16
|
+
|
|
17
|
+
### Claude Code
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
claude mcp add --transport stdio semantic-search -- npx @nacho-labs/mcp-semantic-search
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Cursor / VS Code / any MCP client
|
|
24
|
+
|
|
25
|
+
Add to your MCP config (`.mcp.json`, `mcp.json`, or client-specific config):
|
|
26
|
+
|
|
27
|
+
```json
|
|
28
|
+
{
|
|
29
|
+
"mcpServers": {
|
|
30
|
+
"semantic-search": {
|
|
31
|
+
"type": "stdio",
|
|
32
|
+
"command": "npx",
|
|
33
|
+
"args": ["@nacho-labs/mcp-semantic-search"]
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
That's it. Your AI tool now has six semantic memory tools.
|
|
40
|
+
|
|
41
|
+
## Tools
|
|
42
|
+
|
|
43
|
+
| Tool | Description |
|
|
44
|
+
| ---- | ----------- |
|
|
45
|
+
| `semantic_search` | Search indexed documents by meaning |
|
|
46
|
+
| `semantic_index` | Add a document to the index |
|
|
47
|
+
| `semantic_index_batch` | Add multiple documents at once |
|
|
48
|
+
| `semantic_remove` | Remove a document by ID |
|
|
49
|
+
| `semantic_stats` | Get index size, store location, and config |
|
|
50
|
+
| `semantic_clear` | Remove all documents (requires confirmation) |
|
|
51
|
+
|
|
52
|
+
## What it does
|
|
53
|
+
|
|
54
|
+
```text
|
|
55
|
+
You ask Claude: "How do we handle rate limiting?"
|
|
56
|
+
|
|
|
57
|
+
Claude calls: semantic_search("rate limiting")
|
|
58
|
+
|
|
|
59
|
+
Server embeds: query -> 384-dimension vector
|
|
60
|
+
|
|
|
61
|
+
Cosine search: against all indexed vectors
|
|
62
|
+
|
|
|
63
|
+
Returns: "We throttle API requests using sliding windows..."
|
|
64
|
+
(matched by meaning, not keywords)
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
The embedding model understands meaning:
|
|
68
|
+
|
|
69
|
+
| Query | Finds |
|
|
70
|
+
| ----- | ----- |
|
|
71
|
+
| "rate limiting" | "We throttle API requests using sliding windows" |
|
|
72
|
+
| "how to deploy" | "Production runs via docker compose up with..." |
|
|
73
|
+
| "error handling" | "We use Result types instead of try/catch for..." |
|
|
74
|
+
|
|
75
|
+
## What to index
|
|
76
|
+
|
|
77
|
+
High-value content for project memory:
|
|
78
|
+
|
|
79
|
+
**Architecture decisions** — "We chose PostgreSQL over DynamoDB because we need
|
|
80
|
+
complex joins for the reporting module."
|
|
81
|
+
|
|
82
|
+
**Code patterns** — "Authentication middleware is in src/middleware/auth.ts.
|
|
83
|
+
Uses JWT with RS256, tokens expire after 1 hour, refresh tokens after 30 days."
|
|
84
|
+
|
|
85
|
+
**Conventions** — "All API endpoints return { data, error, meta } shape.
|
|
86
|
+
Errors use RFC 7807 problem details format."
|
|
87
|
+
|
|
88
|
+
**Debugging insights** — "If the worker queue backs up, check Redis memory.
|
|
89
|
+
The default maxmemory-policy is noeviction which causes write failures."
|
|
90
|
+
|
|
91
|
+
## Configuration
|
|
92
|
+
|
|
93
|
+
### CLI arguments
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
npx @nacho-labs/mcp-semantic-search \
|
|
97
|
+
--store /path/to/store.json \
|
|
98
|
+
--similarity 0.5 \
|
|
99
|
+
--model Xenova/all-mpnet-base-v2 \
|
|
100
|
+
--cache-dir /tmp/models
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Environment variables
|
|
104
|
+
|
|
105
|
+
| Variable | Description | Default |
|
|
106
|
+
| -------- | ----------- | ------- |
|
|
107
|
+
| `MCP_SEMANTIC_STORE` | Path to persistence file | `.semantic-store.json` |
|
|
108
|
+
| `MCP_SEMANTIC_SIMILARITY` | Min similarity threshold (0-1) | `0.6` |
|
|
109
|
+
| `MCP_SEMANTIC_MODEL` | Embedding model | `Xenova/all-MiniLM-L6-v2` |
|
|
110
|
+
| `MCP_SEMANTIC_CACHE_DIR` | Model cache directory | `.cache/transformers` |
|
|
111
|
+
|
|
112
|
+
### With environment variables in MCP config
|
|
113
|
+
|
|
114
|
+
```json
|
|
115
|
+
{
|
|
116
|
+
"mcpServers": {
|
|
117
|
+
"semantic-search": {
|
|
118
|
+
"type": "stdio",
|
|
119
|
+
"command": "npx",
|
|
120
|
+
"args": ["@nacho-labs/mcp-semantic-search"],
|
|
121
|
+
"env": {
|
|
122
|
+
"MCP_SEMANTIC_STORE": "/home/user/.semantic-memory/project.json",
|
|
123
|
+
"MCP_SEMANTIC_SIMILARITY": "0.5"
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Performance
|
|
131
|
+
|
|
132
|
+
| Operation | Time |
|
|
133
|
+
| --------- | ---- |
|
|
134
|
+
| Server startup (model cached) | ~500ms |
|
|
135
|
+
| Server startup (first run) | ~2-5s |
|
|
136
|
+
| Index a document | ~10-50ms |
|
|
137
|
+
| Search 1000 documents | ~5-10ms |
|
|
138
|
+
|
|
139
|
+
**Memory:** ~100MB for model + ~1.5KB per document.
|
|
140
|
+
|
|
141
|
+
The in-memory store works well up to ~10K documents. Beyond that, consider a
|
|
142
|
+
dedicated vector database.
|
|
143
|
+
|
|
144
|
+
## Persistence
|
|
145
|
+
|
|
146
|
+
The index is saved to disk automatically after every write operation (index,
|
|
147
|
+
remove, clear). On startup, the server loads the existing store if present.
|
|
148
|
+
|
|
149
|
+
Default location: `.semantic-store.json` in the working directory.
|
|
150
|
+
|
|
151
|
+
## How it's built
|
|
152
|
+
|
|
153
|
+
This MCP server is a thin wrapper around two packages:
|
|
154
|
+
|
|
155
|
+
- **[@nacho-labs/nachos-embeddings](https://www.npmjs.com/package/@nacho-labs/nachos-embeddings)** — Local vector embeddings and semantic search
|
|
156
|
+
- **[@modelcontextprotocol/sdk](https://www.npmjs.com/package/@modelcontextprotocol/sdk)** — Official MCP TypeScript SDK
|
|
157
|
+
|
|
158
|
+
The embeddings package can also be used directly in your own code. See its
|
|
159
|
+
[README](https://github.com/nacho-labs-llc/nachos-embeddings) for the
|
|
160
|
+
standalone API.
|
|
161
|
+
|
|
162
|
+
## Development
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
git clone https://github.com/nacho-labs-llc/mcp-semantic-search.git
|
|
166
|
+
cd mcp-semantic-search
|
|
167
|
+
npm install
|
|
168
|
+
npm run build
|
|
169
|
+
npm start
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## License
|
|
173
|
+
|
|
174
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* MCP Semantic Search Server
|
|
4
|
+
*
|
|
5
|
+
* Gives AI tools (Claude Code, Cursor, etc.) persistent semantic memory
|
|
6
|
+
* powered by local vector embeddings. No API keys, no cloud, no costs.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* npx @nacho-labs/mcp-semantic-search
|
|
10
|
+
* npx @nacho-labs/mcp-semantic-search --store /path/to/store.json
|
|
11
|
+
* npx @nacho-labs/mcp-semantic-search --similarity 0.5
|
|
12
|
+
*/
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;GAUG"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* MCP Semantic Search Server
|
|
4
|
+
*
|
|
5
|
+
* Gives AI tools (Claude Code, Cursor, etc.) persistent semantic memory
|
|
6
|
+
* powered by local vector embeddings. No API keys, no cloud, no costs.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* npx @nacho-labs/mcp-semantic-search
|
|
10
|
+
* npx @nacho-labs/mcp-semantic-search --store /path/to/store.json
|
|
11
|
+
* npx @nacho-labs/mcp-semantic-search --similarity 0.5
|
|
12
|
+
*/
|
|
13
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
14
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
15
|
+
import { z } from 'zod';
|
|
16
|
+
import { SemanticSearch } from '@nacho-labs/nachos-embeddings';
|
|
17
|
+
import { readFile, writeFile, mkdir } from 'node:fs/promises';
|
|
18
|
+
import { existsSync } from 'node:fs';
|
|
19
|
+
import { dirname, resolve } from 'node:path';
|
|
20
|
+
// --- Configuration via CLI args and env vars ---
|
|
21
|
+
function getConfig() {
|
|
22
|
+
const args = process.argv.slice(2);
|
|
23
|
+
function getArg(name, fallback) {
|
|
24
|
+
const idx = args.indexOf(`--${name}`);
|
|
25
|
+
if (idx !== -1 && idx + 1 < args.length) {
|
|
26
|
+
return args[idx + 1];
|
|
27
|
+
}
|
|
28
|
+
return fallback;
|
|
29
|
+
}
|
|
30
|
+
const storePath = resolve(process.env['MCP_SEMANTIC_STORE'] ??
|
|
31
|
+
getArg('store', '.semantic-store.json'));
|
|
32
|
+
const minSimilarity = parseFloat(process.env['MCP_SEMANTIC_SIMILARITY'] ??
|
|
33
|
+
getArg('similarity', '0.6'));
|
|
34
|
+
const model = process.env['MCP_SEMANTIC_MODEL'] ??
|
|
35
|
+
getArg('model', 'Xenova/all-MiniLM-L6-v2');
|
|
36
|
+
const cacheDir = process.env['MCP_SEMANTIC_CACHE_DIR'] ??
|
|
37
|
+
getArg('cache-dir', '.cache/transformers');
|
|
38
|
+
return { storePath, minSimilarity, model, cacheDir };
|
|
39
|
+
}
|
|
40
|
+
const config = getConfig();
|
|
41
|
+
// --- Initialize search engine ---
|
|
42
|
+
const search = new SemanticSearch({
|
|
43
|
+
minSimilarity: config.minSimilarity,
|
|
44
|
+
model: config.model,
|
|
45
|
+
cacheDir: config.cacheDir,
|
|
46
|
+
});
|
|
47
|
+
try {
|
|
48
|
+
await search.init();
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
console.error('Failed to load embedding model.', 'An internet connection is required on first run to download the model (~25MB).', err);
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
// Load persisted index
|
|
55
|
+
if (existsSync(config.storePath)) {
|
|
56
|
+
try {
|
|
57
|
+
const raw = await readFile(config.storePath, 'utf-8');
|
|
58
|
+
const data = JSON.parse(raw);
|
|
59
|
+
if (Array.isArray(data)) {
|
|
60
|
+
search.import(data);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
catch (err) {
|
|
64
|
+
console.error(`Warning: Failed to load store from ${config.storePath}:`, err);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
async function persist() {
|
|
68
|
+
const dir = dirname(config.storePath);
|
|
69
|
+
if (!existsSync(dir)) {
|
|
70
|
+
await mkdir(dir, { recursive: true });
|
|
71
|
+
}
|
|
72
|
+
await writeFile(config.storePath, JSON.stringify(search.export()));
|
|
73
|
+
}
|
|
74
|
+
// --- MCP Server ---
|
|
75
|
+
const server = new McpServer({
|
|
76
|
+
name: 'mcp-semantic-search',
|
|
77
|
+
version: '0.1.0',
|
|
78
|
+
}, {
|
|
79
|
+
capabilities: {
|
|
80
|
+
logging: {},
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
// Tool: Semantic search
|
|
84
|
+
server.registerTool('semantic_search', {
|
|
85
|
+
title: 'Semantic Search',
|
|
86
|
+
description: 'Search indexed documents by meaning. Finds relevant content even when the wording differs from the query. Use this to recall past decisions, find related code patterns, or look up previously indexed context.',
|
|
87
|
+
inputSchema: z.object({
|
|
88
|
+
query: z.string().describe('Natural language search query'),
|
|
89
|
+
limit: z
|
|
90
|
+
.number()
|
|
91
|
+
.optional()
|
|
92
|
+
.default(5)
|
|
93
|
+
.describe('Maximum number of results to return'),
|
|
94
|
+
}),
|
|
95
|
+
}, async ({ query, limit }) => {
|
|
96
|
+
const results = await search.search(query, { limit });
|
|
97
|
+
if (results.length === 0) {
|
|
98
|
+
return {
|
|
99
|
+
content: [{ type: 'text', text: 'No relevant results found.' }],
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
const formatted = results
|
|
103
|
+
.map((r, i) => `${i + 1}. [${(r.similarity * 100).toFixed(0)}% match] ${r.text}` +
|
|
104
|
+
(r.metadata && Object.keys(r.metadata).length > 0
|
|
105
|
+
? `\n metadata: ${JSON.stringify(r.metadata)}`
|
|
106
|
+
: ''))
|
|
107
|
+
.join('\n\n');
|
|
108
|
+
return {
|
|
109
|
+
content: [
|
|
110
|
+
{ type: 'text', text: `Found ${results.length} result(s):\n\n${formatted}` },
|
|
111
|
+
],
|
|
112
|
+
};
|
|
113
|
+
});
|
|
114
|
+
// Tool: Index a document
|
|
115
|
+
server.registerTool('semantic_index', {
|
|
116
|
+
title: 'Index Document',
|
|
117
|
+
description: 'Add a document to the semantic search index for later recall. Use this to remember decisions, patterns, file summaries, conventions, debugging insights, or any context worth recalling later. Documents persist across sessions.',
|
|
118
|
+
inputSchema: z.object({
|
|
119
|
+
id: z
|
|
120
|
+
.string()
|
|
121
|
+
.describe('Unique document ID. Use descriptive IDs like "adr-012", "auth-pattern", "deploy-steps"'),
|
|
122
|
+
text: z.string().describe('The text content to index and make searchable'),
|
|
123
|
+
metadata: z
|
|
124
|
+
.record(z.string())
|
|
125
|
+
.optional()
|
|
126
|
+
.describe('Optional key-value metadata (e.g. {"kind": "decision", "date": "2026-02-22"})'),
|
|
127
|
+
}),
|
|
128
|
+
}, async ({ id, text, metadata }) => {
|
|
129
|
+
await search.addDocument({ id, text, metadata });
|
|
130
|
+
await persist();
|
|
131
|
+
return {
|
|
132
|
+
content: [
|
|
133
|
+
{
|
|
134
|
+
type: 'text',
|
|
135
|
+
text: `Indexed "${id}" (${search.size()} total documents in store)`,
|
|
136
|
+
},
|
|
137
|
+
],
|
|
138
|
+
};
|
|
139
|
+
});
|
|
140
|
+
// Tool: Batch index multiple documents
|
|
141
|
+
server.registerTool('semantic_index_batch', {
|
|
142
|
+
title: 'Batch Index Documents',
|
|
143
|
+
description: 'Add multiple documents to the index at once. More efficient than indexing one at a time.',
|
|
144
|
+
inputSchema: z.object({
|
|
145
|
+
documents: z.array(z.object({
|
|
146
|
+
id: z.string().describe('Unique document ID'),
|
|
147
|
+
text: z.string().describe('Text content to index'),
|
|
148
|
+
metadata: z
|
|
149
|
+
.record(z.string())
|
|
150
|
+
.optional()
|
|
151
|
+
.describe('Optional key-value metadata'),
|
|
152
|
+
})).describe('Array of documents to index'),
|
|
153
|
+
}),
|
|
154
|
+
}, async ({ documents }) => {
|
|
155
|
+
await search.addDocuments(documents);
|
|
156
|
+
await persist();
|
|
157
|
+
return {
|
|
158
|
+
content: [
|
|
159
|
+
{
|
|
160
|
+
type: 'text',
|
|
161
|
+
text: `Indexed ${documents.length} documents (${search.size()} total in store)`,
|
|
162
|
+
},
|
|
163
|
+
],
|
|
164
|
+
};
|
|
165
|
+
});
|
|
166
|
+
// Tool: Remove a document
|
|
167
|
+
server.registerTool('semantic_remove', {
|
|
168
|
+
title: 'Remove Document',
|
|
169
|
+
description: 'Remove a document from the semantic search index by its ID.',
|
|
170
|
+
inputSchema: z.object({
|
|
171
|
+
id: z.string().describe('Document ID to remove'),
|
|
172
|
+
}),
|
|
173
|
+
}, async ({ id }) => {
|
|
174
|
+
const removed = search.remove(id);
|
|
175
|
+
if (removed)
|
|
176
|
+
await persist();
|
|
177
|
+
return {
|
|
178
|
+
content: [
|
|
179
|
+
{
|
|
180
|
+
type: 'text',
|
|
181
|
+
text: removed
|
|
182
|
+
? `Removed "${id}" (${search.size()} documents remaining)`
|
|
183
|
+
: `Document "${id}" not found in index`,
|
|
184
|
+
},
|
|
185
|
+
],
|
|
186
|
+
};
|
|
187
|
+
});
|
|
188
|
+
// Tool: Get index stats
|
|
189
|
+
server.registerTool('semantic_stats', {
|
|
190
|
+
title: 'Index Stats',
|
|
191
|
+
description: 'Get information about the semantic search index: document count and storage location.',
|
|
192
|
+
inputSchema: z.object({}),
|
|
193
|
+
}, async () => ({
|
|
194
|
+
content: [
|
|
195
|
+
{
|
|
196
|
+
type: 'text',
|
|
197
|
+
text: [
|
|
198
|
+
`Documents indexed: ${search.size()}`,
|
|
199
|
+
`Store location: ${config.storePath}`,
|
|
200
|
+
`Model: ${config.model}`,
|
|
201
|
+
`Min similarity: ${config.minSimilarity}`,
|
|
202
|
+
].join('\n'),
|
|
203
|
+
},
|
|
204
|
+
],
|
|
205
|
+
}));
|
|
206
|
+
// Tool: Clear all documents
|
|
207
|
+
server.registerTool('semantic_clear', {
|
|
208
|
+
title: 'Clear Index',
|
|
209
|
+
description: 'Remove ALL documents from the semantic search index. This is irreversible.',
|
|
210
|
+
inputSchema: z.object({
|
|
211
|
+
confirm: z
|
|
212
|
+
.boolean()
|
|
213
|
+
.describe('Must be true to confirm clearing all documents'),
|
|
214
|
+
}),
|
|
215
|
+
}, async ({ confirm }) => {
|
|
216
|
+
if (!confirm) {
|
|
217
|
+
return {
|
|
218
|
+
content: [
|
|
219
|
+
{
|
|
220
|
+
type: 'text',
|
|
221
|
+
text: 'Clear cancelled. Set confirm: true to clear all documents.',
|
|
222
|
+
},
|
|
223
|
+
],
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
const count = search.size();
|
|
227
|
+
search.clear();
|
|
228
|
+
await persist();
|
|
229
|
+
return {
|
|
230
|
+
content: [
|
|
231
|
+
{
|
|
232
|
+
type: 'text',
|
|
233
|
+
text: `Cleared ${count} documents from the index.`,
|
|
234
|
+
},
|
|
235
|
+
],
|
|
236
|
+
};
|
|
237
|
+
});
|
|
238
|
+
// --- Start server ---
|
|
239
|
+
const transport = new StdioServerTransport();
|
|
240
|
+
await server.connect(transport);
|
|
241
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nacho-labs/mcp-semantic-search",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "MCP server for local semantic search — give Claude Code, Cursor, and other AI tools persistent memory powered by nachos-embeddings",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"mcp-semantic-search": "./dist/index.js"
|
|
10
|
+
},
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"import": "./dist/index.js"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist",
|
|
19
|
+
"server.json",
|
|
20
|
+
"README.md",
|
|
21
|
+
"LICENSE"
|
|
22
|
+
],
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "tsc",
|
|
25
|
+
"dev": "tsc --watch",
|
|
26
|
+
"start": "node dist/index.js",
|
|
27
|
+
"typecheck": "tsc --noEmit",
|
|
28
|
+
"clean": "rm -rf dist *.tsbuildinfo",
|
|
29
|
+
"prepublishOnly": "npm run build",
|
|
30
|
+
"version:patch": "npm version patch",
|
|
31
|
+
"version:minor": "npm version minor",
|
|
32
|
+
"version:major": "npm version major",
|
|
33
|
+
"publish:npm": "npm publish --access public",
|
|
34
|
+
"release:patch": "npm run version:patch && npm run publish:npm",
|
|
35
|
+
"release:minor": "npm run version:minor && npm run publish:npm",
|
|
36
|
+
"release:major": "npm run version:major && npm run publish:npm"
|
|
37
|
+
},
|
|
38
|
+
"keywords": [
|
|
39
|
+
"mcp",
|
|
40
|
+
"model-context-protocol",
|
|
41
|
+
"semantic-search",
|
|
42
|
+
"embeddings",
|
|
43
|
+
"vector-search",
|
|
44
|
+
"claude",
|
|
45
|
+
"claude-code",
|
|
46
|
+
"ai-memory",
|
|
47
|
+
"local",
|
|
48
|
+
"privacy"
|
|
49
|
+
],
|
|
50
|
+
"author": "Nate Richardson <hello@naterichardson.com> (https://naterichardson.com)",
|
|
51
|
+
"license": "MIT",
|
|
52
|
+
"engines": {
|
|
53
|
+
"node": ">=18.0.0"
|
|
54
|
+
},
|
|
55
|
+
"repository": {
|
|
56
|
+
"type": "git",
|
|
57
|
+
"url": "git+https://github.com/nacho-labs-llc/mcp-semantic-search.git"
|
|
58
|
+
},
|
|
59
|
+
"dependencies": {
|
|
60
|
+
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
61
|
+
"@nacho-labs/nachos-embeddings": "^0.1.0",
|
|
62
|
+
"zod": "^3.23.0"
|
|
63
|
+
},
|
|
64
|
+
"devDependencies": {
|
|
65
|
+
"@types/node": "^22.0.0",
|
|
66
|
+
"typescript": "^5.7.0"
|
|
67
|
+
}
|
|
68
|
+
}
|
package/server.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
|
|
3
|
+
"name": "io.github.nacho-labs-llc/mcp-semantic-search",
|
|
4
|
+
"description": "Local semantic search for AI coding tools. Index decisions, patterns, and context — recall them by meaning, not keywords. Powered by nachos-embeddings (Transformers.js). No API keys, no cloud, no costs.",
|
|
5
|
+
"title": "Semantic Search MCP Server",
|
|
6
|
+
"version": "0.1.0",
|
|
7
|
+
"repository": {
|
|
8
|
+
"url": "https://github.com/nacho-labs-llc/mcp-semantic-search",
|
|
9
|
+
"source": "github"
|
|
10
|
+
},
|
|
11
|
+
"packages": [
|
|
12
|
+
{
|
|
13
|
+
"registryType": "npm",
|
|
14
|
+
"identifier": "@nacho-labs/mcp-semantic-search",
|
|
15
|
+
"version": "0.1.0",
|
|
16
|
+
"transport": {
|
|
17
|
+
"type": "stdio"
|
|
18
|
+
},
|
|
19
|
+
"environmentVariables": [
|
|
20
|
+
{
|
|
21
|
+
"name": "MCP_SEMANTIC_STORE",
|
|
22
|
+
"description": "Path to the JSON file where the index is persisted. Defaults to .semantic-store.json in the working directory.",
|
|
23
|
+
"isRequired": false,
|
|
24
|
+
"isSecret": false,
|
|
25
|
+
"format": "string"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"name": "MCP_SEMANTIC_SIMILARITY",
|
|
29
|
+
"description": "Minimum similarity threshold (0-1). Defaults to 0.6.",
|
|
30
|
+
"isRequired": false,
|
|
31
|
+
"isSecret": false,
|
|
32
|
+
"format": "string"
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"name": "MCP_SEMANTIC_MODEL",
|
|
36
|
+
"description": "Embedding model to use. Defaults to Xenova/all-MiniLM-L6-v2.",
|
|
37
|
+
"isRequired": false,
|
|
38
|
+
"isSecret": false,
|
|
39
|
+
"format": "string"
|
|
40
|
+
}
|
|
41
|
+
]
|
|
42
|
+
}
|
|
43
|
+
]
|
|
44
|
+
}
|