Creating personal MCP servers
I have started to use Claude and Claude Code a fair bit. I went to a conference in December 2025 where people were talking about MCP servers, and I didn't understand what they were, so I used Claude Code to explore them. It turns out it's not that hard to create your own personal MCP servers!
As background, the Model Context Protocol (MCP) is a way for AI to talk with a system. You use a tool, such as Claude Desktop, and you tell it about MCP servers. The MCP servers provide an endpoint for Claude Desktop to use. For example, if you had an MCP server for Chipotle, the MCP server might let an AI tool look up restaurants by location, get a list of the menu items, or maybe even place an order. MCP servers are kind of like API servers except they're specific to AI tools.
Current locally-created MCP servers
Tools can provide their own MCP servers, but it's also possible to create your own. I currently have these:
fclibrary-mcp: This lets me search the Forsyth County public library's collections.hardcover-mcp: This lets me search my book lists on Hardcover, add books, and update book status. I can't say much about Hardcover except that I switched from Goodreads to it to get API access1.notmuch-mcp: This lets me search mynotmuchemail.org-mcp: This lets me search and edit my org-mode content, including my tasks and projects.orgroam-mcp: This lets me search and edit my org-roam content, which is basically my personal Zettelkastenpinboard-mcp: This lets me search and edit my saved bookmarksreadwise-mcp: This lets me search, add tags, and otherwise edit my Readwise Reader content
I didn't write the code for any of these; I worked with Claude Code to create the MCP servers themselves. I did set standards, e.g. they're all Python-based.
I then added all of these to Claude Desktop so I could use them. Claude Desktop runs these as binaries when it starts, after you update its .json config file, which is a little weird? It's a pipe-based connection not a network connection.
Use cases
Here are some specific examples of things I've done with these:
- Claude Desktop has added tags to my Readwise Reader untagged, unread content, and moved less-relevant/timely content from my "Inbox" to "Later". (I am slowly working through a backlog of years of unread content that I pulled from my pinboard.in unread bookmarks last year.)
- Claude Desktop can look at my unread books from Hardcover and search for whether they are available at the library. It can also recommend new books and add them to my unread list.
- Claude Desktop can add tasks to org projects.
MCP server layout
Here's roughly how one MCP server is laid out:
$ find .
orgroam-mcp/
CONTEXT.md
pyproject.toml
orgroam_mcp/
orgroam_mcp/__init__.py
orgroam_mcp/server.py
The CONTEXT.md file is literally passed to Claude Desktop. It uses natural language to describe the "tools" along with examples.
The pyproject.toml is because I want to have separate Python uv environments per server. Here's the dependencies for this project:
dependencies = [
"mcp[cli]>=1.25,<2",
"orgparse>=0.4",
"mcp-shared",
]
(mcp-shared is another library within the repo for things like logging.)
The server.py uses FastMCP:
mcp = FastMCP("orgroam-mcp", instructions=_load_instructions())
Then there's a function for each MCP tool:
@mcp.tool() def search_notes(query: str, limit: int = 20) -> str:
So for some of these (notably the library-querying MCP server), the Python functions are in turn calling other APIs. In this particular case, orgroam-mcp is reading files on the filesystem in my org-roam directory.
Footnotes:
Goodreads turned off their API in 2020.