Vibecoding Our First MCP Server A developer and their team built a functional MCP server prototype using FastMCP to let AI assistants interact with an accounting API through natural language queries. The server wrapped API endpoints for contacts, invoices, and transactions as MCP tools, enabling users to retrieve data and execute operations without the application UI or direct API calls. After testing locally with Claude Desktop and Kiro, the team extended the server for HTTP access to allow remote colleagues using Langdock to test the system. In the previous posts https://dev.to/dvddpl/vibecoding-in-between-meetings-learning-mcp-servers-and-building-a-poc-with-aws-kiro-dkm of this serie, I covered the why behind this journey: reclaiming building time as an EM, adopting an AI-native SDLC, and understanding what MCP servers actually are. Now it's time to get into the how . Our Product team wanted to explore whether AI assistants could interact with our accounting API and allow customers to query their data and execute transactions through natural language instead of the UI of our application or for the more tech-savyy users making API calls. The user or an agent could simply ask for invoices, contacts, or transactions and get answers, in a human readable format. The first version was deliberately simple. As I described in this post https://dev.to/dvddpl/i-didnt-get-mcp-until-i-built-one-20c5 my team and I had very limited knowledge of MCP servers and add to discover the topic, and learn it while vibe coding the Proof of Concept. It turned out that creating an MCP server with STDIO transport is really trivial. Especially thanks to FastMCP https://gofastmcp.com/ : in the end it's about wrapping the desired endpoints of our API with the @mcp.tool annotation. python from fastmcp import FastMCP from typing import Optional import httpx import os mcp = FastMCP "my-first-mcp" API BASE URL = "https://my.app.de/api/v1" API TOKEN = os.getenv "MY API TOKEN" HEADERS = { "Authorization": API TOKEN, "Content-Type": "application/json", "Accept": "application/json" } @mcp.tool async def get contacts limit: Optional int = 10 - str: """Retrieve contacts from our API.""" async with httpx.AsyncClient as client: response = await client.get f"{API BASE URL}/Contact", headers=HEADERS, params={"limit": limit} response.raise for status data = response.json if not data.get "objects" : return "No contacts found." result = f"Contacts showing {len data 'objects' } :\n" for contact in data "objects" : name = contact.get "name" or "Unknown" customer number = contact.get "customerNumber", "N/A" result += f"• {name} {customer number} \n" return result.strip Replicate for a minimal set of endpoints/methods get invoices , get vouchers , get check accounts , get transactions , create contact , all following the same pattern: call the API, format the response as text, return it - and that's it. Of course, no classes, no separation of concerns, no error handling beyond a basic try/except , but enough to prove the concept works. And it did. We configured it in Claude Desktop and Kiro : { "mcpServers": { "accounting server": { "command": "/Users/you/.local/bin/uv", "args": "--directory", "/path/to/mcp prototype", "run", "poc mcp-server.py" , "env": { "API TOKEN": "