Most teams write their first MCP server in an afternoon and then lose a week to the second one.
The first server is easy because you are the only user. It runs over stdio on your laptop, you point one client at it, and the tools work. Nothing about that setup tells you what happens when someone else needs it.
Then the questions start. Who is allowed to call this tool? What happens when a call returns the wrong shape and the model acts on it anyway? How do you ship the config to a team without pasting tokens into a Slack thread?
That is the real curve, and it is worth knowing the shape of it before you start.
The three primitives are enough for most work: tools the model can call, resources it can read, and prompts it can reuse. Transport is stdio while it is local, and streamable HTTP once it is not.
Two things I would decide early. Scope the credentials narrowly, because an MCP server is a door into whatever it is wired to, so a read replica and a scoped token beat your own credentials every time. And keep the tool count low, because every extra tool is another line in the model's decision space and most agents get worse, not better, past a dozen of them.
Full walkthrough, from first server in Python or TypeScript through production deployment with OAuth and debugging: https://www.adaptiverecall.com/mcp-servers/