import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import z from "zod";
import iconv from "iconv-lite";
const server = new McpServer({
name: "japan-areacode-mcp",
version: "1.0.0",
});
const BASE_URL = "https://www.soumu.go.jp/main_content/000323625.csv"
interface AreaCodeData {
kenCode: string;
sityousonCode: string;
tiikiCode: string;
kenName: string;
sityousonName1: string;
sityousonName2: string;
sityousonName3: string;
yomigana: string;
}
function parseCSV(csvContent: string): AreaCodeData[] {
const lines = csvContent.split("\n");
const data: AreaCodeData[] = [];
for (let i = 1; i < lines.length; i++) {
const line = lines[i].trim();
if (!line) continue;
const columns = line.split(",");
if (columns.length >= 8) {
data.push({
kenCode: columns[0] || "",
sityousonCode: columns[1] || "",
tiikiCode: columns[2] || "",
kenName: columns[3] || "",
sityousonName1: columns[4] || "",
sityousonName2: columns[5] || "",
sityousonName3: columns[6] || "",
yomigana: columns[7] || "",
});
}
}
return data;
}
server.registerTool("list-areacode", {
description: "List all area codes",
outputSchema: z.object({
data: z.array(z.object({
kenCode: z.string(),
sityousonCode: z.string(),
tiikiCode: z.string(),
kenName: z.string(),
sityousonName1: z.string(),
sityousonName2: z.string(),
sityousonName3: z.string(),
yomigana: z.string(),
})),
}),
}, async () => {
const csv = await fetch(BASE_URL);
const arrayBuffer = await csv.arrayBuffer();
const buffer = Buffer.from(arrayBuffer);
const data = iconv.decode(buffer, "shift_jis");
const structuredData = {
data: parseCSV(data),
};
return {
content: [
{
type: "text" as const,
text: JSON.stringify(structuredData, null, 2),
},
],
structuredContent: structuredData,
};
});
server.registerTool("find-areacode", {
description: "Find the area code of a given prefecture",
inputSchema: z.object({
query: z.string(),
}),
outputSchema: z.object({
data: z.object({
kenCode: z.string(),
sityousonCode: z.string(),
tiikiCode: z.string(),
kenName: z.string(),
sityousonName1: z.string(),
sityousonName2: z.string(),
sityousonName3: z.string(),
yomigana: z.string(),
}).nullable(),
}),
}, async ({ query }) => {
const csv = await fetch(BASE_URL);
const arrayBuffer = await csv.arrayBuffer();
const buffer = Buffer.from(arrayBuffer);
const data = iconv.decode(buffer, "shift_jis");
const parsedData = parseCSV(data);
const areaCode = parsedData.find(
(item) =>
item.kenName.includes(query) ||
item.sityousonName1.includes(query) ||
item.sityousonName2.includes(query) ||
item.sityousonName3.includes(query) ||
item.yomigana.includes(query)
);
if (!areaCode) {
return {
content: [
{
type: "text" as const,
text: "No area code found",
},
],
structuredContent: {
data: null,
},
};
}
const structuredData = {
data: areaCode,
};
return {
content: [
{
type: "text" as const,
text: JSON.stringify(structuredData, null, 2),
},
],
structuredContent: structuredData,
};
});
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("Server started");
}
main().catch((error) => {
console.error(error);
process.exit(1);
});