ipinfo-mcp-server 0.2.2__tar.gz → 0.2.3__tar.gz

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.
Files changed (67) hide show
  1. ipinfo_mcp_server-0.2.3/.cursor-plugin/marketplace.json +17 -0
  2. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/.mcpbignore +2 -0
  3. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/PKG-INFO +14 -13
  4. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/README.md +13 -12
  5. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/manifest.json +1 -1
  6. ipinfo_mcp_server-0.2.3/plugins/ipinfo/.cursor-plugin/plugin.json +20 -0
  7. ipinfo_mcp_server-0.2.3/plugins/ipinfo/README.md +47 -0
  8. ipinfo_mcp_server-0.2.3/plugins/ipinfo/assets/logo-dark.png +0 -0
  9. ipinfo_mcp_server-0.2.3/plugins/ipinfo/assets/logo.png +0 -0
  10. ipinfo_mcp_server-0.2.3/plugins/ipinfo/mcp.json +9 -0
  11. ipinfo_mcp_server-0.2.3/plugins/ipinfo/plugin.json +109 -0
  12. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/pyproject.toml +1 -1
  13. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/server.json +2 -2
  14. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/src/ipinfo_mcp/server.py +10 -3
  15. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/uv.lock +1 -1
  16. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/.dockerignore +0 -0
  17. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/.env.example +0 -0
  18. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/.github/dependabot.yml +0 -0
  19. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/.github/workflows/build.yml +0 -0
  20. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/.github/workflows/codeql.yml +0 -0
  21. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/.github/workflows/mcp-registry.yml +0 -0
  22. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/.github/workflows/pypi.yml +0 -0
  23. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/.github/workflows/release.yml +0 -0
  24. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/.github/workflows/scorecard.yml +0 -0
  25. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/.github/workflows/test.yml +0 -0
  26. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/.gitignore +0 -0
  27. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/CONTRIBUTING.md +0 -0
  28. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/Dockerfile +0 -0
  29. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/LICENSE.txt +0 -0
  30. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/SECURITY.md +0 -0
  31. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/assets/logo-dark.png +0 -0
  32. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/assets/logo-light.png +0 -0
  33. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/src/ipinfo_mcp/__init__.py +0 -0
  34. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/src/ipinfo_mcp/__main__.py +0 -0
  35. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/src/ipinfo_mcp/auth.py +0 -0
  36. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/src/ipinfo_mcp/cache.py +0 -0
  37. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/src/ipinfo_mcp/client.py +0 -0
  38. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/src/ipinfo_mcp/errors.py +0 -0
  39. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/src/ipinfo_mcp/landing.html +0 -0
  40. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/src/ipinfo_mcp/logging.py +0 -0
  41. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/src/ipinfo_mcp/pagination.py +0 -0
  42. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/src/ipinfo_mcp/params.py +0 -0
  43. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/src/ipinfo_mcp/tools/__init__.py +0 -0
  44. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/src/ipinfo_mcp/tools/asn.py +0 -0
  45. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/src/ipinfo_mcp/tools/geolocate.py +0 -0
  46. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/src/ipinfo_mcp/tools/lookup.py +0 -0
  47. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/src/ipinfo_mcp/tools/privacy.py +0 -0
  48. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/src/ipinfo_mcp/tools/quota.py +0 -0
  49. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/src/ipinfo_mcp/tools/resproxy.py +0 -0
  50. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/src/ipinfo_mcp/types.py +0 -0
  51. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/src/ipinfo_mcp/validation.py +0 -0
  52. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/tests/__init__.py +0 -0
  53. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/tests/conftest.py +0 -0
  54. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/tests/integration/__init__.py +0 -0
  55. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/tests/integration/test_client.py +0 -0
  56. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/tests/test_auth.py +0 -0
  57. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/tests/test_cache.py +0 -0
  58. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/tests/test_client.py +0 -0
  59. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/tests/test_pagination.py +0 -0
  60. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/tests/test_validation.py +0 -0
  61. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/tests/tools/__init__.py +0 -0
  62. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/tests/tools/test_asn.py +0 -0
  63. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/tests/tools/test_geolocate.py +0 -0
  64. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/tests/tools/test_lookup.py +0 -0
  65. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/tests/tools/test_privacy.py +0 -0
  66. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/tests/tools/test_quota.py +0 -0
  67. {ipinfo_mcp_server-0.2.2 → ipinfo_mcp_server-0.2.3}/tests/tools/test_resproxy.py +0 -0
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "ipinfo",
3
+ "owner": {
4
+ "name": "IPinfo",
5
+ "email": "support@ipinfo.io"
6
+ },
7
+ "metadata": {
8
+ "description": "Official IPinfo plugins"
9
+ },
10
+ "plugins": [
11
+ {
12
+ "name": "ipinfo",
13
+ "source": "./plugins/ipinfo",
14
+ "description": "IP address intelligence from IPinfo: geolocation, network ownership, and VPN, proxy, Tor, and residential proxy detection."
15
+ }
16
+ ]
17
+ }
@@ -9,3 +9,5 @@ tests
9
9
  .env.example
