<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[AI Engineer]]></title><description><![CDATA[Builder documenting the journey. This is where I share everything I learn along the way.
From prototypes to production. From ideas to shipped products.]]></description><link>https://ai-engineer-prod.dev</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1763009754888/afb546fa-348d-49bc-8255-3c2cbbf1fe22.png</url><title>AI Engineer</title><link>https://ai-engineer-prod.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Thu, 16 Apr 2026 20:59:34 GMT</lastBuildDate><atom:link href="https://ai-engineer-prod.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[You're Using MCP Wrongly]]></title><description><![CDATA[TL;DR: Many developers overload their MCP setup by wiring every server and tool into one giant agent, causing context bloat, latency, and flaky behavior. Treating MCP like an architecture problem, pruning tools, grouping them by task, and routing wor...]]></description><link>https://ai-engineer-prod.dev/youre-using-mcp-wrongly</link><guid isPermaLink="true">https://ai-engineer-prod.dev/youre-using-mcp-wrongly</guid><category><![CDATA[mcp]]></category><category><![CDATA[#ai-tools]]></category><dc:creator><![CDATA[Darren Lee]]></dc:creator><pubDate>Wed, 19 Nov 2025 03:04:09 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1763521285717/b2175846-564c-4682-a20f-eb32bdde2784.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>TL;DR</strong>: Many developers overload their MCP setup by wiring every server and tool into one giant agent, causing context bloat, latency, and flaky behavior. Treating MCP like an architecture problem, pruning tools, grouping them by task, and routing work through small, focused sub‑agents in Claude, GitHub Copilot, and similar IDEs helps keeps context lean and makes AI orchestration faster, safer, and more predictable.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1763452531650/5b0b072e-7efb-4e79-8bdc-7bcb9c8b8f64.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-introduction">Introduction</h2>
<p>Most developers wire up the Model Context Protocol (MCP) by dumping every tool from every MCP server into a single agent, then wonder why Claude, Cursor, or other AI IDEs feel slow, distracted, and unreliable.<br />The reality is that tool definitions alone can consume 20–30% of a large context window, and when combined with context poisoning risks, this “just connect all the tools” habit quietly destroys both performance and safety.​</p>
<p>In this guide, you’ll learn: what context bloat actually is in the MCP protocol, why “too many tools” breaks agents, how Claude subagents solve this, and how to design a sub-agent architecture that keeps your MCP setup fast, lean, and secure.​</p>
<hr />
<h2 id="heading-quick-refresher-what-mcp-actually-does">Quick Refresher: What MCP Actually Does</h2>
<p>Before debugging context bloat, it helps to restate what the Model Context Protocol is doing inside your stack.​</p>
<ul>
<li><p>MCP is a JSON-RPC–based protocol that lets AI clients like Claude Desktop or Cursor connect to external capabilities through an MCP server.​</p>
</li>
<li><p>An MCP server wraps existing APIs, services, or data (files, databases, SaaS APIs) and exposes them as tools, resources, and prompts that the model can call autonomously.​</p>
</li>
</ul>
<p>In other words, MCP is the translation layer between “LLM wants to act” and “real-world systems that actually do the work”, and that translation happens through tool definitions that live inside the model’s context.</p>
<p>For full details on MCP server you can check out <a target="_blank" href="https://ai-engineer-prod.dev/the-complete-guide-to-model-context-protocol-mcp">the complete guide to Model Context Protocol article</a> that we’ve written earlier. ​</p>
<hr />
<h2 id="heading-the-context-window-reality-check">The Context Window Reality Check</h2>
<p>Modern Claude models and IDE agents advertise huge context windows, up to 200K tokens, but most engineers underestimate how quickly MCP tools can eat that up.​ Every tool your MCP server exposes adds names, descriptions, schemas, examples, and sometimes long-form instructions that the AI needs to read and reason about.​</p>
<p>If you attach a heavy MCP server (for example, one that bundles Playwright, scraping, PDF handling, and more), that one MCP server alone can consume 10% of your usable context, even before you add project files, system prompts, or user instructions.​ If you stack three or four such MCP servers on a single agent and you can easily burn 40K+ tokens just on tool metadata, leaving far less room for the actual task.​</p>
<p>This is the foundation of the <strong>context bloat</strong> and <strong>context poisoning</strong> problem in MCP-based AI orchestration. ​</p>
<h3 id="heading-playwright-mcp-context-side">Playwright MCP context side</h3>
<p>As an example, let’s take a look at Playwright MCP. Claude Code offers a handy <code>/context</code> command that lets you check how much of the context window has been used. From this, you can see that the Playwright MCP alone takes up nearly <strong>8% of the total context window.</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1763512946340/45951aba-8ad7-4b08-be6e-712d6df80f2d.png" alt class="image--center mx-auto" /></p>
<hr />
<h2 id="heading-why-too-many-tools-breaks-your-agent">Why “Too Many Tools” Breaks Your Agent</h2>
<p>The problem is not just “lots of tokens”. It’s how LLMs use those MCP tools when planning and acting.​</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1763451845898/b85b4b59-d2ae-4524-a8e1-6b7680b62b22.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-attention-dilution">Attention Dilution</h3>
<p>Language models don’t call tools blindly. They scan the list of available tools and decide which one looks relevant.​ When you expose 50+ MCP tools, the model must mentally evaluate many irrelevant options for each decision, which adds noise and leads to more indecisive or suboptimal behaviour.​</p>
<h3 id="heading-latency-degradation">Latency Degradation</h3>
<p>Each planning step over a large tool list costs compute and time, so your responses slow down as the MCP tool catalog grows.​ In multi-step workflows such as deep research agents or multi-stage refactors, this overhead compounds, creating 2–3× slower runs compared to a focused tool set.</p>
<h3 id="heading-goal-drift">Goal Drift</h3>
<p>With too many tools visible, the agent often goes off-script: instead of doing the exact thing you asked, sometimes it tries “bonus” actions it thinks might be helpful.​ You requested a simple scrape; it decides to reformat, summarise, and cross-check with other MCP tools, burning context and time on tasks you never asked for.​</p>
<hr />
<h3 id="heading-how-do-we-solve-the-mcp-context-issue-use-sub-agents">How do we solve the MCP context issue? Use sub-agents.</h3>
<p>Right now, MCP servers can’t be limited only to sub-agents while hidden from the main agent. However, we can still achieve the same outcome by enabling the tools globally, but having only the sub-agent execute and think through them.</p>
<p>This matters because reasoning about how to use a tool also consumes tokens. Taking Playwright as an example, the main agent doesn’t need to understand how to operate the tool — it just needs to know whether the result is successful. By delegating execution to a sub-agent, all the “tool-use thinking” is contained within that sub-agent, instead of bloating the main agent’s context.</p>
<p>So instead of imagining an MCP setup as <em>one all-knowing agent with every tool</em>, think in terms of a small hierarchy of agents with clearly separated responsibilities:</p>
<ul>
<li><p><strong>A lead/orchestrator agent</strong><br />  Handles task planning, decomposition, and routing.</p>
</li>
<li><p><strong>Multiple specialized sub-agents</strong><br />  Each handles focused work — research, analysis, execution, validation — and only loads the tools relevant to its job.</p>
</li>
</ul>
<p>Instead of one agent being aware of 60 tools across multiple MCP servers, you might have four sub-agents, each with only 10–15 tools. This dramatically reduces the context overhead required per agent.</p>
<hr />
<h2 id="heading-example-architecture-from-monolith-to-sub-agents">Example Architecture: From Monolith to Sub-Agents</h2>
<p><strong>Lead Agent (Orchestrator)</strong></p>
<ul>
<li><p>Purpose: Understand the user request, break it into steps, and route tasks.​</p>
</li>
<li><p>Tools: Minimal set, often none beyond high-level control and access to a shared memory or queue.​</p>
</li>
</ul>
<p><strong>Research Sub-Agent</strong></p>
<ul>
<li><p>Tools: Web-scraping and browser MCP servers, file readers, basic resource loaders.​</p>
</li>
<li><p>Job: Gather data, fetch content, read documents, then pass structured results back.​</p>
</li>
</ul>
<p><strong>Playwright Sub-Agent</strong></p>
<ul>
<li><p>Tools: Headless browser automation (Playwright MCP server), DOM inspectors, interaction APIs (click, type, navigate), screenshot and PDF capture, network-log hooks.</p>
</li>
<li><p>Job: Execute deterministic browser actions in a controlled environment, then return structured results.</p>
</li>
</ul>
<p><strong>Validation Sub-Agent</strong></p>
<ul>
<li><p>Tools: Test runners, linters, checkers, assertions exposed via dedicated MCP servers.</p>
</li>
<li><p>Job: Verify correctness, run tests, enforce guardrails before results return to the user.</p>
</li>
</ul>
<p>This structure makes the model context protocol feel like a team of AI specialists rather than one overwhelmed intern staring at a wall of tools.​</p>
<hr />
<h2 id="heading-implementation-claude-codes-subagents-and-github-copilots-custom-agents">Implementation: Claude Code’s Subagents and Github Copilot’s Custom Agents</h2>
<p>Both Claude Code and GitHub Copilot use a similar pattern: they break work into smaller, focused agents with their own roles, configuration, and tool access.</p>
<p><strong>In Claude Code</strong>, subagents are first-class implementations of this idea: you can scope them by task or MCP—one for backend microservices, one for frontend UI, another for database migrations—each wired up to different MCP servers. Each subagent has its own context window and configuration file, keeping its working memory small and focused so its reasoning stays clean and isn’t distracted by unrelated tools.</p>
<p><strong>GitHub Copilot</strong>’s custom agents follow the same principle. Each one is defined by a lightweight YAML‑plus‑Markdown agent profile (for example, a *.<a target="_blank" href="http://agent.md">agent.md</a> file in .github/agents/ or your user profile) that sets its role, model, and available tools, effectively acting as a dedicated guide for that persona.​</p>
<p>The result in both systems is the same: small, purpose‑built agents that stay sharp, relevant, and tightly scoped to the task at hand.</p>
<hr />
<h2 id="heading-managing-mcp-servers">Managing MCP servers</h2>
<p>Due to current limitations, you still need to manually enable or disable MCP servers before handing control over to a sub-agent. As of now, there’s no built-in way to expose MCP tools only to a sub-agent while hiding them from the main agent, though I suspect this is likely a feature that will arrive in the near future.</p>
<p>The process varies depending on the platform:</p>
<ul>
<li><p><strong>Claude Code</strong> – Use the <code>/mcp</code> command to view and toggle MCP servers.</p>
</li>
<li><p><strong>GitHub Copilot</strong> – Edit the <code>mcp.json</code> file and comment out the servers you want to disable.</p>
</li>
<li><p><strong>Cursor MCP</strong> – Enable or disable MCP servers directly through the in-app UI settings.</p>
</li>
</ul>
<p>Until tool-scoping becomes native, this manual setup ensures that only the intended sub-agent performs the tool-heavy reasoning, keeping the main agent’s context clean.</p>
<hr />
<h2 id="heading-when-you-dont-need-sub-agents">When You Don’t Need Sub-Agents</h2>
<p>Sub-agents are powerful, but they’re not mandatory for every MCP use case.​</p>
<ul>
<li><p>If you only use 5–10 tools and your workflows are simple, a single well-configured MCP agent might be enough.​</p>
</li>
<li><p>If you lack external memory (database, queue, KV store) to pass data between agents, heavy orchestration may introduce more fragility than value.</p>
</li>
<li><p>When the whole context of the task matters, a single agent would perform better. Since the sub agent will only pass a summary back to the main agent.</p>
</li>
</ul>
<p>In these cases, the main win is still to <strong>prune your MCP servers and tools</strong> so that only essentials are loaded into the main context.​​</p>
<hr />
<h2 id="heading-takeaways-design-around-sub-agents-not-a-giant-tool-wall">Takeaways: Design Around Sub-Agents, Not a Giant Tool Wall</h2>
<p>The default “connect all MCP servers to one agent” pattern is convenient for demos but wasteful and risky in production.​  </p>
<p>By designing around Claude subagents and Github custom agents, and a clear sub-agent architecture, you reclaim valuable context, improve latency, and reduce both distraction and tool poisoning risk.​</p>
<p>The practical next steps are simple! Do a quick audit on which MCP tools are actually used for which tasks, group them into a handful of purpose-built agents, and let a lean orchestrator coordinate the work.​<br />Do that, and your model context protocol setup will feel less like a cluttered toolbox and more like a well-run AI engineering team that knows exactly which MCP server to call, when, and why.​</p>
]]></content:encoded></item><item><title><![CDATA[The complete guide to Model Context Protocol (MCP)]]></title><description><![CDATA[TLDR; Think of Model Context Protocol (MCP) as a “universal language” that lets different AI tools understand and work with each other. If done correctly, MCP helps AI agents to be more effective at using tools.
Introduction
You’re probably here beca...]]></description><link>https://ai-engineer-prod.dev/the-complete-guide-to-model-context-protocol-mcp</link><guid isPermaLink="true">https://ai-engineer-prod.dev/the-complete-guide-to-model-context-protocol-mcp</guid><category><![CDATA[mcp]]></category><category><![CDATA[AI]]></category><category><![CDATA[Developer]]></category><category><![CDATA[Model Context Protocol]]></category><category><![CDATA[ai-agent]]></category><dc:creator><![CDATA[Darren Lee]]></dc:creator><pubDate>Thu, 13 Nov 2025 03:38:29 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1763004859865/9cbc3a49-a134-434b-af22-a13118e1a5f4.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>TLDR; Think of Model Context Protocol (MCP) as a “universal language” that lets different AI tools understand and work with each other. If done correctly, MCP helps AI agents to be more effective at using tools.</p>
<h1 id="heading-introduction">Introduction</h1>
<p>You’re probably here because you’ve heard the buzz about MCP and all of a sudden, every tool you use seems to have its own MCP server. But what is MCP? How does MCP work? And like every developer would ask: <em>“How do I build my own MCP server?”</em> You’re in the right place. I’ve gone down the MCP (Model Context Protocol) rabbit hole to satisfy my curiosity. I’ve consolidated everything I’ve learned here so you don’t have to.</p>
<h2 id="heading-some-context-on-how-mcp-started-and-its-current-state"><strong>Some context on how MCP started and its current state</strong></h2>
<p>Here’s how everything started, Model Context Protocol emerged in November 2024 as Anthropic's open standard for connecting AI systems to external data and tools, solving what developers call the "N×M integration problem." <a target="_blank" href="https://github.com/modelcontextprotocol/inspector"><strong>Within s</strong></a><strong>ix months, MCP achieved adoption by OpenAI, Google DeepMind, and Microsoft</strong>, amassing over 16,000 servers across the ecosystem. Yet beneath this explosive growth lies a more complex reality: 43% of implementations contain critical security vulnerabilities, enterprises face a steep learning curve, and the protocol itself remains in active evolution.</p>
<p>In this guide, I hope to cuts through the hype to deliver actionable intelligence for developers building real-world MCP implementations.</p>
<h3 id="heading-before-mcp">Before MCP</h3>
<p>If you understand the problem MCP solves, its existence makes sense. Developers are used to working with APIs, where they're responsible for preparing the expected input. Take a weather API endpoint—the docs list required parameters like <code>lat</code>, <code>lon</code>, and others. Your job as a developer is to prepare your software to pass exactly what the endpoint expects. Building a weather alert app? You'd load <code>lat</code> and <code>lon</code> from user data, call the API, and return something useful.</p>
<p>!!! Insert diagram</p>
<p>Now imagine you want AI to handle this. You'd need to spell out exactly where to get the data, how to prepare it, and the conditions for each field. You'd repeat this for every single endpoint the AI needs to access. Working with 10 different API providers? Good luck—especially when one endpoint changes and everything breaks.</p>
<h2 id="heading-why-and-how-does-mcp-works">Why and how does MCP works?</h2>
<p>MCP (Model Context Protocol) is a standardized way for APIs to tell AI how to use them—similar to how API documentation tells developers how to use them. The key innovation? It shifts responsibility to the API provider. Instead of developers spelling out every detail for the AI, the weather API itself now tells the AI how to use its endpoints. That's MCP.</p>
<h3 id="heading-a-real-life-example"><strong>A real-life example</strong></h3>
<p>Let’s take a look at <strong>Figma MCP</strong>, to really understand how MCP works.</p>
<p>Let's look at this open-source Figma MCP server. Here's the API endpoint developers had to work with:</p>
<pre><code class="lang-typescript">  <span class="hljs-comment">// Taken from Figma-Context-MCP ./src/services/Figma.ts</span>

  <span class="hljs-comment">/**
   * Get raw Figma API response for specific nodes (for use with flexible extractors)
   */</span>
  <span class="hljs-keyword">async</span> getRawNode(
    fileKey: <span class="hljs-built_in">string</span>,
    nodeId: <span class="hljs-built_in">string</span>,
    depth?: <span class="hljs-built_in">number</span> | <span class="hljs-literal">null</span>,
  ): <span class="hljs-built_in">Promise</span>&lt;GetFileNodesResponse&gt; {
    <span class="hljs-keyword">const</span> endpoint = <span class="hljs-string">`/files/<span class="hljs-subst">${fileKey}</span>/nodes?ids=<span class="hljs-subst">${nodeId}</span><span class="hljs-subst">${depth ? <span class="hljs-string">`&amp;depth=<span class="hljs-subst">${depth}</span>`</span> : <span class="hljs-string">""</span>}</span>`</span>;
    Logger.log(
      <span class="hljs-string">`Retrieving raw Figma node: <span class="hljs-subst">${nodeId}</span> from <span class="hljs-subst">${fileKey}</span> (depth: <span class="hljs-subst">${depth ?? <span class="hljs-string">"default"</span>}</span>)`</span>,
    );

    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.request&lt;GetFileNodesResponse&gt;(endpoint);
    writeLogs(<span class="hljs-string">"figma-raw.json"</span>, response);

    <span class="hljs-keyword">return</span> response;
  }
