Skip to main content

MCP Sieve — semantic tool selection proxy for LLMs. Aggregates downstream MCP servers into 2 static tools (select + call) via Ollama embeddings.

Project description

MCP Sieve

A semantic proxy for MCP servers. Solves tool selection degradation — when an LLM has too many tools, it picks the wrong ones.

The sieve sits between the client (Claude Code, Hermes, any MCP client) and downstream MCP servers. The client sees 2 tools instead of dozens: mcp_router_select + mcp_router_call. The first finds relevant tools via embeddings, the second proxies the call.

How it works

Client (Claude Code / Hermes)
  ↓ sees only 2 tools
mcp_router_select(task="...")  →  embeddings → top-N relevant tools
mcp_router_call(tool_name, arguments)  →  proxies to downstream
  ↓
downstream MCP servers (time, fetch, git, arxiv, playwright, ...)

Two call paths:

  1. Path 1 (notifications/tools/list_changed): select finds tools → sieve updates tools/list → client calls tools directly. Works with clients that support dynamic toolset updates.

  2. Path 2 (mcp_router_call proxy): for clients with a frozen toolset (Hermes, Claude Code with prompt caching). select returns tools with inputSchemacall proxies execution. No /reset needed when new downstream tools are discovered.

Install

git clone <repo> ~/Projects/mcp-sieve
cd ~/Projects/mcp-sieve
uv pip install -e .

Requires Ollama with an embed model:

ollama pull nomic-embed-text

Quick start

Copy the example config and edit it:

cp config.example.yaml config.yaml
# edit config.yaml — add your downstream servers and paths

Run standalone:

python -m mcp_router.server

Server listens on stdio (JSON-RPC).

Connect to Claude Code

In ~/.claude.jsonprojects["<path>"].mcpServers:

"sieve": {
  "type": "stdio",
  "command": "uvx",
  "args": ["--from", "/path/to/mcp-sieve", "mcp-sieve"],
  "env": {
    "MCP_ROUTER_CONFIG": "/path/to/mcp-sieve/config.yaml"
  }
}

Or via CLI:

claude mcp add sieve -- uvx --from /path/to/mcp-sieve mcp-sieve

Windows: MCP_ROUTER_CONFIG is required — uvx installs the package into an isolated venv, __file__ points into uv-cache. See Windows notes below.

Connect to Hermes

hermes mcp add sieve --command uvx --args "--from" --args "/path/to/mcp-sieve" --args "mcp-sieve"
hermes mcp test sieve
# /reset in chat

Config

config.yaml (see config.example.yaml for a full template):

downstream:
  - name: time
    command: uvx
    args: ["mcp-server-time"]

  - name: fetch
    command: uvx
    args: ["mcp-server-fetch"]

  - name: git
    command: uvx
    args: ["mcp-server-git", "--repository", "/path/to/your/repo"]

  # Windows: npx is a .cmd file — needs cmd /c
  - name: context7
    command: cmd
    args: ["/c", "npx", "-y", "@upstash/context7-mcp@latest"]

  - name: filesystem
    command: cmd
    args: ["/c", "npx", "-y", "@modelcontextprotocol/server-filesystem", "/path/to/dir"]

  # Remote MCP over HTTP (streamable) or SSE — no local process.
  # transport defaults to stdio; a bare url implies http.
  - name: gitmcp
    transport: http
    url: "https://gitmcp.io/docs"

embeddings:
  ollama_url: "http://127.0.0.1:11434/api/embeddings"
  model: "nomic-embed-text"
  top_n: 10

Env variables:

  • MCP_ROUTER_CONFIG — path to config.yaml (otherwise looks in CWD or next to source)
  • MCP_SIEVE_DOWNSTREAM_<N>_NAME / _COMMAND / _ARGS / _URL / _TRANSPORT — define downstream servers without a file (Docker/k8s). N starts at 1, stops at the first gap. _ARGS is a JSON array or whitespace-split. A same-named entry overrides the yaml one.
  • MCP_SIEVE_OLLAMA_URL / MCP_SIEVE_EMBED_MODEL / MCP_SIEVE_TOP_N — embeddings overrides

Crashed downstream servers (Ollama, npx) auto-reconnect with exponential backoff — no restart needed.

Windows notes

  1. npx → cmd /c npx: npx is a .cmd file, Python subprocess (MCP SDK) can't find it without a shell. uvx is a real binary, works directly.

  2. uvx --from and dependencies: uvx --from <project> installs the package into an isolated uv-cache venv. All imports must be in pyproject.toml [project.dependencies] — implicit deps from the dev env won't be picked up.

  3. uv cache clean: if the cache is locked (os error 32), kill MCP server processes first:

    powershell -Command "Get-Process | Where-Object { $_.ProcessName -match 'mcp|uv' } | Stop-Process -Force"
    uv cache clean --force
    
  4. Debug connection failures: claude --debug writes to ~/.claude/debug/<session>.txt. Grep Server stderr: for real server tracebacks.

Stack

  • MCP Python SDK (mcp) — stdio + HTTP/SSE transports, notifications/tools/list_changed
  • Ollama — local embeddings (nomic-embed-text), free
  • numpy — cosine similarity
  • httpx — HTTP client for Ollama API

Fallback

If Ollama is unavailable — the sieve doesn't crash. mcp_router_select returns all downstream tools without ranking, with a warning in the response.

Performance

Tested with 9 downstream servers (74 tools):

  • mcp_router_select: 83–166ms
  • mcp_router_call: 15–774ms (longest: playwright browser navigation)
  • Startup: ~16s (all 9 downstream connect + 74 embeddings built)

Status

Working end-to-end in Claude Code and Hermes. See TASKS.md for the roadmap and benchmark results.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mcp_sieve-0.1.0.tar.gz (13.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mcp_sieve-0.1.0-py3-none-any.whl (11.8 kB view details)

Uploaded Python 3

File details

Details for the file mcp_sieve-0.1.0.tar.gz.

File metadata

  • Download URL: mcp_sieve-0.1.0.tar.gz
  • Upload date:
  • Size: 13.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for mcp_sieve-0.1.0.tar.gz
Algorithm Hash digest
SHA256 d75d605ec028e95a580860e7e8c4f5913c3297e8860fe21be589ed731155636e
MD5 40b0ed41c0549b84bc1e60a86b6691ff
BLAKE2b-256 062a16a002bad9d18fa10109673b199be92f4622a1bada24d76b88b988b47ce5

See more details on using hashes here.

File details

Details for the file mcp_sieve-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: mcp_sieve-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 11.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for mcp_sieve-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 eb6a4c5175113638c22d10b8cd9effae910870b63795eae887f599e13cef1c13
MD5 a3b033f1e5084475f0f90e6a3e4bd84f
BLAKE2b-256 d36875113389db930885a0fda7f67bc50bdb052c77f17f5fa845c072b9647d16

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page