This project is a Go-based MCP server that can act as both:
- a coding agent service for reading, writing, and editing files inside a safe workspace root
- a retrieval-enabled agent service that uses:
- RAG through an external vector database
- CAG through locally cached context bundles
It is designed so you can either:
- use the built-in free file-based vector store by default
- or connect to an external vector database running in another container or service
At a high level, this server gives an MCP-compatible model or client a set of tools it can call.
Those tools let the model:
- read local files
- write local files
- edit local files
- fetch web pages
- run web search through a configured external search URL
- ingest knowledge into a vector database
- search that knowledge later
- store reusable cached context
- retrieve cached context later
That means the same MCP server can behave like:
- a coding assistant
- a documentation retrieval assistant
- a project-aware agent
- a context-aware assistant with reusable memory packs
RAG stands for Retrieval-Augmented Generation.
In this server, RAG means:
- You ingest content into a vector database.
- That content is chunked and embedded.
- Later, when the model needs knowledge, it calls
search_knowledge. - The most relevant chunks are returned.
- The model uses those chunks to answer with better context.
Practical example:
- You ingest
docs/runbook.md - The server sends chunked vectors to Qdrant
- Later the model asks: "How do we roll back a blue-green deploy?"
search_knowledgereturns the most relevant chunks- The model answers using those retrieved chunks
Use RAG when:
- the knowledge base is large
- you want semantic search
- you want to search documents by meaning, not only exact words
- you want to keep knowledge outside the model prompt until needed
CAG here means Cached-Augmented Generation.
In this server, CAG is the lightweight reusable context layer.
Instead of searching a vector database every time, you can store named context bundles locally and reuse them directly.
Examples:
- customer-specific instructions
- product constraints
- coding conventions
- project briefing notes
- reusable agent setup context
Practical example:
- Save a context called
customer-alpha - Store notes like SLA language, preferred wording, and restrictions
- Later the model calls
get_cached_context - The model immediately gets that known context without a vector search
Use CAG when:
- the context is small and stable
- the same context is reused often
- you want deterministic reusable context packs
- you do not need semantic retrieval for that information
RAG:
- best for searching large document sets
- uses the external vector database
- good for semantic retrieval
- good for changing or growing corpora
CAG:
- best for small reusable context bundles
- stored locally by key
- fast and direct
- good for repeated known context
The two are complementary, not competing.
A strong agent often uses both:
- CAG for stable repeated context
- RAG for document retrieval on demand
The system is split into two parts:
- MCP Server
- Vector Database
The MCP server:
- exposes tools to the model
- manages file operations
- manages cached context
- talks to the vector database for RAG
The vector database:
- stores embeddings and metadata
- serves semantic search results
- runs separately from the MCP server
Current vector backends:
fileas the default free local optionqdrantchroma
read_fileReads a text file insideREAD_ROOTwrite_fileCreates or overwrites a text file insideREAD_ROOTedit_fileEdits a text file insideREAD_ROOTusingreplaceorappend
fetch_urlFetches a remote URL with size and timeout controlsweb_searchUses the search URL template defined in envechoSimple test tool
ingest_knowledgeSends content into the vector databasesearch_knowledgeSearches the vector database for relevant chunks
cache_contextSaves a named context bundle locallyget_cached_contextRetrieves a saved context bundlelist_cached_contextsLists saved context bundles
This server is intended to be usable as a coding agent.
To keep that safe, file operations are restricted by READ_ROOT.
That means:
read_filecan only read insideREAD_ROOTwrite_filecan only write insideREAD_ROOTedit_filecan only edit insideREAD_ROOT- file-based knowledge ingestion is also restricted to
READ_ROOT
If a path is outside READ_ROOT, the request is rejected.
Use this when the server should run as an HTTP service.
Endpoints:
GET /ssePOST /messageGET /healthzGET /readyz
If BASE_PATH=/mcp, the endpoints become:
/mcp/sse/mcp/message/mcp/healthz/mcp/readyz
Use this when the MCP client launches the server directly as a process.
This project expects external links and service addresses to come from environment variables.
That includes:
- vector database URL
- public base URL
- web search URL template
The local .env file can use export KEY=value format.
Example:
export SERVER_NAME=ProductionMCP
export SERVER_VERSION=2.0.0
export TRANSPORT=sse
export HOST=0.0.0.0
export PORT=4090
export BASE_PATH=
export DATA_DIR=./data
export READ_ROOT=.
export KNOWLEDGE_STORE_PATH=./data/knowledge-store.json
export VECTOR_DB_PROVIDER=qdrant
export VECTOR_DB_URL=http://localhost:6333
export VECTOR_DB_API_KEY=
export VECTOR_DB_USERNAME=
export VECTOR_DB_PASSWORD=
export VECTOR_DB_COLLECTION=mcp_knowledge
export VECTOR_DB_DIMENSION=384
export VECTOR_DB_DISTANCE=Cosine
export WEB_SEARCH_URL_TEMPLATE=https://search.yahoo.com/search?p=%s
export PUBLIC_BASE_URL=http://localhost:4090
export HTTP_TIMEOUT=20s
export FETCH_MAX_BYTES=2097152
export FILE_MAX_BYTES=5242880
export SEARCH_RESULT_LIMIT=5
export DEFAULT_CHUNK_SIZE=900
export DEFAULT_CHUNK_OVERLAP=150TRANSPORTsseorstdioHOSTBind host for HTTP modePORTBind port for HTTP modeBASE_PATHOptional URL prefixPUBLIC_BASE_URLPublicly advertised base URL for the service
READ_ROOTThe workspace root the coding agent is allowed to useFILE_MAX_BYTESMaximum allowed file read/write size
VECTOR_DB_PROVIDERCurrently supported values:fileqdrantchroma
VECTOR_DB_URLAddress of the external vector database serviceVECTOR_DB_FILE_PATHLocal JSON file path used whenVECTOR_DB_PROVIDER=fileVECTOR_DB_API_KEYAPI key if your selected backend uses oneVECTOR_DB_USERNAMEOptional username for basic authVECTOR_DB_PASSWORDOptional password for basic authVECTOR_DB_COLLECTIONCollection name used by the serverVECTOR_DB_DIMENSIONEmbedding dimension used by this serverVECTOR_DB_DISTANCEDistance metric used by providers that support it directly, such as QdrantVECTOR_DB_TENANTUsed by ChromaVECTOR_DB_DATABASEUsed by Chroma
WEB_SEARCH_URL_TEMPLATEExternal search URL template used byweb_search
Important:
WEB_SEARCH_URL_TEMPLATE must contain %s because the server inserts the encoded query there.
Example:
https://search.yahoo.com/search?p=%s
The default provider is:
file
This is a local file-based vector store that persists vectors to disk as JSON.
That means:
- it is free to use
- it requires no external service
- it works out of the box
- it is a good default for local development and lightweight deployments
Example:
export VECTOR_DB_PROVIDER=file
export VECTOR_DB_FILE_PATH=./data/vector-store.json
export VECTOR_DB_COLLECTION=mcp_knowledge
export VECTOR_DB_DIMENSION=384Use the file backend when:
- you want zero setup
- you want a fully local install
- you do not want to run another container
- your corpus size is moderate
This is the core setup for RAG.
If you do not use the default file backend, the MCP server does not run the vector database itself.
You run your chosen vector database separately, then point the MCP server to it with:
VECTOR_DB_URL- optional credentials
- collection settings
If Qdrant is running locally on port 6333:
export VECTOR_DB_PROVIDER=qdrant
export VECTOR_DB_URL=http://localhost:6333
export VECTOR_DB_COLLECTION=mcp_knowledge
export VECTOR_DB_DIMENSION=384
export VECTOR_DB_DISTANCE=CosineIf Chroma is running locally on port 8000:
export VECTOR_DB_PROVIDER=chroma
export VECTOR_DB_URL=http://localhost:8000
export VECTOR_DB_TENANT=default_tenant
export VECTOR_DB_DATABASE=default_database
export VECTOR_DB_COLLECTION=mcp_knowledge
export VECTOR_DB_DIMENSION=384services:
mcp:
build: .
environment:
TRANSPORT: sse
HOST: 0.0.0.0
PORT: 8080
PUBLIC_BASE_URL: http://localhost:8080
VECTOR_DB_PROVIDER: qdrant
VECTOR_DB_URL: http://qdrant:6333
VECTOR_DB_COLLECTION: mcp_knowledge
VECTOR_DB_DIMENSION: 384
VECTOR_DB_DISTANCE: Cosine
WEB_SEARCH_URL_TEMPLATE: https://search.yahoo.com/search?p=%s
depends_on:
- qdrant
ports:
- "8080:8080"
qdrant:
image: qdrant/qdrant:latest
ports:
- "6333:6333"In that setup:
- the MCP server reaches Qdrant at
http://qdrant:6333 - your local machine reaches the MCP server at
http://localhost:8080
You can swap Qdrant for Chroma by changing VECTOR_DB_PROVIDER and VECTOR_DB_URL and, for Chroma, also setting VECTOR_DB_TENANT and VECTOR_DB_DATABASE.
go run .Typical startup output:
MCP server ProductionMCP v2.0.0 listening on 0.0.0.0:4090
SSE endpoint: http://localhost:4090/sse
Message endpoint: http://localhost:4090/message
Knowledge store: /absolute/path/data/knowledge-store.json
Vector database: http://localhost:6333 collection=mcp_knowledge
TRANSPORT=stdio go run .An MCP-compatible client connects to the server and lets the model call tools.
Connect to:
- SSE stream:
PUBLIC_BASE_URL + BASE_PATH + /sse - message endpoint:
PUBLIC_BASE_URL + BASE_PATH + /message
Example with current sample env:
http://localhost:4090/ssehttp://localhost:4090/message
The client launches the process directly.
Example request:
{
"source_type": "file",
"path": "docs/runbook.md",
"title": "Ops Runbook",
"tags": ["ops", "deploy"]
}What happens:
- The file is read
- The text is chunked
- Embeddings are generated
- The chunks are written into Qdrant
Example request:
{
"query": "blue green deploy rollback procedure",
"limit": 3
}What happens:
- The query is embedded
- Qdrant performs vector search
- The top matching chunks are returned
- The model answers using those chunks
Example request:
{
"key": "customer-alpha",
"title": "Customer Alpha Notes",
"content": "Use premium SLA wording. Avoid casual language. Include migration caveats.",
"tags": ["customer", "enterprise"]
}Example request:
{
"key": "customer-alpha"
}What happens:
- The server loads the saved context bundle
- The model gets that stable context directly
- No vector search is needed for that data
This server can also support coding-agent tasks inside READ_ROOT.
Typical flow:
- Use
read_file - Decide on changes
- Use
write_filefor full-file writes - Use
edit_filefor targeted replacements or appends
{
"path": "tmp/example.txt",
"content": "hello world"
}{
"path": "main.go",
"operation": "replace",
"old_text": "func main() {}",
"new_text": "func main() {\n\tprintln(\"hello\")\n}"
}{
"path": "main.go",
"operation": "append",
"new_text": "\n// done\n"
}- file operations are restricted to
READ_ROOT - cached context is stored locally on disk
- RAG retrieval depends on external vector DB connectivity
- readiness depends on vector DB health
- external service links should be provided through env
- web fetches and search responses are bounded by byte limits
The vector backend is currently implemented for multiple free/self-hostable providers.
That means:
VECTOR_DB_PROVIDERcan currently befile,qdrant, orchroma- the external vector service must match the selected provider
The MCP surface is already shaped so another vector backend could be added later without changing how clients use the tools.
Run:
GOCACHE=$(pwd)/.gocache go test ./...The tests are hermetic and do not rely on live internet access.