docs-search-mcp
Use this MCP server to give an AI client read-only access to local notes, web pages, and timezone conversion with built-in safety guards.
list_notes: list available.md/.txtnote files with sizes.search_notes(query, limit): BM25 keyword search over note sections, returning paths, headings, scores, and snippets.read_note(path, max_chars): read one note, refusing paths outside the notes folder, symlinks, or unsupported file types.fetch_url(url, max_length, start_index, raw): fetch public web pages as markdown/raw text, paginated, honoring robots.txt and blocking private/internal addresses.convert_time(source_timezone, time, target_timezone, date?): convert HH:MM between IANA timezones, DST-aware when a date is provided.
Click on "Deploy 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., "@docs-search-mcp search my notes for BM25 keyword search"
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.
docs-search-mcp
A Model Context Protocol server in Python that gives an AI client (Claude Desktop, Claude Code or any MCP client) five tools: search and read a folder of local notes, fetch a public web page as markdown, and convert times between timezones.
The problem
Tools exposed to a model are an attack surface. A notes tool must not read outside its folder, and a web-fetch tool must not let the model (or a prompt injection) make your machine request internal addresses. This server provides useful tools with those protections built in and tested through a real MCP client.
Related MCP server: vault-mcp-bridge
Tools
Tool | What it does |
| Lists |
| BM25 keyword search over note sections; returns path, heading, score and snippet |
| Reads one note; refuses paths outside the folder, symlinks and other file types |
| Fetches a page as markdown, paginated; honours robots.txt; refuses private addresses |
| HH:MM conversion between IANA zones, DST-aware for a given date |
All tools are marked read-only through MCP annotations (fetch_url additionally openWorldHint).
Architecture
MCP client (Claude Desktop / Code / your script)
| JSON-RPC over stdio (or streamable HTTP)
v
server.py (FastMCP: tool registration, schemas from type hints, annotations, error mapping)
|-- notes.py BM25 index over sections, safe path resolution
|-- web.py SSRF guard -> robots.txt -> size-capped fetch -> HTML to markdown
'-- timeconv.py zoneinfo conversion, DST edge casesStack: Python 3.10+, the official mcp SDK (1.x, FastMCP), httpx, markdownify, zoneinfo/tzdata, pytest + pytest-asyncio.
Key technical decisions
SSRF guard. The host is resolved, non-public addresses are blocked (private, loopback, link-local), and the check is repeated on every redirect hop. Responses are size-capped and redirects are limited.
Path traversal and symlink protection. The final path is resolved and verified to stay under the notes root.
Errors as tool errors. Invalid input returns
isError: truewith a message the model can act on; the server keeps running. Logs go to stderr so stdout stays the protocol channel.DST-aware time conversion. An optional
datemakes offsets correct for that day, and non-existent or ambiguous wall-clock times around DST changes are detected.Section-level BM25. Notes are split by heading so results point at the relevant section, not just the file.
FastMCP. Tool schemas are derived from type hints and docstrings, which keeps schema and implementation in sync.
How to run
python -m venv .venv && source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e ".[dev]"
python -m pytest # 39 tests, no network needed
python examples/client_demo.py # starts the server and calls the tools through an MCP client
docs-search-mcp --docs-dir /path/to/your/notes # run the server (stdio)Configuration: see .env.example. To use it from Claude Desktop, add examples/claude_desktop_config.json
to the MCP config (use the absolute path to docs-search-mcp inside your venv if it is not on PATH) and restart the app.
Example
examples/client_demo_output.txt is real output from client_demo.py: searching "stdio logs stdout"
returns the Transports section of mcp-notes.md, and converting 10:00 Warsaw to Dubai on 2026-07-15 returns 12:00 (UTC+2 to UTC+4).
Testing
39 tests cover note search and path safety, URL validation and SSRF cases, robots.txt handling, DST edge cases, and a protocol-level test that starts the server and calls every tool through the official MCP Python client.
Limitations
Keyword search only (no embeddings); the index is built at startup, so new notes need a restart
The SSRF guard resolves DNS before connecting, so a DNS-rebinding attacker could still race it; do not expose the server to untrusted networks
HTML cleanup is simple and JavaScript-rendered pages return little; there is no authentication on the HTTP transport
Verified with the official Python MCP client and a local HTTP test server, not inside Claude Desktop
License
MIT, see LICENSE. Third-party attributions: SOURCES.md.
Available Tools
5 toolsconvert_timeARead-onlyIdempotent
Convert a 24-hour HH:MM time between IANA timezones (e.g. Europe/Warsaw -> Asia/Dubai). Optional date (YYYY-MM-DD) makes daylight-saving correct for that day; default is today.
Inputs: time (required), source_timezone (required), target_timezone (required), date.
fetch_urlARead-onlyIdempotent
Fetch a public web page and return it as markdown (or raw text). Honors robots.txt and refuses private/internal addresses. Long pages: pass next_start_index as start_index.
Inputs: url (required), raw, max_length, start_index.
list_notesARead-onlyIdempotent
List the note files (.md/.txt) available to search, with sizes in bytes.
Inputs: no named parameters. Returns: result
read_noteARead-onlyIdempotent
Read one note by its relative path as returned by list_notes / search_notes.
Inputs: path (required), max_chars.
search_notesARead-onlyIdempotent
Keyword-search (BM25) the notes. Returns the best matching sections with a snippet. Use read_note afterwards to see a whole file.
Inputs: query (required), limit. Returns: result
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 5 tools
The four notes/web tools are clearly distinct (list, search, read, fetch), but convert_time is a complete non-sequitur for a docs-search server and muddies the server's overall purpose. An agent may wonder why a timezone converter lives alongside note search.
All five tools follow a consistent snake_case verb_noun pattern: fetch_url, convert_time, list_notes, search_notes, read_note. Naming is highly predictable and readable.
Five tools is a well-scoped, lightweight set for a search server, and the notes trio (list/search/read) earns its place. Slightly penalized because convert_time does not belong to the domain.
For a read-only search server, list/search/read plus fetch_url covers the core retrieval lifecycle with no obvious dead ends. The only oddity is the unrelated convert_time tool rather than a true missing operation.
Related MCP Connectors
Serve a folder of Markdown notes as an MCP server: hybrid search, reading, and sourced answers.
Agent-native MCP server over the public saagarpatel.dev corpus. Read-only, stateless.
Your personal library, readable by AI agents: durable snapshots, hybrid search, 46 MCP tools.
Read-only search and Markdown access to liz's public docs, prompts, resources, and an MCP App.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceAn MCP server that gives AI agents read and write access to a folder of Markdown notes, supporting full-text search, reading, listing, and writing notes. It is deliberately small, with no dependencies beyond the MCP SDK, and includes proper path traversal protection.MIT
- AlicenseNot gradedqualityDmaintenanceRead-only MCP bridge that exposes secure search and fetch tools over an Obsidian-compatible Markdown vault, enabling ChatGPT to query notes without write access.1Apache 2.0
- FlicenseNot gradedqualityCmaintenanceExposes a folder of Markdown runbooks to an AI assistant via three tools (list_notes, search_notes, read_note) over MCP's streamable-http transport.-
- AlicenseNot gradedqualityCmaintenanceExposes a Markdown-based second brain as MCP tools, enabling MCP clients like Claude Code, Codex, Claude Desktop, n8n, and bots to read context, search notes, retrieve wiki pages, and optionally register decisions or sources.MIT