Build Your First MCP Server in Python

Build a local MCP server in Python that gives Claude new tools.

Introduction

30 Second Summary

AI assistants like Claude are powerful, but they're stuck in a box. They can only work with what's in front of them unless you give them a way to reach out and interact with the real world.

In this project, you will build a Python server that gives Claude the ability to search and create notes on your computer. You'll use the Model Context Protocol (MCP), the open standard that AI apps use to connect to external tools and data.

What You'll Build

A local MCP server in Python that exposes custom tools and resources to AI applications through the stdio transport.

By the end of this project, you'll have:

  • A working MCP server with two tools: one to search notes and one to create notes.
  • Hands-on experience using the MCP Inspector to test and debug your server.
  • A live connection between your server and Claude for Desktop, so Claude can use your tools in real conversations.
  • Secret Mission: Add a TODO summary tool that scans all your notes and collects action items.

Are there any prerequisites?

You'll need basic Python knowledge (functions, type hints, async/await). No prior MCP experience is needed.

Install Python and uv

Before you write any code, you need the right tools installed on your machine.

This project uses Python as its programming language and uv as its package manager. You also need Node.js because the MCP Inspector (a testing tool you will use later) runs on it.

In this step, get ready to:
  • Verify that Python 3.10+ is installed on your machine.
  • Install the uv package manager.
  • Verify that Node.js is available for the MCP Inspector.
Verify Python installation

The MCP Python SDK requires Python 3.10 or higher. Let's check what version you have.

  • Open your terminal.
  • Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
  • Type Terminal (macOS) or PowerShell (Windows) and press Enter to open it.
  • Check your Python version by running this command:
python3 --version

Check the version number that appears and pick the tab below that matches what you see.

✔️ I see version 3.10 or higher

Your Python version is compatible. You are ready to move on to the next substep.

ⓧ I see a version lower than 3.10

Your system has an older Python that won't work with the MCP SDK. You need to install a newer version.

  • Visit the official Python downloads page:
  • python.org/downloads
  • Download and install Python 3.10 or higher.
  • During installation on Windows, check the box that says Add Python to PATH.
  • Close and reopen your terminal after installing.
  • Run python3 --version again to confirm the new version appears.

macOS users with an older system Python

macOS ships with an older Python by default. After installing a newer version from python.org, you may need to use python3.12 or python3.13 to invoke the new version directly.

ⓧ Command not found

Python is not installed on your system yet. Let's install it.

  • Visit the official Python downloads page:
  • python.org/downloads
  • Download and install the latest Python version (3.10 or higher).
  • During installation on Windows, check the box that says Add Python to PATH.
  • Close and reopen your terminal after installing.
  • Run python3 --version again to confirm it works.

Windows users

On Windows, try python --version instead of python3 --version. The Python installer on Windows typically registers the command as python rather than python3.

Install uv

The uv package manager is an extremely fast Python project manager. You will use it to create your project, manage dependencies, and run your server.

  • Install uv by running the install command for your operating system:

macOS

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

Windows

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

What does this command do?

This downloads a small installer script from Astral (the company behind uv) and runs it. The script installs the uv binary and adds it to your PATH so you can use it from any terminal window.

  • Close and reopen your terminal so the PATH changes take effect.
  • Verify the installation by running:
uv --version

You should see a version number printed in your terminal.

Command not found after installing uv?

Make sure you fully closed and reopened your terminal after running the install command. The installer updates your shell profile, but existing terminal sessions won't pick up the change.

If it still doesn't work, try opening a brand new terminal window (not a new tab in the same window).

Help me troubleshoot why uv is not found after installing it.

Verify Node.js is available

The MCP Inspector is a browser-based debugging tool you will use to test your server. It requires Node.js v16 or higher to run.

  • Check your Node.js version by running:
node --version

Check the output and pick the tab that matches what you see.

✔️ I see version 16 or higher

Node.js is ready. You have everything you need to continue.

ⓧ I see a version lower than 16

