semantic-search-mcp
semantic-search-mcp
작고 독립적인 RAG-lite 검색 엔진입니다. 디스크의 파일을 색인화하고 "이 쿼리와 의미상 관련 있는 것이 무엇인지"만 알려줍니다. 그 이상은 하지 않습니다. LLM을 호출하지 않으며 답변을 생성하지도 않습니다. 가장 관련성 높은 텍스트 청크(파일, 줄, 점수)를 반환하므로, 이를 소비하는 주체(사람, 스크립트, 또는 MCP를 통한 LLM)가 원하는 대로 처리할 수 있습니다.
모든 작업은 첫 실행 후 로컬 및 오프라인에서 실행됩니다.
임베딩:
@huggingface/transformers가 CPU에서 int8 양자화된 가중치로Xenova/all-MiniLM-L6-v2를 실행합니다. GPU, API 키, 쿼리 시 네트워크 호출이 필요 없습니다.벡터 저장소:
@lancedb/lancedb— 임베디드, 파일 기반 벡터 데이터베이스. 서버 프로세스나 Docker가 필요 없습니다.인터페이스: CLI와 stdio MCP 서버를 제공하므로, MCP를 인식하는 모든 에이전트(Claude Code, Cursor, Zed 등)가 코퍼스를 직접 검색할 수 있습니다.
빠른 시작
npm install -g @adborroto/semantic-search-mcp
semantic-search add ~/code/my-project # add a folder to the corpus
semantic-search index # embed it (incremental on later runs)
semantic-search search "how does the retry logic work"전체 설정입니다. 수동으로 작성할 설정 파일이 없습니다. add가 생성 및 관리를 대신합니다. 아무것도 설치하지 않고 시도하려면:
npx @adborroto/semantic-search-mcp add ~/code/my-project설치 크기에 대한 주의: 약 950MB의 종속성에 첫 사용 시 다운로드되는 약 25MB의 임베딩 모델이 추가됩니다. 거의 모두가 이 계층에서 피할 수 없는 네이티브 바이너리입니다.
@lancedb/lancedb(약 430MB, 플랫폼 바이너리 포함)와 ONNX 런타임(약 300MB, 모든 플랫폼 빌드를 하나의 패키지로 제공)이 있습니다. 둘 다 한 번 캐시되며, 첫 실행 이후에는 모든 것이 오프라인으로 작동합니다.
요구 사항
Node.js >= 22 (폴백 백엔드에서 사용하는
node:sqlite는 22부터 안정화됨).종속성을 위해 약 950MB 디스크, 임베딩 모델을 위해 약 25MB, 색인된 청크당 약 1–3KB 추가 필요.
GPU, 외부 서비스, 데이터베이스 서버가 필요 없음.
"RAG-lite"인 이유
전체 RAG 파이프라인은: 청크 검색 → LLM에 전달 → LLM이 답변 작성입니다. 이 프로젝트는 첫 번째 단계에서 멈춥니다. 이를 통해 간단하고, 빠르며, 실행 비용이 저렴하고, 추론하기 쉬워집니다. 또한, 자체적인 의견이 담긴 생성 계층을 번들링하는 대신, 이미 사용 중인 LLM이나 에이전트 프레임워크와 깔끔하게 결합됩니다.
코퍼스 관리
semantic-search add ~/code/api ~/notes # add one or more folders
semantic-search list # show what's configured
semantic-search remove api # by folder name...
semantic-search remove ~/notes # ...or by path
semantic-search config # where config + index actually liveadd는 각 경로가 실제 디렉토리인지 확인하고, 절대 경로로 변환하며, 중복(심볼릭 링크를 통해 도달한 동일 디렉토리 포함)을 건너뜁니다. remove는 해당 폴더의 청크를 인덱스에서 제거하여 결과에 나타나지 않도록 합니다. 코퍼스에서 제거하되 검색 가능하게 유지하려면 --keep-index를 전달하세요.
저장 위치
설정과 인덱스는 XDG 기본 디렉토리 사양을 따르므로 업그레이드 후에도 유지되며 모든 설치 방법에서 공유됩니다.
항목 | 위치 |
설정 |
|
인덱스 + 모델 캐시 |
|
SS_CONFIG_PATH, SS_INDEX_DIR, SS_MODEL_CACHE_DIR 또는 표준 XDG_CONFIG_HOME / XDG_DATA_HOME으로 재정의할 수 있습니다. SS_STORE_BACKEND=sqlite는 폴백 백엔드를 강제합니다.
인덱스에는 색인한 모든 내용의 원문 텍스트가 포함됩니다. 이를 비공개 코드에 사용하는 경우,
~/.local/share/semantic-search/에는 해당 내용이 일반 텍스트로 저장됩니다. 절대 커밋하지 말고, 버그 보고서에 첨부하지 마세요.
모든 옵션은 src/config.js에 문서화되어 있습니다(청크 크기, 무시 패턴, 모델 이름, top-k, 동시성). config.json을 직접 편집해도 작동합니다. add/remove는 자신이 소유하지 않은 키는 보존합니다.
사용법
색인
semantic-search index # all configured folders
semantic-search index ~/code/one-project # just this folder, ignoring config
semantic-search index --force # reprocess everything색인은 증분식입니다. 변경되지 않은 파일은 수정 시간으로 건너뛰고, 내용이 실제로 변경되지 않은(터치만 한) 파일은 재임베딩을 건너뛰며, 디스크에서 삭제된 파일은 인덱스에서 제거됩니다. 실제로 변경된 것만 다시 처리됩니다.
여러 폴더가 구성된 경우, index는 폴더별 헤더와 결합된 총계를 표시하며 순차적으로 처리합니다.
[1/3] my-api /home/me/code/my-api ─────────────────────────────
↺ indexed src/auth/middleware.js (8 chunks)
2 indexed 1,203 skipped 16 chunks 4.1s
[2/3] my-app /home/me/code/my-app ─────────────────────────────
...
──────────────────────────────────────────────────────────────
total 5 indexed 3,891 skipped 0 deleted 41 chunks 12.3s각 index <path> 호출은 해당 경로 아래의 파일에 대한 오래된 항목만 제거하므로, 폴더 B를 색인해도 폴더 A의 항목은 건드리지 않습니다.
유용한 플래그: --max-files <n>은 N개의 새 파일 후 중단(대규모 코퍼스에서 메모리 제한), --concurrency <n>은 병렬 처리 설정, --verbose는 각 파일을 stderr에 기록합니다.
검색
semantic-search search "how does the retry logic work" -k 5파일 경로, 줄 번호, 점수, 텍스트 미리보기의 테이블을 출력합니다. 내부적으로: 쿼리를 임베딩하고, 가장 가까운 벡터 매칭 풀을 가져오고, 리터럴 쿼리 용어도 포함하는 청크에 대해 약간의 어휘 부스트를 적용한 후, 상위 k를 반환합니다.
파일 제외
색인은 기본적으로 node_modules/, .git/, 빌드 출력물, 잠금 파일 및 500,000바이트를 초과하는 파일을 건너뜁니다. 더 많이 제외하려면 gitignore 스타일의 .indexignore를 다음 위치 중 하나에 넣으세요.
색인하는 폴더 내부 — 패턴은 해당 폴더를 기준으로 하므로, 리포지토리가 자체 생성된 출력물을 제외할 수 있습니다.
설정 파일 옆 (
~/.config/semantic-search/.indexignore) — 모든 곳에 적용됩니다.
iOS, Android, Flutter, Ruby, JVM 빌드 아티팩트를 포함한 시작점은 .indexignore.example을 참조하세요.
MCP 서버
semantic-search mcp여섯 가지 도구를 노출하는 stdio MCP 서버를 시작합니다.
search(query, k?) — 의미 검색, 원시 JSON 반환:
[{ filePath, text, score, offset, startLine }, ...]gather(query, k?, contextLines?) — 동일한 검색, 컨텍스트 창에 바로 넣을 수 있는 단일 형식화된 마크다운 블록으로 반환:
### [1/5] my-api · src/auth/session.js · line 42 · score 0.923
```
...chunk text...
```contextLines(기본값 0)은 각 청크 주변의 소스 파일에서 N줄을 더 읽습니다. 청크 경계가 필요한 컨텍스트를 잘라낼 때 유용합니다.
list_folders() — 이름과 절대 경로가 있는 모든 구성된 폴더. 에이전트가 어떤 코퍼스가 있는지 알 수 있도록 첫 호출로 적합합니다.
cat_file(filePath, startLine?, endLine?) — search/gather에서 반환된 절대 경로로 파일을 읽습니다. 구성된 폴더로 제한됩니다(보안 참조).
grep(pattern, folder?, fileGlob?, caseSensitive?, maxResults?) — 리터럴 또는 정규식 검색, 유사도가 아닌 정확한 일치가 필요할 때 사용합니다. 색인과 동일한 .indexignore 규칙을 따릅니다.
my-api · src/auth/session.js:42 export function createSession(user) {index(root?, force?, maxFiles?, concurrency?) — 증분 재색인을 트리거하여, 에이전트가 셸을 사용하지 않고 코퍼스를 새로고침할 수 있습니다.
모든 검색 도구는 CLI와 동일한 순위 및 파일 확인 코드를 공유합니다. 재구현하지 않습니다.
MCP 클라이언트에 등록
Claude Code:
claude mcp add --scope user semantic-search -- semantic-search mcp
claude mcp list # should show "✔ Connected"JSON 서버 정의를 받는 모든 클라이언트:
{
"mcpServers": {
"semantic-search": {
"command": "semantic-search",
"args": ["mcp"]
}
}
}여기서는 npx보다 전역 설치를 선호합니다. 기본 npx는 서버가 실행될 때마다 패키지를 다시 확인하여 시작 지연 시간이 추가되고 업그레이드가 공지 없이 적용됩니다. npx를 사용하는 경우 버전을 고정하세요. npx -y @adborroto/semantic-search-mcp@0.1.0 mcp
새 MCP 서버는 일반적으로 세션이 시작될 때만 인식되므로, 등록 후 새 세션을 시작하세요.
보안
이것은 로컬, 단일 사용자 도구로, 단순한 신뢰 모델을 가집니다. 구성된 폴더 내의 모든 것은 서버에 접근할 수 있는 모든 MCP 클라이언트가 읽을 수 있습니다.
cat_file은 구성된 폴더 외부의 경로를 거부하며, 먼저 심볼릭 링크를 확인하여 폴더 내부에 심어진 링크를 통해 탈출할 수 없도록 합니다.grep은.indexignore규칙을 적용하므로, 색인에서 의도적으로 제외된 파일이 정확 일치 검색을 통해 유출되지 않습니다.하위 프로세스는 argv 배열로 생성되며(셸 사용 안 함), 패턴이 명령을 주입할 수 없습니다.
이를 고려하여, LLM 제공자에게 넘기고 싶지 않은 코퍼스를 가리키지 마세요. 청크는 요청한 클라이언트에게 반환됩니다. SECURITY.md 참조.
작동 방식
청크 분할
텍스트는 문단으로 분할된 후, 임베딩 모델의 실제 토크나이저로 계산된 약 200 토큰 크기의 청크에 약 35 토큰의 오버랩으로 탐욕적으로 패킹됩니다. 문자 수 근사가 아닙니다. 이는 임의적이지 않습니다. all-MiniLM-L6-v2는 256 토큰 창을 가지며, 더 긴 것은 자동으로 잘리므로, 청크는 [CLS]/[SEP] 토큰을 위한 여유를 두고 내부에 맞도록 크기가 조정됩니다. 오버랩은 또한 오버랩과 다음 문단이 결코 그 한계를 위반할 수 없도록 제한됩니다. 그렇지 않으면 청크의 꼬리가 임베드 시점에 잘리면서도 search에서 반환됩니다.
하드 제한보다 큰 단일 문단(축소된 번들, 하나의 거대한 로그 줄)은 동일한 오버랩 로직으로 단어 수준 패킹으로 대체되며, 500자를 초과하는 단일 "단어"는 먼저 분할되므로, 토크나이저에 한 번에 너무 큰 것이 전달되지 않습니다.
토큰 수는 문단/단어당 한 번 계산되고 오버랩 계산을 위해 캐시됩니다. 이전 버전은 오버랩 조회마다 다시 토큰화하여 작은 입력에서는 괜찮았지만, 대규모 리포지토리에서는 CPU 폭주와 멀티 GB 메모리 증가를 유발했습니다. 청크 분할기를 확장하는 경우 이 속성을 유지하세요.
증분 재색인
별도의 매니페스트가 없습니다. 벡터 저장소 자체가 매니페스트입니다. 모든 저장된 청크는 소스 파일의 mtimeMs와 sha256 콘텐츠 해시를 함께 저장합니다. 각 실행 시:
파일의 디스크
mtime이 저장된 것과 일치하면 파일을 읽지 않고 건너뜁니다.mtime이 변경되었지만 콘텐츠 해시가 동일하면(touch), 재임베딩을 건너뜁니다.그렇지 않으면 해당 파일의 이전 청크를 삭제하고 새로 임베딩된 청크를 삽입합니다.
탐색 후, 디스크에 더 이상 존재하지 않고(색인 중인 루트 아래에 있는) 색인된 경로는 제거됩니다.
저장소 백엔드
기본값은 LanceDB입니다. 임베디드, 파일 기반, 실제 벡터 검색. node:sqlite + 무차별 코사인 폴백(src/store/sqliteFallbackStore.js)은 동일한 인터페이스(src/store/vectorStore.js)를 구현하여, LanceDB의 네이티브 바인딩이 로드되지 않는 환경(샌드박스 컨테이너, 특수 아키텍처)에서 사용합니다. SS_STORE_BACKEND=sqlite로 전환합니다.
폴백은 검색당 전체 테이블 스캔을 수행합니다. 수만 개의 청크에는 적합하지만, 그 이상은 아닙니다. LanceDB의 기본 메트릭은 L2이며 코사인이 아니므로, 이 프로젝트는 모든 쿼리에 .distanceType('cosine')을 명시적으로 설정합니다. 임베딩은 정규화된 벡터로 비교되기 때문입니다.
프로젝트 구조
src/
config.js Defaults + config file resolution (XDG) — the only source of tunables
configFile.js Read/modify/write the config file (backs add/remove/list)
embeddings.js transformers.js pipeline + tokenizer (lazy singletons)
chunker.js Token-aware paragraph packing with overlap
ignoreRules.js .indexignore layering, shared by the indexer and grep
safePath.js Path confinement for the MCP file-reading tools
version.js Version read from package.json
extractors/ text (.txt .md .js .ts .py .rb .json), pdf (pdf-parse), docx (mammoth)
store/
vectorStore.js Storage interface + backend selector
lancedbStore.js LanceDB implementation (default)
sqliteFallbackStore.js node:sqlite + manual cosine fallback
indexer.js Walk + extract + chunk + embed + incremental upsert/prune
search.js Embed query + vector search + lexical boost — shared by CLI and MCP
mcp-server.js MCP stdio server: the six tools above
index.js CLI entrypoint (commander)
scripts/index-all.sh Batched indexing for very large corpora on constrained hosts (Linux)개발
git clone https://github.com/adborroto/semantic-search-mcp.git
cd semantic-search-mcp
npm install
npm test # unit + end-to-end (node:test, no framework)
npm run test:unit # skip the slow end-to-end test
npm run lint체크아웃 루트의 config.json은 XDG 위치보다 우선하므로, 실제 설정에 영향을 주지 않고 스크래치 코퍼스로 개발할 수 있습니다. 테스트는 항상 임시 디렉토리에 씁니다. CONTRIBUTING.md 참조.
범위 외 (의도적)
답변 생성. 청크를 반환하며, 답변은 반환하지 않습니다. 직접 LLM에 전달하세요.
두 번째 모델로 재순위화. 어휘 부스트는 저렴하고 종속성이 없는 근사치입니다. 실제 교차 인코더 재순위화를 대체하지 않습니다.
웹 UI. CLI 및 MCP만 제공합니다.
대규모 코퍼스. 개인 또는 팀 규모의 문서 및 코드 코퍼스(수만 개의 청크, 수백만 개는 아님)를 위해 설계되었습니다. 두 백엔드 모두 이 규모를 가정합니다.
라이선스
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Agent-native MCP server over the public saagarpatel.dev corpus. Read-only, stateless.
Agentic search over your Dewey document collections from any MCP-compatible client.
Hosted MCP memory: save sessions/decisions once, search from Claude, Cursor, ChatGPT. EU-hosted FTS.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/adborroto/semantic-search-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server