DEV Community

Cover image for Build a Custom MCP Server and Connect It to Your Real App — No Weather API
Jitan Gupta
Jitan Gupta

Posted on

Build a Custom MCP Server and Connect It to Your Real App — No Weather API

Your AI tool can already write code, summarize docs, and answer questions. But can it talk to YOUR app?

MCP — Model Context Protocol is the standard that lets AI tools like Claude, Cowork, and others interact directly with external systems. Not through copy-paste. Not through screenshots. Through actual tool calls that read, create, and update data in your app.

I built an MCP server that connects my AI workflow tool (Cowork) to my Content Board app — a web app where I track every YouTube video from idea to published. One prompt, and Cowork reads data from Firestore, processes it, and writes it back. No manual copy-paste. No tab switching.

Here's how I built it, step by step.

What is MCP? Three Parts, That's It

MCP has three components:

  • Client — the AI tool you're using (Claude Desktop, Cowork, VS Code with Copilot)
  • Server — the bridge you build. It exposes "tools" — list items, get details, update records. The Client decides when to call which tool
  • App — your data layer. Firestore, Postgres, a REST API, whatever your app uses

Client says what it needs. Server translates. App provides the data.

Client (Cowork) ←→ MCP Server ←→ Firestore ←→ Content Board
Enter fullscreen mode Exit fullscreen mode

Note: MCP servers aren't just local. GitHub has hundreds of open-source servers. Companies like Canva, Figma, and Slack ship official MCP integrations. But building your own is how you actually understand what's happening under the hood.

Step 1: Scaffold the MCP Server

I used Claude Code to generate the skeleton. One prompt:

"Create an MCP server. Use TypeScript, MCP SDK, define an entry point, and add a ping tool for health checks."

What it produced — a single index.ts:

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";

const server = new McpServer({
  name: "content-board",
  version: "1.0.0",
});

// Health check tool
server.tool("ping", "Check if the server is running", {}, async () => ({
  content: [{ type: "text", text: "pong" }],
}));

const transport = new StdioServerTransport();
await server.connect(transport);
Enter fullscreen mode Exit fullscreen mode

The package.json pulls in two key dependencies: @modelcontextprotocol/sdk and zod for input validation.

Note: Zod isn't optional here. MCP uses it to define and validate tool input schemas at runtime. Every tool parameter goes through Zod.

Step 2: Test with MCP Inspector (No Claude Needed)

Before connecting to any AI client, test your server standalone using MCP Inspector:

npx @modelcontextprotocol/inspector npx tsx src/index.ts
Enter fullscreen mode Exit fullscreen mode

This opens a browser UI where you can see your tools, run them manually, and inspect responses. No Claude subscription required.

Note: Your dev environment and MCP Inspector run in separate processes. If you set env vars in a .env file, you'll need to add them separately in Inspector's environment panel. This tripped me up — the server kept failing because Inspector couldn't find my Firebase credentials.

Step 3: Build Real Tools — The Part That Matters

I built four tools for my workflow:

  • list_content — list all videos with optional status filter
  • get_content — get full details for one video (including learnings, feedback, production data)
  • create_content — add a new video idea
  • update_content — update any field (status, description, script, etc.)

Here's the key insight — the tool description is the most important part of your MCP server. It's not documentation. It's an instruction for the AI Client to decide when and how to use the tool.

server.tool(
  "list_content",
  `List content items from Content Board.
  Returns: id, title, status, phase, description (truncated).
  Use this to browse what's in the pipeline.
  Supports optional status filter: 'idea', 'draft', 'published'.
  This tool is read-only — it will never modify data.`,
  {
    status: z.string().optional().describe("Filter by status"),
  },
  async ({ status }) => {
    // Firestore query + response formatting
  }
);
Enter fullscreen mode Exit fullscreen mode

If your description is vague, the Client will call the wrong tool or pass wrong parameters. If it's specific — when to use it, what it returns, what it won't do — the Client behaves predictably.

Step 4: Register Locally and Use It

After building and testing all tools in MCP Inspector, register the server locally:

  1. Build the TypeScript project so you have JS output
  2. Edit claude_desktop_config.json (in your user's AppData/Roaming/Claude folder)
  3. Add your server config — command, arguments, environment variables
  4. Restart your AI client

The server shows up as a connector. Now any prompt can use your tools.

The Payoff

I went back to my Cowork session where I'd just approved a video script. One message:

"Here's the video ID — update the shooting script field in Content Board."

Cowork called get_content to load the video details, then update_content to write the script back. Content Board reflected the change on page refresh.

One prompt. Read, process, update. No copy-paste. No tab switching.

See the Full Build

The article covers the pattern, but watching the MCP Inspector debugging, the env var failures, and the live Cowork integration makes it click:

Timestamps for the impatient:

  • 0:00 — What we're building
  • 7:44 — MCP server creation with Claude Code
  • 8:42 — MCP Inspector tutorial
  • 10:00 — Building tools with Firestore
  • 15:09 — Registering in Cowork
  • 16:22 — Key takeaways

What You Walk Away With

  • MCP = Client + Server + App. That's the entire mental model. Everything else is implementation.
  • Tool descriptions are instructions, not docs. The AI Client uses them to decide what to call and when. Be specific about what the tool does AND what it doesn't do.
  • The development pattern is always the same: define tools → test in Inspector → register locally → use. Works for any app, any backend.
  • Start with your own app. Weather API tutorials teach you the SDK. Building for your real workflow teaches you MCP.

Both repos are open source:


I'm building AI workflows for real engineering teams — not toy demos. Follow along if you want the unfiltered version.

Top comments (0)