</code></pre>
<p>To make this useful, developers needed to build additional modules and components around it—just to get information about a single node.</p>
<p><strong>With MCP: Instant Integration</strong><br />Connect your AI agent to the Figma MCP server. It instantly knows what to provide to get node information. No extra setup required.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1763004194706/eaef265a-a630-471b-92d7-dbbec4e684d7.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-a-list-of-mcp-servers">A list of MCP servers</h2>
<p>You can get a list of MCP server <a target="_blank" href="https://www.pulsemcp.com/servers">here</a> or refer to cursor mcp <a target="_blank" href="https://cursor.com/docs/context/mcp/directory">list</a>. But here are a few that I personally find it useful as a developer</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Name</strong></td><td><strong>URL</strong></td><td><strong>Why Useful (For Developers)</strong></td></tr>
</thead>
<tbody>
<tr>
<td>Figma</td><td><a target="_blank" href="https://figma.com">https://figma.com</a></td><td>Figma offers responsive design, advanced component creation, interactive prototyping, and a Dev Mode for precise handoff—making it easier for developers to collaborate with designers, inspect specs, and t<strong>ranslate design into production code efficiently .</strong></td></tr>
<tr>
<td>Task-master</td><td><a target="_blank" href="https://mcpmarket.com/task-master">https://mcpmarket.com/task-master</a></td><td><strong>Task-master automates task planning</strong>, parsing PRDs into actionable tasks, and integrates directly with MCP servers and <strong>AI-driven editors</strong>, allowing developers to streamline workflows, automate CI/CD setup, and focus on coding rather than on meta-work .</td></tr>
<tr>
<td>Context7</td><td><a target="_blank" href="https://upstash.com/context7">https://upstash.com/context7</a></td><td>Context7 plugs <strong>up-to-date, version-specific documentation</strong> and code examples into your workflow, reducing time spent on debugging and validation, thus accelerating development and lowering technical debt for both new and experienced developers .</td></tr>
<tr>
<td>Firecrawl</td><td><a target="_blank" href="https://firecrawl.dev">https://firecrawl.dev</a></td><td>Firecrawl enables fast, scalable web scraping and data extraction, supports <strong>turning URLs into structured LLM-ready data</strong>, automates lead enrichment, supports dynamic content and anti-bot mechanisms, and accelerates agentic AI development for research or production use .</td></tr>
</tbody>
</table>
</div><h2 id="heading-how-to-use-mcp">How to use MCP?</h2>
<p><strong>Using MCP with Cursor and Other AI Tools</strong></p>
<p>You can use MCP with chat models (ChatGPT, Claude), AI-powered IDEs (GitHub Copilot, Cursor, Claude Code), or directly in your terminal. While setup varies by provider, the process typically follows three steps: configure the MCP, get your token, and enable it.</p>
<p><strong>Setting Up Cursor MCP</strong></p>
<p>Cursor maintains an official Cursor MCP list with pre-configured servers. For any MCP in this list, integration is straightforward:</p>
<ol>
<li><p>Open Cursor settings using <code>Ctrl+Shift+P</code> (or <code>Cmd+Shift+P</code> on Mac)</p>
</li>
<li><p>Navigate to the <strong>Tools &amp; MCP</strong> tab</p>
</li>
<li><p>Click the <strong>Add</strong> button next to your desired MCP server</p>
</li>
</ol>
<p>Cursor handles the configuration automatically—no manual setup required.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762937324777/347eb452-a14c-421c-8fa7-9af413c9801f.png" alt class="image--center mx-auto" /></p>
<p>Click <code>install</code> and you’ll see this screen next:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762937513185/d0691349-8037-4024-a3e4-b1cab8aaea14.png" alt class="image--center mx-auto" /></p>
<p>If you expand on the tools, you’ll see exactly what your AI agent (cursor in this case) have access to:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762937556196/a6122797-db8a-453c-b4c1-e9cc5eb773ad.png" alt class="image--center mx-auto" /></p>
<p>Now let’s get to the fun part!</p>
<h1 id="heading-building-your-own-mcp-with-fastmcp">Building your own MCP with FastMCP</h1>
<p>Up to this point, we’ve talked a lot about what is mcp, why mcp and how to use it. Now let’s get our hands dirty. To start off, building an MCP server involves exposing capabilities through <strong>tools</strong> (functions that perform actions), <strong>resources</strong> (data providers), and <strong>prompts</strong> (reusable templates).</p>
<h2 id="heading-what-is-fastmcp">What is FastMCP?</h2>
<p>FastMCP is a Python framework that makes it easy to build MCP servers. It has become the preferred Python frame for this task due to its significant developer experience improvements.</p>
<h3 id="heading-why-use-fastmcp">Why Use FastMCP?</h3>
<p><strong>Before MCP existed</strong>, integrating AI with APIs was painful:</p>
<ul>
<li><p>Developers had to write detailed instructions for every single API endpoint</p>
</li>
<li><p>Each API required custom prompt engineering</p>
</li>
<li><p>When an API changed, everything broke</p>
</li>
<li><p>Managing 10+ different APIs? A maintenance nightmare.</p>
</li>
</ul>
<p><strong>With FastMCP and MCP</strong>, your server tells AI agents exactly how to use it—automatically.</p>
<hr />
<h2 id="heading-understanding-mcp-server-capabilities">Understanding MCP Server Capabilities</h2>
<p>FastMCP lets you expose three types of capabilities:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Capability</td><td>Decorator</td><td>Purpose</td><td>Example</td></tr>
</thead>
<tbody>
<tr>
<td><strong>Tools</strong></td><td><code>@mcp.tool()</code></td><td>Functions that DO things</td><td>Generate fortune, send email, fetch data</td></tr>
<tr>
<td><strong>Resources</strong></td><td><code>@mcp.resource()</code></td><td>Data that can be READ</td><td>View archives, access files, read stats</td></tr>
<tr>
<td><strong>Prompts</strong></td><td><code>@mcp.prompt()</code></td><td>Templates that GUIDE AI behavior</td><td>Personality modes, task instructions</td></tr>
</tbody>
</table>
</div><p><strong>Most MCP servers primarily use Tools.</strong> Resources and Prompts are optional extras for specific use cases.</p>
<hr />
<h2 id="heading-building-your-first-fastmcp-server">Building Your First FastMCP Server</h2>
<h3 id="heading-step-0-prerequisite">Step 0: Prerequisite</h3>
<ol>
<li><p>Install <a target="_blank" href="https://docs.astral.sh/uv/getting-started/installation/">uv</a> (Python package and project manager)</p>
</li>
<li><p>Create a folder with <code>pyproject.toml</code> file</p>
</li>
</ol>
<pre><code class="lang-python">[project]
name = <span class="hljs-string">"a-sample-project"</span>
version = <span class="hljs-string">"1.0.0"</span>
</code></pre>
<h3 id="heading-step-1-install-fastmcp">Step 1: Install FastMCP</h3>
<pre><code class="lang-bash">uv add fastmcp
</code></pre>
<p>After running this you’ll see fastmcp added into your dependencies array in the <code>pyproject.toml</code> file.</p>
<h3 id="heading-step-2-create-your-mcp-server">Step 2: Create Your MCP Server</h3>
<p>Create a file called <code>fortune_teller.py</code>:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> fastmcp <span class="hljs-keyword">import</span> FastMCP

