ipgeolocation-io-mcp 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +606 -0
- package/dist/client.d.ts +97 -0
- package/dist/client.js +173 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +31 -0
- package/dist/tools/abuse.d.ts +2 -0
- package/dist/tools/abuse.js +49 -0
- package/dist/tools/asn.d.ts +2 -0
- package/dist/tools/asn.js +59 -0
- package/dist/tools/astronomy.d.ts +2 -0
- package/dist/tools/astronomy.js +140 -0
- package/dist/tools/geolocation.d.ts +2 -0
- package/dist/tools/geolocation.js +261 -0
- package/dist/tools/security.d.ts +2 -0
- package/dist/tools/security.js +95 -0
- package/dist/tools/timezone.d.ts +2 -0
- package/dist/tools/timezone.js +168 -0
- package/dist/tools/useragent.d.ts +2 -0
- package/dist/tools/useragent.js +78 -0
- package/package.json +64 -0
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { getIpGeolocation, getIpGeolocationBulk, getMyIp } from "../client.js";
|
|
3
|
+
export function registerGeolocationTools(server) {
|
|
4
|
+
server.registerTool("lookup_ip", {
|
|
5
|
+
title: "IP Geolocation Lookup",
|
|
6
|
+
annotations: {
|
|
7
|
+
readOnlyHint: true,
|
|
8
|
+
},
|
|
9
|
+
description: `Look up geolocation data for a single IP address or domain using ipgeolocation.io's unified endpoint (GET /v3/ipgeo). Costs 1 credit per request on all plans.
|
|
10
|
+
|
|
11
|
+
FREE PLAN returns: ip, location (continent, country, state, district, city, zipcode, latitude, longitude, is_eu, country_flag, country_emoji, geoname_id), country_metadata (calling_code, tld, languages), currency (code, name, symbol), time_zone (name, offset, DST info, current_time), and basic ASN (as_number, organization, country). The fields and excludes parameters work on the free plan. Domain lookups and the include parameter are not available on the free plan. The lang parameter returns a 401 error on the free plan for any language other than en.
|
|
12
|
+
|
|
13
|
+
PAID PLANS return everything above plus: network (connection_type, route, is_anycast), company (name, type, domain), and extended ASN (as_number, organization, country, type, domain, date_allocated, rir). The ASN object identifies the organization that holds the IP block allocation from a Regional Internet Registry (ARIN, RIPE, APNIC, etc.). The company object identifies the organization actually using the IP address. These are often the same, but differ when the ASN holder subleases IP space to another organization. For example, the ASN holder might be a cloud provider like Amazon while the company is a business running its infrastructure on that cloud. Paid plans also enable the include parameter to add extra modules: security (+2 credits, 3 total), abuse (+1 credit, 2 total), hostname (+0), liveHostname (+0), hostnameFallbackLive (+0), user_agent (+0), geo_accuracy (+0), dma_code (+0), or * for all (4 credits total). Paid plans support the lang parameter for non-English responses and can look up domains in addition to IPs. Tip: use include=security&fields=security to get only security data for 2 credits instead of 3.
|
|
14
|
+
|
|
15
|
+
If no IP is provided, returns data for the caller's IP. For basic ASN info on the free plan, use this tool. For detailed ASN data (peers, routes, WHOIS), use lookup_asn instead (paid only). For standalone security checks at 2 credits each, use check_security instead. For standalone abuse lookups at 1 credit, use get_abuse_contact instead.`,
|
|
16
|
+
inputSchema: {
|
|
17
|
+
ip: z
|
|
18
|
+
.string()
|
|
19
|
+
.optional()
|
|
20
|
+
.describe("IPv4 address, IPv6 address, or domain name to look up. Domain lookups require a paid plan. Omit to use the caller's IP."),
|
|
21
|
+
lang: z
|
|
22
|
+
.string()
|
|
23
|
+
.optional()
|
|
24
|
+
.describe("Response language code (en, de, ru, ja, fr, cn, es, cs, it, ko, fa, pt). Paid plans only. Free plan returns a 401 error if you pass any value other than en. Defaults to en."),
|
|
25
|
+
include: z
|
|
26
|
+
.string()
|
|
27
|
+
.optional()
|
|
28
|
+
.describe("Comma-separated extra modules to include in the response. Paid plans only. Options: security (+2 credits), abuse (+1 credit), hostname, liveHostname, hostnameFallbackLive, user_agent, geo_accuracy, dma_code, or * for all (4 credits total). Free plan cannot use this parameter."),
|
|
29
|
+
fields: z
|
|
30
|
+
.string()
|
|
31
|
+
.optional()
|
|
32
|
+
.describe("Comma-separated dot-path fields to return (e.g. location.city,asn.organization). Works on all plans including free. Reduces response size and can reduce credit cost when combined with include."),
|
|
33
|
+
excludes: z
|
|
34
|
+
.string()
|
|
35
|
+
.optional()
|
|
36
|
+
.describe("Comma-separated dot-path fields to exclude from response (e.g. currency,location.continent_code). Works on all plans including free."),
|
|
37
|
+
},
|
|
38
|
+
}, async (params) => {
|
|
39
|
+
try {
|
|
40
|
+
const result = await getIpGeolocation(params);
|
|
41
|
+
return {
|
|
42
|
+
content: [
|
|
43
|
+
{ type: "text", text: JSON.stringify(result, null, 2) },
|
|
44
|
+
],
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
return {
|
|
49
|
+
content: [
|
|
50
|
+
{
|
|
51
|
+
type: "text",
|
|
52
|
+
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
53
|
+
},
|
|
54
|
+
],
|
|
55
|
+
isError: true,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
server.registerTool("bulk_lookup_ip", {
|
|
60
|
+
title: "Bulk IP Geolocation",
|
|
61
|
+
annotations: {
|
|
62
|
+
readOnlyHint: true,
|
|
63
|
+
},
|
|
64
|
+
description: `Look up geolocation data for multiple IP addresses in a single request using ipgeolocation.io's bulk endpoint (POST /v3/ipgeo-bulk). Accepts up to 50,000 IPs per request. Paid plans only. Free plan returns 401 Unauthorized.
|
|
65
|
+
|
|
66
|
+
Costs 1 credit per IP for base geolocation data. Each IP in the response contains the same fields as a single lookup_ip call on a paid plan: ip, location, country_metadata, currency, time_zone, network, company, and extended ASN (as_number, organization, country, type, domain, date_allocated, rir).
|
|
67
|
+
|
|
68
|
+
Optional include modules add credits per IP: security (+2 per IP), abuse (+1 per IP), hostname (+0), liveHostname (+0), hostnameFallbackLive (+0), user_agent (+0), geo_accuracy (+0), dma_code (+0), or * for all (4 credits per IP total).
|
|
69
|
+
|
|
70
|
+
Returns a JSON array with one geolocation object per IP. Use this tool when you need to look up more than one IP at a time. For a single IP lookup, use lookup_ip instead. For bulk security-only checks, use bulk_security_check instead (2 credits per IP).`,
|
|
71
|
+
inputSchema: {
|
|
72
|
+
ips: z
|
|
73
|
+
.array(z.string())
|
|
74
|
+
.min(1)
|
|
75
|
+
.max(50000)
|
|
76
|
+
.describe("Array of IPv4 and/or IPv6 addresses to look up. Minimum 1, maximum 50,000. Domain names are also accepted."),
|
|
77
|
+
lang: z
|
|
78
|
+
.string()
|
|
79
|
+
.optional()
|
|
80
|
+
.describe("Response language code (en, de, ru, ja, fr, cn, es, cs, it, ko, fa, pt). Defaults to en."),
|
|
81
|
+
include: z
|
|
82
|
+
.string()
|
|
83
|
+
.optional()
|
|
84
|
+
.describe("Comma-separated extra modules to include per IP. Options: security (+2 credits/IP), abuse (+1 credit/IP), hostname, liveHostname, hostnameFallbackLive, user_agent, geo_accuracy, dma_code, or * for all (4 credits/IP total)."),
|
|
85
|
+
fields: z
|
|
86
|
+
.string()
|
|
87
|
+
.optional()
|
|
88
|
+
.describe("Comma-separated dot-path fields to return per IP (e.g. location.city,asn.organization). Reduces response size and can reduce credit cost when combined with include."),
|
|
89
|
+
excludes: z
|
|
90
|
+
.string()
|
|
91
|
+
.optional()
|
|
92
|
+
.describe("Comma-separated dot-path fields to exclude per IP (e.g. currency,time_zone)."),
|
|
93
|
+
},
|
|
94
|
+
}, async (params) => {
|
|
95
|
+
try {
|
|
96
|
+
const result = await getIpGeolocationBulk(params);
|
|
97
|
+
return {
|
|
98
|
+
content: [
|
|
99
|
+
{ type: "text", text: JSON.stringify(result, null, 2) },
|
|
100
|
+
],
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
return {
|
|
105
|
+
content: [
|
|
106
|
+
{
|
|
107
|
+
type: "text",
|
|
108
|
+
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
109
|
+
},
|
|
110
|
+
],
|
|
111
|
+
isError: true,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
server.registerTool("get_my_ip", {
|
|
116
|
+
title: "Get My IP Address",
|
|
117
|
+
annotations: {
|
|
118
|
+
readOnlyHint: true,
|
|
119
|
+
},
|
|
120
|
+
description: "Get the public IP address of the machine running this MCP server. No API key required. No credits charged. Uses the /v3/getip endpoint. Useful for discovering the server's own IP before doing a geolocation lookup with lookup_ip.",
|
|
121
|
+
inputSchema: {},
|
|
122
|
+
}, async () => {
|
|
123
|
+
try {
|
|
124
|
+
const ip = await getMyIp();
|
|
125
|
+
return {
|
|
126
|
+
content: [{ type: "text", text: ip }],
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
catch (error) {
|
|
130
|
+
return {
|
|
131
|
+
content: [
|
|
132
|
+
{
|
|
133
|
+
type: "text",
|
|
134
|
+
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
135
|
+
},
|
|
136
|
+
],
|
|
137
|
+
isError: true,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
server.registerTool("lookup_company", {
|
|
142
|
+
title: "Company/Organization Lookup",
|
|
143
|
+
annotations: {
|
|
144
|
+
readOnlyHint: true,
|
|
145
|
+
},
|
|
146
|
+
description: `Identify the organization using a specific IP address. Uses ipgeolocation.io's unified endpoint (GET /v3/ipgeo) with fields filtered to company and ASN data. Paid plans only. Free plan does not return company data. Costs 1 credit.
|
|
147
|
+
|
|
148
|
+
Returns two objects: company (name, type, domain) and asn (as_number, organization, country, type, domain, date_allocated, rir). The ASN object identifies the organization that holds the IP block allocation from a Regional Internet Registry (ARIN, RIPE, APNIC, etc.). The company object identifies the organization actually using the IP address. These are often the same, but differ when the ASN holder subleases IP space to another organization. For example, 1.1.1.1 has ASN organization "Cloudflare, Inc." (who routes it) but company "APNIC Research and Development" (who owns the block).
|
|
149
|
+
|
|
150
|
+
Use this tool when you need to know which company or organization is behind an IP address. For full geolocation data including company, use lookup_ip instead. For detailed ASN data (peers, routes, WHOIS), use lookup_asn instead.`,
|
|
151
|
+
inputSchema: {
|
|
152
|
+
ip: z
|
|
153
|
+
.string()
|
|
154
|
+
.optional()
|
|
155
|
+
.describe("IPv4 or IPv6 address to look up. Omit to check the caller's IP."),
|
|
156
|
+
},
|
|
157
|
+
}, async (params) => {
|
|
158
|
+
try {
|
|
159
|
+
const result = await getIpGeolocation({
|
|
160
|
+
ip: params.ip,
|
|
161
|
+
fields: "company,asn",
|
|
162
|
+
});
|
|
163
|
+
return {
|
|
164
|
+
content: [
|
|
165
|
+
{ type: "text", text: JSON.stringify(result, null, 2) },
|
|
166
|
+
],
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
catch (error) {
|
|
170
|
+
return {
|
|
171
|
+
content: [
|
|
172
|
+
{
|
|
173
|
+
type: "text",
|
|
174
|
+
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
175
|
+
},
|
|
176
|
+
],
|
|
177
|
+
isError: true,
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
server.registerTool("lookup_currency", {
|
|
182
|
+
title: "Currency and Country Metadata",
|
|
183
|
+
annotations: {
|
|
184
|
+
readOnlyHint: true,
|
|
185
|
+
},
|
|
186
|
+
description: `Get the local currency and country metadata for any IP address. Uses ipgeolocation.io's unified endpoint (GET /v3/ipgeo) with fields filtered to currency and country_metadata. Works on all plans including free. Costs 1 credit.
|
|
187
|
+
|
|
188
|
+
Returns two objects: currency (code, name, symbol) and country_metadata (calling_code, tld, languages). For example, a Japanese IP returns currency {code: "JPY", name: "Japanese Yen", symbol: "¥"} and country_metadata {calling_code: "+81", tld: ".jp", languages: ["ja"]}.
|
|
189
|
+
|
|
190
|
+
Use this tool when you need to know the currency, international calling code, country TLD, or spoken languages for an IP's country. For full geolocation data, use lookup_ip instead.`,
|
|
191
|
+
inputSchema: {
|
|
192
|
+
ip: z
|
|
193
|
+
.string()
|
|
194
|
+
.optional()
|
|
195
|
+
.describe("IPv4 or IPv6 address to look up. Omit to check the caller's IP."),
|
|
196
|
+
},
|
|
197
|
+
}, async (params) => {
|
|
198
|
+
try {
|
|
199
|
+
const result = await getIpGeolocation({
|
|
200
|
+
ip: params.ip,
|
|
201
|
+
fields: "currency,country_metadata",
|
|
202
|
+
});
|
|
203
|
+
return {
|
|
204
|
+
content: [
|
|
205
|
+
{ type: "text", text: JSON.stringify(result, null, 2) },
|
|
206
|
+
],
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
catch (error) {
|
|
210
|
+
return {
|
|
211
|
+
content: [
|
|
212
|
+
{
|
|
213
|
+
type: "text",
|
|
214
|
+
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
215
|
+
},
|
|
216
|
+
],
|
|
217
|
+
isError: true,
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
server.registerTool("lookup_network", {
|
|
222
|
+
title: "Network/Routing Info",
|
|
223
|
+
annotations: {
|
|
224
|
+
readOnlyHint: true,
|
|
225
|
+
},
|
|
226
|
+
description: `Get network routing information for any IP address, including whether it uses anycast. Uses ipgeolocation.io's unified endpoint (GET /v3/ipgeo) with fields filtered to network data. Paid plans only. Free plan does not return network data. Costs 1 credit.
|
|
227
|
+
|
|
228
|
+
Returns: network (connection_type, route, is_anycast). The route field shows the announced BGP prefix (e.g. "1.1.1.0/24"). The is_anycast field indicates whether the IP is served from multiple geographic locations using anycast routing. The connection_type field identifies the type of network connection when available.
|
|
229
|
+
|
|
230
|
+
Use this tool when you need to check if an IP is anycast, find its BGP route prefix, or identify its connection type. For full geolocation data including network, use lookup_ip instead.`,
|
|
231
|
+
inputSchema: {
|
|
232
|
+
ip: z
|
|
233
|
+
.string()
|
|
234
|
+
.optional()
|
|
235
|
+
.describe("IPv4 or IPv6 address to look up. Omit to check the caller's IP."),
|
|
236
|
+
},
|
|
237
|
+
}, async (params) => {
|
|
238
|
+
try {
|
|
239
|
+
const result = await getIpGeolocation({
|
|
240
|
+
ip: params.ip,
|
|
241
|
+
fields: "network",
|
|
242
|
+
});
|
|
243
|
+
return {
|
|
244
|
+
content: [
|
|
245
|
+
{ type: "text", text: JSON.stringify(result, null, 2) },
|
|
246
|
+
],
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
catch (error) {
|
|
250
|
+
return {
|
|
251
|
+
content: [
|
|
252
|
+
{
|
|
253
|
+
type: "text",
|
|
254
|
+
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
255
|
+
},
|
|
256
|
+
],
|
|
257
|
+
isError: true,
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { getSecurity, getSecurityBulk } from "../client.js";
|
|
3
|
+
export function registerSecurityTools(server) {
|
|
4
|
+
server.registerTool("check_security", {
|
|
5
|
+
title: "VPN/Proxy/Threat Detection",
|
|
6
|
+
annotations: {
|
|
7
|
+
readOnlyHint: true,
|
|
8
|
+
},
|
|
9
|
+
description: `Check if an IP address is a VPN, proxy, Tor node, bot, or known attacker using ipgeolocation.io's dedicated security endpoint (GET /v3/security). Paid plans only. Free plan returns 401 Unauthorized. Costs 2 credits per lookup.
|
|
10
|
+
|
|
11
|
+
Returns: threat_score (0-100), is_tor, is_proxy, proxy_provider_names, proxy_confidence_score (0-100), proxy_last_seen, is_residential_proxy, is_vpn, vpn_provider_names, vpn_confidence_score (0-100), vpn_last_seen, is_relay, relay_provider_name, is_anonymous, is_known_attacker, is_bot, is_spam, is_cloud_provider, cloud_provider_name.
|
|
12
|
+
|
|
13
|
+
This is the same security data you get from lookup_ip with include=security, but using this dedicated endpoint costs 2 credits instead of 3 (because you skip the base geolocation). If you need both geolocation and security data together, use lookup_ip with include=security (3 credits) instead. If you only need security data, this tool is cheaper. For checking multiple IPs at once, use bulk_security_check instead.`,
|
|
14
|
+
inputSchema: {
|
|
15
|
+
ip: z
|
|
16
|
+
.string()
|
|
17
|
+
.optional()
|
|
18
|
+
.describe("IPv4 or IPv6 address to check. Omit to check the caller's IP."),
|
|
19
|
+
fields: z
|
|
20
|
+
.string()
|
|
21
|
+
.optional()
|
|
22
|
+
.describe("Comma-separated dot-path fields to return (e.g. security.threat_score,security.is_vpn). Reduces response size."),
|
|
23
|
+
excludes: z
|
|
24
|
+
.string()
|
|
25
|
+
.optional()
|
|
26
|
+
.describe("Comma-separated dot-path fields to exclude (e.g. security.is_tor,security.is_cloud_provider)."),
|
|
27
|
+
},
|
|
28
|
+
}, async (params) => {
|
|
29
|
+
try {
|
|
30
|
+
const result = await getSecurity(params);
|
|
31
|
+
return {
|
|
32
|
+
content: [
|
|
33
|
+
{ type: "text", text: JSON.stringify(result, null, 2) },
|
|
34
|
+
],
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
return {
|
|
39
|
+
content: [
|
|
40
|
+
{
|
|
41
|
+
type: "text",
|
|
42
|
+
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
43
|
+
},
|
|
44
|
+
],
|
|
45
|
+
isError: true,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
server.registerTool("bulk_security_check", {
|
|
50
|
+
title: "Bulk Security Check",
|
|
51
|
+
annotations: {
|
|
52
|
+
readOnlyHint: true,
|
|
53
|
+
},
|
|
54
|
+
description: `Check up to 50,000 IP addresses for VPN, proxy, Tor, bot, and threat indicators in a single request using ipgeolocation.io's bulk security endpoint (POST /v3/security-bulk). Paid plans only. Free plan returns 401 Unauthorized. Costs 2 credits per valid IP in the request.
|
|
55
|
+
|
|
56
|
+
Returns a JSON array of security assessment objects, one per IP. Each object contains the same fields as check_security: threat_score, is_tor, is_proxy, proxy_provider_names, proxy_confidence_score, is_vpn, vpn_provider_names, vpn_confidence_score, is_bot, is_spam, is_known_attacker, is_anonymous, is_cloud_provider, and more.
|
|
57
|
+
|
|
58
|
+
Use this tool when you need security checks on multiple IPs at once. For a single IP, use check_security instead. If you also need geolocation data with security, use bulk_lookup_ip with include=security instead (but that costs 3 credits per IP vs 2 credits per IP here).`,
|
|
59
|
+
inputSchema: {
|
|
60
|
+
ips: z
|
|
61
|
+
.array(z.string())
|
|
62
|
+
.min(1)
|
|
63
|
+
.max(50000)
|
|
64
|
+
.describe("Array of IPv4 and/or IPv6 addresses to check. Minimum 1, maximum 50,000."),
|
|
65
|
+
fields: z
|
|
66
|
+
.string()
|
|
67
|
+
.optional()
|
|
68
|
+
.describe("Comma-separated dot-path fields to return per IP (e.g. security.threat_score,security.is_vpn). Reduces response size."),
|
|
69
|
+
excludes: z
|
|
70
|
+
.string()
|
|
71
|
+
.optional()
|
|
72
|
+
.describe("Comma-separated dot-path fields to exclude per IP (e.g. security.is_tor,security.is_cloud_provider)."),
|
|
73
|
+
},
|
|
74
|
+
}, async (params) => {
|
|
75
|
+
try {
|
|
76
|
+
const result = await getSecurityBulk(params);
|
|
77
|
+
return {
|
|
78
|
+
content: [
|
|
79
|
+
{ type: "text", text: JSON.stringify(result, null, 2) },
|
|
80
|
+
],
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
return {
|
|
85
|
+
content: [
|
|
86
|
+
{
|
|
87
|
+
type: "text",
|
|
88
|
+
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
89
|
+
},
|
|
90
|
+
],
|
|
91
|
+
isError: true,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { getTimezone, convertTimezone } from "../client.js";
|
|
3
|
+
export function registerTimezoneTools(server) {
|
|
4
|
+
server.registerTool("get_timezone", {
|
|
5
|
+
title: "Timezone Lookup",
|
|
6
|
+
annotations: {
|
|
7
|
+
readOnlyHint: true,
|
|
8
|
+
},
|
|
9
|
+
description: `Get current time and timezone details for any location using ipgeolocation.io (GET /v3/timezone). Works on all plans including free. Costs 1 credit per request.
|
|
10
|
+
|
|
11
|
+
Look up by IANA timezone name, coordinates, city/address, IP address, IATA airport code, ICAO airport code, or UN/LOCODE. All lookup modes work on both free and paid plans. If no parameters are provided, returns timezone data for the caller's IP.
|
|
12
|
+
|
|
13
|
+
Returns: timezone name, UTC offset, offset with DST, current_time, current_time_unix, timezone abbreviations (standard and DST), is_dst flag, dst_savings, dst_exists, dst_start, dst_end. Airport code lookups also return airport name, city, elevation, and coordinates.
|
|
14
|
+
|
|
15
|
+
The lang parameter for non-English responses is available on paid plans only. Free plan returns English responses regardless of the lang value.`,
|
|
16
|
+
inputSchema: {
|
|
17
|
+
tz: z
|
|
18
|
+
.string()
|
|
19
|
+
.optional()
|
|
20
|
+
.describe("IANA timezone name (e.g. America/New_York, Europe/London). Highest priority if multiple params provided."),
|
|
21
|
+
lat: z
|
|
22
|
+
.string()
|
|
23
|
+
.optional()
|
|
24
|
+
.describe("Latitude coordinate. Must be used together with long."),
|
|
25
|
+
long: z
|
|
26
|
+
.string()
|
|
27
|
+
.optional()
|
|
28
|
+
.describe("Longitude coordinate. Must be used together with lat."),
|
|
29
|
+
location: z
|
|
30
|
+
.string()
|
|
31
|
+
.optional()
|
|
32
|
+
.describe("City or address string (e.g. London, UK)."),
|
|
33
|
+
ip: z
|
|
34
|
+
.string()
|
|
35
|
+
.optional()
|
|
36
|
+
.describe("IPv4 or IPv6 address to get timezone for."),
|
|
37
|
+
iata_code: z
|
|
38
|
+
.string()
|
|
39
|
+
.optional()
|
|
40
|
+
.describe("3-letter IATA airport code (e.g. JFK, LHR). Returns airport details in the response."),
|
|
41
|
+
icao_code: z
|
|
42
|
+
.string()
|
|
43
|
+
.optional()
|
|
44
|
+
.describe("4-letter ICAO airport code (e.g. KJFK, EGLL). Returns airport details in the response."),
|
|
45
|
+
lo_code: z
|
|
46
|
+
.string()
|
|
47
|
+
.optional()
|
|
48
|
+
.describe("5-character UN/LOCODE (e.g. DEBER, USNYC)."),
|
|
49
|
+
lang: z
|
|
50
|
+
.string()
|
|
51
|
+
.optional()
|
|
52
|
+
.describe("Response language for location fields in IP-based lookups (en, de, ru, ja, fr, cn, es, cs, it, ko, fa, pt). Paid plans only. Free plan returns English."),
|
|
53
|
+
},
|
|
54
|
+
}, async (params) => {
|
|
55
|
+
try {
|
|
56
|
+
const result = await getTimezone(params);
|
|
57
|
+
return {
|
|
58
|
+
content: [
|
|
59
|
+
{ type: "text", text: JSON.stringify(result, null, 2) },
|
|
60
|
+
],
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
return {
|
|
65
|
+
content: [
|
|
66
|
+
{
|
|
67
|
+
type: "text",
|
|
68
|
+
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
isError: true,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
server.registerTool("convert_timezone", {
|
|
76
|
+
title: "Timezone Conversion",
|
|
77
|
+
annotations: {
|
|
78
|
+
readOnlyHint: true,
|
|
79
|
+
},
|
|
80
|
+
description: `Convert time between two locations using ipgeolocation.io (GET /v3/timezone/convert). Works on all plans including free. Costs 1 credit per request.
|
|
81
|
+
|
|
82
|
+
Specify source and destination by IANA timezone name, coordinates, city/address, IATA airport code, ICAO airport code, or UN/LOCODE. All location modes work on both free and paid plans.
|
|
83
|
+
|
|
84
|
+
Returns: original time, converted time, diff_hour, and diff_min between the two locations. If no time is specified, converts the current time.`,
|
|
85
|
+
inputSchema: {
|
|
86
|
+
time: z
|
|
87
|
+
.string()
|
|
88
|
+
.optional()
|
|
89
|
+
.describe("Time to convert in yyyy-MM-dd HH:mm or yyyy-MM-dd HH:mm:ss format. Defaults to current time."),
|
|
90
|
+
tz_from: z
|
|
91
|
+
.string()
|
|
92
|
+
.optional()
|
|
93
|
+
.describe("Source IANA timezone name (e.g. America/New_York)."),
|
|
94
|
+
tz_to: z
|
|
95
|
+
.string()
|
|
96
|
+
.optional()
|
|
97
|
+
.describe("Destination IANA timezone name (e.g. Asia/Tokyo)."),
|
|
98
|
+
lat_from: z
|
|
99
|
+
.string()
|
|
100
|
+
.optional()
|
|
101
|
+
.describe("Source latitude. Use with long_from."),
|
|
102
|
+
long_from: z
|
|
103
|
+
.string()
|
|
104
|
+
.optional()
|
|
105
|
+
.describe("Source longitude. Use with lat_from."),
|
|
106
|
+
lat_to: z
|
|
107
|
+
.string()
|
|
108
|
+
.optional()
|
|
109
|
+
.describe("Destination latitude. Use with long_to."),
|
|
110
|
+
long_to: z
|
|
111
|
+
.string()
|
|
112
|
+
.optional()
|
|
113
|
+
.describe("Destination longitude. Use with lat_to."),
|
|
114
|
+
location_from: z
|
|
115
|
+
.string()
|
|
116
|
+
.optional()
|
|
117
|
+
.describe("Source city or address string."),
|
|
118
|
+
location_to: z
|
|
119
|
+
.string()
|
|
120
|
+
.optional()
|
|
121
|
+
.describe("Destination city or address string."),
|
|
122
|
+
iata_from: z
|
|
123
|
+
.string()
|
|
124
|
+
.optional()
|
|
125
|
+
.describe("Source 3-letter IATA airport code."),
|
|
126
|
+
iata_to: z
|
|
127
|
+
.string()
|
|
128
|
+
.optional()
|
|
129
|
+
.describe("Destination 3-letter IATA airport code."),
|
|
130
|
+
icao_from: z
|
|
131
|
+
.string()
|
|
132
|
+
.optional()
|
|
133
|
+
.describe("Source 4-letter ICAO airport code."),
|
|
134
|
+
icao_to: z
|
|
135
|
+
.string()
|
|
136
|
+
.optional()
|
|
137
|
+
.describe("Destination 4-letter ICAO airport code."),
|
|
138
|
+
locode_from: z
|
|
139
|
+
.string()
|
|
140
|
+
.optional()
|
|
141
|
+
.describe("Source 5-character UN/LOCODE."),
|
|
142
|
+
locode_to: z
|
|
143
|
+
.string()
|
|
144
|
+
.optional()
|
|
145
|
+
.describe("Destination 5-character UN/LOCODE."),
|
|
146
|
+
},
|
|
147
|
+
}, async (params) => {
|
|
148
|
+
try {
|
|
149
|
+
const result = await convertTimezone(params);
|
|
150
|
+
return {
|
|
151
|
+
content: [
|
|
152
|
+
{ type: "text", text: JSON.stringify(result, null, 2) },
|
|
153
|
+
],
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
catch (error) {
|
|
157
|
+
return {
|
|
158
|
+
content: [
|
|
159
|
+
{
|
|
160
|
+
type: "text",
|
|
161
|
+
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
162
|
+
},
|
|
163
|
+
],
|
|
164
|
+
isError: true,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { parseUserAgent, parseUserAgentBulk } from "../client.js";
|
|
3
|
+
export function registerUserAgentTools(server) {
|
|
4
|
+
server.registerTool("parse_user_agent", {
|
|
5
|
+
title: "User-Agent Parser",
|
|
6
|
+
annotations: {
|
|
7
|
+
readOnlyHint: true,
|
|
8
|
+
},
|
|
9
|
+
description: `Parse a user-agent string into structured device, browser, OS, and engine details using ipgeolocation.io's dedicated User-Agent endpoint (POST /v3/user-agent). Paid plans only. Free plan returns 401 Unauthorized. Costs 1 credit per request.
|
|
10
|
+
|
|
11
|
+
Returns: user_agent_string, name (browser/bot name), type (Browser, Crawler, etc.), version, version_major, device (name, type, brand, cpu), engine (name, type, version, version_major), operating_system (name, type, version, version_major, build).
|
|
12
|
+
|
|
13
|
+
This is the same user-agent data you can get from lookup_ip with include=user_agent, but that always parses the caller's User-Agent header and costs 1 credit for base geolocation plus 0 for the UA module. This dedicated endpoint lets you parse any arbitrary user-agent string you supply without doing an IP lookup. For parsing multiple UA strings at once, use bulk_parse_user_agent instead.`,
|
|
14
|
+
inputSchema: {
|
|
15
|
+
uaString: z
|
|
16
|
+
.string()
|
|
17
|
+
.describe("The user-agent string to parse (e.g. Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36)."),
|
|
18
|
+
},
|
|
19
|
+
}, async (params) => {
|
|
20
|
+
try {
|
|
21
|
+
const result = await parseUserAgent(params);
|
|
22
|
+
return {
|
|
23
|
+
content: [
|
|
24
|
+
{ type: "text", text: JSON.stringify(result, null, 2) },
|
|
25
|
+
],
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
return {
|
|
30
|
+
content: [
|
|
31
|
+
{
|
|
32
|
+
type: "text",
|
|
33
|
+
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
34
|
+
},
|
|
35
|
+
],
|
|
36
|
+
isError: true,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
server.registerTool("bulk_parse_user_agent", {
|
|
41
|
+
title: "Bulk User-Agent Parser",
|
|
42
|
+
annotations: {
|
|
43
|
+
readOnlyHint: true,
|
|
44
|
+
},
|
|
45
|
+
description: `Parse up to 50,000 user-agent strings in a single request using ipgeolocation.io's bulk User-Agent endpoint (POST /v3/user-agent-bulk). Paid plans only. Free plan returns 401 Unauthorized. Costs 1 credit per user-agent string.
|
|
46
|
+
|
|
47
|
+
Returns a JSON array of parsed user-agent objects. Each object contains the same fields as parse_user_agent: user_agent_string, name, type, version, version_major, device (name, type, brand, cpu), engine (name, type, version, version_major), operating_system (name, type, version, version_major, build).
|
|
48
|
+
|
|
49
|
+
Use this tool when you need to parse multiple user-agent strings at once. For a single UA string, use parse_user_agent instead.`,
|
|
50
|
+
inputSchema: {
|
|
51
|
+
uaStrings: z
|
|
52
|
+
.array(z.string())
|
|
53
|
+
.min(1)
|
|
54
|
+
.max(50000)
|
|
55
|
+
.describe("Array of user-agent strings to parse. Minimum 1, maximum 50,000."),
|
|
56
|
+
},
|
|
57
|
+
}, async (params) => {
|
|
58
|
+
try {
|
|
59
|
+
const result = await parseUserAgentBulk(params);
|
|
60
|
+
return {
|
|
61
|
+
content: [
|
|
62
|
+
{ type: "text", text: JSON.stringify(result, null, 2) },
|
|
63
|
+
],
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
return {
|
|
68
|
+
content: [
|
|
69
|
+
{
|
|
70
|
+
type: "text",
|
|
71
|
+
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
72
|
+
},
|
|
73
|
+
],
|
|
74
|
+
isError: true,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
}
|