Skip to content

Explore theLAB

← All field guides

Make it useful / Intermediate

Build Your First MCP Tool

Build a small SQLite notes server and connect it to a tool-capable assistant.

Allow
1-2 hours
Before you start
Python 3.11+, a virtual environment, and an MCP client
Finish with
A local notes tool with bounded inputs, persistent storage, and a disposable-data check.

Reviewed . Commands and examples are reference builds; check installed versions. Hardware-dependent steps are not certified as end-to-end tested.

What you will build

A small local MCP server that can add, list, and delete notes in a dedicated SQLite database. You will connect it to an assistant and test a write using disposable data.

The reference tool runs through standard input/output, not an unauthenticated HTTP port. It is deliberately single-user: one database per trusted operating-system account. Do not turn it into a shared network service without adding authentication and server-enforced ownership.

Before you start

Use Python 3.11+, a virtual environment, and an MCP client such as LibreChat with a tool-capable model. Allow 1-2 hours. The tool itself needs no hosted API; model use may cost money depending on your chosen provider.

Create a fresh mcp-notes-lab directory. Download notes_server.py there and inspect the code before installing or running anything.

python3 -m venv .venv
.venv/bin/python -m pip install 'mcp>=1.20,<2'
.venv/bin/python -m pip freeze > requirements.lock.txt
.venv/bin/python notes_server.py --self-test

The version range selects the documented v1 SDK interface. Record the exact resolved version in the lock file and review updates rather than assuming all future releases behave identically.

1. Inspect the tool boundaries

The server accepts a bounded title and body, generates note IDs itself, uses parameterized SQLite queries, and limits list results. Its test uses a temporary database, so it does not delete your real notes.

delete_note is a real delete operation. The assistant's confirmation UI is helpful, but the server does not implement an independent approval token. Use only disposable notes until you understand the client's permission policy.

2. Configure the client

For a LibreChat backend that can access the files directly, add an operator-managed server entry to its existing configuration:

mcpServers:
  field-notes:
    command: /opt/field-notes/.venv/bin/python
    args:
      - /opt/field-notes/notes_server.py
    env:
      NOTES_DB: /opt/field-notes/data/notes.sqlite3
    startup: false

These paths are examples. Install the files and virtual environment where the backend actually runs. Your laptop's paths are not available inside a LibreChat container. A host virtual environment is also not generally portable into a different container OS; build the dependency into the image or install it in a compatible runtime.

Keep code read-only to the runtime where possible and give it write access only to the data directory. Restart or reinitialize the configured server as required by your client release. Do not replace an existing mcpServers map with this snippet.

3. Verify discovery before asking the model

Use your client's MCP tool list or the official MCP Inspector to confirm add_note, list_notes, and delete_note exist with the expected argument schema. The process should stay available while connected.

Protocol messages use stdout. Do not add ordinary print debugging to the running server; log diagnostic messages to stderr instead.

Checkpoint: direct tool discovery succeeds. If it does not, debugging the model's prompt is premature.

4. Exercise the whole loop

Ask the assistant: "Use field-notes to add a note titled FIELD GUIDE TEST with body disposable verification." Inspect the actual tool call and returned ID.

Then ask it to list notes and verify the same ID and body. Restart the connection and list again to establish persistence. Finally, explicitly authorize deletion of that test ID and verify it is absent. A conversational promise to save a note is not evidence that a tool call happened.

When it breaks

Check the executable path, SDK installation, file permissions, and database directory from inside the backend runtime. A connected server with no model calls usually points to tool selection, endpoint compatibility, or the agent's configuration.

If the tool times out after a write, list notes before retrying; a lost response does not mean the first write failed. This learning tool does not provide request-id deduplication.

Cleanup and security

Disable the client entry before removing the virtual environment. Stop the server before backing up its SQLite database. The server's data is private even though its source code is public.

For shared deployment, add verified identity, resource ownership, bounded concurrency, audit logs, and retry-safe writes. Never trust a model-supplied user ID as authentication.

References