mcp = FastMCP(<span class="hljs-string">"Fortune Teller 🔮"</span>)

<span class="hljs-comment"># TOOL: Performs an action</span>
<span class="hljs-meta">@mcp.tool()</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">predict_fortune</span>(<span class="hljs-params">name: str, category: str = <span class="hljs-string">"random"</span></span>) -&gt; str:</span>
    <span class="hljs-string">"""
    Generate a new fortune prediction.

    Args:
        name: The person's name to personalize the fortune
        category: Type of fortune (career, love, money, or random)

    Returns:
        A personalized fortune message
    """</span>
    <span class="hljs-keyword">import</span> random

    fortunes = {
        <span class="hljs-string">"career"</span>: [
            <span class="hljs-string">f"<span class="hljs-subst">{name}</span>, your next bug fix will be legendary! 🐛→✨"</span>,
            <span class="hljs-string">f"<span class="hljs-subst">{name}</span>, you'll finally understand that legacy codebase! 📚"</span>,
        ],
        <span class="hljs-string">"love"</span>: [
            <span class="hljs-string">f"<span class="hljs-subst">{name}</span>, you'll meet someone special in a GitHub discussion! 💕"</span>,
            <span class="hljs-string">f"<span class="hljs-subst">{name}</span>, your code review will spark romance! ❤️"</span>,
        ],
        <span class="hljs-string">"money"</span>: [
            <span class="hljs-string">f"<span class="hljs-subst">{name}</span>, you'll find a forgotten $20 in your jacket! 💰"</span>,
            <span class="hljs-string">f"<span class="hljs-subst">{name}</span>, your side project will earn DOZENS of dollars! 💸"</span>,
        ],
        <span class="hljs-string">"random"</span>: [
            <span class="hljs-string">f"<span class="hljs-subst">{name}</span>, your code will compile on the first try! 🎯"</span>,
            <span class="hljs-string">f"<span class="hljs-subst">{name}</span>, you'll finally understand async/await! ✨"</span>,
        ]
    }

    fortune_list = fortunes.get(category, fortunes[<span class="hljs-string">"random"</span>])
    <span class="hljs-keyword">return</span> random.choice(fortune_list)

