Skip to main content
Glama

JR East Delay Information MCP Server

by tinjyuu
index.ts3.33 kB
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { z } from "zod"; import * as cheerio from "cheerio"; // Map of area names to JR East train info page paths const AREA_URLS: Record<string, string> = { kanto: "https://traininfo.jreast.co.jp/train_info/kanto.aspx", tohoku: "https://traininfo.jreast.co.jp/train_info/tohoku.aspx", shinetsu: "https://traininfo.jreast.co.jp/train_info/shinetsu.aspx", shinkansen: "https://traininfo.jreast.co.jp/train_info/shinkansen.aspx", choykori: "https://traininfo.jreast.co.jp/train_info/chyokyori.aspx", }; export interface DelayInfo { area: string; line: string; status: string; category: "delay" | "suspension" | "notice" | "other"; error?: string; } /** * Scrape delay information from a JR East area page. * Returns array of DelayInfo without the area property (added later). */ export async function scrapeArea(url: string): Promise<Omit<DelayInfo, "area">[]> { const res = await fetch(url); if (!res.ok) { throw new Error(`Failed to fetch ${url}: ${res.status}`); } const html = await res.text(); const $ = cheerio.load(html); const results: Omit<DelayInfo, "area">[] = []; $(".rosenBox").each((i, el) => { const lineName = $(el).find(".rosen_nameBox_inn .name").text().trim(); const status = $(el).find(".rosen_infoBox .status").text().trim(); const detail = $(el).find(".rosen_infoBox .status_Text").text().trim(); if (!lineName || !status) return; // 平常運転はスキップ if (/平常運転|Normal operation/.test(status)) return; let category: DelayInfo["category"] = "other"; if (/遅延|Delay/.test(status)) category = "delay"; else if (/運休|Suspension|Suspend/.test(status)) category = "suspension"; else if (/お知らせ|Notice/.test(status)) category = "notice"; results.push({ line: lineName, status: detail ? `${status} ${detail}` : status, category, }); }); return results; } async function main() { const server = new McpServer({ name: "jr-east-delay", version: "1.0.0", }); // Tool: getDelays server.tool( "getDelays", { area: z.enum(["kanto", "tohoku", "shinetsu", "shinkansen"]).optional(), }, async ({ area }) => { const areas = (area ? [area] : Object.keys(AREA_URLS)) as Array<keyof typeof AREA_URLS>; const allResults: DelayInfo[] = []; for (const a of areas) { try { const url = AREA_URLS[a]; const res = await scrapeArea(url); res.forEach((r) => allResults.push({ area: a, ...r })); } catch (err) { allResults.push({ area: a, line: "", status: "", category: "other", error: (err as Error).message }); } } const text = allResults.length > 0 ? allResults .map((r) => r.error ? `[${r.area}] ERROR: ${r.error}` : `[${r.area}] ${r.line}: ${r.status}` ) .join("\n") : "No delays found."; return { content: [ { type: "text", text, }, ], }; } ); const transport = new StdioServerTransport(); await server.connect(transport); } await main();

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/tinjyuu/mcp-jr-east-delay'

If you have feedback or need assistance with the MCP directory API, please join our Discord server