UNPKG

aiwen-mcp-server-geoip

Version:

MCP server for using the aiwen geo loc API

431 lines (430 loc) 13 kB
#!/usr/bin/env node import { Server } from "@modelcontextprotocol/sdk/server/index.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js"; import fetch from "node-fetch"; function getApiKey() { const apiKey = process.env.AIWEN_API_KEY; if (!apiKey) { console.error("AIWEN_API_KEY environment variable is not set"); process.exit(1); } return apiKey; } const AIWEN_API_KEY = getApiKey(); function getLocationAccuracy() { const validValues = ["city", "district", "street"]; let v4_acc = process.env.IPV4_ACCURACY || "city"; let v6_acc = process.env.IPV6_ACCURACY || "city"; if (!validValues.includes(v4_acc)) { console.error("Invalid IPV4_ACCURACY. Valid options are: city, district, street"); process.exit(1); } if (!validValues.includes(v6_acc)) { console.error("Invalid IPV6_ACCURACY. Valid options are: city, district, street"); process.exit(1); } console.error("IPv4定位精度 IPV4_ACCURACY: ", v4_acc); console.error("IPv6定位精度 IPV6_ACCURACY: ", v6_acc); return { v4_acc, v6_acc }; } const { v4_acc: IPV4_ACCURACY, v6_acc: IPV6_ACCURACY } = getLocationAccuracy(); // Tool definitions const IP_LOCATION_TOOL = { name: "aiwen_ip_location", description: "IP定位 根据IP地址获取IP位置 大洲、国家、省份、城市(支持城市、区县、街道三种精度)、经纬度、所属机构、运营商、精度等信息", inputSchema: { type: "object", properties: { ip: { type: "string", description: "IP地址 IPv4或IPv6", } }, required: ["ip"], } }; const USER_NETWORK_IP = { name: "user_network_ip", description: "获取当前网络IP地址和IP位置信息(支持城市、区县、街道三种精度),支持IPv4和IPv6", inputSchema: { type: "object", properties: {}, }, }; const IP_USAGE_SCENE = { name: "ip_usage_scene", description: "IP应用场景 根据IP地址获取IP应用场景 输出包括保留IP、未分配IP、组织机构、移动网络、家庭宽带、数据中心、企业专线、CDN、卫星通信、交换中心、Anycast等网络应用场景", inputSchema: { type: "object", properties: { ip: { type: "string", description: "IP地址 IPv4或IPv6", }, }, required: ["ip"], } }; // ip_whois_info const IP_WHOIS_INFO = { name: "ip_whois_info", description: "whois信息 根据IP地址查询Whois注册信息 获取IP所属网段范围、所属机构名称、技术联系人、管理员等信息", inputSchema: { type: "object", properties: { ip: { type: "string", description: "IP地址 IPv4", }, }, required: ["ip"], } }; // ip_as_mapping const IP_AS_MAPPING = { name: "ip_as_mapping", description: "查询IP地址AS号(自治域号)信息", inputSchema: { type: "object", properties: { ip: { type: "string", description: "IP地址 IPv4", }, }, required: ["ip"], } }; // ip_host_info const IP_HOST_INFO = { name: "ip_host_info", description: "IP宿主信息 根据IP地址查询IP的自治域编号(AS Number)、AS名称、运营商、所属机构等归属属性", inputSchema: { type: "object", properties: { ip: { type: "string", description: "IP地址 IPv4", }, }, required: ["ip"], } }; // ip_risk_portrait const IP_RISK_PORTRAIT = { name: "ip_risk_portrait", description: "IP风险画像 根据IP地址获取IP风险画像 识别VPN、代理、秒拨、数据中心、Tor节点、端口扫描、暴力破解等高风险行为,输出风险评分、分级结果、IP位置等信息", inputSchema: { type: "object", properties: { ip: { type: "string", description: "IP地址 IPv4", }, }, required: ["ip"], } }; // ip_identity_check const IP_IDENTITY_CHECK = { name: "ip_identity_check", description: "IP真假人 根据IP地址判断访问者是否为真实用户或机器流量 返回真人概率(real_person_rate)、秒播概率(mb_rate)", inputSchema: { type: "object", properties: { ip: { type: "string", description: "IP地址 IPv4", }, }, required: ["ip"], } }; // ip_industry_classify const IP_INDUSTRY_CLASSIFY = { name: "ip_industry_classify", description: "IPv4行业 查询IP地址行业分类", inputSchema: { type: "object", properties: { ip: { type: "string", description: "IP地址 IPv4", }, }, required: ["ip"], } }; const IP_TOOLS = [ IP_LOCATION_TOOL, USER_NETWORK_IP, IP_USAGE_SCENE, IP_WHOIS_INFO, IP_AS_MAPPING, IP_HOST_INFO, IP_RISK_PORTRAIT, IP_IDENTITY_CHECK, IP_INDUSTRY_CLASSIFY, ]; const API_HOST = "https://api.ipplus360.com"; // API handlers const apiSuffixMap = { ipv4: { city: "ip/geo/v1/city/", district: "ip/geo/v1/district/", street: "ip/geo/v1/street/psi/", }, ipv6: { city: "ip/geo/v1/ipv6/", district: "ip/geo/v1/ipv6/district/", street: "ip/geo/v1/ipv6/street/biz/", }, }; export class AiwenClient { apiHost; apiKey; constructor(apiHost, apiKey) { this.apiHost = apiHost; this.apiKey = apiKey; } checkIpType(ip) { return ip.includes(':') ? 'ipv6' : 'ipv4'; } async coreRequest(url, params) { const commonParams = { key: this.apiKey, channel: 'node_mcp' }; const finalParams = new URLSearchParams({ ...params, ...commonParams }); const fullUrl = `${url}?${finalParams.toString()}`; // logger.debug(`Making request to: ${fullUrl}`); const response = await fetch(fullUrl, { method: 'GET' }); const data = await response.json(); return data; } async ipLocation(ip) { const ipType = this.checkIpType(ip); let apiSuffix; if (ipType === 'ipv4') { apiSuffix = apiSuffixMap.ipv4[IPV4_ACCURACY]; } else { apiSuffix = apiSuffixMap.ipv6[IPV6_ACCURACY]; } const url = `${this.apiHost}/${apiSuffix}`; const params = { ip, coordsys: "WGS84", }; return await this.coreRequest(url, params); } async ipUsageScene(ip) { const ipType = this.checkIpType(ip); let apiSuffix; if (ipType === 'ipv4') { apiSuffix = "ip/info/v1/scene/"; } else { apiSuffix = "ip/info/v1/ipv6Scene/"; } const url = `${this.apiHost}/${apiSuffix}`; const params = { ip, lang: "cn", }; return await this.coreRequest(url, params); } async ipWhoisInfo(ip) { const apiSuffix = "ip/info/v1/ipWhois"; const url = `${this.apiHost}/${apiSuffix}`; return await this.coreRequest(url, { ip }); } async IPAsMapping(ip) { const apiSuffix = "as/info/v1/asWhois"; const url = `${this.apiHost}/${apiSuffix}`; return await this.coreRequest(url, { ip }); } async ipHostInfo(ip) { const apiSuffix = "ip/geo/v1/host/"; const url = `${this.apiHost}/${apiSuffix}`; return await this.coreRequest(url, { ip }); } async ipRiskPortrait(ip) { const apiSuffix = "ip/info/v3/portrait/"; const url = `${this.apiHost}/${apiSuffix}`; return await this.coreRequest(url, { ip }); } async ipIdentityCheck(ip) { const apiSuffix = "ip/info/v1/person/"; const url = `${this.apiHost}/${apiSuffix}`; return await this.coreRequest(url, { ip }); } async ipIndustryClassify(ip) { const apiSuffix = "ip/info/v1/industry/"; const url = `${this.apiHost}/${apiSuffix}`; return await this.coreRequest(url, { ip }); } } const aiwenClient = new AiwenClient(API_HOST, AIWEN_API_KEY); async function handleIPLocation(ip) { const data = await aiwenClient.ipLocation(ip); return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }], isError: false }; } async function handleNetworkIp() { const url = new URL("https://www.ipuu.net/ipuu/user/getIP"); url.searchParams.append("channel", "node_mcp"); const response = await fetch(url.toString()); const data = await response.json(); if (data.code !== 200) { return { content: [{ type: "text", text: `user network ip query failed: ${data.msg || data.code}` }], isError: true }; } const ip = data.data; return await handleIPLocation(ip); } async function handleIPUsageScene(ip) { const data = await aiwenClient.ipUsageScene(ip); return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }], isError: false }; } async function handleIPWhoisInfo(ip) { const data = await aiwenClient.ipWhoisInfo(ip); return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }], isError: false }; } async function handleIPAsMapping(ip) { const data = await aiwenClient.IPAsMapping(ip); return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }], isError: false }; } async function handleIPHostInfo(ip) { const data = await aiwenClient.ipHostInfo(ip); return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }], isError: false }; } async function handleIPRiskPortrait(ip) { const data = await aiwenClient.ipRiskPortrait(ip); return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }], isError: false }; } async function handleIPIdentityCheck(ip) { const data = await aiwenClient.ipIdentityCheck(ip); return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }], isError: false }; } async function handleIPIndustryClassify(ip) { const data = await aiwenClient.ipIndustryClassify(ip); return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }], isError: false }; } // Server setup const server = new Server({ name: "mcp-server/aiwen_geoip", version: "1.0.0", }, { capabilities: { tools: {}, }, }); // Set up request handlers server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: IP_TOOLS, })); const toolHandlers = { aiwen_ip_location: handleIPLocation, user_network_ip: handleNetworkIp, ip_usage_scene: handleIPUsageScene, ip_whois_info: handleIPWhoisInfo, ip_as_mapping: handleIPAsMapping, ip_host_info: handleIPHostInfo, ip_risk_portrait: handleIPRiskPortrait, ip_identity_check: handleIPIdentityCheck, ip_industry_classify: handleIPIndustryClassify, }; server.setRequestHandler(CallToolRequestSchema, async (request) => { try { const handler = toolHandlers[request.params.name]; if (!handler) { return { content: [{ type: "text", text: `Unknown tool: ${request.params.name}` }], isError: true }; } ; if (request.params.name === "user_network_ip") { return await handleNetworkIp(); } const { ip } = request.params.arguments; return await handler(ip); } catch (error) { return { content: [{ type: "text", text: `Error: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } }); async function runServer() { const transport = new StdioServerTransport(); await server.connect(transport); console.error("Awien geoip MCP Server running on stdio"); } runServer().catch((error) => { console.error("Fatal error running server:", error); process.exit(1); });