<span class="hljs-comment"># RESOURCE: Provides readable data</span>
<span class="hljs-meta">@mcp.resource("fortune://history")</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">fortune_history</span>() -&gt; str:</span>
    <span class="hljs-string">"""View all past fortune predictions."""</span>
    <span class="hljs-keyword">return</span> <span class="hljs-string">"""
    📜 Fortune History Archive

    Recent fortunes:
    - Alice: Your code will compile on the first try! 🎯
    - Bob: You'll find a forgotten $20 in your jacket! 💰
    - Carol: Your next bug fix will be legendary! 🐛→✨

    Total fortunes predicted: 1,337
    Accuracy rate: 0% (but 100% entertaining!)
    """</span>

<span class="hljs-comment"># PROMPT: Guides the AI's behavior</span>
<span class="hljs-meta">@mcp.prompt()</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">fortune_teller_mode</span>() -&gt; str:</span>
    <span class="hljs-string">"""Activate mystical fortune teller personality."""</span>
    <span class="hljs-keyword">return</span> <span class="hljs-string">"""You are a mystical fortune teller with a quirky sense of humor.

Your role:
- Greet users warmly and ask for their name
- Offer different types of fortunes (career, love, money, random)
- Deliver fortunes with emojis and dramatic flair
- Always end with "The stars have spoken! ✨"

Be entertaining, not accurate!"""</span>

