Semantic Search MCP
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Semantic Search MCPfind notes related to machine learning algorithms"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Semantic Search
Semantic search over markdown files. Find related notes by meaning, not just keywords. Detect duplicates before creating new notes.
Supports two server transports:
stdio MCP — For Claude Code integration (one process per session)
HTTP — Combined MCP-over-HTTP + REST on one port; one warm process shared by all clients
Features
Semantic search using sentence-transformers
Duplicate/similar note detection
Auto-updating index with file watcher
Multi-directory support
Inline tag extraction (
#tag-name)
Related MCP server: mcp-recall-md
Install
CPU-only install — recommended for macOS (any Mac, Apple Silicon or Intel) and Linux/Windows without an NVIDIA GPU. Saves ~5GB of CUDA binaries. On macOS, Apple GPU (MPS) is still auto-detected and used via PyTorch's built-in MPS backend — the "CPU" label refers only to the absence of CUDA, not to the compute device at runtime.
uv tool install --index https://download.pytorch.org/whl/cpu \
git+https://github.com/bborbe/semantic-searchCUDA install — only for Linux/Windows with a dedicated NVIDIA GPU. Not applicable to macOS (NVIDIA CUDA is not supported on Mac).
uv tool install git+https://github.com/bborbe/semantic-searchUpgrade
uv tool upgrade semantic-searchServer Modes
stdio MCP (per-session Claude Code)
Spawns one process per Claude Code session. Simple, but each session loads its own ~400 MB–1 GB model copy.
claude mcp add -s project semantic-search \
--env CONTENT_PATH=/path/to/vault \
-- \
uvx --from git+https://github.com/bborbe/semantic-search semantic-search-mcp serveTools available:
search_related(query, top_k=5)— Find semantically related notesget_content(path, snippet, query, context_lines)— Retrieve file content from indexed vaultscheck_duplicates(file_path)— Detect duplicate/similar notes
HTTP (shared across all clients)
Single long-running process serves MCP-over-HTTP at /mcp plus REST at /search, /duplicates, /health, /reindex. All Claude Code sessions and REST clients share one warm indexer.
CONTENT_PATH=/path/to/vault semantic-search-http --host 127.0.0.1 --port 8321Point Claude Code at it via MCP config:
{
"mcpServers": {
"semantic-search": {
"type": "http",
"url": "http://127.0.0.1:8321/mcp"
}
}
}REST endpoints:
Endpoint | Method | Description |
| POST | MCP-over-HTTP (Claude Code) |
| GET | Semantic search |
| GET | Find duplicate notes |
| GET | Retrieve file content |
| GET | Health check with index stats |
| GET/POST | Force index rebuild |
Example queries:
# Search
curl 'http://127.0.0.1:8321/search?q=kubernetes+deployment'
# Find duplicates
curl 'http://127.0.0.1:8321/duplicates?file=notes/my-note.md'
# Health check
curl 'http://127.0.0.1:8321/health'Two-Step Flow
Search for related notes, then fetch the full content of any result:
# Step 1: Search for related notes
curl 'http://127.0.0.1:8321/search?q=kubernetes+deployment'
# Returns: [{"path": "notes/k8s-guide.md", "score": 0.92}, ...]
# Step 2: Fetch the content of a result
curl 'http://127.0.0.1:8321/content?path=notes/k8s-guide.md'
# Returns: {"path": "/full/resolved/path.md", "content": "# Kubernetes Guide\n...", "mode": "full"}Snippet Mode
Retrieve a focused snippet around a specific query term within a file:
# Get a focused snippet around "service mesh" in the file
curl 'http://127.0.0.1:8321/content?path=notes/k8s-guide.md&snippet=true&query=service+mesh&context_lines=10'
# Returns: {"path": "...", "content": "...\n## Service Mesh\n...", "mode": "snippet"}Remote Deployment
get_content and GET /content enable remote deployment of semantic-search clients. Callers no longer need filesystem access to the vault directory — all content retrieval happens over HTTP/MCP from any network location. The server enforces path validation: files outside indexed roots are never served.
Claude Code Plugin
This repo also ships as a Claude Code marketplace plugin with commands for setup, search, and research.
Install
claude plugin marketplace add bborbe/semantic-search
claude plugin install semantic-searchUpdate
claude plugin marketplace update semantic-search
claude plugin update semantic-search@semantic-searchQuick Start
# One-shot interactive setup: installs the binary, writes the launchd/systemd
# unit, registers the MCP server in your Claude config.
/semantic-search:configure
# Search indexed markdown
/semantic-search:search kubernetes deployment
# Multi-step research across results
/semantic-search:research kafka backup strategyCommands
Command | Description |
| Install |
| Semantic search via the running MCP server |
| Multi-step research — search, categorize, read top sources, synthesize |
Run in Background
For production-style usage, run semantic-search-http as a background service so every Claude Code session (and any REST client) shares one warm process.
Platform | Guide |
macOS (launchd) | |
Linux (systemd) |
Quick example (macOS):
launchctl load ~/Library/LaunchAgents/com.github.bborbe.semantic-search-http.plistQuick example (Linux):
systemctl --user enable --now semantic-search-http.serviceCLI Commands
One-shot commands without running a server:
# Search
CONTENT_PATH=/path/to/vault semantic-search search "kubernetes deployment"
# Find duplicates
CONTENT_PATH=/path/to/vault semantic-search duplicates path/to/note.mdBinaries
Binary | Purpose |
| Combined HTTP server — MCP at |
| stdio MCP server — one per Claude Code session. Use when HTTP service is not set up. |
| CLI only — |
Configuration
Environment Variables
Variable | Description | Default |
| Directory to index (comma-separated for multiple) |
|
| Logging level (DEBUG, INFO, WARNING, ERROR) |
|
Multiple Directories
Index multiple directories by separating paths with commas:
CONTENT_PATH=/path/to/vault1,/path/to/vault2,/path/to/docsAll directories are indexed together and searched as one unified index.
Excluding Files with .semanticignore
Place a .semanticignore file at the root of any vault to exclude paths from indexing. Each vault uses its own rules independently; a missing .semanticignore means "index everything" (no change for existing vaults).
Syntax — gitignore-style patterns powered by the pathspec library's gitwildmatch dialect. The full gitignore rule set applies:
Patterns are matched relative to the vault root.
Trailing
/matches directories (and everything inside them):archive/**matches across directory boundaries:**/draft.mdLeading
/anchors a pattern to the vault root:/scratch.md!negates a pattern (re-includes a previously excluded path):!archive/keep.md
Behaviour — matching paths are excluded from:
Full index rebuilds (
rebuild_index)Single-file add/update events (
add_file_to_index)File-watcher
created/modified/movedevents
The .semanticignore file itself is never indexed.
Runtime reload — editing .semanticignore while the watcher is running triggers an atomic reload of that vault's rules. Subsequent file events immediately use the new patterns; no restart is required.
Example .semanticignore:
# Exclude an entire directory
archive/
# Exclude all draft files in any subdirectory
**/draft.md
# Re-include one specific file from the excluded directory
!archive/keep.md
# Anchor a pattern to the vault root only
/scratch.mdHow It Works
First run downloads a small embedding model (~90MB) and indexes your markdown files (<1s for typical vaults). The index auto-updates when files change via filesystem watcher.
Indexed Content
Each markdown file is indexed with weighted components:
Component | Weight | Notes |
Filename | 3x | |
Frontmatter | 3x | |
Frontmatter | 2x | Merged with inline tags |
Frontmatter | 2x | |
Inline tags ( | 2x | Extracted from body |
First H1 heading | 2x | |
Body content | 1x | First 500 words |
Development
# Clone
git clone https://github.com/bborbe/semantic-search
cd semantic-search
# Install dev dependencies
make install
# Run checks
make check
# Run tests
make testLicense
BSD 2-Clause License — see LICENSE.
Available Tools
3 toolscheck_duplicatesA
Find notes that are potential duplicates of the given file.
| Name | Required | Description | Default |
|---|---|---|---|
| file_path | Yes | Path to the file (absolute or relative to content directory) |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, and the description does not disclose behavioral details beyond the basic 'Find' action—such as how duplicates are determined, whether the operation is read-only, or any side effects. The burden falls on the description, which is minimal.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, front-loaded sentence with no wasted words, making it highly concise and easy to parse.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's simplicity (one parameter, output schema present), the description conveys the main purpose adequately. However, it lacks guidance on when to use vs alternatives, which is somewhat a gap but not critical for such a straightforward tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% for the single parameter, so the schema fully describes file_path. The description adds no extra semantic meaning beyond what the schema already states.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('Find') and resource ('notes that are potential duplicates of the given file'), clearly distinguishing it from sibling tools like search_related and get_content.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage for checking duplicates but does not explicitly state when to use this tool versus alternatives, nor any exclusions or prerequisites.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_contentB
Fetch the content of a file from the indexed vault.
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | File path (absolute or relative to an indexed root) | |
| query | No | Search string to find the best-matching line (only used when snippet=True) | |
| snippet | No | If True, return a snippet around the best-matching line instead of the full file | |
| context_lines | No | Number of lines before and after the match to include (default 20) |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden of behavioral disclosure. It only states the primary action but does not disclose edge cases (e.g., file not found, path resolution), or behavior around optional parameters like snippet and query despite their existence in the schema. This leaves significant behavioral aspects undisclosed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, tightly worded sentence that immediately conveys the core purpose. There is no fluff or redundancy, and the information is front-loaded. For the tool's purpose, this length is appropriately concise.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool has moderate complexity with optional snippet/query parameters and an output schema, and the schema covers parameter semantics. However, the description is thin on operational context, such as how path resolution works or when to use snippet mode. While not incomplete for basic selection, the description itself needed to provide more contextual glue; the schema partially compensates, but gaps remain.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so a baseline of 3 is appropriate. The description itself does not add any parameter semantics beyond the schema, but the schema already documents each parameter (path, query, snippet, context_lines) clearly. The description neither enhances nor detracts from what the schema provides.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's action ('Fetch the content of a file') and the resource ('indexed vault'), using a specific verb and resource. It distinguishes itself from sibling tools 'search_related' and 'check_duplicates' by focusing on direct content retrieval rather than search or duplication checks.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides no guidance on when to use this tool versus alternatives. It does not mention related tools or any exclusionary conditions (e.g., 'use search_related instead when looking for related content'). The intended usage is only implicitly derived from the tool's name and action.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
TDQS
Each tool serves a distinct purpose: semantic search, duplicate detection, and content retrieval. There is no overlap or ambiguity between them.
All tool names follow a consistent verb_noun pattern (search_related, check_duplicates, get_content) using snake_case. The naming is predictable and readable.
Three tools is an appropriate, focused set for a semantic search server. Each tool earns its place and the scope is well-defined.
The server covers the core needs of semantic search: finding related notes, detecting duplicates, and retrieving content. There are no missing operations that would hinder its stated purpose.
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
Search and reason over your Obsidian-style Markdown vault, right from ChatGPT.
Search your Obsidian vault to quickly find notes by title or keyword, summarize related content, a…
Token-efficient MCP memory for Markdown vaults. Tiered search, GraphRAG, AI memories.
AI research library. Save, organise and reuse notes and webpages as clean markdown context.
Related MCP Servers
- AlicenseNot gradedqualityAmaintenanceEnables semantic search and knowledge graph exploration of Obsidian vaults using Smart Connections embeddings. Provides intelligent note discovery, similarity search, and connection mapping through natural language queries.19554MIT
- AlicenseAqualityCmaintenanceEnables semantic search over local markdown note collections using vector embeddings, with real-time file watching and zero-config setup.4MIT
- FlicenseNot gradedqualityDmaintenanceEnables managing and searching markdown notes with semantic search, question answering, and note generation, and provides an MCP server for GitHub Copilot integration.4
- AlicenseNot gradedqualityCmaintenanceEnables semantic search over an Obsidian vault using natural language, retrieving relevant notes and extracted conclusions.MIT
Appeared in Searches
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/bborbe/semantic-search'
If you have feedback or need assistance with the MCP directory API, please join our Discord server