Skip to main content
Glama
manish0502

mcp-notes

by manish0502

mcp-notes

An MCP server for capturing and querying project notes — backed by MongoDB, served over stdio or Express. A complete, minimal reference implementation of all three MCP primitives.

Stack: MongoDB + Express + Node (TypeScript), Mongoose ODM.


Demo

https://github.com/user-attachments/assets/b49dcb2d-029e-42d3-a3ce-12cb7e0d773f

Three minutes in the MCP Inspector: listing the tools, calling them against MongoDB, reading resources, and the raw JSON-RPC behind each call.

Related MCP server: notes-mcp

What MCP actually gives you

Three primitives, and who controls each one is the part people get wrong:

Primitive

Controlled by

Purpose

Here

Tools

the model

actions with side effects

add_note, search_notes, update_note, delete_note

Resources

the application

read-only data addressed by URI

notes://all, notes://tags

Prompts

the user

reusable templates, usually a slash command

review_open_notes

Tools are the only primitive that can change anything. A resource is read, never called. A prompt returns messages that seed a conversation — not an answer.

How a request flows

  Claude Code / Desktop
          │  JSON-RPC over stdio  (or HTTP POST /mcp)
          ▼
  src/transports/        stdio.ts  │  http.ts  (Express)
          │
          ▼
  src/mcp/server.ts      tools · resources · prompts
          │              zod validates arguments before any handler runs
          ▼
  src/services/          business logic — knows Mongo, knows nothing about MCP
          │
          ▼
  src/models/            Mongoose schema → plain DTO
          │
          ▼
      MongoDB

Each layer only knows the one below it. The service has no idea it is being called over a protocol, which is why it can be tested without one.

The tools, and their annotations

annotations are hints to the client about what a tool does. They are advisory, not enforced — but clients use them to decide what needs human approval and what is safe to cache. Omit them and every caller must assume the worst.

Tool

readOnly

destructive

idempotent

Why

add_note

no

no

no

writes, but only inserts — nothing is lost. Twice = two notes

search_notes

yes

–

–

safe to call freely, safe to cache

update_note

no

no

yes

overwrites fields; same patch twice = same end state

delete_note

no

yes

yes

the one tool a client should confirm first

Quick start

MongoDB must be running on localhost:27017.

npm install
npm test
npm run dev

Set MONGODB_URI to use a different database (default mongodb://127.0.0.1:27017/mcp_notes).

Try it with the MCP Inspector

npm run inspect

Register it with Claude Code or Claude Desktop

{
  "mcpServers": {
    "notes": {
      "command": "npx",
      "args": ["tsx", "/absolute/path/to/mcp-notes/src/index.ts"],
      "env": { "MONGODB_URI": "mongodb://127.0.0.1:27017/mcp_notes" }
    }
  }
}

Or run it over HTTP

MCP_TRANSPORT=http PORT=3100 npm run dev
curl -s -X POST http://127.0.0.1:3100/mcp -H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream' -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

The HTTP mode is stateless: a fresh server per request, no session id, so it scales horizontally with no sticky routing. There is also a plain GET /healthz that reports whether Mongo is reachable.

Layout

Path

Job

src/config/db.ts

the only file that knows the Mongo URI

src/models/note.model.ts

Mongoose schema; converts documents to plain DTOs

src/services/note.service.ts

business logic and queries. No MCP here

src/mcp/schemas.ts

zod input shapes — these become the published JSON Schema

src/mcp/server.ts

the MCP surface: tools, resources, prompts

src/transports/stdio.ts

what Claude Code spawns

src/transports/http.ts

Express + streamable HTTP

src/index.ts

composition root: connect Mongo, pick a transport

test/note.service.test.ts

queries against real MongoDB

test/mcp-server.test.ts

a real MCP client talking to the server in-process

Five things worth knowing

1. stdout is the protocol channel. One console.log in a stdio server corrupts the JSON-RPC stream and the client disconnects with a parse error. All diagnostics go to stderr.

2. isError is not an exception. A bad note id returns { isError: true } with a readable message — the call succeeded, the tool reported a problem, and the model can read it and retry. Throwing instead looks like a server fault.

3. The SDK validates arguments for you. The zod shapes in src/mcp/schemas.ts become JSON Schema for tools/list and are enforced before your handler runs. A call missing a required field never reaches your code — it comes back as an isError result naming the offending field. You never hand-validate tool arguments.

4. Prompt arguments are strings. Tools accept rich JSON Schema types; prompts transmit arguments as strings only. That is why reviewPromptShape exists separately instead of reusing the search shape.

5. .describe() is prompt engineering. Every description in the zod shape is published to the model and is how it decides which tool to call. Vague descriptions are the most common reason a correct tool never gets used.

Tests

36 tests, no mocks. test/note.service.test.ts runs real queries against a dedicated database that is wiped between tests. test/mcp-server.test.ts wires a genuine MCP Client to the server over InMemoryTransport — the same code path as stdio, without spawning a process. That second file is the most valuable test to write for any MCP server: it catches schema mistakes and missing annotations that service-level unit tests cannot see.

They need a local mongod. For CI, add a MongoDB service container or swap in mongodb-memory-server.

License

MIT

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    A minimal MCP server for persistent note-taking, enabling create, update, delete, and search of notes with tags, plus resource-based retrieval of all notes or by title.
    -
  • A
    license
    A
    quality
    D
    maintenance
    MCP server for a personal notes/knowledge base that enables AI assistants to create, search, and retrieve notes using natural language. It exposes tools like create_note and search_notes, resources for each note, and a summarize_tag prompt.
    6
    MIT