<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:
    mcp.run(transport=<span class="hljs-string">"http"</span>, port=<span class="hljs-number">8000</span>)
</code></pre>
<h3 id="heading-step-3-understanding-your-code">Step 3: Understanding Your Code</h3>
<p><strong>Why docstrings and type hints matter:</strong></p>
<p>FastMCP uses <a target="_blank" href="https://deepwiki.com/modelcontextprotocol/python-sdk/2.4-context-and-lifespan-management">Python's introspection</a> to automatically generate a structured manifest that tells AI agents how to use your tools. Here's what happens:</p>
<pre><code class="lang-python"><span class="hljs-meta">@mcp.tool()</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">predict_fortune</span>(<span class="hljs-params">name: str, category: str = <span class="hljs-string">"random"</span></span>) -&gt; str:</span>
    <span class="hljs-comment">#   ^^^^^^^^^^^^^^  ^^^^       ^^^^^^^^              ^^^</span>
    <span class="hljs-comment">#   |               |          |                     |</span>
    <span class="hljs-comment">#   Tool name       Parameter  Default value         Return type</span>

    <span class="hljs-string">"""
    Generate a new fortune prediction.
    # ↑ Becomes the tool description

    Args:
        name: The person's name to personalize the fortune
        # ↑ Becomes parameter description for 'name'

        category: Type of fortune (career, love, money, or random)
        # ↑ Becomes parameter description for 'category'
    """</span>
