project-memory-mcp

project-memory-mcp

Stores manual project memories, enables semantic retrieval, and tracks per-memory confidence using PostgreSQL with pgvector and OpenAI-compatible embeddings.

Category
Visit Server

README

project-memory-mcp

A TypeScript MCP server for project memory: it stores manual project memories, retrieves them semantically, and tracks per-memory confidence. Metadata and vectors both live in PostgreSQL (via the pgvector extension), and embeddings come from an OpenAI-compatible API.

Architecture

  • MCP server exposes tools over stdio.
  • PostgreSQL stores projects, memories, confidence feedback, and memory embeddings (pgvector vector column). Semantic search is exact cosine KNN in SQL — at this server's scale (memories are project knowledge, not a code index) a dedicated vector DB added a second store to keep consistent for no retrieval benefit.
  • Embeddings are generated by a configurable OpenAI-compatible /v1/embeddings API.
  • PostgreSQL is an external service. This server only reads its address from config, and requires the pgvector extension (the migrations run CREATE EXTENSION IF NOT EXISTS vector).

Tools

These are the tools exposed over MCP (stdio and the HTTP /mcp endpoint). The server stores and retrieves manual project memories only; it never reads project source files. Clients contribute knowledge through add_memory.

Setup and health:

  • help: start here. Returns a guide to call order, tool arguments, how projectId works, and the scaffold (files + contents) to wire a project into the auto-memory workflow. Takes no arguments.
  • health_check: check PostgreSQL and embedding API connectivity.
  • register_project: register a project and obtain a server-generated projectId used to scope all other tools.

Retrieval:

  • search_knowledge: semantic search across project memories.

Memory management:

  • add_memory: add manual knowledge and index it.
  • list_memories: list memories with optional archived/kind/tag filters.
  • update_memory: update a memory and refresh its embedding.
  • archive_memory: archive a memory so it no longer appears in search results.

Confidence:

  • record_confidence_feedback: submit trust feedback for a memory.
  • get_confidence: read computed confidence for a memory.
  • list_confidence_feedback: list feedback records for audit.
  • list_suspect_confidence: list suspect or rejected memories.

Configuration

Service config controls infrastructure:

{
  "database": {
    "urlEnv": "DATABASE_URL"
  },
  "embedding": {
    "provider": "openai-compatible",
    "baseUrl": "https://api.example.com/v1",
    "apiKeyEnv": "EMBEDDING_API_KEY",
    "model": "embedding-model-name",
    "dimensions": 1536,
    "batchSize": 64
  }
}

Project config identifies the project:

{
  "projectId": "my-project",
  "name": "My Project"
}

projectId scopes all retrieval, memory, and confidence data. name is optional and used only for display. An optional root may be supplied for informational display in the capability manifest, but the server never reads project files — retrieval isolation is keyed solely on projectId.

Local Dependencies

PostgreSQL (with pgvector) is started separately. For local development only, this repo includes a commented docker-compose.yml that uses the pgvector/pgvector:pg16 image:

docker compose up -d postgres

Then set:

cp .env.example .env

Fill EMBEDDING_API_KEY and make sure DATABASE_URL points at your PostgreSQL service.

Install And Build

pnpm install
pnpm build

CLI

project-memory migrate \
  --service-config ./examples/project-memory.service.json \
  --project-config ./examples/project-memory.config.json

project-memory search "where is authentication handled?" \
  --service-config ./examples/project-memory.service.json \
  --project-config ./examples/project-memory.config.json

project-memory add-memory \
  --title "Use API embeddings" \
  --content "The first version uses an OpenAI-compatible embedding API instead of self-hosted embeddings." \
  --kind decision

project-memory feedback \
  --target-id mem_xxx \
  --signal contradict \
  --rationale "This advice conflicts with the current project convention."

project-memory confidence --target-id mem_xxx

Other CLI commands:

project-memory list-memories [--include-archived] [--kind <k>] [--tag <t>] [--limit <n>]
project-memory update-memory --id mem_xxx [--title ...] [--content ...] [--kind ...] [--tags a,b] [--source ...]
project-memory archive-memory --id mem_xxx
project-memory list-feedback [--target-id mem_xxx] [--limit <n>]
project-memory list-suspect

Confidence starts at 0.7. Feedback signals are support, confirm, dispute, contradict, obsolete, and uncertain: support/confirm raise confidence, while dispute/contradict/obsolete/uncertain lower it. Very low confidence records are marked suspect or rejected; rejected memories are excluded from retrieval, and suspect memories are heavily down-ranked.

MCP Client Example

There are two ways to connect, depending on where the server runs.

Local (stdio)

Use this when the server binary lives on the same machine as the MCP client, which spawns it as a child process over stdio:

{
  "mcpServers": {
    "project-memory": {
      "command": "node",
      "args": ["/path/to/project-memory-mcp/dist/index.js"],
      "env": {
        "PROJECT_MEMORY_SERVICE_CONFIG": "/path/to/project-memory.service.json",
        "PROJECT_MEMORY_PROJECT_CONFIG": "/path/to/project-memory.config.json",
        "DATABASE_URL": "postgres://project_memory:project_memory@localhost:5432/project_memory",
        "EMBEDDING_API_KEY": "your-api-key"
      }
    }
  }
}

Remote (HTTP)

When the server runs elsewhere — for example in a Docker container on another host — the client cannot spawn it over stdio. Connect over the Streamable HTTP /mcp endpoint instead. Both Claude Code and Codex support remote HTTP MCP servers natively; no stdio bridge is required.

The /mcp endpoint does not require the bearer token, so MCP clients connect without an Authorization header. The token only guards the read-only REST endpoints (see HTTP Endpoint).

Claude Code — add via the CLI (user scope is the most reliable for remote servers):

