@littlesirius/get-local-ipinfo-mcp
Version:
MCP 工具服务:获取本机公网 IP 及地理位置信息,支持反爬虫和速率限制处理。
138 lines (137 loc) • 4.75 kB
JavaScript
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
const server = new McpServer({
name: "get-local-ipinfo-mcp", // 修改为新名称
version: "1.0.0",
capabilities: {
resources: {},
tools: {
enabled: true,
},
},
});
/**
* 获取当前主机的公网 IP 及地理位置信息
* 优先使用 ipapi.co,自动伪造请求头,支持速率/反爬虫错误处理。
* @returns {Promise<object>} 成功时返回 IP 信息对象,失败时返回错误对象(含 HTTP 状态码、原因等)。
*/
async function getIPInfo() {
try {
// 动态导入 node-fetch 以兼容 CommonJS/ESM
const fetch = (await import("node-fetch")).default;
// 发送请求到 ipapi.co,获取 JSON 格式的 IP 信息
const response = await fetch("https://ipapi.co/json/", {
headers: {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36",
Accept: "application/json, text/plain, */*",
},
});
const data = await response.json();
// 如果 API 返回错误(如限流),直接返回错误信息
if (data.error) {
console.error("ipapi.co 响应原始数据:", data);
return {
error: true,
message: data.message || "未知错误",
reason: data.reason || "",
status: response.status,
};
}
// 定义 zod schema
const ipInfoSchema = z.object({
ip: z.string(),
network: z.string().optional(),
version: z.string().optional(),
city: z.string().optional(),
region: z.string().optional(),
country: z.string().optional(),
latitude: z.number().optional(),
longitude: z.number().optional(),
});
// 校验和解析 data
const result = ipInfoSchema.safeParse(data);
if (!result.success) {
console.error("ipapi.co 响应原始数据:", data);
console.error("IP信息解析失败:", result.error);
return {
error: true,
message: "IP信息解析失败",
reason: result.error.message,
status: response.status,
};
}
const ipInfo = result.data;
// 打印 IP 信息到 stderr,便于调试
console.error("IP信息:", ipInfo);
return ipInfo;
}
catch (error) {
// 捕获并输出错误信息
console.error("获取IP信息失败:", error);
}
}
/**
* 注册 MCP 工具方法 get_public_ip_info
* 工具描述:获取当前主机公网 IP 地址及相关信息,自动处理 API 错误和限流。
*/
server.tool("get_public_ip_info", "获取公网 IP 地址信息", {}, async () => {
// 调用辅助函数获取 IP 信息
const ipInfo = await getIPInfo();
if (!ipInfo || ("error" in ipInfo && ipInfo.error)) {
// 获取失败时返回详细错误文本
const err = ipInfo;
let text = "获取公网 IP 信息失败。";
if (err && err.status !== undefined) {
text += `\nHTTP状态码: ${err.status}`;
}
if (err && err.message) {
text += `\n原因: ${err.message}`;
}
if (err && err.reason) {
text += `\n详情: ${err.reason}`;
}
return {
content: [
{
type: "text",
text,
},
],
};
}
// 拼接详细信息文本,便于展示
const info = ipInfo;
const infoText = [
`IP: ${info.ip}`,
`Network: ${info.network}`,
`Version: ${info.version}`,
`City: ${info.city}`,
`Region: ${info.region}`,
`Country: ${info.country}`,
`Latitude: ${info.latitude}`,
`Longitude: ${info.longitude}`,
].join("\n");
// 返回 IP 信息文本内容
return {
content: [
{
type: "text",
text: infoText,
},
],
};
});
/**
* MCP 服务器主入口
* 使用 stdio 作为传输层,启动后等待请求。
*/
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("get-local-ipinfo MCP 服务器已通过 stdio 运行");
}
main().catch((error) => {
console.error("main() 中发生致命错误:", error);
process.exit(1);
});