Skip to content
Conduit

mcp server

smart-note

TIZ36/smart-notecommunitylistedunreviewed

Set up

Runs on your computer. Pick your agent and operating system.

This project does not publish an install method we can turn into a config. Follow the README instead.

README

synced Oct 22, 2026

Why SmartNote

SmartNote is a self-hosted memory and notes backend for AI agents. There is no GUI — the product is the API:

  • 🤖 Agents see your notes as first-class memory. A native MCP streamable-HTTP server lets Claude Code / Cursor / Opencode call search, add_memory, add_document, set_preference — scoped to a workspace.
  • ☁️ The cloud does the work AI needs. A small FastAPI service chunks, embeds (pgvector), enriches with your LLM, and builds an entity graph across documents.
  • 🧰 REST + SDKs for everything else. Anything the MCP tools do is also reachable over the /v1/* REST API, with first-party Python and TypeScript SDKs.
  • 🔑 One API key. No SaaS account, no per-tool wiring. Issue once, paste anywhere.

🚀 Quick Start

You need one thing: the cloud stack (Docker). Total time: ~5 minutes.

1 · Bring up the cloud

git clone https://github.com/TIZ36/smart-note.git
cd smart-note
./scripts/restart-cloud.sh

This builds the API image, starts Postgres + pgvector + the embed service, and runs migrations. When it prints ✓ api healthy, you have:

ServiceURL
REST APIhttp://localhost:58000
MCP endpointhttp://localhost:58000/mcp/
Postgreslocalhost:55432
Embedding servicehttp://localhost:58009

First run takes longer: the embed-model image downloads ~600 MB. Subsequent boots are seconds.

2 · Mint a workspace API key

./scripts/issue-cloud-apikey.sh

You get an sn_live_… token printed once. Save it — it scopes everything below to one workspace.

3 · Connect an MCP client

Point any modern MCP client at the /mcp/ endpoint with the token as a bearer header (see MCP for AI agents). Or talk to the REST API / SDKs directly (see REST API & SDKs).

# Stop cloud, keep data
cd cloud/infra && docker compose down

# Stop + wipe DB (clean slate)
cd cloud/infra && docker compose down -v

🤖 MCP for AI agents

SmartNote exposes a native MCP streamable-HTTP endpoint at /mcp/. No stdio bridge, no spawn, no absolute paths. Any modern MCP client connects with just a URL + bearer token.

Claude Code · Cursor · Opencode

Project-scoped config (e.g. .mcp.json):

{
  "mcpServers": {
    "smartnote": {
      "url": "http://localhost:58000/mcp/",
      "headers": {
        "Authorization": "Bearer sn_live_..."
      }
    }
  }
}

Tools the agent gets

ToolWhat it does
searchDefault lookup — fans out to memories ∪ document chunks in parallel, merges by score.
search_memory / search_documentsSource-scoped variants.
add_memory · set_preferencePersist a fact or preference (supersede history kept).
propose_memorySubmit a draft memory for user review (lands in the pending-proposals queue).
add_document · update_document · append_to_document · delete_documentManage long-form notes (upload → chunk → embed).
get_document · get_memoryFetch full content by id.
queue_enrich_jobs · submit_enrichmentsDrive cloud-side LLM enrichment.
set_enrich_providerConfigure the workspace's cloud-side LLM.

Every tool is workspace-scoped via the bearer key — one workspace per key.


🔌 REST API & SDKs

Everything the MCP tools expose is also available over the /v1/* REST API. Get a short-lived JWT from your sn_live_… key, then call the endpoints:

curl -X POST http://localhost:58000/v1/auth/token \
  -H "Content-Type: application/json" \
  -d '{"api_key": "sn_live_…"}'
# expect: {"jwt": "...", "expires_at": …}

First-party SDKs wrap the same surface:

SDKLocation
Pythoncloud/sdk-py/
TypeScriptcloud/sdk-ts/

Both target the REST API (documents, memories, preferences, search, enrichment) using a workspace API key.


🏗 Architecture

                          ┌─────────────────────────────┐
   AI agents (MCP)  ──────►  Cloud (single Docker host)  │
   /mcp streamable        │                              │
                          │  ┌──────────────────────┐    │
   SDKs / REST clients ───►  │ FastAPI (cloud/api/) │    │
   /v1/* HTTP             │  │   /v1/* REST         │    │
                          │  │   /mcp (streamable)  │    │
                          │  └──────────┬───────────┘    │
                          │             │                │
                          │  ┌──────────▼───────────┐    │
                          │  │ Postgres + pgvector  │    │
                          │  │   documents          │    │
                          │  │   chunks, blobs      │    │
                          │  │   memories           │    │
                          │  │   entities + links   │    │
                          │  └──────────────────────┘    │
                          │                              │
                          │  ┌──────────────────────┐    │
                          │  │ Embedding service    │    │
                          │  │ (self-hosted)        │    │
                          │  └──────────────────────┘    │
                          └─────────────────────────────┘

Processing pipeline (per document):
  chunk_embed   ──►  chunk_enrich       ──►  graph_topology
   (chunks +         (LLM tags · topics       (cross-doc links:
    pgvector)         · entities · summary)    shared entities,
                                               shared tags)
                  └─►  wiki_abstract ────►    same                ← for wiki_topic docs
                       (chapter summary +
                        entities)

Project layout

smart-note/
├── cloud/
│   ├── api/                  # FastAPI app — REST + MCP
│   │   ├── app/
│   │   │   ├── routers/      # documents, memories, notes, preferences, …
│   │   │   ├── services/     # processing_runs, enrich, kb, embedding, …
│   │   │   ├── contexts/     # knowledge, storage event subscriptions
│   │   │   └── mcp_http.py   # MCP streamable-HTTP server
│   │   └── scripts/          # backfills + one-shot maintenance
│   ├── mcp/                  # MCP server
│   ├── migrations/           # 0NN_*.sql, idempotent, run on startup
│   ├── infra/                # docker-compose.yml + Caddy + .env
│   ├── sdk-py/               # Python SDK
│   └── sdk-ts/               # TypeScript SDK
├── local_embedding/          # self-hosted embedding service
├── scripts/                  # restart-cloud / issue-apikey / clean-all-data
└── docs/

⚙️ Configuration

The cloud needs an OpenAI-compatible LLM to power enrichment (chunk_enrich), wiki abstracts, and the MCP classifier. It speaks /chat/completions. Recommended:

  • Budget: deepseek-chat at https://api.deepseek.com/v1
  • Quality: gpt-4o-mini at https://api.openai.com/v1
  • Reasoner: deepseek-reasoner

Set it from an MCP-connected agent: call set_enrich_provider(api_key=…, base_url=…, model=…). Without it, enrichment jobs stay disabled. The provider config is stored per-workspace in Postgres (memories, kind=preference).

./scripts/restart-cloud.sh                            # rebuild + restart api (the right way)
cd cloud/infra && docker compose logs -f api          # tail live logs
cd cloud/infra && docker compose exec postgres psql -U smartnote -d smartnote   # SQL shell

./scripts/clean-all-data.sh                           # wipe Postgres + restart cloud
./scripts/issue-cloud-apikey.sh                       # mint a new workspace key

The cloud auto-runs SQL files from cloud/migrations/ at startup in lexical order. Conventions:

  • Filename: 0NN_short_name.sql
  • Every statement must be idempotent (CREATE … IF NOT EXISTS, ADD COLUMN IF NOT EXISTS)
  • No migration ledger by design — keep them re-runnable

After adding a migration, ./scripts/restart-cloud.sh picks it up on the next build.

cloud/infra/ holds the compose files and a Caddy reverse proxy for production. See cloud/infra/DEPLOY.md for the production / LAN / shared-Postgres overrides (docker-compose.prod.yml, docker-compose.lan.yml, docker-compose.shared.yml).


🛟 Troubleshooting

The bearer key is invalid or was wiped (you ran clean-all-data.sh). Mint a new one with ./scripts/issue-cloud-apikey.sh and update your client config. Verify a key against the REST API:

curl -X POST http://localhost:58000/v1/auth/token \
  -H "Content-Type: application/json" \
  -d '{"api_key": "sn_live_…"}'
# expect: {"jwt": "...", "expires_at": …}

docker compose restart api does not rebuild the image. The cloud has no live-mount; code is baked at build time.

Use ./scripts/restart-cloud.sh (which runs docker compose up -d --build api).

The cloud LLM provider isn't set. From an MCP-connected agent, call set_enrich_provider(api_key=…, base_url=…, model=…).

You're using a reasoner model (DeepSeek-Reasoner / o1) and it spent the entire token budget on hidden chain-of-thought. Switch to deepseek-chat / gpt-4o-mini, or allow a larger max_tokens.


🗺 Roadmap

  • Auto-enrich after ingest (currently manual to control LLM spend)
  • Multi-workspace tooling
  • OAuth for shared workspaces

License

MIT — see LICENSE.

Contributing

Issues and PRs at https://github.com/TIZ36/smart-note. For substantial changes, open an issue first to align on scope.

↑↓ navigate openesc close