No Python environment setup and no AWS keys are required for normal plug-and-play usage.
- Build the image
docker build -t everspring-mcp:latest . - Run MCP server (
xslimtier)docker run --name everspring-xslim --rm -i -e EVERSPRING_MODEL_TIER=xslim -e EVERSPRING_DATA_DIR=/home/everspring/.everspring -v everspring-data-xslim:/home/everspring/.everspring everspring-mcp:latest python -m everspring_mcp.main serve --tier xslim --transport stdio
- Install dependencies
uv sync
- Download a pre-built slim snapshot
uv run python -m everspring_mcp.main sync --mode snapshot-download --snapshot-tier slim --snapshot-model BAAI/bge-base-en-v1.5
- Start MCP server
uv run python -m everspring_mcp.main serve --tier slim
On the very first run, the container can automatically download a ChromaDB/SQLite snapshot from S3 (roughly 750MB to 1.5GB depending on tier/model). This may take longer than strict 60-second MCP startup timeout windows in some clients.
To avoid connection timeouts, run the Docker command manually once in your terminal first and let the initial snapshot download complete, then configure/launch the MCP server from Claude/Copilot.
EverSpring MCP is a Spring documentation ingestion, indexing, and retrieval system with an MCP server interface.
Primary CLI entrypoint: python -m everspring_mcp.main.
main.py exposes operational commands for:
- scrape: discover/crawl Spring docs and upload raw artifacts to S3
- sync: manifest sync and snapshot upload/download
- status: local sync status reporting
- index: chunk + embed + upsert into Chroma
- search: query local index
- serve: start MCP stdio server
- client: interactive terminal client
- model-cache: prefetch embedding model artifacts
It also includes:
- tier-aware model defaults (
main,slim,xslim) - tier/model-aware default Chroma directory naming
- startup snapshot auto-refresh for
index/search/serve
Scrape -> Sync -> Index -> Retrieve -> MCP Serve
- Scrape: Spring documentation is discovered, parsed, and uploaded to S3 (
raw-datalayout). - Sync: Local
docs+metadata.dbare synchronized (manifest mode) or restored from snapshots. - Index: Local docs are chunked, embedded, and written to Chroma with batching.
- Retrieve: Query-time retrieval runs tier-aware search logic.
- Serve: MCP server exposes documentation search tools over stdio.
For non-main tiers, retrieval uses a hybrid pipeline:
- Dense retrieval from Chroma
- Sparse retrieval from BM25
- Fusion with Reciprocal Rank Fusion (RRF)
Main details:
- RRF constant is defined in retriever (
RRF_K = 60). tier=mainintentionally bypasses BM25/RRF and uses model-native dense path.tier=slim/xslimuses hybrid dense+sparse retrieval.
uv sync --devFor AMD ROCm workflows (if you use the project extra):
uv sync --extra amd
export HSA_OVERRIDE_GFX_VERSION=12.0.1| Tier | Default embedding model | Default chunk size (max_tokens) |
Default overlap (overlap_tokens) |
|---|---|---|---|
main |
BAAI/bge-m3 |
2048 | 200 |
slim |
BAAI/bge-base-en-v1.5 |
512 | 50 |
xslim |
BAAI/bge-small-en-v1.5 |
384 | 40 |
Notes:
- Default Chroma dir pattern:
~/.everspring/chroma-{tier}-{model_slug} - Current retrieval behavior:
tier=main: dense/model-native path (BM25 build/check skipped)tier!=main: hybrid path (dense + BM25)
- Install dependencies
uv sync --dev
- Prepare local data (either sync snapshots or run full scrape/sync/index flow)
- Start MCP server
uv run python -m everspring_mcp.main serve --tier main
- Optional local terminal client
uv run python -m everspring_mcp.main client
| Argument | Required | Values | Default | Description |
|---|---|---|---|---|
--log-level |
No | DEBUG, INFO, WARNING, ERROR |
INFO |
Console/file log level |
--log-file |
No | path | None |
Optional extra log file |
| Argument | Required | Values | Default | Description |
|---|---|---|---|---|
--entry-url |
Conditional* | URL | None |
Discovery entry URL |
--module |
Conditional* | Spring module enum values | None |
Target Spring module |
--version |
Conditional* | version string (4.0.5) |
None |
Target version |
--submodule |
No | string | None |
Optional submodule |
--content-type |
No | content type enum values | reference |
Doc content type |
--registry-path |
No | file path | None |
Submodule registry JSON |
--concurrency |
No | int | 5 |
Parallel scrape concurrency |
--s3-bucket |
No | string | None |
S3 bucket override |
--s3-region |
No | string | None |
S3 region override |
--s3-prefix |
No | string | None |
S3 prefix override |
--no-hash-check |
No | flag | false |
Disable content hash checks |
--json |
No | flag | false |
JSON output |
* entry-url, module, version must be provided together when used.
| Argument | Required | Values | Default | Description |
|---|---|---|---|---|
--mode |
No | manifest, manifest-prime, snapshot-upload, snapshot-download |
manifest |
Sync operation mode |
--module |
Conditional | string | None |
Module for non---all manifest sync |
--version |
Conditional | string | None |
Version for non---all manifest sync |
--submodule |
No | string | None |
Optional submodule |
--all |
No | flag | false |
Sync all targets from matrix |
--force |
No | flag | false |
Force manifest/manifest-prime operations |
--parallel-jobs |
No | int (>=1) |
5 |
Parallel workers |
--snapshot-model |
No | model name | None |
Snapshot namespace model override |
--snapshot-tier |
No | main, slim, xslim |
None |
Snapshot namespace tier override |
--s3-bucket |
No | string | None |
S3 bucket override |
--s3-region |
No | string | None |
S3 region override |
--s3-prefix |
No | string | None |
S3 prefix override |
--data-dir |
No | path | None |
Local data directory override |
--json |
No | flag | false |
JSON output |
Snapshot namespace path format:
s3://<bucket>/<prefix>/db-snapshots/{model_slug}-{tier}/...
| Argument | Required | Values | Default | Description |
|---|---|---|---|---|
--module |
No | string | None |
Module filter |
--version |
No | string | None |
Version filter |
--submodule |
No | string | None |
Submodule filter |
--all |
No | flag | false |
Show status for all local manifest targets |
--data-dir |
No | path | None |
Local data directory override |
--json |
No | flag | false |
JSON output |
| Argument | Required | Values | Default | Description |
|---|---|---|---|---|
--limit |
No | int | 50 |
Max unindexed docs to process |
--tier |
No | main, slim, xslim |
main |
Embedding tier |
--embed-model |
No | model name | tier default | Embedding model override |
--batch-size |
No | int | config default | Embedding batch size |
--chunk-workers |
No | int | config default | CPU chunk preparation workers |
--upsert-batch-size |
No | int | config default | Chroma upsert batch size |
--max-tokens |
No | int | tier default | Chunk token limit override |
--overlap-tokens |
No | int | tier default | Chunk overlap override |
--build-bm25 |
No | flag | false |
Build BM25 (skipped for tier=main) |
--reindex |
No | flag | false |
Reset indexed flags and rebuild vectors |
--module |
No | string | None |
Filter for --reindex |
--version |
No | int | None |
Major version filter for --reindex |
--submodule |
No | string | None |
Submodule filter for --reindex |
--data-dir, --db-filename, --docs-subdir, --chroma-dir, --collection |
No | paths/strings | None |
Local/index storage overrides |
--json |
No | flag | false |
JSON output |
| Argument | Required | Values | Default | Description |
|---|---|---|---|---|
--query, -q |
Yes | string | โ | Search query |
--top-k, -k |
No | int | 3 |
Result count |
--module |
No | string | None |
Module filter |
--version |
No | int | None |
Major version filter |
--build-index |
No | flag | false |
Rebuild BM25 before search (tier!=main) |
--no-dedup |
No | flag | false |
Disable URL dedup |
--tier |
No | main, slim, xslim |
main |
Search tier/model |
--json |
No | flag | false |
JSON output |
| Argument | Required | Values | Default | Description |
|---|---|---|---|---|
--transport |
No | stdio |
stdio |
MCP transport |
--tier |
No | main, slim, xslim |
main |
Serving tier/model |
--json |
No | flag | false |
Emit startup status JSON |
| Argument | Required | Values | Default | Description |
|---|---|---|---|---|
--no-progress |
No | flag | false |
Disable progress display |
| Argument | Required | Values | Default | Description |
|---|---|---|---|---|
--embed-model |
No | model name | config default | Model override |
--batch-size |
No | int | config default | Batch size override |
--json |
No | flag | false |
JSON output |
| Variable | Required when | Description |
|---|---|---|
EVERSPRING_S3_BUCKET |
scrape (if no explicit --s3-bucket override) |
S3 bucket for scrape uploads |
AWS credentials (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, optional session token) |
Any S3 operation (scrape, sync snapshot/manifest) |
AWS auth for S3 |
| Variable | Default | Used by |
|---|---|---|
EVERSPRING_S3_BUCKET |
everspring-mcp-kb |
sync/scrape |
AWS_REGION |
eu-central-1 (sync), us-east-1 fallback in scraper config |
sync/scrape |
EVERSPRING_S3_PREFIX |
spring-docs (sync), spring-docs/raw-data (scrape env config) |
sync/scrape |
EVERSPRING_DATA_DIR |
~/.everspring |
sync/vector |
EVERSPRING_MODEL_TIER |
main |
sync snapshot namespace |
EVERSPRING_EMBED_MODEL |
tier default | vector + sync snapshot namespace model |
EVERSPRING_CHROMA_DIR |
~/.everspring/chroma (overridden dynamically by CLI tier/model) |
vector |
EVERSPRING_CHROMA_COLLECTION |
spring_docs |
vector |
EVERSPRING_EMBED_TIER |
main |
vector |
EVERSPRING_INDEX_CHUNK_WORKERS |
auto (cpu_count based) |
vector index |
EVERSPRING_CHROMA_UPSERT_BATCH_SIZE |
512 |
vector index |
EVERSPRING_INDEX_PREFETCH_BATCHES |
3 |
vector index prefetch |
python -m everspring_mcp.main sync \
--mode snapshot-upload \
--snapshot-model BAAI/bge-m3 \
--snapshot-tier main \
--json
python -m everspring_mcp.main sync \
--mode snapshot-download \
--snapshot-model BAAI/bge-m3 \
--snapshot-tier main \
--jsonpython -m everspring_mcp.main index --tier main --build-bm25 --json
python -m everspring_mcp.main search --tier main --query "security filter chain" --json
python -m everspring_mcp.main serve --tier mainindex/search/serveperform startup snapshot freshness checks for active model+tier; if a newer remote snapshot is applied, process restarts automatically once.- Keep
data_dirconsistent betweensync,index, andsearch/serveto avoid โdocs exist but DB emptyโ mismatches.
{
"mcpServers": {
"everspring-main": {
"command": "docker",
"args": [
"run",
"--name",
"everspring-main",
"--rm",
"-i",
"-e",
"EVERSPRING_MODEL_TIER=main",
"-e",
"EVERSPRING_DATA_DIR=/home/everspring/.everspring",
"-v",
"everspring-data-main:/home/everspring/.everspring",
"everspring-mcp:latest",
"python",
"-m",
"everspring_mcp.main",
"serve",
"--tier",
"main",
"--transport",
"stdio"
]
},
"everspring-slim": {
"command": "docker",
"args": [
"run",
"--name",
"everspring-slim",
"--rm",
"-i",
"-e",
"EVERSPRING_MODEL_TIER=slim",
"-e",
"EVERSPRING_DATA_DIR=/home/everspring/.everspring",
"-v",
"everspring-data-slim:/home/everspring/.everspring",
"everspring-mcp:latest",
"python",
"-m",
"everspring_mcp.main",
"serve",
"--tier",
"slim",
"--transport",
"stdio"
]
},
"everspring-xslim": {
"command": "docker",
"args": [
"run",
"--name",
"everspring-xslim",
"--rm",
"-i",
"-e",
"EVERSPRING_MODEL_TIER=xslim",
"-e",
"EVERSPRING_DATA_DIR=/home/everspring/.everspring",
"-v",
"everspring-data-xslim:/home/everspring/.everspring",
"everspring-mcp:latest",
"python",
"-m",
"everspring_mcp.main",
"serve",
"--tier",
"xslim",
"--transport",
"stdio"
]
}
}
}Volume isolation matters: each tier must use a different Docker volume (for example
everspring-data-slimvseverspring-data-xslim) to prevent Chroma/SQLite conflicts.STDIO safety: do not add
-t(TTY) to Docker args in MCP config. Keep-ionly.
Once connected, call search_spring_docs with:
query(required)top_k(default:3)module(optional)version_major(optional)
- Sync raw markdown corpus only
uv run python -m everspring_mcp.main sync --mode manifest
- Build your own local vector DB with a custom embedding model
uv run python -m everspring_mcp.main index --embed-model "custom/model"
Point the pipeline to your own S3 bucket by overriding:
export EVERSPRING_S3_BUCKET=your-enterprise-bucketThis project operates on a fully automated Continuous Integration and Continuous Deployment (CI/CD) pipeline. The infrastructure has been modernized with the following technologies to ensure a secure and high-performance environment:
- Environment: Rootless Podman (a container runtime that does not require root privileges, enhancing security).
- Application Server: Granian (a high-performance Python HTTP server).
- Resource Management: Hard limits of 4GB RAM and 2 CPUs are applied per container, specifically to accommodate the memory requirements of the BGE-M3 embedding model.
- Data Persistence: Application data is securely stored on the host using
everspring-data-[tier]volumes.
- GitHub Actions: Pushing code to the
mainbranch triggers a Docker image build, which is then pushed to the GHCR (GitHub Container Registry). - Webhook: Upon a successful build, a webhook payload is sent to automatically trigger the Jenkins server.
- Jenkins Pipeline: Executing steps defined in the
Jenkinsfile, Jenkins:- Pulls the latest image from GHCR.
- Stops and cleans up the existing container.
- Deploys the new image with strict resource limits and dynamic environment variables (Tier, Workers, Threads).
- User Namespace Mapping: ID mappings are configured in
/etc/subuidand/etc/subgid(range100000-165535) to allow thejenkinsuser to manage rootless Podman layers. (For detailed host setup and configuration instructions, please refer to docs/setup.md). - Matrix-Based Security: Project privacy on Jenkins is enforced using Matrix Authorization:
- Admin: Full access.
- Anonymous: Restricted to
Job/Readaccess (solely to allow GitHub to fetch and display the build status badge).
- SSH Credentials: Communication between Jenkins and GitHub is securely handled via SSH keys stored within the Jenkins Credentials Store.