Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

EIP Vector MCP

Local MCP server for searching Ethereum Improvement Proposals with Qdrant, FastEmbed dense embeddings, and FastEmbed BM25 sparse vectors.

The MCP client talks to this server. The server talks to Qdrant. Qdrant stores the embedded EIP corpus.

What Is Included

  • src/eip_mcp/server.py: FastMCP stdio server.
  • src/eip_mcp/search.py: hybrid dense/sparse search service.
  • scripts/index_corpus.py: corpus indexing command.
  • scripts/smoke_search.py: local search smoke-test command.
  • docker-compose.yml: local Qdrant service.

The generated corpus is intentionally not committed:

data/search-corpus.json

Generate the EIP search corpus from the EIPs workspace/build pipeline, then put the artifact at that path before indexing. You can also point somewhere else with EIP_CORPUS_PATH.

Setup

Requirements:

uv sync --locked
docker compose up -d qdrant

The committed uv.lock pins the Python dependency tree used by uv sync --locked. Use --locked for the tested dependency set; drop it only when intentionally refreshing dependencies.

Place the corpus:

mkdir -p data
cp /path/to/search-corpus.json data/search-corpus.json

The first embedding/indexing run downloads the FastEmbed models into var/fastembed, so a fresh machine may pause while the model cache warms.

Index

Index the full corpus into Qdrant:

uv run --locked python -m scripts.index_corpus --batch-size 64

The command recreates the eip_chunks collection by default. Use --no-recreate only when you intentionally want to append/upsert into the existing collection.

Watch progress from another terminal:

total=$(uv run --locked python -c 'import json; print(len(json.load(open("data/search-corpus.json"))["chunks"]))')
while sleep 10; do
  curl -fsS http://localhost:6333/collections/eip_chunks \
    | TOTAL="$total" uv run --locked python -c 'import json,os,sys; r=json.load(sys.stdin)["result"]; p=r.get("points_count",0); print("{}/{} indexed status={}".format(p, os.environ["TOTAL"], r.get("status")))'
done

For a tiny local smoke index only:

uv run --locked python -m scripts.index_corpus --limit 200 --batch-size 32

Verify

Run direct search checks:

uv run --locked python -m scripts.smoke_search "Where is BASEFEE specified?"
uv run --locked python -m scripts.smoke_search "Explain EIP-7702 authorization tuples"
uv run --locked python -m scripts.smoke_search "Show ERC-20 transfer requirements"

Check collection metadata:

uv run --locked python - <<'PY'
from eip_mcp.search import SearchService
print(SearchService().index_info())
PY

For the current corpus, a complete index should report 17037 indexed points.

MCP Server

Run the MCP server over stdio:

uv run --locked python -m eip_mcp.server

Tools exposed:

  • search_eips: hybrid dense/sparse search with optional metadata filters (proposal, status, eip_type, proposal_category).
  • get_eip: ordered chunks for one EIP/ERC proposal.
  • get_chunk: exact chunk lookup by returned chunk_id.
  • index_info: corpus, model, and Qdrant collection metadata.

MCP Config

Use absolute paths in MCP client config. After uv sync --locked, the virtualenv interpreter is under .venv/bin/python on macOS/Linux and .venv\Scripts\python.exe on Windows.

Codex ~/.codex/config.toml example:

[mcp_servers.eip-search]
command = "/absolute/path/to/eip-vector/.venv/bin/python"
args = ["-m", "eip_mcp.server"]
cwd = "/absolute/path/to/eip-vector"

[mcp_servers.eip-search.env]
QDRANT_URL = "http://localhost:6333"
EIP_CORPUS_PATH = "data/search-corpus.json"
EIP_QDRANT_COLLECTION = "eip_chunks"

Claude Desktop style JSON example:

{
  "mcpServers": {
    "eip-search": {
      "command": "/absolute/path/to/eip-vector/.venv/bin/python",
      "args": ["-m", "eip_mcp.server"],
      "cwd": "/absolute/path/to/eip-vector",
      "env": {
        "QDRANT_URL": "http://localhost:6333",
        "EIP_CORPUS_PATH": "data/search-corpus.json",
        "EIP_QDRANT_COLLECTION": "eip_chunks"
      }
    }
  }
}

Configuration

Environment variables:

  • QDRANT_URL: Qdrant URL. Default: http://localhost:6333.
  • EIP_QDRANT_COLLECTION: Qdrant collection. Default: eip_chunks.
  • EIP_CORPUS_PATH: corpus path. Default: data/search-corpus.json.
  • EIP_DENSE_MODEL: dense model. Default: BAAI/bge-small-en-v1.5.
  • EIP_SPARSE_MODEL: sparse model. Default: Qdrant/bm25.
  • FASTEMBED_CACHE_PATH: model cache path. Default: var/fastembed.
  • EIP_INDEX_BATCH_SIZE: indexing batch size. Default: 64.

Git Hygiene

Do not commit generated runtime data:

  • .venv/
  • data/search-corpus.json
  • var/qdrant/
  • var/fastembed/

The repo is meant to contain the server, indexer, docs, and Docker config. The corpus and Qdrant database are local/generated artifacts.

About

Semantic search MCP setup for EIPs

Resources

Stars

Watchers

Forks

Contributors

Languages