<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Thuận Lê</title>
    <description>The latest articles on DEV Community by Thuận Lê (@leo17).</description>
    <link>https://dev.to/leo17</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3972455%2Fe218f015-e5ce-4247-93e6-01a392ee76d6.jpg</url>
      <title>DEV Community: Thuận Lê</title>
      <link>https://dev.to/leo17</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/leo17"/>
    <language>en</language>
    <item>
      <title>I built 3 MCP servers in a day — then used one to audit and fix my own sites</title>
      <dc:creator>Thuận Lê</dc:creator>
      <pubDate>Sun, 07 Jun 2026 11:43:09 +0000</pubDate>
      <link>https://dev.to/leo17/i-built-3-mcp-servers-in-a-day-then-used-one-to-audit-and-fix-my-own-sites-119p</link>
      <guid>https://dev.to/leo17/i-built-3-mcp-servers-in-a-day-then-used-one-to-audit-and-fix-my-own-sites-119p</guid>
      <description>&lt;p&gt;Most MCP examples I'd seen stopped at a "hello world" weather tool. I wanted to know what it takes to build &lt;em&gt;real&lt;/em&gt; ones — so in one day I built three Model Context Protocol servers, each a different shape, and then pointed one of them at my own production sites. It found real problems. I fixed them. Here are the numbers and what I learned.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick context: what an MCP server is
&lt;/h2&gt;

&lt;p&gt;An MCP (Model Context Protocol) server gives an AI assistant like Claude a set of typed tools it can call. Instead of pasting data into a chat, you expose your system — a database, an API, whatever — as tools, and the model calls them with structured arguments. You write the server once; any MCP client can use it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three servers, three shapes
&lt;/h2&gt;

&lt;p&gt;I picked three different "shapes" on purpose, so I wasn't rebuilding the same thing three times:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. stayhub-mcp — wrapping a database.&lt;/strong&gt; Read-only tools over the Postgres database of StayHub, a booking app I built (Prisma + Neon). Five tools: search listings, listing detail, booking stats, top cities by revenue, and availability for a date range. Now I can ask Claude "top cities by bookings this month?" and it queries the DB.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. web-audit-mcp — wrapping external APIs.&lt;/strong&gt; Three tools to audit any URL: &lt;code&gt;audit_performance&lt;/code&gt; (Google PageSpeed / Lighthouse), &lt;code&gt;audit_seo_meta&lt;/code&gt; (parse title / description / Open Graph / headings with cheerio), and &lt;code&gt;check_headers&lt;/code&gt; (status + security headers). No database — just HTTP.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. deploy-status-mcp — wrapping DevOps APIs.&lt;/strong&gt; Read-only deployment status across Cloudflare Pages, Vercel, and Netlify. "Did my last deploy succeed?" without leaving the editor.&lt;/p&gt;

&lt;p&gt;All three share the same small stack: TypeScript + the MCP SDK + Zod for input validation + dotenv. Each one has an end-to-end test that spawns the real server over stdio and calls every tool. Secrets go in a gitignored &lt;code&gt;.env&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fun part: dogfooding
&lt;/h2&gt;

&lt;p&gt;The second server, web-audit-mcp, turned out to be the most useful — because I immediately ran it on my own sites.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;My portfolio (static HTML on Cloudflare Pages):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The audit flagged the title (71 chars) and meta description (181 chars) as too long for Google — they'd be truncated in search results. Easy fix.&lt;/li&gt;
&lt;li&gt;Performance was 73 on mobile, with a slow First Contentful Paint of 3.3s. The cause was a render-blocking Google Fonts stylesheet. I switched it to a non-blocking load (&lt;code&gt;preload&lt;/code&gt; + &lt;code&gt;media="print" onload&lt;/code&gt;). Result: &lt;strong&gt;FCP 3.3s → 1.7s, Performance 73 → 97.&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A lesson hid in here. One run reported LCP at 4.4s, and I almost started "optimizing" the hero animation. But re-running the audit showed LCP at 1.7s consistently — the 4.4s was just lab-measurement variance. The fix that mattered (the font) was already done. Without re-measuring, I'd have "fixed" something that wasn't broken.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;My SaaS (StayHub, Next.js on Vercel):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The audit found no Open Graph tags on the homepage — so sharing the link on Facebook / Zalo showed no preview card. I added Open Graph + Twitter Card metadata and a branded &lt;code&gt;opengraph-image.tsx&lt;/code&gt; (generated with &lt;code&gt;next/og&lt;/code&gt;). Now shares show a proper card.&lt;/li&gt;
&lt;li&gt;After the fix: &lt;strong&gt;SEO warnings → 0.&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And the best part: dogfooding found a bug &lt;em&gt;in my own tool&lt;/em&gt;. The audit reported a heading as "Nghỉ dưỡngHoàn hảo" — two words glued together. The site was fine; my tool was extracting text and ignoring &lt;code&gt;&amp;lt;br&amp;gt;&lt;/code&gt; tags. So I fixed the tool to treat &lt;code&gt;&amp;lt;br&amp;gt;&lt;/code&gt; as whitespace. You only find that kind of thing by using what you build.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd tell myself before starting
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pick different shapes.&lt;/strong&gt; Three database wrappers would have taught me one thing three times. DB / external API / DevOps taught me three.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep tools read-only when you can.&lt;/strong&gt; All of mine only read. That makes them safe to point at production and removes a whole class of "oops" — and honestly, read tools cover most of what you actually want from an assistant.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write an end-to-end test.&lt;/strong&gt; Spawning the real server over stdio and calling each tool caught more than a unit test would have, and it doubles as living documentation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dogfood immediately.&lt;/strong&gt; The audit server only earned its keep when I ran it on my own sites — and it paid me back by finding real issues &lt;em&gt;and&lt;/em&gt; a bug in itself.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The three repos are open source (MIT):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;stayhub-mcp&lt;/strong&gt; — &lt;a href="https://github.com/LEO17061996/stayhub-mcp" rel="noopener noreferrer"&gt;https://github.com/LEO17061996/stayhub-mcp&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;web-audit-mcp&lt;/strong&gt; — &lt;a href="https://github.com/LEO17061996/web-audit-mcp" rel="noopener noreferrer"&gt;https://github.com/LEO17061996/web-audit-mcp&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;deploy-status-mcp&lt;/strong&gt; — &lt;a href="https://github.com/LEO17061996/deploy-status-mcp" rel="noopener noreferrer"&gt;https://github.com/LEO17061996/deploy-status-mcp&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you've been reading about MCP but haven't built one, pick something you already own — a database, an API you call a lot, your deployment dashboard — and wrap it. The second one is much faster than the first.&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>claude</category>
      <category>typescript</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