claude mcp add --transport http --scope user project-memory \
  https://your-host:8788/mcp

Or in ~/.claude.json:

{
  "mcpServers": {
    "project-memory": {
      "type": "http",
      "url": "https://your-host:8788/mcp"
    }
  }
}

Codex — in ~/.codex/config.toml:

[mcp_servers.project-memory]
url = "https://your-host:8788/mcp"

After connecting, call register_project once to obtain a projectId, then pass that projectId to search_knowledge, add_memory, and the other project-scoped tools.

HTTP Endpoint

The stdio MCP entry remains the default for local MCP clients. A network entry is also available for agents that can connect over HTTP:

pnpm start:http

Defaults:

http://127.0.0.1:8788

Useful endpoints:

GET  /                      Capability manifest: what this MCP is and what it can do.
GET  /help                  Usage guide: call order, tool arguments, and the auto-memory scaffold.
GET  /health                PostgreSQL and embedding API health.
GET  /status                Dependency health for the configured project.
GET  /tools                 Tool names and descriptions.
GET  /memories              List memories (query: includeArchived, kind, tag, limit, projectId).
GET  /confidence/suspect    List suspect or rejected memories.
GET  /confidence/feedback   List confidence feedback (query: targetId, limit, projectId).
POST /mcp                   MCP Streamable HTTP endpoint.
GET  /mcp                   MCP Streamable HTTP SSE stream when supported by the client.

Configure the bind address with:

PROJECT_MEMORY_HTTP_HOST=127.0.0.1
PROJECT_MEMORY_HTTP_PORT=8788
PROJECT_MEMORY_HTTP_TOKEN=change-me

When PROJECT_MEMORY_HTTP_TOKEN is set, the read-only REST endpoints require:

Authorization: Bearer <token>

Two endpoints are exempt from the token:

  • /health — so external health checks work without credentials.
  • /mcp — MCP Streamable HTTP clients (Claude Code, Codex) do not reliably forward custom headers on every request during the initialize/session handshake, so the MCP endpoint is reachable without the token. This is intended for the trusted deployment this server targets; do not expose /mcp to untrusted networks.

Example:

curl http://127.0.0.1:8788/ \
  -H "Authorization: Bearer $PROJECT_MEMORY_HTTP_TOKEN"

Docker Deployment

The deployment image runs only the Project Memory MCP HTTP server. PostgreSQL (with pgvector) and the embedding API remain external services.

Build:

docker build -t project-memory-mcp:local .

Run:

docker run --rm -p 8788:8788 \
  -e PROJECT_MEMORY_HTTP_TOKEN="change-me" \
  -e DATABASE_URL="postgres://user:password@postgres-host:5432/project_memory" \
  -e EMBEDDING_BASE_URL="https://api.example.com/v1" \
  -e EMBEDDING_MODEL="text-embedding-3-small" \
  -e EMBEDDING_DIMENSIONS="1536" \
  -e EMBEDDING_BATCH_SIZE="64" \
  -e EMBEDDING_API_KEY="your-key" \
  project-memory-mcp:local

Or use the deployment compose file:

PROJECT_MEMORY_HTTP_TOKEN="change-me" \
DATABASE_URL="postgres://user:password@postgres-host:5432/project_memory" \
EMBEDDING_BASE_URL="https://api.example.com/v1" \
EMBEDDING_MODEL="text-embedding-3-small" \
EMBEDDING_DIMENSIONS="1536" \
EMBEDDING_API_KEY="your-key" \
docker compose -f docker-compose.deploy.yml up -d

Health check:

curl http://127.0.0.1:8788/health

Capability manifest:

curl http://127.0.0.1:8788/ \
  -H "Authorization: Bearer change-me"

Operations

For production deployments, see docs/OPERATIONS.md. It covers:

  • Fresh deployment — empty PostgreSQL → running server, including how schema migrations run automatically at startup.
  • Backup / restore — all state is in PostgreSQL; a pg_dump is a complete backup (the pgvector vector column included).
  • Re-embedding — changing embedding.model or dimensions invalidates every stored vector; the doc gives the re-embed procedure.
  • Connection pool & timeout tuning — the PostgreSQL pool and the embedding HTTP request are both bounded so a slow dependency cannot hang requests. Defaults are conservative; override via env:
DATABASE_POOL_MAX=10                      # max pooled PostgreSQL connections
DATABASE_POOL_IDLE_TIMEOUT_MS=30000       # idle client eviction
DATABASE_POOL_CONNECTION_TIMEOUT_MS=10000 # fail fast if no connection acquired
EMBEDDING_REQUEST_TIMEOUT_MS=30000        # abort a hung embedding API call

These may also be set under database.pool and embedding.requestTimeoutMs in the service config.

Notes

This server is intentionally memory-centric: it stores manual project memories, retrieves them semantically, and tracks per-memory confidence from agent feedback.

Two earlier subsystems were removed once they proved to be write-only dead weight. PostgreSQL graph nodes/edges were only ever written, never read. A code/document indexing pipeline (scan → chunk → embed → store) was also removed: the server runs remotely and never has access to project source files, local agents read source directly, and search_knowledge only ever read memory vectors — never the chunk vectors the pipeline produced. Removing both kept the runtime lean and the responsibility singular.

Vector storage was then consolidated out of Qdrant into PostgreSQL via pgvector. Once code indexing was gone, the vector store held only memory vectors — a few hundred per project, filtered by projectId before any comparison — where exact cosine KNN in SQL is fast and accurate. The dedicated vector DB only added a second store to keep consistent (the dual-write orphan-handling that add/update/archive carried) for no retrieval benefit at that scale. If a large-scale code index ever returns, a dedicated vector DB may be worth reintroducing; at the current scope it is not.

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured