MCP Servers and Tools for AI: How We Build Tools That Truly Extend Agent Capabilities — and Who This Path Is For, and Who It Isn't

Imagine: you've connected an MCP server to Claude Desktop or to your agent, the agent "sees" it, the tools are listed — but on the very first real request it picks the wrong tool, sends garbage arguments, and silently gets an error. On the surface everything works. In reality, it doesn't.

This is a typical point where a newcomer to MCP gets stuck. Not on "how to write a server" — that's actually quick. But on tool design, on transports, and on what happens when five other people's servers live next to yours.

MCP (Model Context Protocol) is an open protocol that describes how an AI application (client) communicates with external sources of context and actions (servers). The server declares tools, resources, and prompts; the client reads them and passes them to the model. It's worth understanding this topic because this is exactly where it's decided whether an agent will be useful in real work or remain a demo.

What MCP Actually Gives You and Where the Boundary Lies

The key idea is simple: instead of hardcoding "how to query the database" into the prompt, you describe an action as a tool with a name, description, and argument schema. The model decides on its own when to call it. This removes a huge chunk of logic from the prompt and makes behavior more predictable — but only if the tool description is written for the model, not for a human.

And here's the first non-obvious thing. A tool description is not documentation, it's a prompt. The model sees the name, description, and JSON schema of arguments and chooses based on them. The more tools with similar names you have in your server (get_user, fetch_user, find_user), the higher the chance the agent picks the wrong one. A practitioner limits the set and makes descriptions mutually exclusive.

Key distinction MCP doesn't make the model smarter — it expands the set of actions it chooses from. A poorly designed set of tools degrades the result more than its absence.

Breaking Down One Task: A Server for Working with Tickets

Let's take a concrete case: there's an internal ticketing system, and you want the agent to find a ticket by number, view its status, and move it to another status. Let's break down how a practitioner does this and where things break.

Step 1. Separate reading and writing. Read tools (get_ticket, list_tickets) are safe and can be called freely. The write tool (update_ticket_status) is potentially destructive: the agent might mistakenly move a ticket to "closed." A practitioner either doesn't give the agent write permission at all, or requires explicit confirmation and restricts allowed transitions in the argument schema itself (an enumeration of statuses, not a free string).

Step 2. Make arguments strict. If ticket_id is a string without a format, the model will send "ticket 1234" or "#1234." If it's an integer with the description "numeric identifier without a hash," errors are an order of magnitude fewer. The argument schema is your main tool for protecting against garbage input.

Step 3. Think through the response. The tool returns not the entire database record but a compact result: number, status, date, assignee. If you return 40 fields, you'll eat up the model's context and increase the chance it gets confused on the next step. The tool response is also part of the design.

Step 4. Errors as data, not as a crash. If the ticket doesn't exist, the tool should return a clear "not found" result, not throw an exception that the client shows as a server failure. The model can handle "not found"; with "internal error" it often starts repeating the call.

What will go wrong if you do it differently. Classic scenario: the developer provides one universal tool manage_ticket(action, params) with a free-form parameter string. The model fills params however it can, the server parses it and crashes on half the calls. Second scenario: a write tool without transition restrictions — the agent "closes" tickets that shouldn't be closed, and you only notice it in the logs after the fact.

Transports: Why Choosing stdio or SSE Is Not a Formality

MCP supports several transports, and the choice between them determines where the server can even be run.

  • stdio — the server is launched as a child process of the client, communicating via standard input/output. Simple, local, no network. Downside: one client — one process, doesn't scale horizontally, and logs easily get mixed with the protocol stream.
  • SSE / HTTP — the server lives separately and is accessible over the network. Needed when the server is shared by a team or multiple clients. The price is authentication, network timeouts, access issues.

Rule of thumb: start with stdio, switch to a network transport when the server must serve more than one client. Many projects suffer from the opposite — they immediately set up a network server and then spend time on authentication that isn't needed for a local scenario at all.

What to check first If a stdio server "stays silent" in the client, it's almost always because a logger is writing something to stdout. Service messages must go to stderr, otherwise the protocol stream breaks.

Where the MCP Schema Itself Breaks

These aren't reader errors — they're failure modes of the architecture itself. It's useful to know them in advance.

1. The tool stopped working on the source side. The external API changed its response format or introduced a rate limit. Your server is formally alive but returns garbage. Catch it early: keep a check on the source response and return an explicit "source unavailable" error rather than an empty result. If it's already too late — the call logs show the error rate for a specific tool has risen.

2. The model picks a tool for the wrong purpose. As the number of tools grows (your own + other people's servers), the uncertainty of choice grows. Catch it early: monitor which tools the agent calls on typical requests. If it's already too late — reduce the set, rename conflicting tools, add explicit usage boundaries to descriptions.

3. The client context changed. The client updated, changed how it displays tools or its limit on their number. The server works, but the tools simply don't appear. Catch it early: pin the client version in tests. If it's already too late — check the connection with a minimal server with one tool.

4. The argument schema turned out too loose. At first everything is fine, then the model starts sending arguments that formally pass but are semantically incorrect. Catch it early: validate not only type but also range/format. If it's already too late — tighten the schema and add enumerations instead of free strings.

Learning Paths and Their Honest Price

There are three real routes, and they differ not only in time.

Path Time Money What you get
Self-study from docs and examples weeks, unevenly free a working server, but gaps in tool design and transports
Your own pet project + reading others' code 1–2 months free best for retention, but no feedback on decisions
Structured course more compact course fee ordered topics and analysis of typical mistakes

The self-study path honestly works if you already have experience with APIs and can read specifications. The main barrier is having no one to check your decision against: you've built a tool, it seems to respond, but whether it's designed correctly for the model is unclear. Design errors show up later and cost more than syntax errors.

A course closes exactly this barrier: it covers the design of tools and resources, transports, and how to bring a server to production with monitoring — that is, precisely the places where self-study stalls. If the topic overlaps with agent security, it's useful to also look at the material on AI security and guardrails, and for implementation context — business automation with AI agents.

Who This Path Is For, and Who It Isn't

It's for you if you're a developer with experience working with APIs and JSON, you want to give your agents real actions, not just text, and you're ready to think about tool design, not just code. It's also for those building internal integrations and wanting a standard way to connect sources to different clients.

It's not for you if you're expecting "magic": MCP doesn't decide for you which actions to give the model and how to limit risk. It's not for you if you lack basic experience with HTTP and data schemas — you should close that gap first. And it's not worth going here for a quick result without a willingness to dig into transports and failures.

MCP is about building MCP servers and tools that extend the capabilities of any AI agents and integrations deliberately, not haphazardly. If you want to go through this path with an analysis of typical mistakes and feedback on your decisions — check out MCP Servers and Tools for AI: the topic is covered there from the protocol to a production server with monitoring.

You can start here: Building MCP Servers.

← All posts

Ask AI about this article

Ask a question about this article — ASI Biont will answer based on its text.