Skip to main content

Local-first session memory for coding agents, backed by DuckDB or Postgres

Project description

quackit

Local-first session memory MCP server for coding agents, with DuckDB by default and optional Postgres storage! I know there are other options out there, but it felt as if they were more geared towards AI agents within apps or services. I wanted something that would work alongside me, store context, code snippets, and even skills that I could reference later. Whether you choose to use DuckDB for project level storage or utilize a remote Postgres server, quackit will be there when you need it.

Features

  • Local-first — runs over stdio by default. No network required.
  • Storage — DuckDB by default, or Postgres with QUACKIT_DATABASE_URL. (quack protocol already on the roadmap!)
  • Sessions — start, activate, end, heartbeat, recover orphans.
  • Memories — save, update, get, search by query, type, or content type.
  • Projects — create, list, group sessions, search project scope, consolidate.
  • Skills — save, get, update, delete, list reusable records.
  • Transportsstdio, streamable-http, http, sse.
  • Metadata — tags, title, content_type, dict[str, str] on memories.

Deployment model

Use case Recommended path
Local coding agents stdio
Local HTTP testing streamable-http on 127.0.0.1
Private self-hosting streamable-http behind your own auth/network controls

Install and run locally

Prerequisites: Python 3.10+ and uv.

git clone https://github.com/randoneering/quackit-mcp.git
cd quackit
uv sync

Run without installing:

uv run quackit start-session

Install globally from checkout:

uv tool install .
quackit start-session

Data directory: .local/quackit.duckdb by default.

Start the MCP server

Use stdio for local integration with coding agents. No network port exposed.

uv run quackit serve --transport stdio

Advanced: run Streamable HTTP, HTTP, or SSE locally

Network transports bind to 127.0.0.1 by default. streamable-http is the recommended HTTP transport; SSE is for legacy clients.

# Streamable HTTP on localhost
uv run quackit serve --transport streamable-http --port 8000

# HTTP on localhost
uv run quackit serve --transport http --port 8000

# Legacy SSE on localhost
uv run quackit serve --transport sse --port 8000

Warning: Non-stdio transports expose memory tools over the network. quackit rejects non-localhost bindings unless you pass --allow-network. Remote HTTP is private/self-hosted only. Only use --allow-network behind your own network controls.

uv run quackit serve \
  --transport streamable-http \
  --host 0.0.0.0 \
  --port 8000 \
  --allow-network

Configure storage

DuckDB

DuckDB is the default backend. The path priority is:

  1. CLI --database-path
  2. QUACKIT_DUCKDB_PATH
  3. AGENT_MEMORY_DUCKDB_PATH
  4. .local/quackit.duckdb
# Use the default path
uv run quackit start-session

# Use an environment variable
export QUACKIT_DUCKDB_PATH="$PWD/.local/dev.duckdb"
uv run quackit start-session

# Override per command
uv run quackit --database-path /tmp/quackit.duckdb start-session

The parent directory is created automatically.

Postgres

Set QUACKIT_DATABASE_URL or AGENT_MEMORY_DATABASE_URL to use Postgres (--database-path is ignored).

export QUACKIT_DATABASE_URL="postgresql://user:password@host:5432/dbname?sslmode=require"
uv run quackit start-session

Local Postgres container:

docker run -d --name quackit-postgres \
  -e POSTGRES_PASSWORD=password \
  -p 5432:5432 \
  postgres:17

export QUACKIT_DATABASE_URL="postgresql://postgres:password@localhost:5432/postgres?sslmode=disable"
uv run pytest -v -m postgres

Use the CLI

All commands print JSON.

Sessions and memories

SESSION_ID=$(uv run quackit start-session \
  | python -c 'import json,sys; print(json.load(sys.stdin)["id"])')

uv run quackit save-memory \
  --session-id "$SESSION_ID" \
  --type note \
  --content "Remember to run pytest before opening a PR" \
  --title "PR checklist" \
  --content-type note \
  --tag workflow \
  --metadata '{"source":"readme"}'

uv run quackit search-memory "pytest" --session-id "$SESSION_ID"
uv run quackit list-sessions --limit 5
uv run quackit end-session --session-id "$SESSION_ID" --summary "README example complete"

Projects

