Build a Weather MCP Server with TypeScript Using HTTP SSE (Part 2)

This tutorial walks through creating a weather‑focused MCP server with the Model Context Protocol TypeScript SDK, explaining Server‑Sent Events, setting up the Node.js environment, writing the TypeScript code, building, running, and testing the HTTP SSE service end‑to‑end.

Ubiquitous Tech
Ubiquitous Tech
Ubiquitous Tech
Build a Weather MCP Server with TypeScript Using HTTP SSE (Part 2)

With the AI boom expected in 2025, MCP services are becoming essential for developers. This article demonstrates how to build a weather‑based MCP server using the Model Context Protocol TypeScript SDK and the HTTP Server‑Sent Events (SSE) communication mode.

SSE is an HTTP‑based streaming mechanism that lets a server push events to a client over a single long‑lived GET request, making it suitable for real‑time updates such as chat, weather forecasts, or news feeds.

Development environment : Install Node.js (recommended via NVM to switch versions easily). Create a project folder and initialize the following package.json (fields translated to English):

{
  "name": "@wuchubuzai/tianqi-mcp-server",
  "version": "0.0.1",
  "description": "Weather‑based MCP Server",
  "author": "AuthorName",
  "type": "module",
  "license": "MIT",
  "main": "bin/index.js",
  "bin": { "tianqi-mcp-server": "dist/index.js" },
  "files": ["dist"],
  "scripts": {
    "build": "tsc && shx chmod +x dist/*.js",
    "prepare": "npm run build",
    "watch": "tsc --watch"
  },
  "dependencies": {
    "@modelcontextprotocol/sdk": "1.10.2",
    "@types/node-fetch": "^2.6.12",
    "express": "^4.18.2",
    "node-fetch": "^3.3.2"
  },
  "devDependencies": {
    "@types/express": "^5.0.1",
    "@types/node": "^22.15.3",
    "shx": "^0.3.4",
    "typescript": "^5.8.3"
  },
  "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org" }
}

Initialize the TypeScript project with the following tsconfig.json:

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "Node16",
    "moduleResolution": "Node16",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true,
    "outDir": "./dist",
    "rootDir": "."
  },
  "include": ["./**/*.ts"],
  "exclude": ["node_modules"]
}

Define the weather tool that will be exposed to the MCP client:

const GET_TIANQI: Tool = {
  name: "get_city_tianqi",
  description: "Return weather information for the queried city based on city name",
  inputSchema: {
    type: "object",
    properties: {
      city: { type: "string", description: "Name of the city to query" }
    },
    required: ["city"]
  }
};
const SUPPORT_TOOLS = [GET_TIANQI] as const;

Implement a helper that fetches weather data from a free API and returns a structured MCP response:

function buildSuccessResponse(text: string) {
  return { content: [{ type: "text", text }], isError: false };
}
function buildErrorResponse(text: string) {
  return { content: [{ type: "text", text }], isError: true };
}
async function handleGetTianqiData(city: string) {
  // Parameter validation
  if (!city) {
    return buildErrorResponse("Incomplete parameters, please ensure city parameter is provided");
  }
  const url = "https://api.susu.cn/API/moji.php?city=" + city + "&n=1";
  const response1 = await fetch(url, { method: "GET" });
  const respBody: any = await response1.json();
  return buildSuccessResponse(JSON.stringify(respBody, null, 2));
}

Set up the Express server, create the SSE transport, register the tool handlers, and start listening on port 3000:

#!/usr/bin/env node
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
import express from "express";
import { CallToolRequestSchema, ListToolsRequestSchema, Tool } from "@modelcontextprotocol/sdk/types.js";
import fetch from "node-fetch";

const app = express();
app.use(express.json());

const transports: Record<string, Record<string, SSEServerTransport>> = { sse: {} };

app.get('/sse', async (req: any, res: any) => {
  console.log("http /sse request start.......");
  const transport = new SSEServerTransport('/messages', res);
  transports.sse[transport.sessionId] = transport;
  res.on('close', () => { delete transports.sse[transport.sessionId]; });

  const server = new Server({ name: "tianqi-mcp-server", version: "0.0.1" }, { capabilities: { tools: {} } });
  server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: SUPPORT_TOOLS }));
  server.setRequestHandler(CallToolRequestSchema, async (request) => {
    try {
      switch (request.params.name) {
        case "get_city_tianqi": {
          const { city } = request.params.arguments as { city: string };
          return await handleGetTianqiData(city);
        }
        default:
          return { content: [{ type: "text", text: `Unknown tool: ${request.params.name}` }], isError: true };
      }
    } catch (error) {
      return { content: [{ type: "text", text: `Error: ${error instanceof Error ? error.message : String(error)}` }], isError: true };
    }
  });

  await server.connect(transport);
  console.log("http /sse request connect");
});

app.post('/messages', async (req: any, res: any) => {
  const sessionId = req.query.sessionId as string;
  const transport = transports.sse[sessionId];
  if (transport) {
    await transport.handlePostMessage(req, res, req.body);
  } else {
    res.status(400).send('No transport found for sessionId');
  }
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log("HTTP SSE Server Started.....");
  console.log(`Server is running on port ${PORT}`);
}).on('error', (err) => {
  console.error('Server error', err);
});

After writing the code, install dependencies with npm install, build the project using npm run build, and start the server with node dist/index.js. The server will expose /sse for SSE connections and /messages for client‑to‑server messages.

Testing can be done with the Cherry Studio client: configure the MCP endpoint as http://<em>your‑host</em>:3000/sse, send a request like {"name":"get_city_tianqi","arguments":{"city":"Beijing"}}, and observe the weather JSON returned from the free API. Console logs show request handling and any errors.

To deploy, place the compiled server on any reachable host and expose the /sse URL. This lightweight HTTP SSE MCP server is well‑suited for enterprise scenarios where a simple, real‑time AI tool integration is needed.

The tutorial illustrates the full development workflow, from environment preparation and project scaffolding to code implementation, building, running, and verification, providing a concrete example of how the Model Context Protocol can be leveraged with TypeScript to create AI‑enabled services.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

TypeScriptMCPNode.jsExpressServer-Sent EventsHTTP SSE
Ubiquitous Tech
Written by

Ubiquitous Tech

A ubiquitous public account for pirate enthusiasts, regularly sharing curated experiences, tech learning, and growth insights. Currently publishing articles on AI RAG customer service, AI MCP technology, and open-source design. Personal free Knowledge Planet: Awakening New World Programmer.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.