10
10
  .gitignore
11
11
  Dockerfile
12
+ plugins
13
+ .cursor-plugin
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: ipinfo-mcp-server
3
- Version: 0.2.2
3
+ Version: 0.2.3
4
4
  Summary: Official IPinfo MCP Server - IP intelligence tools for AI assistants
5
5
  Author-email: IPinfo <support@ipinfo.io>
6
6
  License-Expression: Apache-2.0
@@ -139,18 +139,19 @@ Takes no parameters. Returns `token` (omitted when connected with OAuth), `reque
139
139
 
140
140
  The server is configured through environment variables:
141
141
 
142
- | Variable | Default | Description |
143
- | ------------------------- | -------------------------------- | ----------------------------------------------------------------------- |
144
- | `IPINFO_TOKEN` | | API token (stdio transport; over HTTP the token comes from the request) |
145
- | `IPINFO_API_BASE_URL` | `https://api.ipinfo.io` | Base URL for `api.ipinfo.io` endpoints |
146
- | `IPINFO_LEGACY_BASE_URL` | `https://ipinfo.io` | Base URL for legacy `ipinfo.io` endpoints (e.g. `/me`) |
147
- | `IPINFO_CACHE_TTL` | `3600` | Seconds a cached IP result stays fresh |
148
- | `IPINFO_TRANSPORT` | `stdio` | Transport type (`stdio` or `http`) |
149
- | `HOST` | `0.0.0.0` | HTTP host (only for `http` transport) |
150
- | `PORT` | `8000` | HTTP port (only for `http` transport) |
151
- | `IPINFO_OAUTH_ISSUER` | | OAuth issuer whose access tokens are accepted; OAuth is off when unset |
152
- | `IPINFO_MCP_RESOURCE_URL` | | Public URL of this server, required with `IPINFO_OAUTH_ISSUER` |
153
- | `IPINFO_OAUTH_JWKS_URI` | `<issuer>/.well-known/jwks.json` | Where the issuer publishes its signing keys |
142
+ | Variable | Default | Description |
143
+ | ------------------------------ | -------------------------------- | ------------------------------------------------------------------------------------- |
144
+ | `IPINFO_TOKEN` | | API token (stdio transport; over HTTP the token comes from the request) |
145
+ | `IPINFO_API_BASE_URL` | `https://api.ipinfo.io` | Base URL for `api.ipinfo.io` endpoints |
146
+ | `IPINFO_LEGACY_BASE_URL` | `https://ipinfo.io` | Base URL for legacy `ipinfo.io` endpoints (e.g. `/me`) |
147
+ | `IPINFO_CACHE_TTL` | `3600` | Seconds a cached IP result stays fresh |
148
+ | `IPINFO_TRANSPORT` | `stdio` | Transport type (`stdio` or `http`) |
149
+ | `HOST` | `0.0.0.0` | HTTP host (only for `http` transport) |
150
+ | `PORT` | `8000` | HTTP port (only for `http` transport) |
151
+ | `IPINFO_OAUTH_ISSUER` | | OAuth issuer whose access tokens are accepted; OAuth is off when unset |
152
+ | `IPINFO_MCP_RESOURCE_URL` | | Public URL of this server, required with `IPINFO_OAUTH_ISSUER` |
153
+ | `IPINFO_OAUTH_JWKS_URI` | `<issuer>/.well-known/jwks.json` | Where the issuer publishes its signing keys |
154
+ | `IPINFO_OPENAI_APPS_CHALLENGE` | | Token served at `/.well-known/openai-apps-challenge` for OpenAI's domain verification |
154
155
 
155
156
  With the `http` transport, each request authenticates with its own `Authorization: Bearer <token>` header.
156
157
 
