WTF is MCP ?


What is MCP and why it matters
MCP is a protocol which standardizes how applications provide context to LLMs. MCP basically allows us to give our LLMs access to various external systems.
Imagine you're building a web application with Supabase as your database. When you need to create tables or run migrations, let’s say you asked an LLM to generate the SQL, then manually executed it.
But what if the LLM could run those migrations for you?
That’s where MCP comes in! With AI tools that support MCP—like Cursor, Windsurf, and Claude Desktop—you can let the LLM interact with your systems directly.
MCP Architecture
MCP follows a client-server architecture with four key components:
Hosts – AI tools like Cursor, Claude, etc.
Clients – Applications that stay connected to MCP servers via hosts.
MCP Servers – Provide context to clients by linking to data sources or external services.
Data Sources – The actual databases, or remote services that MCP servers interact with.
How to use MCP
Let’s take cursor as an example. You can find an MCP section in cursor settings where you can add your MCP. For supabase, you can just add an MCP server by passing the CLI command npx -y @modelcontextprotocol/server-postgres <connection-string>
. You can read more about this here
Now you can ask the cursor chat to query your db or run any migrations in your supabase project and it does it for you.
How to build an MCP server
We’ve seen how to use an MCP server in tools like cursor but do we build one? There are SDKs for building MCP clients and servers in various programming languages like Python, Typescript etc. Let’s use the Typescript SDK in order to build a weather forecast MCP. This is the same example provided in modelcontextprotocol.io for building an MCP server. I’ll try to simplify it here.
Setting Up the Project
First, ensure you have Node.js and npm installed. Then, create a project directory and install the necessary dependencies:. modelcontextprotocol/sdk
is the typescript SDK which I was talking about earlier and zod
is used for schema validation in typescript.
mkdir weather
cd weather
npm init -y
npm install @modelcontextprotocol/sdk zod
npm install -D @types/node typescript
Configuring the Project
Add the following to your package.json
. Adding "type": "module"
means that Node.js will treat your JavaScript files as ECMAScript Modules (ESM) instead of CommonJS (CJS). This helps us in using modern ES module syntax like import/export in our code. The “build” script is to build our project at the end.
"type": "module",
"scripts": {
"build": "tsc && chmod 755 build/index.js"
}
Create a tsconfig.json
and paste the following. This file configures TypeScript compilation settings:
{
"compilerOptions": {
"target": "ES2022",
"module": "Node16",
"moduleResolution": "Node16",
"outDir": "./build",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}
Now add this code in src/index.ts
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
const NWS_API_BASE = "https://api.weather.gov";
const USER_AGENT = "weather-app/1.0";
// Create server instance
const server = new McpServer({
name: "weather",
version: "1.0.0",
});
// Helper function for making NWS API requests
async function makeNWSRequest<T>(url: string): Promise<T | null> {
const headers = {
"User-Agent": USER_AGENT,
Accept: "application/geo+json",
};
try {
const response = await fetch(url, { headers });
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return (await response.json()) as T;
} catch (error) {
console.error("Error making NWS request:", error);
return null;
}
}
interface AlertFeature {
properties: {
event?: string;
areaDesc?: string;
severity?: string;
status?: string;
headline?: string;
};
}
// Format alert data
function formatAlert(feature: AlertFeature): string {
const props = feature.properties;
return [
`Event: ${props.event || "Unknown"}`,
`Area: ${props.areaDesc || "Unknown"}`,
`Severity: ${props.severity || "Unknown"}`,
`Status: ${props.status || "Unknown"}`,
`Headline: ${props.headline || "No headline"}`,
"---",
].join("\n");
}
interface ForecastPeriod {
name?: string;
temperature?: number;
temperatureUnit?: string;
windSpeed?: string;
windDirection?: string;
shortForecast?: string;
}
interface AlertsResponse {
features: AlertFeature[];
}
interface PointsResponse {
properties: {
forecast?: string;
};
}
interface ForecastResponse {
properties: {
periods: ForecastPeriod[];
};
}
// Register weather tools
server.tool(
"get-alerts",
"Get weather alerts for a state",
{
state: z.string().length(2).describe("Two-letter state code (e.g. CA, NY)"),
},
async ({ state }) => {
const stateCode = state.toUpperCase();
const alertsUrl = `${NWS_API_BASE}/alerts?area=${stateCode}`;
const alertsData = await makeNWSRequest<AlertsResponse>(alertsUrl);
if (!alertsData) {
return {
content: [
{
type: "text",
text: "Failed to retrieve alerts data",
},
],
};
}
const features = alertsData.features || [];
if (features.length === 0) {
return {
content: [
{
type: "text",
text: `No active alerts for ${stateCode}`,
},
],
};
}
const formattedAlerts = features.map(formatAlert);
const alertsText = `Active alerts for ${stateCode}:\n\n${formattedAlerts.join("\n")}`;
return {
content: [
{
type: "text",
text: alertsText,
},
],
};
},
);
server.tool(
"get-forecast",
"Get weather forecast for a location",
{
latitude: z.number().min(-90).max(90).describe("Latitude of the location"),
longitude: z.number().min(-180).max(180).describe("Longitude of the location"),
},
async ({ latitude, longitude }) => {
// Get grid point data
const pointsUrl = `${NWS_API_BASE}/points/${latitude.toFixed(4)},${longitude.toFixed(4)}`;
const pointsData = await makeNWSRequest<PointsResponse>(pointsUrl);
if (!pointsData) {
return {
content: [
{
type: "text",
text: `Failed to retrieve grid point data for coordinates: ${latitude}, ${longitude}. This location may not be supported by the NWS API (only US locations are supported).`,
},
],
};
}
const forecastUrl = pointsData.properties?.forecast;
if (!forecastUrl) {
return {
content: [
{
type: "text",
text: "Failed to get forecast URL from grid point data",
},
],
};
}
// Get forecast data
const forecastData = await makeNWSRequest<ForecastResponse>(forecastUrl);
if (!forecastData) {
return {
content: [
{
type: "text",
text: "Failed to retrieve forecast data",
},
],
};
}
const periods = forecastData.properties?.periods || [];
if (periods.length === 0) {
return {
content: [
{
type: "text",
text: "No forecast periods available",
},
],
};
}
// Format forecast periods
const formattedForecast = periods.map((period: ForecastPeriod) =>
[
`${period.name || "Unknown"}:`,
`Temperature: ${period.temperature || "Unknown"}°${period.temperatureUnit || "F"}`,
`Wind: ${period.windSpeed || "Unknown"} ${period.windDirection || ""}`,
`${period.shortForecast || "No forecast available"}`,
"---",
].join("\n"),
);
const forecastText = `Forecast for ${latitude}, ${longitude}:\n\n${formattedForecast.join("\n")}`;
return {
content: [
{
type: "text",
text: forecastText,
},
],
};
},
);
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("Weather MCP Server running on stdio");
}
main().catch((error) => {
console.error("Fatal error in main():", error);
process.exit(1);
});
This code sets up an MCP server using the Model Context Protocol SDK in TypeScript. It provides tools (get-alerts
, get-forecast
) to fetch weather alerts and forecasts from the NWS API based on user-inputted locations.
Running the MCP Server
Now run npm run build
in the terminal. This should create a build folder and index.js file in it.
We can now add this MCP server to cursor. In cursor setting, under MCP section, add an MCP server. The command to be used is node <path to build/index.js>
. Looks the screenshot below, this is how it looks after successfully adding the MCP
Now we can ask Cursor to tell us the weather of any location is the US (because the MCP server uses the NWS API and only US locations are supported).
Simplifying AI Automation with Pre-built MCP Servers
Several platforms provide pre-built MCP servers, making it easy to integrate automation into your tools. Two notable ones are:
Let’s take Smithery’s GitHub MCP server as an example. Instead of manually interacting with GitHub, you can:
✅ Add the MCP server to Cursor (or any AI-powered tool)
✅ Run the provided command with your GitHub Personal Access Token
✅ Start issuing commands like creating repositories, pushing commits, or managing pull requests—just by asking the AI!
Conclusion
MCP unlocks a new level of automation by allowing LLMs to interact with databases, APIs, and other external services in real time. Whether it's managing Supabase migrations or fetching live weather data, MCP makes it possible—without manual intervention!
Want to explore more? Check out modelcontextprotocol.io for in-depth documentation. Thanks for reading and Happy coding!
Subscribe to my newsletter
Read articles from sathwikreddy GV directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

sathwikreddy GV
sathwikreddy GV
Seeking to make an impact in the field of software engineering.