</code></pre>
<p><strong>FastMCP converts this into JSON Schema:</strong></p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"predict_fortune"</span>,
  <span class="hljs-attr">"description"</span>: <span class="hljs-string">"Generate a new fortune prediction."</span>,
  <span class="hljs-attr">"inputSchema"</span>: {
    <span class="hljs-attr">"type"</span>: <span class="hljs-string">"object"</span>,
    <span class="hljs-attr">"properties"</span>: {
      <span class="hljs-attr">"name"</span>: {
        <span class="hljs-attr">"type"</span>: <span class="hljs-string">"string"</span>,
        <span class="hljs-attr">"description"</span>: <span class="hljs-string">"The person's name to personalize the fortune"</span>
      },
      <span class="hljs-attr">"category"</span>: {
        <span class="hljs-attr">"type"</span>: <span class="hljs-string">"string"</span>,
        <span class="hljs-attr">"description"</span>: <span class="hljs-string">"Type of fortune (career, love, money, or random)"</span>,
        <span class="hljs-attr">"default"</span>: <span class="hljs-string">"random"</span>
      }
    },
    <span class="hljs-attr">"required"</span>: [<span class="hljs-string">"name"</span>]
  }
}
</code></pre>
<p>This manifest is what AI agents read to understand your tools!</p>
<h3 id="heading-step-4-run-your-fastmcp-server">Step 4: Run Your FastMCP Server</h3>
<pre><code class="lang-bash"> uv run fortune_teller.py
</code></pre>
<p>You should see this:</p>
<pre><code class="lang-bash">

                             ╭──────────────────────────────────────────────────────────────────────────────╮                              
                             │                                                                              │                              
                             │                         ▄▀▀ ▄▀█ █▀▀ ▀█▀ █▀▄▀█ █▀▀ █▀█                        │                              
                             │                         █▀  █▀█ ▄▄█  █  █ ▀ █ █▄▄ █▀▀                        │                              
                             │                                                                              │                              
                             │                               FastMCP 2.13.0.2                               │                              
                             │                                                                              │                              
                             │                                                                              │                              
                             │                  🖥  Server name: Fortune Teller 🔮                           │                              
                             │                                                                              │                              
                             │                  📦 Transport:   HTTP                                        │                              
                             │                  🔗 Server URL:  http://127.0.0.1:8000/mcp                   │                              
                             │                                                                              │                              
                             │                  📚 Docs:        https://gofastmcp.com                       │                              
                             │                  🚀 Hosting:     https://fastmcp.cloud                       │                              
                             │                                                                              │                              
                             ╰──────────────────────────────────────────────────────────────────────────────╯                              


