mcp-tools-server
An MCP server that provides developer knowledge and utility tools including local documentation search, text summarization, safe arithmetic calculation, unit conversion, and knowledge-base resources.
README
mcp-tools-server — developer knowledge & utilities over MCP
A small, coherent Model Context Protocol (MCP) server that gives an LLM
client a useful toolbox: search a local docs knowledge base, summarize text,
do safe arithmetic, and convert units — plus knowledge-base resources and a
prompt template. It speaks the stdio transport that Cursor and Claude
Desktop use and an optional HTTP/SSE transport (great for docker compose up and reaching it "like an API"), and it ships with a local client harness
so you can watch it work without any host and with zero API keys.
python3 -m venv .venv && . .venv/bin/activate
pip install -r requirements-dev.txt
python -m mcp_tools.demo_client # spins up the server and calls every tool
What is MCP, and why it matters (2026)
Modern AI apps are only as good as the context and tools you can feed the model. Before MCP, every tool integration was a bespoke, per-app, per-vendor affair. The Model Context Protocol is the open standard that fixed that: you write one server that advertises tools (functions the model can call), resources (readable context addressed by URI), and prompts (reusable templates), and any MCP-aware host — Cursor, Claude Desktop, and a growing list of others — can use it. Capability is decoupled from model: a tool you write once works across hosts and across model vendors. That is why, in 2026, MCP has become the common integration layer for AI developer tooling.
Crucially, MCP is a protocol, not an agent framework. There is no LangGraph, no orchestration loop, and no planner in this repo. The server just publishes capabilities and answers JSON-RPC requests; the client's model decides when to call them. (See Design decisions.)
Architecture
JSON-RPC 2.0 over stdio
┌───────────────────────┐ ───── request ─▶ stdin ─┐ ┌──────────────────────────────┐
│ MCP host + client │ └──▶│ dev-knowledge-tools │
│ │ │ MCP server │
│ Cursor / Claude │ │ (mcp.server.fastmcp) │
│ Desktop, or the │◀─┐ │ │
│ bundled demo_client │ └── response ◀─ stdout ◀─────│ tools │
└───────────────────────┘ │ • search_docs ─▶ IDF search │
│ • summarize ─▶ LLM layer │
The host launches the server as a │ • calculate (safe AST) │
subprocess. Requests go to its stdin, │ • convert_units │
responses come back on its stdout, one │ resources │
JSON object per line. The server logs │ • kb://index │
to stderr so the protocol stream stays │ • kb://doc/{name} │
clean. │ prompt │
│ • summarize_document │
└───────────────┬────────────────┘
│
LLM layer (summarize): mock ▸ openai/anthropic/ollama
knowledge base: data/kb/*.md
Repository layout
mcp_tools/
├── server.py # FastMCP server: registers tools/resources/prompt, runs over stdio ← entry point
├── tools.py # the capabilities as plain, tested functions (no protocol here) ← the core
├── search.py # CorpusSearch: deterministic IDF keyword search over the KB
├── config.py # env-driven settings; resolves paths relative to the package
├── demo_client.py # local MCP client that drives the server over stdio ← "see it work"
└── llm/ # tiny provider-agnostic ChatModel layer (mock | openai | anthropic | ollama)
data/kb/*.md # the sample "developer knowledge" knowledge base (6 docs)
tests/ # hermetic pytest suite (imports the functions directly)
Capability catalog
Tools
| Tool | Signature | What it does |
|---|---|---|
search_docs |
(query: str, k: int = 4) |
Ranked snippets from the local KB via IDF keyword scoring. |
summarize |
(text: str, max_sentences: int = 3) |
Condenses text through the LLM layer (offline mock by default). |
calculate |
(expression: str) |
Safe arithmetic (+ - * / // % **, parens) via AST allow-list — no eval. |
convert_units |
(value, from_unit, to_unit) |
Length, mass, time, volume, data, and temperature conversions. |
Resources
| URI | Kind | Contents |
|---|---|---|
kb://index |
static | Markdown list of every knowledge-base document. |
kb://doc/{name} |
template | The full markdown of one document, by file name. |
Prompt — summarize_document(name): a ready-made instruction to summarize a KB
document into a few bullet points.
Note:
fromis a Python keyword, soconvert_unitsusesfrom_unit/to_unit.
Run it
With the Makefile (creates ./.venv):
make install # venv + runtime + dev deps
make demo # start the server, list capabilities, call every tool ← best first run
make test # hermetic pytest suite
make run # start the server on stdio (it waits for a client; Ctrl-C to stop)
make run-http # start the server on HTTP/SSE at http://0.0.0.0:8084/sse
make demo-http # exercise a running HTTP server (see "Run over HTTP / Docker")
Or directly, inside an activated virtualenv:
pip install -r requirements-dev.txt
python -m mcp_tools.demo_client # the harness
python -m mcp_tools.server # the raw server (stdio)
pytest
make demo connects over stdio, prints the server's tools/resources/prompts,
calls each tool (including a deliberately rejected unsafe calculate to show
the guard), and reads the resources — all offline.
Use it from Cursor or Claude Desktop
The server is launched by the host as a subprocess. Point the host at this repo's
venv Python and set PYTHONPATH to the project root (so the package imports from
any working directory — the knowledge base is resolved relative to the package,
not the cwd). Replace /ABSOLUTE/PATH/TO/mcp-tools-server with your checkout path.
Cursor — add to ~/.cursor/mcp.json (global) or .cursor/mcp.json (per-project):
{
"mcpServers": {
"dev-knowledge-tools": {
"command": "/ABSOLUTE/PATH/TO/mcp-tools-server/.venv/bin/python",
"args": ["-m", "mcp_tools.server"],
"env": { "PYTHONPATH": "/ABSOLUTE/PATH/TO/mcp-tools-server" }
}
}
}
Claude Desktop — add to claude_desktop_config.json
(macOS: ~/Library/Application Support/Claude/claude_desktop_config.json):
{
"mcpServers": {
"dev-knowledge-tools": {
"command": "/ABSOLUTE/PATH/TO/mcp-tools-server/.venv/bin/python",
"args": ["-m", "mcp_tools.server"],
"env": { "PYTHONPATH": "/ABSOLUTE/PATH/TO/mcp-tools-server" }
}
}
}
Prefer uv? --directory sets the working
directory, so no PYTHONPATH is needed:
{
"mcpServers": {
"dev-knowledge-tools": {
"command": "uv",
"args": ["--directory", "/ABSOLUTE/PATH/TO/mcp-tools-server", "run", "python", "-m", "mcp_tools.server"]
}
}
}
Restart the host, and the four tools plus the kb:// resources appear.
Run over HTTP / Docker
The same server can serve over HTTP + Server-Sent Events (SSE) instead of
stdio, so you can run it in a container and reach it "like an API". The transport
is chosen by MCP_TRANSPORT (default stdio, so desktop hosts are unaffected).
With Docker (zero setup):
docker compose up # builds the image, serves at http://localhost:8084/sse
# in another terminal — watch it work over HTTP, no Cursor/Claude needed:
make demo-http # or: python -m mcp_tools.demo_client --http
docker compose down # stop and remove
Without Docker:
make run-http # MCP_TRANSPORT=sse MCP_HOST=0.0.0.0 MCP_PORT=8084 python -m mcp_tools.server
make demo-http # in another terminal
Register the HTTP server with an MCP client. Point the client at the SSE URL
(no command/args — the server is already running):
{
"mcpServers": {
"dev-knowledge-tools-http": {
"url": "http://localhost:8084/sse"
}
}
}
It speaks JSON-RPC, not plain REST. An MCP HTTP endpoint is not a REST API
and has no browsable webpage. A bare curl to the SSE URL opens an event stream
and hands you the JSON-RPC message endpoint — it does not return HTML:
$ curl -N http://localhost:8084/sse
event: endpoint
data: /messages/?session_id=…
The full exchange (initialize → list tools → call tool, each a JSON-RPC method)
is what an MCP client does for you; make demo-http is exactly that client. Use
stdio for desktop hosts and HTTP when the server runs elsewhere or behind a port.
A real summarizer (optional)
summarize runs fully offline by default via a deterministic extractive mock
(it returns the leading sentences, never inventing facts). Point it at a real
model with environment variables — no code changes — via the provider-agnostic
ChatModel layer:
export LLM_PROVIDER=ollama OLLAMA_MODEL=llama3.1 # local & free
export LLM_PROVIDER=openai OPENAI_API_KEY=sk-... # hosted
export LLM_PROVIDER=anthropic ANTHROPIC_API_KEY=sk-ant-... # hosted
All settings live in .env.example and load automatically from a
.env. Only the chosen provider's key is ever required.
Testing
pip install -r requirements-dev.txt
pytest
The suite is hermetic and offline: it imports the tool functions and asserts
behaviour directly — search returns the relevant hit, the calculator is correct
and rejects unsafe input, unit conversions are exact, summarize works against
the mock, and the KB resources list/read correctly with path-traversal blocked.
One test lists the server's registered tools/resources/prompt in-process. No
network, no subprocess, deterministic.
Design decisions & tradeoffs
- Tools are plain functions; the server is a thin adapter. Every capability
lives in
tools.pyas an ordinary typed function with a docstring (which doubles as the LLM-facing description).server.pyjust registers them with the SDK. That keeps the logic unit-testable with no protocol in the loop and makes the tool surface obvious. - Pinned to the stable FastMCP API (
mcp>=1.12,<2). The SDK's 2.0 release replacedmcp.server.fastmcp.FastMCPwith a newMCPServer/ClientAPI. This project deliberately targets the widely-adopted 1.x FastMCP interface that every current Cursor/Claude Desktop tutorial uses — maximum compatibility and familiarity — and documents the boundary so migrating to 2.0 is a conscious choice, not a surprise. (This is exactly the case SemVer's<2constraint is for.) - stdio by default, HTTP/SSE on demand. For a local server, stdio needs no
ports, sockets, or auth — the OS process boundary is the trust boundary — which
is why desktop hosts use it, and why it stays the default. Because tool logic is
transport-agnostic, HTTP/SSE (for Docker or "reach it like an API") is a pure
MCP_TRANSPORTswitch that changes only the onemcp.run(transport=...)call — the tools, tests, and knowledge base are untouched. - Safe calculator without
eval.calculateparses to an AST and walks a strict allow-list of numeric operations, so__import__('os').system(...)is rejected as an unsupported node rather than executed. A power-exponent cap guards against resource-exhaustion (2 ** 10_000_000). - Deterministic IDF search, not embeddings. Keyword/IDF scoring is
dependency-free, instant, and reproducible — ideal for a tool an LLM calls and
for hermetic tests. The
search(query, k) -> resultssurface is the seam: swap in embeddings + a vector DB (or a hosted web search) without touching the MCP tool. - Offline mock LLM behind a provider-agnostic seam.
summarizeis genuinely useful with zero keys and stays deterministic in tests, while a real provider is a pureLLM_PROVIDERswitch. The adapters speak each vendor's HTTP API viahttpx— no heavy vendor SDKs. - Package-relative paths. A host launches the server from an arbitrary
working directory, so
config.pyresolves the knowledge base relative to the package (__file__), not the cwd. The server runs the same everywhere. - No agent framework. MCP is the integration layer, not an agent. There is no LangGraph or planner here by design; orchestration is the client's job.
Not included (by design)
Authentication and multi-tenant concerns (the HTTP mode binds an unauthenticated listener meant for localhost/Docker, not the public internet), TLS termination, streaming tool output, embeddings/vector search, and write tools (everything here is read-only and deterministic). Each is a deliberate, well-scoped extension point rather than scope creep — this repo is a focused, legible demonstration of a clean MCP server.
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。