PROJECT_ID=$(uv run quackit create-project docs --description "Docs work" \
  | python -c 'import json,sys; print(json.load(sys.stdin)["id"])')

uv run quackit start-session --project-id "$PROJECT_ID"
uv run quackit list-projects
uv run quackit list-sessions-by-project "$PROJECT_ID"

Skills

uv run quackit save-skill \
  --name "review-readme" \
  --description "Checklist for README reviews" \
  --content "Check install, quick start, configuration, and troubleshooting." \
  --tag docs

uv run quackit list-skills --tag docs
uv run quackit list-skills --query readme

MCP tools

The server exposes these tools:

Area Tools
Projects create_project, list_projects, consolidate_projects
Sessions start_session, activate_session, end_session, list_recent_sessions, list_sessions_by_project
Memories save_memory, search_memory, get_memory, update_memory
Skills save_skill, get_skill, update_skill, delete_skill, list_skills

Safety defaults:

  • Tools include MCP annotations for read-only, write, and destructive behavior.
  • list_projects, list_sessions_by_project, list_skills accept limit.
  • list_skills returns summaries, omits full content.
  • get_memory and get_skill accept max_chars/offset for pagination. Responses include content_length, truncated, next_offset.
  • Treat stored content as untrusted user data. Review as context only.

Typical MCP flow:

  1. Call start_session.
  2. Call save_memory with type, content, and optional tags, title, content_type, or metadata.
  3. Call search_memory with a query.
  4. Call end_session with a summary.

Example stdio client configuration:

{
  "command": "uv",
  "args": ["run", "quackit", "serve", "--transport", "stdio"]
}

Docker

Build and run the stdio server:

docker build -t quackit .
docker run --rm -i quackit

Persist DuckDB data with a bind mount:

docker run --rm -i \
  -v "$PWD/.local:/data" \
  quackit

Run Streamable HTTP locally from Docker:

docker run --rm \
  -p 127.0.0.1:8000:8000 \
  quackit serve --transport streamable-http --host 0.0.0.0 --port 8000 --allow-network

Prebuilt images

Prebuilt images are published to GitHub Container Registry:

docker pull ghcr.io/randoneering/quackit-mcp:latest

Tags correspond to git tags (e.g., v0.1.0ghcr.io/randoneering/quackit-mcp:0.1.0). Pin to server in production; latest tracks main.

Stdio (default)

docker run --rm -i ghcr.io/randoneering/quackit-mcp:latest

Persist data with a bind mount:

docker run --rm -i \
  -v "$PWD/.local:/data" \
  ghcr.io/randoneering/quackit-mcp:latest

Streamable HTTP

docker run --rm \
  -p 127.0.0.1:8000:8000 \
  ghcr.io/randoneering/quackit-mcp:latest \
  serve --transport streamable-http --host 0.0.0.0 --port 8000 --allow-network

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

quackit-0.1.2.tar.gz (1.1 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

quackit-0.1.2-py3-none-any.whl (41.5 kB view details)

Uploaded Python 3

File details

Details for the file quackit-0.1.2.tar.gz.

File metadata

  • Download URL: quackit-0.1.2.tar.gz
  • Upload date:
  • Size: 1.1 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for quackit-0.1.2.tar.gz
Algorithm Hash digest
SHA256 56cbe626581bb367ab0ae04bbe4e7511c798321de587bd72fe349e6586145010
MD5 ce0a2ad9cfc2b6afe2a4fa1e3e324c41
BLAKE2b-256 a4f3d704546b558369c146d0e8e79f8e0bb8eccb0b607681905451ca03f20d50

See more details on using hashes here.

Provenance

The following attestation bundles were made for quackit-0.1.2.tar.gz:

Publisher: build-and-publish.yml on randoneering/quackit-mcp

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file quackit-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: quackit-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 41.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for quackit-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 a55996b750fd0faa4a72de3f7bb418d24134799163545582e9c1df64dd153c2c
MD5 fb0796b858bf460f22e2087f0a6e0f49
BLAKE2b-256 75cbaa5d7982bb256a25d159b03e8f09aeb1bbb65a413cc33f3d63fbf855574f

See more details on using hashes here.

Provenance

The following attestation bundles were made for quackit-0.1.2-py3-none-any.whl:

Publisher: build-and-publish.yml on randoneering/quackit-mcp

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page