published 09/15/2025
It has been a great time to explore and get my hands-on to MCP servers. The background is that our team want to know and then estimate if it makes sense to build MCP server to connect with our own API for LLM/agent projects.
I have read quite some articles and blogs but only trying it out yourself then can you really know how exactly it works. It is more complicated than using it, which just requiring copy and paste the configuration json and then magic happens.
First thing to know is the protocol and it is important to choose the right one:
The main difference is not just where the server will be run - from your local machine or deployment on cloud infrastructure, but how the connection between server and client is created:
STDIO is enough in case you aim for testing tools or building a server for personal use. It allows you to focus on developing components like tools and prompts.
However, if your goal is to build a MCP server for production, learning and starting from HTTP would be more useful, as it requires more understandings and configurations to set it up properly, kind of like developing a web framework with similar concepts.
Let us move on with some concrete things I have learned. I choose FastMCP library cause its documentation is so easy to follow. If it happens to be new to you, quickly check out the examples here.
You probably have heard about lifespan, if you have used FastAPI before(link). This idea for MCP server is pretty much the same:
Define logic that should be executed once before the server starts receiving request and when the server is shutting down.
Think about what is needed for your server once it starts, probably loading configuration, initializing a LLM client. And what should be done before the server stops, maybe some cleanup or saving some results. Lifespan can be easily utilized for this purpose:
from mcp.server.fastmcp import Context, FastMCP
@asynccontextmanager
async def lifespan(server: FastMCP):
# startup code here
# e.g.
# llm_client = get_llm_client(...)
yield
# shutdown code here
# e.g.
# save_results(...)
mcp = FastMCP(name="Demo", lifespan=lifespan) # Add your lifespan