Your Node.js version is too old for the MCP Inspector. You need to upgrade.

  • Visit the official Node.js downloads page:
  • nodejs.org/en/download
  • Download and install the LTS (Long Term Support) version.
  • Close and reopen your terminal after installing.
  • Run node --version again to confirm the updated version.

ⓧ Command not found

Node.js is not installed on your system. Let's install it.

  • Visit the official Node.js downloads page:
  • nodejs.org/en/download
  • Download and install the LTS (Long Term Support) version.
  • Close and reopen your terminal after installing.
  • Run node --version again to confirm it works.

Your development environment is ready. Next up, you will create your MCP server project and install the MCP SDK.

Set Up Your MCP Server Project

Your development tools are ready to go. Now it's time to create the actual project that will become your MCP server.

You'll use uv to scaffold a Python project, install the MCP Python SDK, and write the foundation code that initializes your server.

In this step, get ready to:
  • Create and initialize your project directory with a virtual environment.
  • Install the MCP Python SDK.
  • Create the server file with FastMCP set up.
Create the project directory and initialize it

Every MCP server lives inside its own Python project. The uv tool creates this project structure for you, including a pyproject.toml file for managing dependencies.

  • Move to your Desktop by running this command:
cd ~/Desktop
  • Create your project and move into it by running these commands:
uv init notes-server
cd notes-server

What did uv init create?