[11/13/25 10:50:35] INFO     Starting MCP server <span class="hljs-string">'Fortune Teller 🔮'</span> with transport <span class="hljs-string">'http'</span> on http://127.0.0.1:8000/mcp      server.py:2050
INFO:     Started server process [788]
INFO:     Waiting <span class="hljs-keyword">for</span> application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
</code></pre>
<p>Your server is now running at <code>http://localhost:8000/mcp</code> 🔮</p>
<hr />
<h2 id="heading-connecting-fastmcp-to-cursor-cursor-mcp-integration">Connecting FastMCP to Cursor (Cursor MCP Integration)</h2>
<p>Now let's connect your FastMCP server to Cursor so the AI can use your tools.</p>
<h3 id="heading-setting-up-cursor-mcp">Setting Up Cursor MCP</h3>
<p><strong>Method 1: Using Cursor's MCP Settings</strong></p>
<ol>
<li><p>Open Cursor and press <code>Ctrl+Shift+P</code> (or <code>Cmd+Shift+P</code> on Mac)</p>
</li>
<li><p>Navigate to <strong>Settings</strong> → <strong>Tools &amp; MCP</strong></p>
</li>
<li><p>Click <strong>New MCP Server</strong></p>
</li>
<li><p>Update the <code>mcp.json</code></p>
</li>
</ol>
<pre><code class="lang-json">{
  <span class="hljs-attr">"mcpServers"</span>: {
    <span class="hljs-attr">"fortune-teller"</span>: {
      <span class="hljs-attr">"url"</span>: <span class="hljs-string">"http://localhost:8000/mcp"</span>,
      <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Fortune Teller 🔮"</span>
    }
  }
}
</code></pre>
<ol start="5">
<li>Head back to the cursor settings and you’ll see this</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1763002470221/7961e219-0f44-477c-bb5e-7df6c967e94c.png" alt class="image--center mx-auto" /></p>
<hr />
<h2 id="heading-how-cursor-mcp-uses-your-fastmcp-tools">How Cursor MCP Uses Your FastMCP Tools</h2>
<p>Let's see what happens when you chat with Cursor after connecting your FastMCP server.</p>
<h3 id="heading-example-conversation">Example Conversation</h3>
<p><strong>You:</strong> "Can you predict my fortune for my career?"</p>
<p><strong>Behind the scenes:</strong></p>
<ol>
<li><p><strong>Cursor checks available tools</strong></p>
<pre><code class="lang-python"> Cursor: <span class="hljs-string">"User wants a fortune prediction. Let me check my tools..."</span>

 Found: predict_fortune <span class="hljs-keyword">from</span> Fortune Teller 🔮
 Needs: name (required), category (optional)
</code></pre>
</li>
<li><p><strong>Cursor plans the call</strong></p>
<pre><code class="lang-python"> Cursor: <span class="hljs-string">"I'll call predict_fortune with:
 - name: 'User' (from context)
 - category: 'career' (user specified)"</span>
</code></pre>
</li>
<li><p><strong>Cursor calls your FastMCP tool</strong></p>
<pre><code class="lang-json"> {
   <span class="hljs-attr">"tool"</span>: <span class="hljs-string">"predict_fortune"</span>,
   <span class="hljs-attr">"arguments"</span>: {
     <span class="hljs-attr">"name"</span>: <span class="hljs-string">"User"</span>,
     <span class="hljs-attr">"category"</span>: <span class="hljs-string">"career"</span>
   }
 }
</code></pre>
</li>
<li><p><strong>Your FastMCP server responds</strong></p>
<pre><code class="lang-json"> {
   <span class="hljs-attr">"result"</span>: <span class="hljs-string">"User, your next bug fix will be legendary! 🐛→✨"</span>
 }
</code></pre>
</li>
<li><p><strong>Cursor formats the response</strong></p>
<pre><code class="lang-python"> Cursor: <span class="hljs-string">"🔮 User, your next bug fix will be legendary! 🐛→✨"</span>
</code></pre>
</li>
</ol>
<h3 id="heading-the-magic-self-describing-tools">The Magic: Self-Describing Tools</h3>
<p>Your FastMCP server <strong>self-describes</strong> its capabilities. Cursor doesn't need manual instructions—it automatically knows:</p>
<ul>
<li><p>What tools are available</p>
</li>
<li><p>What parameters each tool needs</p>
</li>
<li><p>What types those parameters should be</p>
</li>
<li><p>Which parameters are required vs optional</p>
</li>
<li><p>What each parameter means (from your docstrings)</p>
</li>
</ul>
<hr />
<h2 id="heading-testing-you-fastmcp-server-inside-cursor">Testing you FastMCP Server inside Cursor</h2>
<p>Start a new cursor window and open up a new cursor chat. Try asking “Can you predict my fortune for my career”?</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1763002674946/542d22a8-4f54-433e-8c00-4ea3d24ec19f.png" alt class="image--center mx-auto" /></p>
<p>As you can see, the cursor mcp knows you is aware of your MCP can calls the right tool. Depending on your setting, cursor may ask you for permission before running it. If you accept it, here’s what you’ll see.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1763002867638/b80151a7-2e4c-4e19-948b-03f0a71ddfb5.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-testing-your-fastmcp-server">Testing Your FastMCP Server</h2>
<p>You can test your FastMCP server without Cursor using the FastMCP client:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> asyncio
<span class="hljs-keyword">from</span> fastmcp <span class="hljs-keyword">import</span> Client

