AI Guides › Step-by-step guides

Build a Two-Tool MCP Server for Claude Desktop

By Nigel Guy · 7 min read

Most people's first custom connector fails for one of two reasons. Either they try to build the "everything" connector on day one, with ten tools and a login, or they paste a config snippet from an old tutorial and spend an evening wondering why Claude never sees it. Both feel like progress right up to the point where nothing appears in the app. The fix is to build the smallest thing that can possibly work, prove each layer separately, and only then make it bigger.

The rule: build a two-tool server, test it outside Claude before you test it inside Claude, and change one thing at a time.

This guide walks you through the Two-Tool Notebook: a tiny local MCP server that lets Claude save a note to a text file on your computer and read it back. It uses only the official MCP Python SDK and the official Inspector. You do not need to be able to write code from scratch, but you will copy, paste and run a handful of commands.

How it actually works

MCP (Model Context Protocol) is an open standard for plugging tools into AI apps. Your "connector" is a small program, the server. Claude Desktop is the host: when it starts, it reads a config file, launches your program in the background and talks to it over the program's standard input and output (the "stdio" transport). Each Python function you mark as a tool becomes something Claude can call, and Claude asks your permission before it does.

Route Where the server runs What you need Who it suits
Local server (this guide) Your own Mac or Windows PC Python, uv, a config file Personal tools, private files
Desktop extension (.mcpb) Your PC, installed by double-click The MCPB packaging tool Sharing a local tool with colleagues
Remote custom connector A server on the public internet Hosting, HTTPS, usually sign-in Using the tool in Claude on web and mobile

Before you start

You need Notes Cost at time of writing
Claude Desktop, latest version macOS or Windows only. Download from claude.ai/download. £0
A Claude account Anthropic's pricing page lists connectors and desktop extensions on the Free plan as well as paid plans. Check the current £ price on the upgrade page if you want more usage. £0 on Free
uv (Python project manager) Installed in Step 1. The SDK needs Python 3.10 or newer. £0
Node.js, LTS version Only for the Inspector test. The Inspector needs Node 22.19.0 or newer. £0
A plain-text editor TextEdit in plain-text mode, Notepad, or VS Code. £0

Step 1 — Install uv

Open Terminal (Mac) or PowerShell (Windows) and run the official installer.

Mac:

curl -LsSf https://astral.sh/uv/install.sh | sh

Windows:

powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"

Close the window and open a new one so the uv command is recognised. If you have no Python 3.10 or newer, run uv python install.

Step 2 — Create the project

uv init notebook
cd notebook
uv add "mcp[cli]"

On Windows PowerShell, the official tutorial writes the last line without quotes: uv add mcp[cli]. The [cli] part adds the mcp command you will use for testing. At time of writing this installs version 2 of the Python SDK.

Step 3 — Write the server

Create a file called notebook.py inside the notebook folder and paste this in:

from datetime import datetime
from pathlib import Path

from mcp.server import MCPServer

mcp = MCPServer("notebook")

NOTES_FILE = Path.home() / "claude-notebook.txt"


@mcp.tool()
def add_note(text: str) -> str:
    """Save a short note to the notebook file, with today's date and time.

    Args:
        text: The note to save, in plain words.
    """
    stamp = datetime.now().strftime("%Y-%m-%d %H:%M")
    with NOTES_FILE.open("a", encoding="utf-8") as f:
        f.write(f"{stamp}  {text}\n")
    return f"Saved: {text}"


@mcp.tool()
def read_notes(last: int = 10) -> str:
    """Return the most recent notes from the notebook file.

    Args:
        last: How many of the newest notes to return.
    """
    if not NOTES_FILE.exists():
        return "The notebook is empty."
    lines = NOTES_FILE.read_text(encoding="utf-8").splitlines()
    return "\n".join(lines[-last:]) or "The notebook is empty."


if __name__ == "__main__":
    mcp.run(transport="stdio")

Two details matter more than they look. The text in triple quotes is what Claude reads to decide when to use each tool, so write it as a plain instruction. And never add print() to a stdio server: anything printed to standard output corrupts the messages between Claude and your program. Use Python's logging module if you need to see what is happening.

If you want Claude (in a normal chat) to adapt the server for you, give it a brief like this: "Here is a working MCP server written with the official Python SDK's MCPServer class. Add one tool called [name] that [does one thing]. Keep the existing tools unchanged, use type hints, give the tool a one-sentence docstring, and do not use print()." Add one tool per round, then repeat Step 4.

Step 4 — Test it outside Claude

From inside the notebook folder:

uv run mcp dev notebook.py

This opens the MCP Inspector in your browser (it prints a link if the page does not open). Connect, open the tools list, and call add_note with any text, then read_notes. If both work here, the code is fine, and any later problem is in the config, not the server. Press Ctrl+C in the terminal to stop it.

Step 5 — Tell Claude Desktop where the server is

First, get the two absolute paths you need. In the notebook folder, run pwd (Mac) or cd (Windows) for the folder path, and which uv (Mac) or where uv (Windows) for the uv path.

In Claude Desktop, open Settings from the Claude menu in your menu bar or system tray (not the account settings inside the chat window), choose the Developer tab, and click Edit Config. This opens claude_desktop_config.json, which lives at:

Add your server, replacing the two paths with your own:

{
  "mcpServers": {
    "notebook": {
      "command": "/full/path/to/uv",
      "args": ["--directory", "/full/path/to/notebook", "run", "notebook.py"]
    }
  }
}

If the file already contains other servers, add the "notebook" block inside the existing mcpServers section rather than pasting a second one. On Windows, write paths with double backslashes (C:\\Users\\you\\notebook) or forward slashes.

Step 6 — Restart properly

Quit Claude Desktop completely from the menu bar or system tray, not by closing the window, then open it again. The config is only read at start-up.

Check it worked

Check Where What good looks like
Server is listed Click + at the bottom left of the message box, hover over Connectors, choose Manage connectors "notebook" appears with add_note and read_notes
Tool runs Ask: "Use my notebook to save: chase the plumber's quote on Friday." Claude asks permission, then confirms the save
File exists Your home folder claude-notebook.txt contains a dated line
Logs are clean Mac ~/Library/Logs/Claude, Windows %APPDATA%\Claude\logs mcp-server-notebook.log shows no errors

If "notebook" is missing, work through this order: JSON syntax (a missing comma is the usual culprit), absolute paths, full path to uv, a genuine full restart, then the log file.

What to skip

Guardrails

Sources

All 751 AI guides · JulieMango plans from £17/mo