@@ -122,18 +122,19 @@ Takes no parameters. Returns `token` (omitted when connected with OAuth), `reque
122
122
 
123
123
  The server is configured through environment variables:
124
124
 
125
- | Variable | Default | Description |
126
- | ------------------------- | -------------------------------- | ----------------------------------------------------------------------- |
127
- | `IPINFO_TOKEN` | | API token (stdio transport; over HTTP the token comes from the request) |
128
- | `IPINFO_API_BASE_URL` | `https://api.ipinfo.io` | Base URL for `api.ipinfo.io` endpoints |
129
- | `IPINFO_LEGACY_BASE_URL` | `https://ipinfo.io` | Base URL for legacy `ipinfo.io` endpoints (e.g. `/me`) |
130
- | `IPINFO_CACHE_TTL` | `3600` | Seconds a cached IP result stays fresh |
131
- | `IPINFO_TRANSPORT` | `stdio` | Transport type (`stdio` or `http`) |
132
- | `HOST` | `0.0.0.0` | HTTP host (only for `http` transport) |
133
- | `PORT` | `8000` | HTTP port (only for `http` transport) |
134
- | `IPINFO_OAUTH_ISSUER` | | OAuth issuer whose access tokens are accepted; OAuth is off when unset |
135
- | `IPINFO_MCP_RESOURCE_URL` | | Public URL of this server, required with `IPINFO_OAUTH_ISSUER` |
136
- | `IPINFO_OAUTH_JWKS_URI` | `<issuer>/.well-known/jwks.json` | Where the issuer publishes its signing keys |
125
+ | Variable | Default | Description |
126
+ | ------------------------------ | -------------------------------- | ------------------------------------------------------------------------------------- |
127
+ | `IPINFO_TOKEN` | | API token (stdio transport; over HTTP the token comes from the request) |
128
+ | `IPINFO_API_BASE_URL` | `https://api.ipinfo.io` | Base URL for `api.ipinfo.io` endpoints |
129
+ | `IPINFO_LEGACY_BASE_URL` | `https://ipinfo.io` | Base URL for legacy `ipinfo.io` endpoints (e.g. `/me`) |
130
+ | `IPINFO_CACHE_TTL` | `3600` | Seconds a cached IP result stays fresh |
131
+ | `IPINFO_TRANSPORT` | `stdio` | Transport type (`stdio` or `http`) |
132
+ | `HOST` | `0.0.0.0` | HTTP host (only for `http` transport) |
133
+ | `PORT` | `8000` | HTTP port (only for `http` transport) |
134
+ | `IPINFO_OAUTH_ISSUER` | | OAuth issuer whose access tokens are accepted; OAuth is off when unset |
135
+ | `IPINFO_MCP_RESOURCE_URL` | | Public URL of this server, required with `IPINFO_OAUTH_ISSUER` |
136
+ | `IPINFO_OAUTH_JWKS_URI` | `<issuer>/.well-known/jwks.json` | Where the issuer publishes its signing keys |
137
+ | `IPINFO_OPENAI_APPS_CHALLENGE` | | Token served at `/.well-known/openai-apps-challenge` for OpenAI's domain verification |
137
138
 
138
139
  With the `http` transport, each request authenticates with its own `Authorization: Bearer <token>` header.
139
140
 
@@ -2,7 +2,7 @@
2
2
  "manifest_version": "0.4",
3
3
  "name": "ipinfo-mcp-server",
4
4
  "display_name": "IPinfo",
5
- "version": "0.2.2",
5
+ "version": "0.2.3",
6
6
  "description": "IP address intelligence tools: geolocation, ASN, privacy detection, residential proxy checks, and more.",