client = Client(<span class="hljs-string">"http://localhost:8000/mcp"</span>)

<span class="hljs-comment"># Test the tool</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_tool</span>():</span>
    <span class="hljs-keyword">async</span> <span class="hljs-keyword">with</span> client:
        result = <span class="hljs-keyword">await</span> client.call_tool(
            <span class="hljs-string">"predict_fortune"</span>, 
            {<span class="hljs-string">"name"</span>: <span class="hljs-string">"Alice"</span>, <span class="hljs-string">"category"</span>: <span class="hljs-string">"career"</span>}
        )
        print(<span class="hljs-string">f"🔮 <span class="hljs-subst">{result}</span>"</span>)

<span class="hljs-comment"># Test the resource</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_resource</span>():</span>
    <span class="hljs-keyword">async</span> <span class="hljs-keyword">with</span> client:
        history = <span class="hljs-keyword">await</span> client.read_resource(<span class="hljs-string">"fortune://history"</span>)
        print(<span class="hljs-string">f"📜 <span class="hljs-subst">{history}</span>"</span>)

<span class="hljs-comment"># Test the prompt</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_prompt</span>():</span>
    <span class="hljs-keyword">async</span> <span class="hljs-keyword">with</span> client:
        prompt = <span class="hljs-keyword">await</span> client.get_prompt(<span class="hljs-string">"fortune_teller_mode"</span>)
        print(<span class="hljs-string">f"🎭 <span class="hljs-subst">{prompt}</span>"</span>)

<span class="hljs-comment"># Run tests</span>
asyncio.run(test_tool())
asyncio.run(test_resource())
asyncio.run(test_prompt())
</code></pre>
<p>Run the file with <code>uv run test.py</code></p>
<p><strong>Output:</strong></p>
<pre><code class="lang-python">🔮 Alice, your next bug fix will be legendary! 🐛→✨
📜 Fortune History Archive...
🎭 You are a mystical fortune teller...
</code></pre>
<hr />
<h2 id="heading-fastmcp-best-practices-for-ai-friendly-tools">FastMCP Best Practices for AI-Friendly Tools</h2>
<p><strong>Quick Rule:</strong> If a human developer would struggle to understand your function without comments, AI will too. Make everything explicit through docstrings and type hints!</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>✅ DO</td><td>❌ DON'T</td></tr>
</thead>
<tbody>
<tr>
<td><strong>Write Clear Docstrings</strong>. Include purpose, parameters (Args), and return value descriptions. AI reads these to understand your tool.</td><td><strong>Skip Docstrings</strong>. Without docstrings, AI has no context about what your tool does or how to use it properly.</td></tr>
<tr>
<td><strong>Use Type Hints</strong>. Always specify parameter and return types (<code>name: str</code>, <code>age: int</code>). This tells AI exactly what data types to provide.</td><td><strong>Use Vague Function Names</strong>. Avoid generic names like <code>process()</code> or <code>calc()</code>. Use descriptive names like <code>convert_markdown_to_html()</code>.</td></tr>
<tr>
<td><strong>Use Literal for Enums</strong>. For parameters with specific valid values, use <code>Literal["option1", "option2"]</code> to tell AI the exact allowed choices.</td><td><strong>Leave Parameters Untyped</strong>. Untyped parameters default to <code>Any</code>, making it unclear what the AI should provide.</td></tr>
<tr>
<td><strong>Use Descriptive Parameter Names</strong>. Name parameters clearly: <code>birth_year</code> instead of <code>x</code>, <code>email_address</code> instead of <code>data</code>.</td><td><strong>Use Single-Letter Variables</strong>. Avoid unclear names like <code>x</code>, <code>y</code>, <code>data</code>, or <code>input</code> that don't explain what they represent.</td></tr>
<tr>
<td><strong>Document Edge Cases</strong>. Explain constraints in docstrings (e.g., "Cannot divide by zero", "Date must be in ISO format").</td><td><strong>Assume AI Knows Context</strong>. Don't assume AI understands implicit rules or constraints without documentation.</td></tr>
</tbody>
</table>
</div><hr />
<h1 id="heading-conclusion">Conclusion</h1>
<p>So there you have it! Model Context Protocol (MCP) in a nutshell. Instead of wrestling with endless API integrations, MCP lets your tools explain themselves to AI agents. If you've made it this far, you've got everything you need to start building. Spin up a FastMCP server, hook it into Cursor MCP, and watch the magic happen. The MCP protocol is still evolving, but with major players like OpenAI and Google backing it, this is clearly where things are headed. Don't overthink it! Start with something simple, see what MCP can do, and iterate from there. The best way to understand what MCP is all about? Build something with it. Your fortune-telling server is waiting!</p>
]]></content:encoded></item></channel></rss>