mcp-zoomeye-org 0.1.0__py3-none-any.whl
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.
- mcp_zoomeye_org/__init__.py +19 -0
- mcp_zoomeye_org/__main__.py +3 -0
- mcp_zoomeye_org/prompts.py +203 -0
- mcp_zoomeye_org/server.py +181 -0
- mcp_zoomeye_org-0.1.0.dist-info/METADATA +440 -0
- mcp_zoomeye_org-0.1.0.dist-info/RECORD +8 -0
- mcp_zoomeye_org-0.1.0.dist-info/WHEEL +4 -0
- mcp_zoomeye_org-0.1.0.dist-info/entry_points.txt +2 -0
@@ -0,0 +1,19 @@
|
|
1
|
+
from .server import serve
|
2
|
+
|
3
|
+
|
4
|
+
def main():
|
5
|
+
"""MCP ZoomEye Server - ZoomEye search for MCP"""
|
6
|
+
import argparse
|
7
|
+
import asyncio
|
8
|
+
|
9
|
+
parser = argparse.ArgumentParser(
|
10
|
+
description="give a model the ability to handle ZoomEye queries"
|
11
|
+
)
|
12
|
+
parser.add_argument("--key", type=str, help="ZoomEye API Key")
|
13
|
+
|
14
|
+
args = parser.parse_args()
|
15
|
+
asyncio.run(serve(args.key))
|
16
|
+
|
17
|
+
|
18
|
+
if __name__ == "__main__":
|
19
|
+
main()
|
@@ -0,0 +1,203 @@
|
|
1
|
+
SEARCH_SYNTAX_GUIDE = """
|
2
|
+
### Search Syntax Guide
|
3
|
+
|
4
|
+
- Search Scope covers devices (IPv4, IPv6) and websites (domains).
|
5
|
+
- When entering a search string, the system will match keywords in "global" mode, including content from various
|
6
|
+
protocols such as HTTP, SSH, FTP, etc. (e.g., HTTP/HTTPS protocol headers, body, SSL, title, and other protocol
|
7
|
+
banners).
|
8
|
+
- Search strings are case-insensitive and will be segmented for matching (the search results page provides a "
|
9
|
+
segmentation" test feature). When using == for search, it enforces exact case-sensitive matching with strict syntax.
|
10
|
+
- Please use quotes for search strings (e.g., "Cisco System" or 'Cisco System'). If the search string contains quotes,
|
11
|
+
use the escape character, e.g.,"a\"b". If the search string contains parentheses, use the escape character, e.g.,
|
12
|
+
portinfo\(\).
|
13
|
+
|
14
|
+
### The logical operators of the syntax:
|
15
|
+
|
16
|
+
- =, Search for assets containing keywords
|
17
|
+
title="knownsec"
|
18
|
+
Search for websites with titles containing Knownsec's assets
|
19
|
+
- ==, Accurate search, indicating a complete match of keywords (case sensitive), can search for data with empty values
|
20
|
+
title=="knownsec"
|
21
|
+
Precise search, which means exact match of keywords (case sensitive), and can search for data with empty values Search
|
22
|
+
for assets with the website title "Knownsec"
|
23
|
+
- ||, Enter "||" in the search box to indicate the logical operation of "or"
|
24
|
+
service="ssh" || service="http"
|
25
|
+
Search for SSH or HTTP data
|
26
|
+
- &&, Enter "&&" in the search box to indicate the logical operation of "and"
|
27
|
+
device="router" && after="2020-01-01"
|
28
|
+
Search for routers after Jan 1, 2020
|
29
|
+
- !=, Enter "!=" in the search box to indicate the logical operation of "not"
|
30
|
+
country="US" && subdivisions!="new york"
|
31
|
+
Search for data in united states excluding new york
|
32
|
+
- (), Enter "()" in the search box to indicate the logical operation of "priority processing"
|
33
|
+
(country="US" && port!=80) || (country="US" && title!="404 Not Found")
|
34
|
+
Search excluding port 80 in US or "404 not found" in the US
|
35
|
+
- *,Fuzzy search, use * for search
|
36
|
+
title="*google"
|
37
|
+
Fuzzy search, use * to search Search for assets containing Knowsec in the website title, and the title can start with
|
38
|
+
any character
|
39
|
+
|
40
|
+
### Grammatical keywords
|
41
|
+
|
42
|
+
#### Geographical Location Search
|
43
|
+
|
44
|
+
- country="CN" Search for country assets
|
45
|
+
Input country abbreviations or names, e.g.
|
46
|
+
country="china"
|
47
|
+
- subdivisions="beijing" Search for assets in the specified administrative region
|
48
|
+
Input in English, e.g.
|
49
|
+
subdivisions="beijing"
|
50
|
+
- city="changsha" Search for city assets
|
51
|
+
Input in English, e.g.
|
52
|
+
city="changsha"
|
53
|
+
|
54
|
+
#### Certificate Search
|
55
|
+
|
56
|
+
- ssl="google" Search for assets with "google" string in ssl certificate Often used to search for corresponding
|
57
|
+
targets by product name and company name
|
58
|
+
- ssl.cert.fingerprint="F3C98F223D82CC41CF83D94671CCC6C69873FABF" Search for certificate-related fingerprint assets
|
59
|
+
- ssl.chain_count=3 Search for SSL chain count assets
|
60
|
+
- ssl.cert.alg="SHA256-RSA" Search for signature algorithms supported by certificates
|
61
|
+
- ssl.cert.issuer.cn="pbx.wildix.com" Search for the common domain name of the user certificate issuer
|
62
|
+
- ssl.cert.pubkey.rsa.bits=2048 Search for rsa_bits certificate public key bit number
|
63
|
+
- ssl.cert.pubkey.ecdsa.bits=256 Search for ecdsa_bits certificate public key bit number
|
64
|
+
- ssl.cert.pubkey.type="RSA" Search for the public key type of the certificate
|
65
|
+
- ssl.cert.serial="18460192207935675900910674501" Search for certificate serial number
|
66
|
+
- ssl.cipher.bits="128" Search for encryption suite bit number
|
67
|
+
- ssl.cipher.name="TLS_AES_128_GCM_SHA256" Search for encryption suite name
|
68
|
+
- ssl.cipher.version="TLSv1.3" Search for encryption suite version
|
69
|
+
- ssl.version="TLSv1.3" Search for the SSL version of the certificate
|
70
|
+
- ssl.cert.subject.cn="example.com" Search for the common domain name of the user certificate holder
|
71
|
+
- ssl.jarm="29d29d15d29d29d00029d29d29d29dea0f89a2e5fb09e4d8e099befed92cfa" Search for assets related to Jarm
|
72
|
+
Fingerprint content
|
73
|
+
- ssl.ja3s=45094d08156d110d8ee97b204143db14 Find assets related to specific JA3S fingerprints
|
74
|
+
|
75
|
+
#### IP or Domain Name Related Information Search
|
76
|
+
|
77
|
+
- ip="8.8.8.8" Search for assets related to the specified IPv4 address
|
78
|
+
ip="2600:3c00::f03c:91ff:fefc:574a" Search for assets related to specified IPv6 address
|
79
|
+
- cidr="52.2.254.36/24" Search for C-class assets of IP
|
80
|
+
cidr="52.2.254.36/16"is the B class of the IP, cidr="52.2.254.36/8"is the A class of the IP, e.g.
|
81
|
+
cidr="52.2.254.36/16"
|
82
|
+
cidr="52.2.254.36/8"
|
83
|
+
- org="Stanford University" Search for assets of related organizations Used to locate IP assets corresponding to
|
84
|
+
universities, structures, and large Internet companies
|
85
|
+
- isp="China Mobile" Search for assets of related network service providers Can be supplemented with org data
|
86
|
+
- asn=42893 Search for IP assets related to corresponding ASN (Autonomous system number)
|
87
|
+
- port=80 Search for related port assets Currently does not support simultaneous open multi-port target search
|
88
|
+
- hostname="google.com" Search for assets of related IP "hostname"
|
89
|
+
- domain="baidu.com" Search for domain-related assets Used to search domain and subdomain data
|
90
|
+
|
91
|
+
- banner="FTP" Search by protocol messages Used for searching HTTP response header data
|
92
|
+
- http.header="http" Search by HTTP response header Used for searching HTTP response header data
|
93
|
+
- http.header_hash="27f9973fe57298c3b63919259877a84d" Search by the hash values calculated from HTTP header.
|
94
|
+
- http.header.server="Nginx" Search by server of the HTTP header Used for searching the server data in HTTP response
|
95
|
+
headers
|
96
|
+
- http.header.version="1.2" Search by version number in the HTTP header
|
97
|
+
- http.header.status_code="200" Search by HTTP response status code Search for assets with HTTP response status code
|
98
|
+
200 or other status codes, such as 302, 404, etc.
|
99
|
+
- http.body="document" Search by HTML body
|
100
|
+
- http.body_hash="84a18166fde3ee7e7c974b8d1e7e21b4" Search by hash value calculated from HTML body
|
101
|
+
|
102
|
+
#### Fingerprint Search
|
103
|
+
|
104
|
+
- app="Cisco ASA SSL VPN" Search for Cisco ASA-SSL-VPN devices For more app rules, please refer to [object Object].
|
105
|
+
Entering keywords such as "Cisco" in the search box will display related app prompts
|
106
|
+
- service="ssh" Search for assets related to the specified service protocol Common service protocols include: http,
|
107
|
+
ftp,
|
108
|
+
ssh, telnet, etc. (other services can be found in the domain name sidebar aggregation display of search results)
|
109
|
+
- device="router" Search for router-related device types Common types include router, switch, storage-misc, etc. (other
|
110
|
+
types can be found in the domain name sidebar aggregation display of search results)
|
111
|
+
- os="RouterOS" Search for related operating systems Common systems include Linux, Windows, RouterOS, IOS, JUNOS,
|
112
|
+
etc. (
|
113
|
+
other systems can be found in the domain name sidebar aggregation display of search results)
|
114
|
+
- title="Cisco" Search for data with "Cisco" in the title of the HTML content
|
115
|
+
- industry="government" Search for assets related to the specified industry type Common industry types include
|
116
|
+
technology, energy, finance, manufacturing, etc. (other types can be supplemented with org data)
|
117
|
+
|
118
|
+
- product="Cisco" Search for assets with "Cisco" in the component information Support mainstream asset component
|
119
|
+
search
|
120
|
+
- protocol="TCP" Search for assets with the transmission protocol as TCP Common transmission protocols include TCP,
|
121
|
+
UDP, TCP6, SCTP
|
122
|
+
- is_honeypot="True" Filter for honeypot assets
|
123
|
+
|
124
|
+
#### Time Node or Interval Related Search
|
125
|
+
|
126
|
+
- after="2020-01-01" && port="50050" Search for assets with an update time after Jan 1, 2020 and a port 50050 Time
|
127
|
+
filters need to be combined with other filters
|
128
|
+
- before="2020-01-01" && port="50050" Search for assets with an update time before Jan 1, 2020 and a port 50050 Time
|
129
|
+
filters need to be combined with other filters
|
130
|
+
|
131
|
+
#### Dig
|
132
|
+
|
133
|
+
- dig="baidu.com 220.181.38.148" Search for assets with related dig content
|
134
|
+
|
135
|
+
#### Iconhash
|
136
|
+
|
137
|
+
- iconhash="f3418a443e7d841097c714d69ec4bcb8" Analyze the target data by MD5 and search for assets with related content
|
138
|
+
based on the icon Search for assets with the "google" icon
|
139
|
+
- iconhash="1941681276" Analyze the target data by MMH3 and search for assets with related content based on the icon
|
140
|
+
Search for assets with the "amazon" icon
|
141
|
+
|
142
|
+
#### Filehash
|
143
|
+
|
144
|
+
- filehash="0b5ce08db7fb8fffe4e14d05588d49d9" Search for assets with related content based on the parsed file data
|
145
|
+
Search
|
146
|
+
for assets parsed with "Gitlab"
|
147
|
+
|
148
|
+
### Syntax Examples:
|
149
|
+
|
150
|
+
- Search for all assets of China Merchants Group in Arabic
|
151
|
+
org="مكتب التجار الصيني" || ssl="مكتب التجار الصيني"
|
152
|
+
|
153
|
+
- Search for Starlink devices
|
154
|
+
app=Starlink || device=Starlink
|
155
|
+
|
156
|
+
- Search for network devices running http service on port 80
|
157
|
+
port=80 && service="http"
|
158
|
+
|
159
|
+
- Search for network devices running ssl on port 443 in Nagoya
|
160
|
+
city=nagoya && port=443 && service=ssl
|
161
|
+
|
162
|
+
- Search for network devices running Windows operating system in the United States
|
163
|
+
country=us && os=windows
|
164
|
+
|
165
|
+
- Search for devices running Microsoft NTP application
|
166
|
+
app="Microsoft NTP"
|
167
|
+
|
168
|
+
- Search for webcams in Tokyo
|
169
|
+
city=tokyo && device=webcam
|
170
|
+
|
171
|
+
- Search for industrial control devices with component 6ES7 315-2EH14-0AB0 running on port 102
|
172
|
+
port=102 && module_id=6ES7 215-1BG40-0XB0
|
173
|
+
|
174
|
+
- Search for assets indexed after 2020-01-01 with port 50050 open
|
175
|
+
after="2020-01-01" && port=50050
|
176
|
+
|
177
|
+
- Search for assets in Delta, Canada
|
178
|
+
country=Canada && city=Delta
|
179
|
+
|
180
|
+
- Search for assets in Poland with Linux system and port 22
|
181
|
+
os=linux && port=22 && country=PL
|
182
|
+
|
183
|
+
- Search for FTP service with hostname example
|
184
|
+
service=ftp && hostname=example
|
185
|
+
|
186
|
+
- Search for IPv4 assets
|
187
|
+
is_ipv4=true
|
188
|
+
|
189
|
+
- Search for IPv6 assets
|
190
|
+
is_ipv6=true
|
191
|
+
|
192
|
+
- Search for IP assets containing "FreeBSD", including both IPv4 and IPv6
|
193
|
+
FreeBSD && (is_ipv4=true || is_ipv6=true)
|
194
|
+
|
195
|
+
- Search for website assets containing FreeBSD
|
196
|
+
FreeBSD && is_domain=true
|
197
|
+
|
198
|
+
- Search for assets with "Knownsec" in the body
|
199
|
+
http.body="Knownsec"
|
200
|
+
|
201
|
+
- Search for specific Header hash
|
202
|
+
http.header_hash="9763f6e29aa78e7ca2179ac82decbc25"
|
203
|
+
"""
|
@@ -0,0 +1,181 @@
|
|
1
|
+
import json
|
2
|
+
import os
|
3
|
+
from enum import Enum
|
4
|
+
from typing import Optional, Sequence
|
5
|
+
|
6
|
+
import httpx
|
7
|
+
from dotenv import load_dotenv
|
8
|
+
from mcp.server import Server
|
9
|
+
from mcp.server.stdio import stdio_server
|
10
|
+
from mcp.types import Tool, TextContent, ImageContent, EmbeddedResource
|
11
|
+
|
12
|
+
from .prompts import SEARCH_SYNTAX_GUIDE
|
13
|
+
|
14
|
+
load_dotenv()
|
15
|
+
|
16
|
+
|
17
|
+
class ZoomeyeTools(str, Enum):
|
18
|
+
ZOOMEYE_SEARCH = "zoomeye_search"
|
19
|
+
"""Search query for ZoomEye."""
|
20
|
+
ZOOMEYE_VULDB_BY_ID = "zoomeye_vuldb_by_id"
|
21
|
+
"""Query vulnerability by ID."""
|
22
|
+
|
23
|
+
ZOOMEYE_VULDB_BY_KEYWORD = "zoomeye_vuldb_by_keyword"
|
24
|
+
"""Query vulnerability by keyword."""
|
25
|
+
|
26
|
+
|
27
|
+
def zoomeye_search(qbase64: str, page: int = 1, pagesize: int = 10, fields: str = "", sub_type: str = "",
|
28
|
+
facets: str = "", ignore_cache: bool = False):
|
29
|
+
"""Search query for ZoomEye.
|
30
|
+
### Parameters
|
31
|
+
|Parameter|Type|Required|Description|
|
32
|
+
| ----- | ----- | ----- | ----- |
|
33
|
+
|qbase64|string|true|Base64 encoded query string. For more, refer to Related references.|
|
34
|
+
|fields|string|false|The fields to return, separated by commas. Default: ip, port, domain, update_time. For more, refer to Response field description|
|
35
|
+
|sub_type|string|false|Data type, supports v4, v6, and web. Default is v4.|
|
36
|
+
|page|integer|false|View asset page number|
|
37
|
+
|pagesize|integer|false|Number of records per page, default is 10, maximum is 10,000.|
|
38
|
+
|facets|string|false|Statistical items, separated by commas if there are multiple. Supports country, subdivisions, city, product, service, device, OS, and port.|
|
39
|
+
|ignore_cache|boolean|false|Whether to ignore the cache. false, supported by Business plan and above.|
|
40
|
+
"""
|
41
|
+
service = ZoomeyeService()
|
42
|
+
return service.query(qbase64=qbase64, page=page, pagesize=pagesize, fields=fields, sub_type=sub_type, facets=facets,
|
43
|
+
ignore_cache=ignore_cache)
|
44
|
+
|
45
|
+
|
46
|
+
class ZoomeyeService:
|
47
|
+
def __init__(self, key: Optional[str] = None):
|
48
|
+
self.key = key
|
49
|
+
self.base_url = "https://api.zoomeye.org"
|
50
|
+
if not self.key:
|
51
|
+
self.key = os.getenv("ZOOMEYE_API_KEY")
|
52
|
+
|
53
|
+
async def get_client(self):
|
54
|
+
proxy = None
|
55
|
+
https_proxy = os.getenv("https_proxy")
|
56
|
+
http_proxy = os.getenv("http_proxy")
|
57
|
+
if https_proxy or http_proxy:
|
58
|
+
proxy = https_proxy or http_proxy
|
59
|
+
return httpx.AsyncClient(proxy=proxy)
|
60
|
+
|
61
|
+
async def query(self, qbase64, page=1, pagesize=10, fields=None, sub_type=None, facets=None, ignore_cache=None):
|
62
|
+
"""Query ZoomEye API with the given parameters.
|
63
|
+
|
64
|
+
Args:
|
65
|
+
qbase64 (str): Base64 encoded query string.
|
66
|
+
page (int, optional): Page number. Defaults to 1.
|
67
|
+
pagesize (int, optional): Number of records per page. Defaults to 10.
|
68
|
+
fields (str, optional): Fields to return, comma separated. Defaults to None.
|
69
|
+
sub_type (str, optional): Data type (v4, v6, web). Defaults to None.
|
70
|
+
facets (str, optional): Statistical items, comma separated. Defaults to None.
|
71
|
+
ignore_cache (bool, optional): Whether to ignore cache. Defaults to None.
|
72
|
+
|
73
|
+
Returns:
|
74
|
+
dict: The API response data.
|
75
|
+
|
76
|
+
Raises:
|
77
|
+
ValueError: If API key is not provided or API request fails.
|
78
|
+
"""
|
79
|
+
if not self.key:
|
80
|
+
raise ValueError(
|
81
|
+
"ZoomEye API key is required. Please set it via environment variable ZOOMEYE_API_KEY or pass it to the constructor.")
|
82
|
+
|
83
|
+
url = f"{self.base_url}/v2/search"
|
84
|
+
headers = {"API-KEY": self.key, "Content-Type": "application/json"}
|
85
|
+
|
86
|
+
# Prepare request data
|
87
|
+
data = {"qbase64": qbase64, "page": page, "pagesize": pagesize}
|
88
|
+
|
89
|
+
# Add optional parameters if provided
|
90
|
+
if fields:
|
91
|
+
data["fields"] = fields
|
92
|
+
if sub_type:
|
93
|
+
data["sub_type"] = sub_type
|
94
|
+
if facets:
|
95
|
+
data["facets"] = facets
|
96
|
+
if ignore_cache is not None:
|
97
|
+
data["ignore_cache"] = ignore_cache
|
98
|
+
|
99
|
+
try:
|
100
|
+
client = await self.get_client()
|
101
|
+
async with client:
|
102
|
+
response = await client.post(url, headers=headers, json=data)
|
103
|
+
response.raise_for_status() # Raise exception for HTTP errors
|
104
|
+
return response.json()
|
105
|
+
except httpx.HTTPError as e:
|
106
|
+
raise ValueError(f"Error querying ZoomEye API: {str(e)}")
|
107
|
+
except json.JSONDecodeError:
|
108
|
+
raise ValueError("Invalid JSON response from ZoomEye API")
|
109
|
+
|
110
|
+
|
111
|
+
async def serve(key: str | None = None) -> None:
|
112
|
+
server = Server("mcp-zoomeye")
|
113
|
+
zoomeye_service = ZoomeyeService(key=key)
|
114
|
+
|
115
|
+
@server.list_tools()
|
116
|
+
async def list_tools() -> list[Tool]:
|
117
|
+
"""Tool list"""
|
118
|
+
return [Tool(name=ZoomeyeTools.ZOOMEYE_SEARCH, description=SEARCH_SYNTAX_GUIDE, inputSchema={"type": "object",
|
119
|
+
"properties": {
|
120
|
+
"qbase64": {
|
121
|
+
"type": "string",
|
122
|
+
"description": "Base64 encoded query string for ZoomEye search", },
|
123
|
+
"page": {
|
124
|
+
"type": "integer",
|
125
|
+
"description": "View asset page number, default is 1",
|
126
|
+
"default": 1},
|
127
|
+
"pagesize": {
|
128
|
+
"type": "integer",
|
129
|
+
"description": "Number of records per page, default is 10, maximum is 1000",
|
130
|
+
"default": 10,
|
131
|
+
"maximum": 1000},
|
132
|
+
"fields": {
|
133
|
+
"type": "string",
|
134
|
+
"description": "The fields to return, separated by commas. Default: ip, port, domain, update_time"},
|
135
|
+
"sub_type": {
|
136
|
+
"type": "string",
|
137
|
+
"description": "Data type, supports v4, v6, and web. Default is v4",
|
138
|
+
"enum": [
|
139
|
+
"v4",
|
140
|
+
"v6",
|
141
|
+
"web"]},
|
142
|
+
"facets": {
|
143
|
+
"type": "string",
|
144
|
+
"description": "Statistical items, separated by commas if there are multiple. Supports country, subdivisions, city, product, service, device, OS, and port"},
|
145
|
+
"ignore_cache": {
|
146
|
+
"type": "boolean",
|
147
|
+
"description": "Whether to ignore the cache. Supported by Business plan and above"}},
|
148
|
+
"required": [
|
149
|
+
"qbase64"], }, )]
|
150
|
+
|
151
|
+
@server.call_tool()
|
152
|
+
async def call_tool(name: str, arguments: dict) -> Sequence[TextContent | ImageContent | EmbeddedResource]:
|
153
|
+
"""Handle tool calls for zoomeye queries."""
|
154
|
+
try:
|
155
|
+
match name:
|
156
|
+
case ZoomeyeTools.ZOOMEYE_SEARCH:
|
157
|
+
qbase64 = arguments.get("qbase64")
|
158
|
+
if not qbase64:
|
159
|
+
raise ValueError("Missing required argument: qbase64")
|
160
|
+
|
161
|
+
page = arguments.get("page", 1)
|
162
|
+
pagesize = arguments.get("pagesize", 10)
|
163
|
+
fields = arguments.get("fields")
|
164
|
+
sub_type = arguments.get("sub_type")
|
165
|
+
facets = arguments.get("facets")
|
166
|
+
ignore_cache = arguments.get("ignore_cache")
|
167
|
+
|
168
|
+
result = await zoomeye_service.query(qbase64=qbase64, page=page, pagesize=pagesize, fields=fields,
|
169
|
+
sub_type=sub_type, facets=facets, ignore_cache=ignore_cache)
|
170
|
+
case _:
|
171
|
+
raise ValueError(f"Unknown tool: {name}")
|
172
|
+
|
173
|
+
formatted_result = json.dumps(result, ensure_ascii=False, indent=2)
|
174
|
+
return [TextContent(type="text", text=formatted_result if result is not None else "")]
|
175
|
+
|
176
|
+
except Exception as e:
|
177
|
+
raise ValueError(f"Error processing mcp-zoomeye-org query: {str(e)}")
|
178
|
+
|
179
|
+
options = server.create_initialization_options()
|
180
|
+
async with stdio_server() as (read_stream, write_stream):
|
181
|
+
await server.run(read_stream, write_stream, options)
|
@@ -0,0 +1,440 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: mcp-zoomeye-org
|
3
|
+
Version: 0.1.0
|
4
|
+
Summary: A Model Context Protocol server providing tools for ZoomEye queries for LLMs
|
5
|
+
Author-email: zoomeye team <zoomeye@knownsec.com>
|
6
|
+
License: MIT
|
7
|
+
Keywords: llm,mcp,zoomeye
|
8
|
+
Classifier: Development Status :: 4 - Beta
|
9
|
+
Classifier: Intended Audience :: Developers
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
13
|
+
Requires-Python: >=3.10
|
14
|
+
Requires-Dist: mcp>=1.0.0
|
15
|
+
Requires-Dist: pydantic>=2.0.0
|
16
|
+
Requires-Dist: python-dotenv>=1.0.0
|
17
|
+
Requires-Dist: requests>=2.32.3
|
18
|
+
Description-Content-Type: text/markdown
|
19
|
+
|
20
|
+
# 🚀 ZoomEye MCP Server
|
21
|
+
|
22
|
+
A Model Context Protocol (MCP) server that provides network asset information based on query conditions. This server allows Large Language Models (LLMs) to obtain network asset information by querying ZoomEye using dorks and other search parameters.
|
23
|
+
|
24
|
+
## 🔔 Announcement
|
25
|
+
|
26
|
+
🎉 We are excited to announce the official open-source release of **ZoomEye MCP Server** — a powerful Model Context Protocol (MCP) server that brings real-time cyber asset intelligence to AI assistants and development environments.
|
27
|
+
|
28
|
+
🚀 Free Trial: 7-Day FREE Access to ZoomEye MCP!
|
29
|
+
Experience ZoomEye MCP — the AI-powered cyberspace asset search engine — absolutely free for 7 days!
|
30
|
+
|
31
|
+
🔍 Search global internet assets, track real-time changes, and unlock AI-driven insights — all in one place.
|
32
|
+
|
33
|
+
👉 How to claim:
|
34
|
+
|
35
|
+
1. Follow us on Twitter: [@zoomeye_team](https://x.com/zoomeye_team)
|
36
|
+
2. DM us "MCP" and your MCP setup screenshot
|
37
|
+
3. Get instant access to your 7-day membership
|
38
|
+
|
39
|
+
🎁 Limited-time free trial — explore the power of AI asset search today!
|
40
|
+
|
41
|
+
💡 Provide insightful feedback that gets officially adopted, and you'll unlock **even more rewards**!
|
42
|
+
|
43
|
+
🔧 Fully compatible with leading MCP environments:
|
44
|
+
|
45
|
+
- Claude Desktop
|
46
|
+
- Cursor
|
47
|
+
- Windsurf
|
48
|
+
- Cline
|
49
|
+
- Continue
|
50
|
+
- Zed
|
51
|
+
- Cherry Studio
|
52
|
+
- Chatbox
|
53
|
+
|
54
|
+
🔗 Explore ZoomEye MCP Server on:
|
55
|
+
|
56
|
+
- GitHub: [knownsec/mcp_zoomeye_org](https://github.com/knownsec/mcp_zoomeye_org)
|
57
|
+
- MCP.so: [mcp.so/server/mcp_zoomeye](https://mcp.so/server/mcp_zoomeye/zoomeye-ai)
|
58
|
+
- Smithery: [smithery.ai/server/@zoomeye-ai/mcp_zoomeye](https://smithery.ai/server/@zoomeye-ai/mcp_zoomeye)
|
59
|
+
- Cursor Directory: [cursor.directory/mcp/zoomeye](https://cursor.directory/mcp/zoomeye)
|
60
|
+
- Pulse MCP: [pulsemcp.com/servers/zoomeye](https://www.pulsemcp.com/servers/zoomeye)
|
61
|
+
- Glama MCP: [glama.ai/mcp/servers](https://glama.ai/mcp/servers)
|
62
|
+
|
63
|
+
We welcome everyone to use, explore, and contribute!
|
64
|
+
|
65
|
+
## 🔑 How can I get a ZoomEye API key?
|
66
|
+
|
67
|
+
To use this MCP server, you’ll need a ZoomEye API key.
|
68
|
+
|
69
|
+
1. Go to https://www.zoomeye.org
|
70
|
+
2. Register or log in
|
71
|
+
3. Click your avatar → **Profile**
|
72
|
+
4. Copy your **API-KEY**
|
73
|
+
5. Set the environment variable:
|
74
|
+
|
75
|
+
`export ZOOMEYE_API_KEY="your_api_key_here"`
|
76
|
+
|
77
|
+

|
78
|
+
|
79
|
+

|
80
|
+
|
81
|
+
## Features
|
82
|
+
|
83
|
+
- Query ZoomEye for network asset information using dorks
|
84
|
+
- Caching mechanism to improve performance and reduce API calls
|
85
|
+
- Automatic retry mechanism for failed API requests
|
86
|
+
- Comprehensive error handling and logging
|
87
|
+
|
88
|
+
## Available Tools
|
89
|
+
|
90
|
+
- `zoomeye_search` - Get network asset information based on query conditions.
|
91
|
+
- Required parameters:
|
92
|
+
- `qbase64` (string): Base64 encoded query string for ZoomEye search
|
93
|
+
- Optional parameters:
|
94
|
+
- `page` (integer): View asset page number, default is 1
|
95
|
+
- `pagesize` (integer): Number of records per page, default is 10, maximum is 1000
|
96
|
+
- `fields` (string): The fields to return, separated by commas
|
97
|
+
- `sub_type` (string): Data type, supports v4, v6, and web. Default is v4
|
98
|
+
- `facets` (string): Statistical items, separated by commas if there are multiple
|
99
|
+
- `ignore_cache` (boolean): Whether to ignore the cache
|
100
|
+
|
101
|
+
## Usage Guide
|
102
|
+
|
103
|
+
### Basic Usage
|
104
|
+
|
105
|
+
Once the server is running, you can interact with it through your AI assistant or development environment. Here's how to use it:
|
106
|
+
|
107
|
+
1. **Start the server** using one of the installation methods above
|
108
|
+
2. **Configure your AI assistant** (Claude Desktop, Cursor, Windsurf, Cline, Continue, Zed, etc.) to use the server
|
109
|
+
3. **Query network information** using natural language
|
110
|
+
|
111
|
+

|
112
|
+
|
113
|
+
### Search Syntax Guide
|
114
|
+
|
115
|
+
- Search Scope covers devices (IPv4, IPv6) and websites (domains).
|
116
|
+
- When entering a search string, the system will match keywords in "global" mode, including content from various
|
117
|
+
protocols such as HTTP, SSH, FTP, etc. (e.g., HTTP/HTTPS protocol headers, body, SSL, title, and other protocol
|
118
|
+
banners).
|
119
|
+
- Search strings are case-insensitive and will be segmented for matching (the search results page provides a "
|
120
|
+
segmentation" test feature). When using == for search, it enforces exact case-sensitive matching with strict syntax.
|
121
|
+
- Please use quotes for search strings (e.g., "Cisco System" or 'Cisco System'). If the search string contains quotes,
|
122
|
+
use the escape character, e.g.,"a\"b". If the search string contains parentheses, use the escape character, e.g.,
|
123
|
+
portinfo\(\).
|
124
|
+
|
125
|
+
You can see more detailed search syntax rules in [prompts.py](src/mcp_zoomeye_org/prompts.py).
|
126
|
+
|
127
|
+
For more information on the ZoomEye Search API, refer to the [ZoomEye API v2 documentation](https://www.zoomeye.org/doc).
|
128
|
+
|
129
|
+
## Getting Started
|
130
|
+
|
131
|
+
### Prerequisites
|
132
|
+
|
133
|
+
1. **ZoomEye API Key**
|
134
|
+
|
135
|
+
- Register for an account at [ZoomEye](https://www.zoomeye.org/)
|
136
|
+
- Obtain your API key from your account settings
|
137
|
+
- The API key will be used to authenticate your requests to the ZoomEye API
|
138
|
+
2. **Python Environment**
|
139
|
+
|
140
|
+
- Python 3.10 or higher is required
|
141
|
+
- Alternatively, you can use Docker to run the server without installing Python
|
142
|
+
|
143
|
+
## Installation
|
144
|
+
|
145
|
+
### Using PIP
|
146
|
+
|
147
|
+
Alternatively, you can install `mcp-zoomeye-org` via pip:
|
148
|
+
|
149
|
+
```bash
|
150
|
+
pip install mcp-zoomeye-org
|
151
|
+
```
|
152
|
+
|
153
|
+
After installation, you can run it as a script using the following command:
|
154
|
+
|
155
|
+
```bash
|
156
|
+
python -m mcp_zoomeye_org
|
157
|
+
```
|
158
|
+
|
159
|
+
### Using uv
|
160
|
+
|
161
|
+
[`uv`](https://docs.astral.sh/uv/) is a fast Python package installer and resolver written in Rust. It's a modern alternative to pip that offers significant performance improvements.
|
162
|
+
|
163
|
+
#### Installation of uv
|
164
|
+
|
165
|
+
```bash
|
166
|
+
# Install uv using curl (macOS/Linux)
|
167
|
+
curl -LsSf https://astral.sh/uv/install.sh | sh
|
168
|
+
|
169
|
+
# Or using PowerShell (Windows)
|
170
|
+
irm https://astral.sh/uv/install.ps1 | iex
|
171
|
+
|
172
|
+
# Or using Homebrew (macOS)
|
173
|
+
brew install uv
|
174
|
+
```
|
175
|
+
|
176
|
+
#### Using uvx to run mac-zoomeye-org
|
177
|
+
|
178
|
+
No specific installation is required when using [`uvx`](https://docs.astral.sh/uv/guides/tools/), which allows you to run Python packages directly:
|
179
|
+
|
180
|
+
#### Installing with uv
|
181
|
+
|
182
|
+
Alternatively, you can install the package using uv:
|
183
|
+
|
184
|
+
```bash
|
185
|
+
# Install in the current environment
|
186
|
+
uv pip install mac-zoomeye-org
|
187
|
+
|
188
|
+
# Or create and install in a new virtual environment
|
189
|
+
uv venv
|
190
|
+
uv pip install mac-zoomeye-org
|
191
|
+
```
|
192
|
+
|
193
|
+
## Configuration
|
194
|
+
|
195
|
+
### Environment Variables
|
196
|
+
|
197
|
+
The ZoomEye MCP server requires the following environment variable:
|
198
|
+
|
199
|
+
- `ZOOMEYE_API_KEY`: Your ZoomEye API key for authentication
|
200
|
+
|
201
|
+
You can set this environment variable in several ways:
|
202
|
+
|
203
|
+
1. **Export in your shell session**:
|
204
|
+
|
205
|
+
```bash
|
206
|
+
export ZOOMEYE_API_KEY="your_api_key_here"
|
207
|
+
```
|
208
|
+
|
209
|
+
### Configure Claude.app
|
210
|
+
|
211
|
+
Add the following in Claude settings:
|
212
|
+
|
213
|
+
<details>
|
214
|
+
<summary>Using uvx</summary>
|
215
|
+
|
216
|
+
```json
|
217
|
+
"mcpServers": {
|
218
|
+
"zoomeye": {
|
219
|
+
"command": "uvx",
|
220
|
+
"args": ["mac-zoomeye-org"],
|
221
|
+
"env": {
|
222
|
+
"ZOOMEYE_API_KEY": "your_api_key_here"
|
223
|
+
}
|
224
|
+
}
|
225
|
+
}
|
226
|
+
```
|
227
|
+
|
228
|
+
</details>
|
229
|
+
|
230
|
+
|
231
|
+
<details>
|
232
|
+
<summary>Installed via pip</summary>
|
233
|
+
|
234
|
+
```json
|
235
|
+
"mcpServers": {
|
236
|
+
"zoomeye": {
|
237
|
+
"command": "python",
|
238
|
+
"args": ["-m", "mcp_server_zoomeye"],
|
239
|
+
"env": {
|
240
|
+
"ZOOMEYE_API_KEY": "your_api_key_here"
|
241
|
+
}
|
242
|
+
}
|
243
|
+
}
|
244
|
+
```
|
245
|
+
|
246
|
+
</details>
|
247
|
+
|
248
|
+
### Configure Zed
|
249
|
+
|
250
|
+
Add the following in Zed's settings.json:
|
251
|
+
|
252
|
+
<details>
|
253
|
+
<summary>Using uvx</summary>
|
254
|
+
|
255
|
+
```json
|
256
|
+
"context_servers": [
|
257
|
+
"mac-zoomeye-org": {
|
258
|
+
"command": "uvx",
|
259
|
+
"args": ["mac-zoomeye-org"],
|
260
|
+
"env": {
|
261
|
+
"ZOOMEYE_API_KEY": "your_api_key_here"
|
262
|
+
}
|
263
|
+
}
|
264
|
+
],
|
265
|
+
```
|
266
|
+
|
267
|
+
</details>
|
268
|
+
|
269
|
+
<details>
|
270
|
+
<summary>Installed via pip</summary>
|
271
|
+
|
272
|
+
```json
|
273
|
+
"context_servers": {
|
274
|
+
"mac-zoomeye-org": {
|
275
|
+
"command": "python",
|
276
|
+
"args": ["-m", "mcp_server_zoomeye"],
|
277
|
+
"env": {
|
278
|
+
"ZOOMEYE_API_KEY": "your_api_key_here"
|
279
|
+
}
|
280
|
+
}
|
281
|
+
},
|
282
|
+
```
|
283
|
+
|
284
|
+
</details>
|
285
|
+
|
286
|
+
## Example Interactions
|
287
|
+
|
288
|
+
### Example 1: Retrieve global Apache Tomcat assets
|
289
|
+
|
290
|
+
```json
|
291
|
+
{
|
292
|
+
"name": "zoomeye_search",
|
293
|
+
"arguments": {
|
294
|
+
"qbase64": "app=\"Apache Tomcat\""
|
295
|
+
}
|
296
|
+
}
|
297
|
+
```
|
298
|
+
|
299
|
+
Response:
|
300
|
+
|
301
|
+
```json
|
302
|
+
{
|
303
|
+
"code": 60000,
|
304
|
+
"message": "success",
|
305
|
+
"total": 163139107,
|
306
|
+
"query": "app=\"Apache Tomcat\"",
|
307
|
+
"data": [
|
308
|
+
{
|
309
|
+
"url": "https://1.1.1.1:443",
|
310
|
+
"ssl.jarm": "29d29d15d29d29d00029d29d29d29dea0f89a2e5fb09e4d8e099befed92cfa",
|
311
|
+
"ssl.ja3s": "45094d08156d110d8ee97b204143db14",
|
312
|
+
"iconhash_md5": "f3418a443e7d841097c714d69ec4bcb8",
|
313
|
+
"robots_md5": "0b5ce08db7fb8fffe4e14d05588d49d9",
|
314
|
+
"security_md5": "0b5ce08db7fb8fffe4e14d05588d49d9",
|
315
|
+
"ip": "1.1.1.1",
|
316
|
+
"domain": "www.google.com",
|
317
|
+
"hostname": "SPACEX",
|
318
|
+
"os": "windows",
|
319
|
+
"port": 443,
|
320
|
+
"service": "https",
|
321
|
+
"title": ["GoogleGoogle appsGoogle Search"],
|
322
|
+
"version": "1.1.0",
|
323
|
+
"device": "webcam",
|
324
|
+
"rdns": "c01031-001.cust.wallcloud.ch",
|
325
|
+
"product": "OpenSSD",
|
326
|
+
"header": "HTTP/1.1 302 Found Location: https://www.google.com/?gws_rd=ssl Cache-Control: private...",
|
327
|
+
"header_hash": "27f9973fe57298c3b63919259877a84d",
|
328
|
+
"body": "HTTP/1.1 302 Found Location: https://www.google.com/?gws_rd=ssl Cache-Control: private...",
|
329
|
+
"body_hash": "84a18166fde3ee7e7c974b8d1e7e21b4",
|
330
|
+
"banner": "SSH-2.0-OpenSSH_7.6p1 Ubuntu-4ubuntu0.3",
|
331
|
+
"update_time": "2024-07-03T14:34:10",
|
332
|
+
"header.server.name": "nginx",
|
333
|
+
"header.server.version": "1.8.1",
|
334
|
+
"continent.name": "Europe",
|
335
|
+
"country.name": "Germany",
|
336
|
+
"province.name": "Hesse",
|
337
|
+
"city.name": "Frankfurt",
|
338
|
+
"lon": "118.753262",
|
339
|
+
"lat": "32.064838",
|
340
|
+
"isp.name": "aviel.ru",
|
341
|
+
"organization.name": "SERVISFIRST BANK",
|
342
|
+
"zipcode": "210003",
|
343
|
+
"idc": 0,
|
344
|
+
"honeypot": 0,
|
345
|
+
"asn": 4837,
|
346
|
+
"protocol": "tcp",
|
347
|
+
"ssl": "SSL Certificate Version: TLS 1.2 CipherSuit: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256...",
|
348
|
+
"primary_industry": "Finance",
|
349
|
+
"sub_industry": "bank",
|
350
|
+
"rank": 60
|
351
|
+
}
|
352
|
+
]
|
353
|
+
}
|
354
|
+
```
|
355
|
+
|
356
|
+
## Debugging and Troubleshooting
|
357
|
+
|
358
|
+
### Using MCP Inspector
|
359
|
+
|
360
|
+
The Model Context Protocol Inspector is a tool that helps debug MCP servers by simulating client interactions. You can use it to test your ZoomEye MCP server:
|
361
|
+
|
362
|
+
```bash
|
363
|
+
# For uvx installation
|
364
|
+
npx @modelcontextprotocol/inspector uvx mac-zoomeye-org
|
365
|
+
|
366
|
+
# If developing locally
|
367
|
+
cd path/to/servers/src/mcp_server_zoomeye
|
368
|
+
npx @modelcontextprotocol/inspector uv run mac-zoomeye-org
|
369
|
+
```
|
370
|
+
|
371
|
+
### Common Issues
|
372
|
+
|
373
|
+
1. **Authentication Errors**
|
374
|
+
|
375
|
+
- Ensure your ZoomEye API key is correct and properly set as an environment variable
|
376
|
+
- Check that your API key has not expired or been revoked
|
377
|
+
2. **Connection Issues**
|
378
|
+
|
379
|
+
- Verify your internet connection
|
380
|
+
- Check if the ZoomEye API is experiencing downtime
|
381
|
+
3. **No Results**
|
382
|
+
|
383
|
+
- Your query might be too specific or contain syntax errors
|
384
|
+
- Try simplifying your query or using different search terms
|
385
|
+
4. **Rate Limiting**
|
386
|
+
|
387
|
+
- ZoomEye API has rate limits based on your account type
|
388
|
+
- Space out your requests or upgrade your account for higher limits
|
389
|
+
|
390
|
+
## Advanced Usage
|
391
|
+
|
392
|
+
### Caching
|
393
|
+
|
394
|
+
The ZoomEye MCP server implements caching to improve performance and reduce API calls:
|
395
|
+
|
396
|
+
- Responses are cached based on the query parameters
|
397
|
+
- Cache duration is configurable (default: 1 hour)
|
398
|
+
- You can bypass the cache by setting `ignore_cache` to `true` in your query
|
399
|
+
|
400
|
+
### Custom Fields
|
401
|
+
|
402
|
+
You can request specific fields in your query results by using the `fields` parameter:
|
403
|
+
|
404
|
+
```json
|
405
|
+
{
|
406
|
+
"name": "zoomeye_search",
|
407
|
+
"arguments": {
|
408
|
+
"qbase64": "app=\"Apache\"",
|
409
|
+
"fields": "ip,port,domain,service,os,country,city"
|
410
|
+
}
|
411
|
+
}
|
412
|
+
```
|
413
|
+
|
414
|
+
### Pagination
|
415
|
+
|
416
|
+
For queries that return many results, you can paginate through them:
|
417
|
+
|
418
|
+
```json
|
419
|
+
{
|
420
|
+
"name": "zoomeye_search",
|
421
|
+
"arguments": {
|
422
|
+
"qbase64": "app=\"Apache\"",
|
423
|
+
"page": 2,
|
424
|
+
"pagesize": 20
|
425
|
+
}
|
426
|
+
}
|
427
|
+
```
|
428
|
+
|
429
|
+
## Contributing
|
430
|
+
|
431
|
+
We encourage contributions to mac-zoomeye-org to help expand and improve its functionality. Whether it's adding new related tools, enhancing existing features, or improving documentation, your input is valuable.
|
432
|
+
|
433
|
+
For examples of other MCP servers and implementation patterns, see:
|
434
|
+
https://github.com/modelcontextprotocol/servers
|
435
|
+
|
436
|
+
Pull requests are welcome! Feel free to contribute new ideas, bug fixes, or enhancements to make mac-zoomeye-org more robust and practical.
|
437
|
+
|
438
|
+
## License
|
439
|
+
|
440
|
+
mac-zoomeye-org is licensed under the MIT License. This means you are free to use, modify, and distribute the software, subject to the terms and conditions of the MIT License. For more information, see the LICENSE file in the project repository.
|
@@ -0,0 +1,8 @@
|
|
1
|
+
mcp_zoomeye_org/__init__.py,sha256=M9-z6h2rrMvPUTCtAw0j_iGphrD8KiFQXylwBfa0qj8,440
|
2
|
+
mcp_zoomeye_org/__main__.py,sha256=DSxm3VDrBM5-hCe_ccFSbTu2jgVO64XuWJxLDR9iBFU,40
|
3
|
+
mcp_zoomeye_org/prompts.py,sha256=swFBgG77S9n1OMIUyuSyWDRWSmnuG3ZE24e5r1Rp26w,10308
|
4
|
+
mcp_zoomeye_org/server.py,sha256=V5umTNmAAERVWEfz7qlP8aKphzD36j1nj0jYUIs0CCE,10759
|
5
|
+
mcp_zoomeye_org-0.1.0.dist-info/METADATA,sha256=jAc7iufy5F43CS7Yg0cu6F5GRvcY6a2bubWub3v2Ft0,12950
|
6
|
+
mcp_zoomeye_org-0.1.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
7
|
+
mcp_zoomeye_org-0.1.0.dist-info/entry_points.txt,sha256=g8ocdd0a8JWOz6QbOTbFOKXKkDRppzfp3cxpNtNpjfI,57
|
8
|
+
mcp_zoomeye_org-0.1.0.dist-info/RECORD,,
|