The uv init command created a new folder called notes-server containing a pyproject.toml (your project's config file), a main.py placeholder, and a README.md. You'll replace main.py with your own server file shortly.

  • Create a virtual environment for your project by running:
uv venv
  • Activate the virtual environment so your terminal uses the project's own Python:

macOS

source .venv/bin/activate

Windows

.venv\Scripts\activate

You should see (.venv) appear at the beginning of your terminal prompt. This confirms the virtual environment is active.

Don't see (.venv) in your prompt?

Make sure you ran the activation command for your operating system. On macOS it starts with source. On Windows PowerShell, use the backslash path.

If you see a permissions error on Windows, you may need to run Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned in PowerShell first, then try the activation command again.

Help me activate my virtual environment

Install the MCP Python SDK

The MCP Python SDK gives you the FastMCP framework for building servers. It handles all the protocol details so you can focus on writing your tools.

  • Install the MCP SDK with CLI tools by running:
uv add "mcp[cli]"

You should see output showing the package being resolved and installed. When it finishes, your terminal returns to the normal prompt with no errors.

What is mcp[cli]?

The mcp package is the official MCP Python SDK. The [cli] part installs extra CLI utilities that help with running and debugging your server.

Seeing a resolution error?

Make sure your virtual environment is active (you should see (.venv) in your prompt). Also check that you're inside the notes-server directory, not one level above it.

Help me fix my uv add error

Create the notes directory and server file

Your server needs a place to store notes and a Python file to hold the server code. You'll create both now.

  • Create the notes directory and an empty server file by running these commands:
mkdir notes
touch notes_server.py
  • Confirm the files exist by running:
ls

You should see notes and notes_server.py in the output alongside the other files uv init created earlier.

  • Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
  • Type VS Code and press Enter to open it.
  • Click File in the top menu bar.
  • Click Open Folder.
  • Navigate to your Desktop, select the notes-server folder, then click Open.
  • In the Explorer sidebar on the left, click notes_server.py to open it in the editor.

The file is empty right now. You'll add the server initialization code next.

  • Copy the following code into notes_server.py:
import os
from pathlib import Path

from mcp.server.fastmcp import FastMCP

# Initialize FastMCP server
mcp = FastMCP("notes")

# Directory for storing notes
NOTES_DIR = Path(__file__).parent / "notes"
NOTES_DIR.mkdir(exist_ok=True)

What does this code do?

  • from mcp.server.fastmcp import FastMCP imports the FastMCP framework from the official MCP SDK. This gives you decorators for defining tools and resources.
  • mcp = FastMCP("notes") creates your server instance. The string "notes" is the server's name that shows up when AI apps connect to it.
  • NOTES_DIR points to the notes/ folder next to your script. This is where your server will read and write note files.
  • NOTES_DIR.mkdir(exist_ok=True) ensures the directory exists every time the server starts. If it already exists, nothing happens.
  • Save notes_server.py by pressing Cmd+S (macOS) or Ctrl+S (Windows).
  • You should see no red underlines or error squiggles in the editor. The imports resolve because you installed the MCP SDK in the previous substep.

Seeing a red underline on the import?

VS Code may not be using your virtual environment's Python interpreter. Click the Python version in the bottom status bar and select the interpreter from .venv inside your notes-server folder.

If you don't see a Python version in the status bar, make sure you have the Python extension installed in VS Code.

Help me fix my import error in VS Code

✔️ Awesome, I've got everything!

Great. Double check you've saved your file before moving on.

ⓧ I'd like to double check the full code

Here's the complete notes_server.py at this point:

import os
from pathlib import Path

from mcp.server.fastmcp import FastMCP

# Initialize FastMCP server
mcp = FastMCP("notes")

# Directory for storing notes
NOTES_DIR = Path(__file__).parent / "notes"
NOTES_DIR.mkdir(exist_ok=True)

Your project skeleton is in place. Next up, you'll build the tools that give your server its superpowers.

Build Your Tools

Your server has a skeleton: imports, a FastMCP instance, and a notes directory. But right now it can't actually do anything for an AI assistant.

In this step, you'll build the actual capabilities that Claude will use. You'll create two tools (functions an AI can call to take action) and one resource (read-only data an AI can access).

In this step, get ready to:
  • Build a search_notes tool that finds notes matching a keyword.
  • Build a create_note tool that saves new notes to your filesystem.
  • Add a resource and entry point to make the server runnable.
Implement the search_notes tool

The first tool you'll build lets an AI search through your notes for a keyword. When Claude calls this tool, it passes in a query string, and your function searches every .txt file in the notes/ directory for matches.

  • In notes_server.py, find the line that says NOTES_DIR.mkdir(exist_ok=True), then add the following code below it:

@mcp.tool()
async def search_notes(query: str) -> str:
    """Search through all notes for a given query string.

    Args:
        query: The search term to look for in notes
    """
    results = []
    for file in NOTES_DIR.glob("*.txt"):
        content = file.read_text()
        if query.lower() in content.lower():
            results.append(f"**{file.stem}**: {content.strip()}")

    if not results:
        return f"No notes found matching '{query}'."

    return f"Found {len(results)} note(s) matching '{query}':\n\n" + "\n\n".join(results)

What does this code do?

The @mcp.tool() decorator registers this function as a tool that AI clients can discover and call. FastMCP automatically generates the tool's input schema from the type hints (query: str) and description from the docstring.

The function uses NOTES_DIR.glob("*.txt") to find all text files, then checks each file's content for the search query using case-insensitive matching. It returns either a formatted list of matching notes or a friendly "not found" message.

Why async functions?

MCP tools are defined as async functions because the MCP protocol uses asynchronous communication. Even though file reading is quick, the async keyword ensures your tools work correctly within the server's event loop.

  • Save notes_server.py.
  • You won't see a visible change yet. The next chunk adds the create_note tool which pairs with this one.

Seeing a red underline or syntax error?

Make sure you left a blank line between NOTES_DIR.mkdir(exist_ok=True) and the @mcp.tool() decorator. Python requires blank lines between top-level definitions.

Also check that the indentation uses spaces, not tabs. Python is strict about consistent indentation.

Why is my @mcp.tool() decorator showing an error in my editor?

Implement the create_note tool

Your second tool lets an AI create new notes. When Claude calls this tool, it passes a name and content, and your function writes a new .txt file to the notes/ directory.

  • Add the following code directly below the search_notes function you just wrote:

@mcp.tool()
async def create_note(name: str, content: str) -> str:
    """Create a new note with the given name and content.

    Args:
        name: The name for the note (will be used as filename)
        content: The text content of the note
    """
    file_path = NOTES_DIR / f"{name}.txt"
    file_path.write_text(content)
    return f"Note '{name}' created successfully at {file_path}."

What does this code do?

This tool takes two arguments: name (used as the filename) and content (the text to write). It constructs a file path inside NOTES_DIR, writes the content, and returns a confirmation message.

Notice the docstring includes an Args: section. FastMCP uses this to generate descriptions for each parameter, so the AI knows what to pass in.

  • Save notes_server.py.
  • You won't see output yet. The next chunk adds the resource and entry point that makes everything runnable.

Seeing an indentation error?

Make sure there is a blank line between the end of search_notes (its last return statement) and the @mcp.tool() decorator for create_note. Each function definition needs a blank line separator.

My create_note function has an indentation or syntax error. Can you help me fix it?

Add a resource and run entry point

Tools let AI take actions. Resources let AI read data without modifying anything. You'll add a resource that gives Claude a summary of all your notes, plus the entry point that starts the server.

  • Add the following code directly below the create_note function:

@mcp.resource("notes://summary")
async def notes_summary() -> str:
    """Get a summary of all notes in the directory."""
    notes = list(NOTES_DIR.glob("*.txt"))
    if not notes:
        return "No notes found."

    summary_lines = []
    for note in sorted(notes):
        content = note.read_text().strip()
        preview = content[:50] + "..." if len(content) > 50 else content
        summary_lines.append(f"- **{note.stem}**: {preview}")

    return f"You have {len(notes)} note(s):\n\n" + "\n".join(summary_lines)

What's the difference between a tool and a resource?

Tools are actions that change state (like creating a file). Resources are read-only data that AI can access without side effects. The @mcp.resource("notes://summary") decorator registers this function at a specific URI that clients can read.

This resource lists all notes with a 50-character preview of each. It gives Claude a quick overview without needing to search for specific keywords.

  • Now add the entry point that starts the server. Paste this below the notes_summary function:

def main():
    mcp.run(transport="stdio")


if __name__ == "__main__":
    main()

What does this code do?

The main() function starts your MCP server using stdio transport. This means the server communicates via standard input/output using JSON-RPC messages. No HTTP server, no ports, no configuration needed.

The if __name__ == "__main__": guard ensures the server only starts when you run the file directly, not when it's imported.

  • Save notes_server.py.
  • Verify that your file has no syntax errors by running:
python -c "import notes_server; print('Server module loaded successfully')"
  • You should see Server module loaded successfully printed in your terminal. This confirms all your functions are syntactically correct.

Seeing a ModuleNotFoundError or SyntaxError?

If you see a ModuleNotFoundError, make sure your virtual environment is activated. You should see (.venv) at the start of your terminal prompt.

If you see a SyntaxError, check the line number in the error message. Common causes are missing colons after function definitions, mismatched quotes in f-strings, or incorrect indentation.

I'm getting an error when importing my notes_server module. Can you help me debug?

✔️ Awesome, I've got everything!

Great. Make sure you've saved notes_server.py and the import check passed.

ⓧ I'd like to double check the full code

Here's the complete notes_server.py file at this point. Compare yours against it:

import os
from pathlib import Path

from mcp.server.fastmcp import FastMCP

# Initialize FastMCP server
mcp = FastMCP("notes")

# Directory for storing notes
NOTES_DIR = Path(__file__).parent / "notes"
NOTES_DIR.mkdir(exist_ok=True)


@mcp.tool()
async def search_notes(query: str) -> str:
    """Search through all notes for a given query string.

    Args:
        query: The search term to look for in notes
    """
    results = []
    for file in NOTES_DIR.glob("*.txt"):
        content = file.read_text()
        if query.lower() in content.lower():
            results.append(f"**{file.stem}**: {content.strip()}")

    if not results:
        return f"No notes found matching '{query}'."

    return f"Found {len(results)} note(s) matching '{query}':\n\n" + "\n\n".join(results)


@mcp.tool()
async def create_note(name: str, content: str) -> str:
    """Create a new note with the given name and content.

    Args:
        name: The name for the note (will be used as filename)
        content: The text content of the note
    """
    file_path = NOTES_DIR / f"{name}.txt"
    file_path.write_text(content)
    return f"Note '{name}' created successfully at {file_path}."


@mcp.resource("notes://summary")
async def notes_summary() -> str:
    """Get a summary of all notes in the directory."""
    notes = list(NOTES_DIR.glob("*.txt"))
    if not notes:
        return "No notes found."

    summary_lines = []
    for note in sorted(notes):
        content = note.read_text().strip()
        preview = content[:50] + "..." if len(content) > 50 else content
        summary_lines.append(f"- **{note.stem}**: {preview}")

    return f"You have {len(notes)} note(s):\n\n" + "\n".join(summary_lines)


def main():
    mcp.run(transport="stdio")


if __name__ == "__main__":
    main()

Your MCP server is complete. It has two tools and one resource ready for AI clients to use. Next up, you'll test everything interactively using the MCP Inspector.

Test with MCP Inspector

Your MCP server code is complete. Before connecting it to a real AI application, you need a way to confirm your tools and resources actually work.

The MCP Inspector is the official interactive debugging tool for MCP servers. It gives you a browser-based interface where you can call tools, view resources, and see exactly what your server returns. In this step, you will launch the Inspector and verify every piece of your server.

In this step, get ready to:
  • Launch the MCP Inspector and connect it to your server.
  • Test your tools interactively by creating and searching for a note.
  • Test your resource to verify it returns a summary of all notes.
Launch the MCP Inspector

The MCP Inspector runs via npx without requiring installation. It connects to your server's stdio transport and provides a visual interface for testing.

  • First, get the absolute path to your notes-server folder by running this command:
pwd

Note the output. It will be something like /Users/yourname/Desktop/notes-server. You will need this path in the next command.

  • Launch the MCP Inspector by running this command:
npx @modelcontextprotocol/inspector uv --directory [[NOTES_SERVER_PATH="absolute path to your notes-server folder (from pwd output)"]] run notes_server.py

What does this command do?

  • npx @modelcontextprotocol/inspector downloads and runs the MCP Inspector without installing it globally.
  • uv --directory /path/to/notes-server run notes_server.py tells the Inspector to start your Python server using uv from your project directory.
  • The Inspector acts as an MCP client, connecting to your server over stdio and displaying everything in a browser UI.
  • The terminal will display a URL (typically http://localhost:5173 or similar). Open that URL in your browser.
  • You should see the MCP Inspector interface with a server connection pane.

What should I see?

The Inspector opens with a connection panel at the top showing your server's transport type (stdio). Below that, you will see tabs for Tools, Resources, Prompts, and a Notifications pane for server logs.

Inspector not loading?

  • Make sure you replaced the path with your actual absolute path from the pwd output. Relative paths will not work.
  • Confirm your virtual environment is activated. The Inspector needs uv to find your installed packages.
  • Check that Node.js is installed by running node --version in a separate terminal window.

Why isn't my MCP Inspector connecting to my server?

Test your tools interactively

The Tools tab lets you call any tool your server exposes and see the exact response. You will test both create_note and search_notes here.

  • Click the Tools tab in the Inspector.
  • You should see create_note and search_notes listed with their descriptions.
  • Select create_note from the tool list.
  • In the input fields, enter meeting for the name parameter.
  • Enter Discuss project timeline with the team for the content parameter.
  • Click the button to execute the tool.

You should see a success response confirming the note was created.

  • Now select search_notes from the tool list.
  • Enter timeline for the query parameter.
  • Execute the tool.

You should see a result showing 1 note matching your query, with the note name and content you just created.

Why test in the Inspector first?

The Inspector shows you the raw JSON-RPC messages your server sends and receives. If something breaks, you can see the exact error message and input schema.

This is much easier to debug than connecting to Claude for Desktop and wondering why a tool call silently failed.

Tool not returning results?

  • If search_notes returns no matches, make sure you ran create_note first. The notes/ directory starts empty.
  • Check that the search term appears somewhere in the note content you created. The search is case-insensitive but still needs a matching substring.

Why is my search_notes tool not finding my test note?

Test your resource

Resources expose read-only data that AI applications can access. Your notes://summary resource provides a quick overview of all notes in the directory.

  • Click the Resources tab in the Inspector.
  • You should see notes://summary listed.
  • Select it to inspect the content.

You should see a summary showing 1 note with the name and a preview of the content from the note you created earlier.

What is the difference between tools and resources?

Tools perform actions. They take input, do something (create files, search data, call APIs), and return a result. AI models decide when to call them.

Resources expose static or read-only data. They do not take input from the model. Think of them as reference material the AI can consult without triggering side effects.

Resource showing no notes?

  • Confirm you successfully created a note in the Tools tab earlier. The resource reads from the same notes/ directory your tools write to.
  • If the tool responded with a success message but the resource shows nothing, check that notes_server.py has the NOTES_DIR variable pointing to the correct notes/ folder.

Why does my notes://summary resource show no notes even though I created one?

Your server is verified and working. Next up, you will connect it to Claude for Desktop so you can use your tools in real conversations with AI.

Connect to Claude for Desktop

Your server is tested and working. You verified it with the MCP Inspector and confirmed both tools respond correctly.

Now you'll connect the server to Claude for Desktop so Claude can call your tools during real conversations. This is where everything comes together. Instead of testing in a debugging tool, you'll ask Claude questions in plain English and watch it use your MCP server to search and create notes.

In this step, get ready to:
  • Configure the Claude for Desktop config file to recognize your server.
  • Restart Claude and verify the server connection.
  • Test your tools with natural language prompts.
Configure Claude for Desktop

Claude for Desktop reads a JSON config file at startup to know which MCP servers to launch. You need to add your notes server to this config so Claude knows how to start it.

  • First, get the absolute path to your notes-server directory by running this command in your terminal:
pwd

Why do you need the absolute path?

Claude for Desktop launches your server as a background process. It needs the full system path (starting from /) because relative paths won't resolve correctly when Claude starts the process from its own working directory.

  • Copy the path that pwd printed. You'll paste it into the config file shortly.
  • Open the Claude for Desktop config file. On macOS, the file is located at:
~/Library/Application Support/Claude/claude_desktop_config.json
  • Open this file in your code editor. If the file does not exist yet, create it.

Open the config file quickly

You can access this file through Claude for Desktop itself. Click the Claude menu in your system's menu bar, select Settings..., navigate to the Developer tab, and click Edit Config.

  • Replace the contents of the file with the following JSON (or add it if the file is empty):
{
  "mcpServers": {
    "notes-server": {
      "command": "uv",
      "args": [
        "--directory",
        "[[NOTES_SERVER_PATH="/absolute/path/to/notes-server"]]",
        "run",
        "notes_server.py"
      ]
    }
  }
}

What does this config do?

This tells Claude for Desktop to launch your server using uv whenever Claude starts. The --directory flag points uv to your project folder so it finds the virtual environment and dependencies.

The command field is the executable to run. The args array passes the arguments that tell uv to run notes_server.py inside your project directory.

  • Replace the placeholder path with the absolute path you copied from pwd earlier (for example, /Users/yourname/Desktop/notes-server).
  • Save the file.

Common config mistakes

Make sure your path is absolute (starts with /). Relative paths like ./notes-server or ~/Desktop/notes-server will not work. Also check for trailing commas or missing quotes in your JSON.

help me fix my claude_desktop_config.json file

Restart Claude and verify the connection

Claude for Desktop only reads its config file at startup. You need to fully quit and reopen it for the new server to load.

  • Fully quit Claude for Desktop by pressing Cmd+Q (macOS). Closing the window is not enough.
  • Reopen Claude for Desktop.
  • In a new conversation, click the Add files, connectors, and more plus icon in the chat input area.
  • Hover over Connectors.
  • Confirm that notes-server appears in the list.

Server not appearing?

If your server does not show up under Connectors, check the following:

  • Make sure you fully quit Claude (Cmd+Q), not just closed the window.
  • Verify your claude_desktop_config.json has valid JSON syntax (no trailing commas, all strings in double quotes).
  • Confirm the path in your config is absolute and correct. Try running uv --directory /your/path run notes_server.py manually to see if it errors.
  • Check logs at ~/Library/Logs/Claude for connection errors.

my MCP server is not showing up in Claude for Desktop

Test with natural language

Your server is connected. Now you'll test it the way you'd actually use it. Ask Claude to do things with your notes using plain English.

  • In a Claude for Desktop conversation, type the following message and send it:
Create a note called shopping with the content: Buy milk, eggs, bread
  • Claude will ask for permission to use the create_note tool. Click Allow to approve it.
  • Verify Claude confirms the note was created successfully.
  • Now test the search tool. Type and send this message:
Search my notes for milk
  • Approve the search_notes tool when Claude asks for permission.
  • Verify Claude returns results that include your shopping note with "Buy milk, eggs, bread" in it.

Why does Claude ask for permission?

Every MCP tool call requires your explicit approval. This is a safety feature. Your server runs with your user permissions, so Claude always asks before executing any action that could read or write data on your system.

Claude not using your tools?

If Claude responds with general knowledge instead of calling your tools, try being more explicit: "Use the search_notes tool to look for milk in my notes." If tool calls fail silently, check your server logs at ~/Library/Logs/Claude for errors.

help me get Claude to use my MCP tools

Secret mission

Add a TODO Summary Tool

Your MCP server can search and create notes. But what if Claude could scan ALL your notes and pull out every TODO item in one go? Build a tool that aggregates data across multiple files and gives Claude the power to be your personal task manager.

Clean Up Your Resources

Clean Up Your Resources

This project runs entirely locally, so there are no ongoing costs. Decide whether to keep your resources running, pause them to come back later, or delete them entirely.

Resources you used:

  • The notes-server project folder on your Desktop (includes notes_server.py, the notes/ directory, and the .venv virtual environment).
  • The MCP server entry in your Claude for Desktop configuration file (claude_desktop_config.json).

Keep everything running

No action needed. Choose this if you plan to keep building on your MCP server or want Claude to continue using your notes tools.

  • Your server only runs when Claude for Desktop actively calls it (via stdio transport). It does not run in the background or consume resources when idle.
  • The notes/ directory will persist on your machine with any notes you created during testing.

Pause - I'll come back to this later

Disconnect the server from Claude for Desktop so it stops appearing as an available connector. Your project files stay on disk so you can reconnect later.

  • Open ~/Library/Application Support/Claude/claude_desktop_config.json in your code editor.
  • Remove the notes-server entry from the mcpServers object (or replace the entire file contents with {} if it was your only server).
  • Save the file and restart Claude for Desktop with Cmd+Q, then reopen it.
  • To reconnect later, add the server entry back to the config file using the same format from Step 5.

Delete - I don't want to use this again

Remove all project resources and the Claude for Desktop configuration. This fully cleans up everything created during this project.

  • Remove the server from Claude for Desktop by opening ~/Library/Application Support/Claude/claude_desktop_config.json and deleting the notes-server entry from the mcpServers object.
  • Save the file and restart Claude for Desktop (Cmd+Q, then reopen).
  • Delete the project folder by running this command in your terminal:
rm -rf ~/Desktop/notes-server
  • Confirm the folder is gone by running:
ls ~/Desktop | grep notes-server

You should see no output, confirming the folder has been removed.

Nice Work!

Nice Work!

You just built your first MCP server. You now understand the protocol that powers AI tool integrations across Claude, ChatGPT, VS Code, and the rest of the industry.

You've learned how to:

  • Build a Python MCP server using the FastMCP framework, exposing custom tools and resources that AI applications can call.
  • Test and debug your server interactively using the MCP Inspector.
  • Connect your server to Claude for Desktop so Claude can search and create notes on your local system through natural language.
  • Added a TODO summary tool that aggregates data across multiple files and returns a formatted summary.

Ready to quiz yourself?