A Model Context Protocol (MCP) server written in Go that provides document storage and vector similarity search backed by PostgreSQL with pgvector. It exposes six tools over SSE transport for storing, querying, listing, updating, and deleting documents with 384-dimensional embeddings.
- Vector similarity search using pgvector HNSW cosine index
- Namespace partitioning to isolate groups of documents
- JSONB metadata filtering on arbitrary key-value pairs
- Pagination with limit/offset on list operations
- Partial updates — modify only the fields you need
- Auto-schema initialization — creates tables and indexes on startup (idempotent)
- Structured JSON logging via
log/slog - Graceful shutdown on SIGINT/SIGTERM
| Tool | Description |
|---|---|
store_data |
Store a record with key, content, metadata, and a 384-dim embedding |
query_similar |
Find records similar to a given embedding vector, with optional namespace and metadata filtering |
get_data |
Retrieve a document by UUID (includes full embedding) |
list_data |
List records with pagination and optional namespace/metadata filtering |
update_data |
Partially update an existing record by UUID |
delete_data |
Delete a document by UUID |
- Go 1.25+
- PostgreSQL with the pgvector extension installed
- Docker (optional, used by integration tests via testcontainers)
Configuration is loaded with the following priority (highest to lowest):
- Environment variables already set in the process (e.g. from Docker, systemd, shell)
.envfile in the working directory (only fills in vars not already set)- Hard-coded defaults
| Variable | Default | Description |
|---|---|---|
MCP_DB_HOST |
192.168.0.65 |
PostgreSQL host |
MCP_DB_PORT |
5432 |
PostgreSQL port |
MCP_DB_USER |
$USER |
Database user |
MCP_DB_PASSWORD |
(empty) | Database password |
MCP_DB_NAME |
mcp_db |
Database name |
MCP_LISTEN_ADDR |
0.0.0.0:5353 |
SSE server listen address |
Make sure PostgreSQL is running and the pgvector extension is available. Create the database:
CREATE DATABASE mcp_db;Option A: Use a .env file (recommended for local development and Docker)
cp .env.example .env
# Edit .env with your valuesOption B: Export environment variables directly
Linux / macOS:
export MCP_DB_HOST=localhost
export MCP_DB_USER=postgres
export MCP_DB_PASSWORD=yourpassword
export MCP_DB_NAME=mcp_dbWindows (PowerShell):
$env:MCP_DB_HOST = "localhost"
$env:MCP_DB_USER = "postgres"
$env:MCP_DB_PASSWORD = "yourpassword"
$env:MCP_DB_NAME = "mcp_db"Environment variables always override .env file values, so you can use both — set defaults in .env and override specific values per environment.
Print the DDL without connecting to the database:
go run main.go --init-schemaThis outputs the SQL that creates the documents table, the HNSW vector index, a namespace B-tree index, and a GIN index for metadata queries.
go run main.goThe server will:
- Connect to PostgreSQL and create the schema if it doesn't exist
- Start listening for SSE connections on
0.0.0.0:5353
Point your MCP client at the SSE endpoint. For example, in a Kiro or other MCP-compatible client config:
{
"mcpServers": {
"go-postgres": {
"url": "http://localhost:5353/sse"
}
}
}CREATE TABLE documents (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
namespace TEXT NOT NULL DEFAULT 'default',
key TEXT NOT NULL,
content TEXT NOT NULL,
metadata JSONB NOT NULL DEFAULT '{}',
embedding vector(384),
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);Indexes:
- HNSW on
embeddingfor cosine similarity search - B-tree on
namespacefor partition filtering - GIN on
metadatafor JSONB containment queries
Unit tests:
go test ./...Integration tests require Docker (testcontainers spins up a PostgreSQL instance automatically):
go test -v -run Integration ./...go build -o mcp-server .
./mcp-serverBuild the image:
docker build -t go-mcp-postgres-server .Run the container:
docker run --rm \
-e MCP_DB_HOST=your-db-host \
-e MCP_DB_PORT=5432 \
-e MCP_DB_USER=postgres \
-e MCP_DB_PASSWORD=changeme \
-e MCP_DB_NAME=mcp_db \
-p 5353:5353 \
go-mcp-postgres-serverSee LICENSE for details.