In my last post, I walked through a RAG pipeline that answers questions from a company policy document. The next question I wanted to answer: what happens when I want other AI systems to use that same capability, without hardcoding a Python import?
That's what pulled me into building an MCP server. In this article, I will explain how I built a custom MCP server that exposes tools to AI agents and how this architecture enables more powerful enterprise AI applications.
What is MCP?
Model Context Protocol is an open protocol that standardizes how AI applications communicate with external tools and data sources.
Instead of creating custom integrations for every AI application, MCP provides a common interface where servers expose tools that AI clients can discover and invoke.
Technology Stack
Python, MCP SDK, Ollama / Local LLM, AI Agent Client, FastAPI (optional integration).
What's actually in the server
I built this with FastMCP, and it currently exposes four tool categories:
- Calculator tools — calculator_add and calculator_multiply.
- search_company_documents — the RAG agent from my last project, but now reached over HTTP instead of a direct function call. The MCP tool sends a request to the RAG agent's FastAPI /search endpoint and returns the answer. This one requires an api_key parameter.
- get_employee_leave — looks up an employee's remaining PTO from an in-memory store. Simple lookup, no external calls.
- get_ticket_information — same pattern, returning ticket status, assigned team, and priority.
Each tool is registered with a @mcp.tool() decorator, which is what makes FastMCP genuinely pleasant to work with.
Challenges I Encountered
The calculator, employee, and ticket tools were straightforward pure functions with no external dependencies. The RAG search tool was a different problem entirely, and it was the hardest part of this whole project.
My RAG agent runs as its own FastAPI service, on its own process, with its own vector store loaded into memory. The MCP server doesn't share any of that — it has to reach across a real network boundary with a plain requests.get() call to http://127.0.0.1:8000/search.
Handling real failure modes like connection refused if the RAG service isn't up, timeouts, a response shape that has to be parsed correctly on the other side.
Future Enhancements
- Extend authentication to the employee and ticket tools, so the protection is uniform rather than partial
- Replace the in-memory employee/ticket dictionaries with a real data source.
- Eventually, wire this MCP server in as the tool layer for a multi-agent workflow — letting a research agent and a writer agent share the same discoverable tool set instead of each having their own direct integrations
Key Takeaways
Building an MCP server changed my perspective on AI applications. The future of enterprise AI is not only about generating better responses. It is about creating systems where AI agents can safely interact with real-world tools and business capabilities.
MCP provides an important foundation for building these next-generation AI applications.
Top comments (5)
I like that you wrapped an existing RAG service instead of rebuilding everything inside the MCP server. Keeping retrieval as its own service makes the architecture much easier to evolve.
One question I had, though: have you thought about resilience between the MCP server and the RAG service? Since they communicate over HTTP, I’d be curious whether you’re using timeouts, retries, circuit breakers, or caching to avoid one service becoming a single point of failure.
Overall, this feels much closer to a production architecture than the typical MCP demos. 🙂
@merbayerp Thank you! I really appreciate that observation.
Right now the setup is intentionally lean — the MCP server calls the RAG service over HTTP with a timeout and a bounded retry, so a slow response doesn't hang the agent indefinitely. I haven't implemented production resilience features like retries, circuit breakers, or caching.
If I were taking this into production, I'd add: Request timeouts and retry logic, Circuit breakers to prevent cascading failures when the RAG service is unavailable and Graceful fallback responses when the retrieval service can't be reached.
I'm planning to explore these patterns as I continue building more production-oriented AI systems.
Nice update!
Just one question: you mention bounded retries already—do you mean advanced retry strategies are the future improvement?
No, what I have today is a very simple bounded retry to avoid failing immediately on a temporary network issue. In future I am planning to optimize it more resiliently using exponential backoff with jitter, configurable retry policies, circuit breakers, and caching to reduce dependency on the RAG service during outages.
That roadmap makes sense. I’d also consider making retries error-aware rather than applying them uniformly. For example, retry transient failures like timeouts or 5xx responses, but fail fast on authentication or validation errors. Pairing that with idempotency, request deadlines, and a correlation ID propagated from the MCP client through the RAG service makes troubleshooting production issues much easier.
At that point, the MCP server starts acting more like a true reliability boundary than just an HTTP proxy. 🙂