7
7
  "author": {
8
8
  "name": "IPinfo",
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "ipinfo",
3
+ "displayName": "IPinfo",
4
+ "version": "1.0.0",
5
+ "description": "IP address intelligence from IPinfo: geolocation, network ownership, and VPN, proxy, Tor, and residential proxy detection.",
6
+ "author": {
7
+ "name": "IPinfo",
8
+ "email": "support@ipinfo.io"
9
+ },
10
+ "homepage": "https://ipinfo.io/developers/mcp-server",
11
+ "repository": "https://github.com/ipinfo/mcp",
12
+ "license": "Apache-2.0",
13
+ "keywords": ["ip", "geolocation", "asn", "vpn", "proxy", "tor", "residential-proxy", "security"],
14
+ "logo": "assets/logo.png",
15
+ "mcpServers": {
16
+ "ipinfo": {
17
+ "url": "https://mcp.ipinfo.io/"
18
+ }
19
+ }
20
+ }
@@ -0,0 +1,47 @@
1
+ # IPinfo plugin
2
+
3
+ Connects your AI assistant to the hosted [IPinfo MCP Server](https://github.com/ipinfo/mcp), so it can answer questions about IP addresses with [IPinfo](https://ipinfo.io) data: where an IP is located, which company or network it belongs to, and whether it's a VPN, proxy, Tor exit node, or residential proxy.
4
+
5
+ ## Setup
6
+
7
+ Install the plugin, then sign in with your IPinfo account when your client asks. There is nothing else to configure: the plugin connects to `https://mcp.ipinfo.io/` and authenticates through OAuth.
8
+
9
+ You need an IPinfo account. Sign up for free at [ipinfo.io/signup](https://ipinfo.io/signup).
10
+
11
+ ## Tools
12
+
13
+ | Tool | Description | Plan requirement |
14
+ | -------------------------------- | ----------------------------------------------------------------- | ------------------------------------- |
15
+ | `ipinfo_lookup` | Full IP data: geolocation, network, and metadata | Any; `detailed: true` needs Core/Plus |
16
+ | `ipinfo_geolocate` | Geographic location | Any; `detailed: true` needs Core/Plus |
17
+ | `ipinfo_asn` | Autonomous system (network ownership) | Any; `detailed: true` needs Core/Plus |
18
+ | `ipinfo_check_privacy` | VPN, proxy, relay, Tor, hosting, anycast, mobile, satellite flags | Paid plan |
19
+ | `ipinfo_check_residential_proxy` | Residential proxy detection | Residential Proxy access |
20
+ | `ipinfo_quota` | API usage and remaining quota | Any |
21
+
22
+ All tools are read-only. Try asking:
23
+
24
+ - "Where is the IP address 8.8.8.8 located?"
25
+ - "Is 185.220.101.1 a VPN, proxy, or Tor exit node?"
26
+ - "Which company operates the network for 1.1.1.1?"
27
+
28
+ ## Support
29
+
30
+ - Documentation: [ipinfo.io/developers/mcp-server](https://ipinfo.io/developers/mcp-server)
31
+ - Support: [support.ipinfo.io](https://support.ipinfo.io/hc/en-us) or support@ipinfo.io
32
+ - Privacy policy: [ipinfo.io/privacy-policy](https://ipinfo.io/privacy-policy)
33
+
34
+ ## Packaging
35
+
36
+ This folder is both an [Agent Plugins](https://agent-plugins.org) package and a Cursor plugin:
37
+
38
+ - `plugin.json` and `mcp.json` are the portable package. OpenAI-specific listing and review details live under `extensions.com.openai` in `plugin.json`.
39
+ - `.cursor-plugin/plugin.json` adds the Cursor listing details, such as the logo. The repository's `.cursor-plugin/marketplace.json` points Cursor at this folder.
40
+
41
+ To build the ZIP for the OpenAI plugin portal, run this from the `plugins` directory. It leaves out the Cursor manifest:
42
+
43
+ ```bash
44
+ zip -r -X ipinfo-plugin.zip ipinfo -x '*.DS_Store' 'ipinfo/.cursor-plugin/*'
45
+ ```
46
+
47
+ Bump `version` in both manifests before every new upload.
@@ -0,0 +1,9 @@
1
+ {
2
+ "$schema": "https://agent-plugins.org/schemas/1.0.0/mcp.schema.json",
3
+ "mcpServers": {
4
+ "ipinfo": {
5
+ "type": "streamable-http",
6
+ "url": "https://mcp.ipinfo.io/"
7
+ }
8
+ }
9
+ }
@@ -0,0 +1,109 @@
1
+ {
2
+ "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
3
+ "name": "ipinfo",
4
+ "version": "1.0.0",
5
+ "description": "IP address intelligence from IPinfo: geolocation, network ownership, and VPN, proxy, Tor, and residential proxy detection.",
6
+ "author": {
7
+ "name": "IPinfo",
8
+ "email": "support@ipinfo.io",
9
+ "url": "https://ipinfo.io"
10
+ },
11
+ "homepage": "https://ipinfo.io/developers/mcp-server",
12
+ "repository": "https://github.com/ipinfo/mcp",
13
+ "license": "Apache-2.0",
14
+ "keywords": [
15
+ "ip",
16
+ "geolocation",
17
+ "asn",
18
+ "vpn",
19
+ "proxy",
20
+ "tor",
21
+ "residential-proxy",
22
+ "security"
23
+ ],
24
+ "extensions": {
25
+ "com.openai": {
26
+ "interface": {
27
+ "displayName": "IPinfo",
28
+ "shortDescription": "IP geolocation and privacy",
29
+ "longDescription": "Look up IP addresses with IPinfo data. Find where an IP is located, down to the city, region, coordinates, timezone, and postal code. See which company or network owns it, with its ASN, organization name, domain, and network type. Check whether it belongs to a VPN, proxy, relay, or Tor exit node, whether it is a known residential proxy, and whether it is a hosting, anycast, mobile, or satellite address. You can also check your IPinfo API usage and remaining quota.\n\nUseful for security and fraud investigations, log and traffic analysis, and any question about where traffic comes from. Lookups accept many IPs at once, IPv4 or IPv6.\n\nSign in with your IPinfo account to connect. Every account includes country, continent, and ASN data. City-level geolocation, privacy detection, and residential proxy detection are available when your IPinfo plan includes them. Private, reserved, and bogon addresses aren't looked up. All tools are read-only and never change your account.",
30
+ "developerName": "IPinfo",
31
+ "category": "Data & Analytics",
32
+ "capabilities": [
33
+ "Geolocate IP addresses",
34
+ "Identify network owners and ASNs",
35
+ "Detect VPNs, proxies, relays, and Tor",
36
+ "Detect residential proxies",
37
+ "Check API usage and quota"
38
+ ],
39
+ "websiteURL": "https://ipinfo.io",
40
+ "supportURL": "https://support.ipinfo.io/",
41
+ "privacyPolicyURL": "https://ipinfo.io/privacy-policy",
42
+ "termsOfServiceURL": "https://ipinfo.io/terms-of-service",
43
+ "defaultPrompt": [
44
+ "Where is the IP address 8.8.8.8 located?",
45
+ "Is 185.220.101.1 a VPN, proxy, or Tor exit node?",
46
+ "Which company operates the network for 1.1.1.1?"
47
+ ],
48
+ "logo": "./assets/logo.png",
49
+ "logoDark": "./assets/logo-dark.png",
50
+ "composerIcon": "./assets/logo.png",
51
+ "composerIconDark": "./assets/logo-dark.png"
52
+ },
53
+ "review": {
54
+ "test_cases": {
55
+ "positive": [
56
+ {
57
+ "description": "Geolocate an IP address",
58
+ "prompt": "Where is the IP address 8.8.8.8 located? Include the city and timezone.",
59
+ "tools_triggered": "ipinfo_geolocate",
60
+ "expected_behavior": "Reports that 8.8.8.8 is in Mountain View, California, United States, with the America/Los_Angeles timezone."
61
+ },
62
+ {
63
+ "description": "Identify who owns a network",
64
+ "prompt": "Which company operates the network for 1.1.1.1?",
65
+ "tools_triggered": "ipinfo_asn",
66
+ "expected_behavior": "Reports that 1.1.1.1 belongs to AS13335, Cloudflare, Inc. (cloudflare.com)."
67
+ },
68
+ {
69
+ "description": "Detect anonymity services",
70
+ "prompt": "Is 185.220.101.1 a VPN, proxy, or Tor exit node?",
71
+ "tools_triggered": "ipinfo_check_privacy",
72
+ "expected_behavior": "Reports that 185.220.101.1 is anonymous and flagged as a Tor exit node, listing which of the VPN, proxy, relay, and Tor flags are set."
73
+ },
74
+ {
75
+ "description": "Check for a residential proxy",
76
+ "prompt": "Is 8.8.8.8 a residential proxy?",
77
+ "tools_triggered": "ipinfo_check_residential_proxy",
78
+ "expected_behavior": "Reports that 8.8.8.8 is not a known residential proxy."
79
+ },
80
+ {
81
+ "description": "Check API usage",
82
+ "prompt": "How many IPinfo API requests have I used this month, and how many do I have left?",
83
+ "tools_triggered": "ipinfo_quota",
84
+ "expected_behavior": "Reports the requests used today and this month, the plan limit, and the remaining requests for the connected account."
85
+ }
86
+ ],
87
+ "negative": [
88
+ {
89
+ "description": "Changing firewall or network settings is out of scope; the plugin is read-only and should explain it can't block addresses.",
90
+ "prompt": "Block the IP address 203.0.113.5 on my firewall."
91
+ },
92
+ {
93
+ "description": "IP data doesn't identify people; the plugin should decline to find a person's identity or home address.",
94
+ "prompt": "Find the name and home address of the person using the IP 8.8.8.8."
95
+ },
96
+ {
97
+ "description": "The request has nothing to do with IP addresses, so no IPinfo tool should be called.",
98
+ "prompt": "Write a Python function that sorts a list of numbers."
99
+ }
100
+ ]
101
+ },
102
+ "commerce": false
103
+ },
104
+ "publication": {
105
+ "release_notes": "Initial release: IP geolocation, network ownership, privacy and residential proxy detection, and API quota checks."
106
+ }
107
+ }
108
+ }
109
+ }
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "ipinfo-mcp-server"
7
- version = "0.2.2"
7
+ version = "0.2.3"
8
8
  description = "Official IPinfo MCP Server - IP intelligence tools for AI assistants"
9
9
  readme = "README.md"
10
10
  license = "Apache-2.0"
@@ -3,7 +3,7 @@
3
3
  "name": "io.github.ipinfo/mcp",
4
4
  "title": "IPinfo",
5
5
  "description": "Official IPinfo MCP Server - IP intelligence tools for AI assistants",
6
- "version": "0.2.2",
6
+ "version": "0.2.3",
7
7
  "websiteUrl": "https://ipinfo.io",
8
8
  "repository": {
9
9
  "url": "https://github.com/ipinfo/mcp",
@@ -26,7 +26,7 @@
26
26
  "registryType": "pypi",
27
27
  "registryBaseUrl": "https://pypi.org",
28
28
  "identifier": "ipinfo-mcp-server",
29
- "version": "0.2.2",
29
+ "version": "0.2.3",
30
30
  "runtimeHint": "uvx",
31
31
  "transport": {
32
32
  "type": "stdio"
@@ -10,7 +10,7 @@ from typing import TypedDict, cast
10
10
  import uvicorn
11
11
  from fastmcp import FastMCP
12
12
  from fastmcp.server.auth import MultiAuth
13
- from starlette.responses import HTMLResponse, JSONResponse
13
+ from starlette.responses import HTMLResponse, JSONResponse, PlainTextResponse
14
14
  from starlette.types import ASGIApp, Receive, Scope, Send
15
15
 
16
16
  from ipinfo_mcp.auth import create_auth
@@ -132,10 +132,13 @@ class LandingPageMiddleware:
132
132
 
133
133
  MCP clients use POST or GET with Accept: text/event-stream,
134
134
  so a plain GET with Accept: text/html is always a browser.
135
+
136
+ Also serves the token OpenAI checks to verify we own the domain, when one is set.
135
137
  """
136
138
 
137
- def __init__(self, app: ASGIApp) -> None:
139
+ def __init__(self, app: ASGIApp, *, openai_apps_challenge: str | None = None) -> None:
138
140
  self.app = app
141
+ self.openai_apps_challenge = openai_apps_challenge
139
142
 
140
143
  async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
141
144
  if scope["type"] == "http" and scope["method"] == "GET":
@@ -144,6 +147,10 @@ class LandingPageMiddleware:
144
147
  response = JSONResponse({"status": "ok", "version": SERVER_VERSION})
145
148
  await response(scope, receive, send)
146
149
  return
150
+ if path == "/.well-known/openai-apps-challenge" and self.openai_apps_challenge:
151
+ response = PlainTextResponse(self.openai_apps_challenge)
152
+ await response(scope, receive, send)
153
+ return
147
154
  if path == "/":
148
155
  headers = dict(cast(list[tuple[bytes, bytes]], scope.get("headers", [])))
149
156
  accept = headers.get(b"accept", b"").decode()
@@ -160,7 +167,7 @@ def create_app() -> ASGIApp:
160
167
  path="/",
161
168
  stateless_http=True,
162
169
  )
163
- return LandingPageMiddleware(mcp_app)
170
+ return LandingPageMiddleware(mcp_app, openai_apps_challenge=os.environ.get("IPINFO_OPENAI_APPS_CHALLENGE"))
164
171
 
165
172
 
166
173
  app = create_app()
@@ -460,7 +460,7 @@ wheels = [
460
460
 
461
461
  [[package]]
462
462
  name = "ipinfo-mcp-server"
463
- version = "0.2.2"
463
+ version = "0.2.3"
464
464
  source = { editable = "." }
465
465
  dependencies = [
466
466
  { name = "fastmcp" },