sec-mcp 0.1.1__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.
- sec_mcp-0.1.1/LICENSE +21 -0
- sec_mcp-0.1.1/PKG-INFO +173 -0
- sec_mcp-0.1.1/README.md +146 -0
- sec_mcp-0.1.1/pyproject.toml +41 -0
- sec_mcp-0.1.1/sec_mcp/__init__.py +10 -0
- sec_mcp-0.1.1/sec_mcp/cli.py +84 -0
- sec_mcp-0.1.1/sec_mcp/config.json +11 -0
- sec_mcp-0.1.1/sec_mcp/mcp_server.py +42 -0
- sec_mcp-0.1.1/sec_mcp/sec_mcp.py +70 -0
- sec_mcp-0.1.1/sec_mcp/storage.py +119 -0
- sec_mcp-0.1.1/sec_mcp/tests/test_cli.py +31 -0
- sec_mcp-0.1.1/sec_mcp/tests/test_core.py +47 -0
- sec_mcp-0.1.1/sec_mcp/tests/test_interface.py +34 -0
- sec_mcp-0.1.1/sec_mcp/tests/test_storage.py +68 -0
- sec_mcp-0.1.1/sec_mcp/tests/test_update_blacklist.py +28 -0
- sec_mcp-0.1.1/sec_mcp/tests/test_utility.py +37 -0
- sec_mcp-0.1.1/sec_mcp/update_blacklist.py +77 -0
- sec_mcp-0.1.1/sec_mcp/utility.py +65 -0
- sec_mcp-0.1.1/sec_mcp.egg-info/PKG-INFO +173 -0
- sec_mcp-0.1.1/sec_mcp.egg-info/SOURCES.txt +24 -0
- sec_mcp-0.1.1/sec_mcp.egg-info/dependency_links.txt +1 -0
- sec_mcp-0.1.1/sec_mcp.egg-info/entry_points.txt +3 -0
- sec_mcp-0.1.1/sec_mcp.egg-info/requires.txt +7 -0
- sec_mcp-0.1.1/sec_mcp.egg-info/top_level.txt +1 -0
- sec_mcp-0.1.1/setup.cfg +4 -0
- sec_mcp-0.1.1/setup.py +27 -0
sec_mcp-0.1.1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Luong NGUYEN
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
sec_mcp-0.1.1/PKG-INFO
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: sec-mcp
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: Python toolkit providing security checks for domains, URLs, IPs, and more.
|
|
5
|
+
Author: Luong NGUYEN
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/Montimage/sec-mcp
|
|
8
|
+
Project-URL: Repository, https://github.com/Montimage/sec-mcp.git
|
|
9
|
+
Project-URL: Documentation, https://github.com/Montimage/sec-mcp#readme
|
|
10
|
+
Keywords: security,blacklist,mcp,phishing,malware
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Topic :: Security
|
|
15
|
+
Requires-Python: >=3.11
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Requires-Dist: requests>=2.31.0
|
|
19
|
+
Requires-Dist: httpx>=0.25.0
|
|
20
|
+
Requires-Dist: click>=8.1.7
|
|
21
|
+
Requires-Dist: idna>=3.4
|
|
22
|
+
Requires-Dist: mcp[cli]>=0.1.0
|
|
23
|
+
Requires-Dist: schedule>=1.2.0
|
|
24
|
+
Requires-Dist: tqdm>=4.66.0
|
|
25
|
+
Dynamic: license-file
|
|
26
|
+
Dynamic: requires-python
|
|
27
|
+
|
|
28
|
+
# sec-mcp: Security Checking Toolkit
|
|
29
|
+
|
|
30
|
+
A Python toolkit providing security checks for domains, URLs, IPs, and more. Integrate easily into any Python application, use via terminal CLI, or run as an MCP server to enrich LLM context with real-time threat insights.
|
|
31
|
+
|
|
32
|
+
## Features
|
|
33
|
+
|
|
34
|
+
- Comprehensive security checks for domains, URLs, IP addresses, and more against multiple blacklist feeds
|
|
35
|
+
- On-demand updates from OpenPhish, PhishStats, URLhaus and custom sources
|
|
36
|
+
- High-performance, thread-safe SQLite storage with in-memory caching for fast lookups
|
|
37
|
+
- Python API via `SecMCP` class for easy integration into your applications
|
|
38
|
+
- Intuitive Click-based CLI for interactive single or batch scans
|
|
39
|
+
- Built-in MCP server support for LLM/AI integrations over JSON/STDIO
|
|
40
|
+
|
|
41
|
+
## Installation
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
pip install sec-mcp
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Usage via CLI
|
|
48
|
+
|
|
49
|
+
1. Install the package:
|
|
50
|
+
```bash
|
|
51
|
+
pip install sec-mcp
|
|
52
|
+
```
|
|
53
|
+
2. Check a single URL/domain/IP:
|
|
54
|
+
```bash
|
|
55
|
+
sec-mcp check https://example.com
|
|
56
|
+
```
|
|
57
|
+
3. Batch check from a file:
|
|
58
|
+
```bash
|
|
59
|
+
sec-mcp batch urls.txt
|
|
60
|
+
```
|
|
61
|
+
4. View blacklist status:
|
|
62
|
+
```bash
|
|
63
|
+
sec-mcp status
|
|
64
|
+
```
|
|
65
|
+
5. Manually trigger an update:
|
|
66
|
+
```bash
|
|
67
|
+
sec-mcp update
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Usage via API (Python)
|
|
71
|
+
|
|
72
|
+
1. Install in your project:
|
|
73
|
+
```bash
|
|
74
|
+
pip install sec-mcp
|
|
75
|
+
```
|
|
76
|
+
2. Import and initialize:
|
|
77
|
+
```python
|
|
78
|
+
from sec_mcp import SecMCP
|
|
79
|
+
|
|
80
|
+
client = SecMCP()
|
|
81
|
+
```
|
|
82
|
+
3. Single check:
|
|
83
|
+
```python
|
|
84
|
+
result = client.check("https://example.com")
|
|
85
|
+
print(result.to_json())
|
|
86
|
+
```
|
|
87
|
+
4. Batch check:
|
|
88
|
+
```python
|
|
89
|
+
urls = ["https://example.com", "https://test.com"]
|
|
90
|
+
results = client.check_batch(urls)
|
|
91
|
+
for r in results:
|
|
92
|
+
print(r.to_json())
|
|
93
|
+
```
|
|
94
|
+
5. Get status and update:
|
|
95
|
+
```python
|
|
96
|
+
status = client.get_status()
|
|
97
|
+
print(status.to_json())
|
|
98
|
+
|
|
99
|
+
client.update()
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Usage via MCP Client
|
|
103
|
+
|
|
104
|
+
To run sec-mcp as an MCP server for AI-driven clients (e.g., Claude):
|
|
105
|
+
|
|
106
|
+
1. Install in editable mode (for development):
|
|
107
|
+
```bash
|
|
108
|
+
pip install -e .
|
|
109
|
+
```
|
|
110
|
+
2. Start the MCP server:
|
|
111
|
+
```bash
|
|
112
|
+
sec-mcp-server
|
|
113
|
+
```
|
|
114
|
+
3. Configure your MCP client (e.g., Claude) to point at the command:
|
|
115
|
+
```json
|
|
116
|
+
{
|
|
117
|
+
"mcpServers": {
|
|
118
|
+
"sec-mcp": {
|
|
119
|
+
"command": ".venv/bin/python3",
|
|
120
|
+
"args": ["-m", "sec_mcp.start_server"]
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Clients will then use the built-in `check_blacklist` tool over JSON/STDIO for real-time security checks.
|
|
127
|
+
|
|
128
|
+
## Configuration
|
|
129
|
+
|
|
130
|
+
The client can be configured via `config.json`:
|
|
131
|
+
|
|
132
|
+
- `blacklist_sources`: URLs for blacklist feeds
|
|
133
|
+
- `update_time`: Daily update schedule (default: "00:00")
|
|
134
|
+
- `cache_size`: In-memory cache size (default: 10000)
|
|
135
|
+
- `log_level`: Logging verbosity (default: "INFO")
|
|
136
|
+
|
|
137
|
+
## Configuring sec-mcp with Claude (MCP Client)
|
|
138
|
+
|
|
139
|
+
To use your MCP Server for security checking (sec-mcp) with an MCP client such as Claude, add it to your Claude configuration as follows:
|
|
140
|
+
|
|
141
|
+
```json
|
|
142
|
+
{
|
|
143
|
+
"mcpServers": {
|
|
144
|
+
"sec-mcp": {
|
|
145
|
+
"command": ".venv/bin/python3",
|
|
146
|
+
"args": ["-m", "sec_mcp.start_server"]
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
- Ensure you have installed all dependencies in your virtual environment (`.venv`).
|
|
153
|
+
- The `command` should point to your Python executable inside `.venv` for best isolation.
|
|
154
|
+
- The `args` array should launch your MCP server using the provided script.
|
|
155
|
+
- You can add other MCP servers in the same configuration if needed.
|
|
156
|
+
|
|
157
|
+
This setup allows Claude (or any compatible MCP client) to connect to your sec-mcp server and use its `check_blacklist` tool for real-time security checks on URLs, domains, or IP addresses.
|
|
158
|
+
|
|
159
|
+
For more details and advanced configuration, see the [Model Context Protocol examples](https://modelcontextprotocol.io/examples).
|
|
160
|
+
|
|
161
|
+
## Development
|
|
162
|
+
|
|
163
|
+
Clone the repository and install in development mode:
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
git clone <repository-url>
|
|
167
|
+
cd sec-mcp
|
|
168
|
+
pip install -e .
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## License
|
|
172
|
+
|
|
173
|
+
MIT
|
sec_mcp-0.1.1/README.md
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# sec-mcp: Security Checking Toolkit
|
|
2
|
+
|
|
3
|
+
A Python toolkit providing security checks for domains, URLs, IPs, and more. Integrate easily into any Python application, use via terminal CLI, or run as an MCP server to enrich LLM context with real-time threat insights.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Comprehensive security checks for domains, URLs, IP addresses, and more against multiple blacklist feeds
|
|
8
|
+
- On-demand updates from OpenPhish, PhishStats, URLhaus and custom sources
|
|
9
|
+
- High-performance, thread-safe SQLite storage with in-memory caching for fast lookups
|
|
10
|
+
- Python API via `SecMCP` class for easy integration into your applications
|
|
11
|
+
- Intuitive Click-based CLI for interactive single or batch scans
|
|
12
|
+
- Built-in MCP server support for LLM/AI integrations over JSON/STDIO
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pip install sec-mcp
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Usage via CLI
|
|
21
|
+
|
|
22
|
+
1. Install the package:
|
|
23
|
+
```bash
|
|
24
|
+
pip install sec-mcp
|
|
25
|
+
```
|
|
26
|
+
2. Check a single URL/domain/IP:
|
|
27
|
+
```bash
|
|
28
|
+
sec-mcp check https://example.com
|
|
29
|
+
```
|
|
30
|
+
3. Batch check from a file:
|
|
31
|
+
```bash
|
|
32
|
+
sec-mcp batch urls.txt
|
|
33
|
+
```
|
|
34
|
+
4. View blacklist status:
|
|
35
|
+
```bash
|
|
36
|
+
sec-mcp status
|
|
37
|
+
```
|
|
38
|
+
5. Manually trigger an update:
|
|
39
|
+
```bash
|
|
40
|
+
sec-mcp update
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Usage via API (Python)
|
|
44
|
+
|
|
45
|
+
1. Install in your project:
|
|
46
|
+
```bash
|
|
47
|
+
pip install sec-mcp
|
|
48
|
+
```
|
|
49
|
+
2. Import and initialize:
|
|
50
|
+
```python
|
|
51
|
+
from sec_mcp import SecMCP
|
|
52
|
+
|
|
53
|
+
client = SecMCP()
|
|
54
|
+
```
|
|
55
|
+
3. Single check:
|
|
56
|
+
```python
|
|
57
|
+
result = client.check("https://example.com")
|
|
58
|
+
print(result.to_json())
|
|
59
|
+
```
|
|
60
|
+
4. Batch check:
|
|
61
|
+
```python
|
|
62
|
+
urls = ["https://example.com", "https://test.com"]
|
|
63
|
+
results = client.check_batch(urls)
|
|
64
|
+
for r in results:
|
|
65
|
+
print(r.to_json())
|
|
66
|
+
```
|
|
67
|
+
5. Get status and update:
|
|
68
|
+
```python
|
|
69
|
+
status = client.get_status()
|
|
70
|
+
print(status.to_json())
|
|
71
|
+
|
|
72
|
+
client.update()
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Usage via MCP Client
|
|
76
|
+
|
|
77
|
+
To run sec-mcp as an MCP server for AI-driven clients (e.g., Claude):
|
|
78
|
+
|
|
79
|
+
1. Install in editable mode (for development):
|
|
80
|
+
```bash
|
|
81
|
+
pip install -e .
|
|
82
|
+
```
|
|
83
|
+
2. Start the MCP server:
|
|
84
|
+
```bash
|
|
85
|
+
sec-mcp-server
|
|
86
|
+
```
|
|
87
|
+
3. Configure your MCP client (e.g., Claude) to point at the command:
|
|
88
|
+
```json
|
|
89
|
+
{
|
|
90
|
+
"mcpServers": {
|
|
91
|
+
"sec-mcp": {
|
|
92
|
+
"command": ".venv/bin/python3",
|
|
93
|
+
"args": ["-m", "sec_mcp.start_server"]
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Clients will then use the built-in `check_blacklist` tool over JSON/STDIO for real-time security checks.
|
|
100
|
+
|
|
101
|
+
## Configuration
|
|
102
|
+
|
|
103
|
+
The client can be configured via `config.json`:
|
|
104
|
+
|
|
105
|
+
- `blacklist_sources`: URLs for blacklist feeds
|
|
106
|
+
- `update_time`: Daily update schedule (default: "00:00")
|
|
107
|
+
- `cache_size`: In-memory cache size (default: 10000)
|
|
108
|
+
- `log_level`: Logging verbosity (default: "INFO")
|
|
109
|
+
|
|
110
|
+
## Configuring sec-mcp with Claude (MCP Client)
|
|
111
|
+
|
|
112
|
+
To use your MCP Server for security checking (sec-mcp) with an MCP client such as Claude, add it to your Claude configuration as follows:
|
|
113
|
+
|
|
114
|
+
```json
|
|
115
|
+
{
|
|
116
|
+
"mcpServers": {
|
|
117
|
+
"sec-mcp": {
|
|
118
|
+
"command": ".venv/bin/python3",
|
|
119
|
+
"args": ["-m", "sec_mcp.start_server"]
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
- Ensure you have installed all dependencies in your virtual environment (`.venv`).
|
|
126
|
+
- The `command` should point to your Python executable inside `.venv` for best isolation.
|
|
127
|
+
- The `args` array should launch your MCP server using the provided script.
|
|
128
|
+
- You can add other MCP servers in the same configuration if needed.
|
|
129
|
+
|
|
130
|
+
This setup allows Claude (or any compatible MCP client) to connect to your sec-mcp server and use its `check_blacklist` tool for real-time security checks on URLs, domains, or IP addresses.
|
|
131
|
+
|
|
132
|
+
For more details and advanced configuration, see the [Model Context Protocol examples](https://modelcontextprotocol.io/examples).
|
|
133
|
+
|
|
134
|
+
## Development
|
|
135
|
+
|
|
136
|
+
Clone the repository and install in development mode:
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
git clone <repository-url>
|
|
140
|
+
cd sec-mcp
|
|
141
|
+
pip install -e .
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## License
|
|
145
|
+
|
|
146
|
+
MIT
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "sec-mcp"
|
|
7
|
+
version = "0.1.1"
|
|
8
|
+
description = "Python toolkit providing security checks for domains, URLs, IPs, and more."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = { text = "MIT" }
|
|
11
|
+
requires-python = ">=3.11"
|
|
12
|
+
authors = [ { name = "Luong NGUYEN" } ]
|
|
13
|
+
dependencies = [
|
|
14
|
+
"requests>=2.31.0",
|
|
15
|
+
"httpx>=0.25.0",
|
|
16
|
+
"click>=8.1.7",
|
|
17
|
+
"idna>=3.4",
|
|
18
|
+
"mcp[cli]>=0.1.0",
|
|
19
|
+
"schedule>=1.2.0",
|
|
20
|
+
"tqdm>=4.66.0",
|
|
21
|
+
]
|
|
22
|
+
classifiers = [
|
|
23
|
+
"License :: OSI Approved :: MIT License",
|
|
24
|
+
"Programming Language :: Python :: 3",
|
|
25
|
+
"Programming Language :: Python :: 3.11",
|
|
26
|
+
"Topic :: Security",
|
|
27
|
+
]
|
|
28
|
+
keywords = ["security", "blacklist", "mcp", "phishing", "malware"]
|
|
29
|
+
|
|
30
|
+
[project.urls]
|
|
31
|
+
Homepage = "https://github.com/Montimage/sec-mcp"
|
|
32
|
+
Repository = "https://github.com/Montimage/sec-mcp.git"
|
|
33
|
+
Documentation = "https://github.com/Montimage/sec-mcp#readme"
|
|
34
|
+
|
|
35
|
+
[project.scripts]
|
|
36
|
+
sec-mcp = "sec_mcp.cli:cli"
|
|
37
|
+
sec-mcp-server = "sec_mcp.start_server:main"
|
|
38
|
+
|
|
39
|
+
[tool.setuptools.packages.find]
|
|
40
|
+
where = ["."]
|
|
41
|
+
include = ["sec_mcp*"]
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"""
|
|
2
|
+
MCP Client - A Python library and CLI for checking domains, URLs, and IPs against blacklists.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from .sec_mcp import SecMCP, CheckResult, StatusInfo
|
|
6
|
+
from .cli import cli
|
|
7
|
+
from .utility import validate_input, setup_logging
|
|
8
|
+
|
|
9
|
+
__version__ = "0.1.1"
|
|
10
|
+
__all__ = ['SecMCP', 'CheckResult', 'StatusInfo', 'cli', 'validate_input', 'setup_logging']
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import click
|
|
2
|
+
from .sec_mcp import SecMCP
|
|
3
|
+
|
|
4
|
+
# Global SecMCP instance for CLI
|
|
5
|
+
core = SecMCP()
|
|
6
|
+
|
|
7
|
+
@click.group()
|
|
8
|
+
@click.version_option(version="0.1.1", message="%(version)s (MCP Client)")
|
|
9
|
+
def cli():
|
|
10
|
+
"""MCP Client CLI for checking domains, URLs, and IPs against blacklists.
|
|
11
|
+
|
|
12
|
+
Examples:
|
|
13
|
+
mcp check https://example.com
|
|
14
|
+
mcp batch urls.txt --json
|
|
15
|
+
mcp status
|
|
16
|
+
"""
|
|
17
|
+
pass
|
|
18
|
+
|
|
19
|
+
@cli.command(help="Check a single domain, URL, or IP against the blacklist.\n\nExample: mcp check https://example.com --json")
|
|
20
|
+
@click.argument('value')
|
|
21
|
+
@click.option('--json', is_flag=True, help='Output in JSON format')
|
|
22
|
+
def check(value: str, json: bool):
|
|
23
|
+
result = core.check(value)
|
|
24
|
+
if json:
|
|
25
|
+
click.echo(result.to_json())
|
|
26
|
+
else:
|
|
27
|
+
if result.blacklisted:
|
|
28
|
+
click.secho(f"Status: Blacklisted", fg="red")
|
|
29
|
+
else:
|
|
30
|
+
click.secho(f"Status: Safe", fg="green")
|
|
31
|
+
click.echo(f"Explanation: {result.explanation}")
|
|
32
|
+
|
|
33
|
+
@cli.command(help="Check multiple inputs from a file against the blacklist.\n\nExample: mcp batch urls.txt --json")
|
|
34
|
+
@click.argument('file', type=click.Path(exists=True))
|
|
35
|
+
@click.option('--json', is_flag=True, help='Output in JSON format')
|
|
36
|
+
def batch(file: str, json: bool):
|
|
37
|
+
with open(file) as f:
|
|
38
|
+
values = [line.strip() for line in f if line.strip()]
|
|
39
|
+
results = core.check_batch(values)
|
|
40
|
+
if json:
|
|
41
|
+
import json as _json
|
|
42
|
+
click.echo(_json.dumps([r.to_json() for r in results], indent=2))
|
|
43
|
+
else:
|
|
44
|
+
for value, result in zip(values, results):
|
|
45
|
+
click.secho(f"{value}:", bold=True)
|
|
46
|
+
if result.blacklisted:
|
|
47
|
+
click.secho(f" Status: Blacklisted", fg="red")
|
|
48
|
+
else:
|
|
49
|
+
click.secho(f" Status: Safe", fg="green")
|
|
50
|
+
click.echo(f" Explanation: {result.explanation}")
|
|
51
|
+
|
|
52
|
+
@cli.command(help="Show blacklist status (entry count, last update, sources).\n\nExample: mcp status --json")
|
|
53
|
+
@click.option('--json', is_flag=True, help='Output in JSON format')
|
|
54
|
+
def status(json):
|
|
55
|
+
status = core.get_status()
|
|
56
|
+
if json:
|
|
57
|
+
import json as _json
|
|
58
|
+
click.echo(_json.dumps(status.to_json(), indent=2))
|
|
59
|
+
else:
|
|
60
|
+
click.secho(f"Total entries: {status.entry_count}", bold=True)
|
|
61
|
+
click.echo(f"Last update: {status.last_update}")
|
|
62
|
+
click.echo("Active sources:")
|
|
63
|
+
for source in status.sources:
|
|
64
|
+
click.echo(f" - {source}")
|
|
65
|
+
click.echo(f"Server status: {status.server_status}")
|
|
66
|
+
|
|
67
|
+
@cli.command(help="Update blacklist feeds immediately.")
|
|
68
|
+
@click.option('--json', is_flag=True, help='Output minimal JSON confirmation')
|
|
69
|
+
def update(json):
|
|
70
|
+
"""Force an immediate update of all blacklists."""
|
|
71
|
+
core.update()
|
|
72
|
+
if json:
|
|
73
|
+
import json as _json
|
|
74
|
+
click.echo(_json.dumps({"updated": True}))
|
|
75
|
+
else:
|
|
76
|
+
click.echo("Blacklist update triggered.")
|
|
77
|
+
|
|
78
|
+
@cli.command(help="Sample random blacklist entries for testing.")
|
|
79
|
+
@click.option('-n', '--count', default=10, help='Number of entries to sample')
|
|
80
|
+
def sample(count: int):
|
|
81
|
+
"""Output a random sample of blacklist values for quick tests."""
|
|
82
|
+
entries = core.sample(count)
|
|
83
|
+
for value in entries:
|
|
84
|
+
click.echo(value)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"blacklist_sources": {
|
|
3
|
+
"OpenPhish": "https://openphish.com/feed.txt",
|
|
4
|
+
"PhishStats": "https://phishstats.info/phish_score.csv",
|
|
5
|
+
"URLhaus": "https://urlhaus.abuse.ch/downloads/text/"
|
|
6
|
+
},
|
|
7
|
+
"update_time": "00:00",
|
|
8
|
+
"cache_size": 10000,
|
|
9
|
+
"log_level": "INFO",
|
|
10
|
+
"db_path": "mcp.db"
|
|
11
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
from mcp.server.fastmcp import FastMCP
|
|
2
|
+
import anyio
|
|
3
|
+
# import SecMCP for server logic
|
|
4
|
+
from .sec_mcp import SecMCP
|
|
5
|
+
from .utility import validate_input
|
|
6
|
+
|
|
7
|
+
# Initialize FastMCP server
|
|
8
|
+
mcp = FastMCP("mcp-blacklist")
|
|
9
|
+
|
|
10
|
+
# Global SecMCP instance for MCP server
|
|
11
|
+
core = SecMCP()
|
|
12
|
+
|
|
13
|
+
@mcp.tool(description="Calculate sum of two numbers. Returns JSON: {sum: number}.")
|
|
14
|
+
async def sum_numbers(a: float, b: float):
|
|
15
|
+
"""Sum two numbers."""
|
|
16
|
+
return {"sum": a + b}
|
|
17
|
+
|
|
18
|
+
@mcp.tool(name="check", description="Check if a domain, URL, or IP address is in the blacklist. Returns JSON: {is_safe: bool, explain: str}.")
|
|
19
|
+
async def check_blacklist(value: str):
|
|
20
|
+
"""Check a single value against the blacklist."""
|
|
21
|
+
if not validate_input(value):
|
|
22
|
+
return {"is_safe": False, "explain": "Invalid input format. Must be a valid domain, URL, or IP address."}
|
|
23
|
+
result = core.check(value)
|
|
24
|
+
return {"is_safe": not result.blacklisted, "explain": result.explanation}
|
|
25
|
+
|
|
26
|
+
@mcp.tool(description="Get status of the blacklist. Returns JSON: {entry_count: int, last_update: str, sources: List[str], server_status: str}.")
|
|
27
|
+
async def get_blacklist_status():
|
|
28
|
+
"""Return current blacklist status."""
|
|
29
|
+
status = core.get_status()
|
|
30
|
+
return {
|
|
31
|
+
"entry_count": status.entry_count,
|
|
32
|
+
"last_update": status.last_update,
|
|
33
|
+
"sources": status.sources,
|
|
34
|
+
"server_status": status.server_status
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
@mcp.tool(description="Force immediate update of all blacklists. Returns JSON: {updated: bool}.")
|
|
38
|
+
async def update_blacklists():
|
|
39
|
+
"""Trigger an immediate blacklist refresh."""
|
|
40
|
+
# Offload to thread to avoid nested event loops
|
|
41
|
+
await anyio.to_thread.run_sync(core.update)
|
|
42
|
+
return {"updated": True}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
from typing import List, Optional
|
|
4
|
+
from .storage import Storage
|
|
5
|
+
from .update_blacklist import BlacklistUpdater
|
|
6
|
+
|
|
7
|
+
@dataclass
|
|
8
|
+
class CheckResult:
|
|
9
|
+
blacklisted: bool
|
|
10
|
+
explanation: str
|
|
11
|
+
|
|
12
|
+
def to_json(self):
|
|
13
|
+
return {
|
|
14
|
+
"is_safe": not self.blacklisted,
|
|
15
|
+
"explain": self.explanation
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
@dataclass
|
|
19
|
+
class StatusInfo:
|
|
20
|
+
entry_count: int
|
|
21
|
+
last_update: datetime
|
|
22
|
+
sources: List[str]
|
|
23
|
+
server_status: str
|
|
24
|
+
|
|
25
|
+
def to_json(self):
|
|
26
|
+
return {
|
|
27
|
+
"entry_count": self.entry_count,
|
|
28
|
+
"last_update": self.last_update.isoformat(),
|
|
29
|
+
"sources": self.sources,
|
|
30
|
+
"server_status": self.server_status
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
class SecMCP:
|
|
34
|
+
def __init__(self):
|
|
35
|
+
self.storage = Storage()
|
|
36
|
+
self.updater = BlacklistUpdater(self.storage)
|
|
37
|
+
|
|
38
|
+
def check(self, value: str) -> CheckResult:
|
|
39
|
+
"""Check a single value against the blacklist."""
|
|
40
|
+
if self.storage.is_blacklisted(value):
|
|
41
|
+
source = self.storage.get_blacklist_source(value)
|
|
42
|
+
return CheckResult(
|
|
43
|
+
blacklisted=True,
|
|
44
|
+
explanation=f"Blacklisted by {source}"
|
|
45
|
+
)
|
|
46
|
+
return CheckResult(
|
|
47
|
+
blacklisted=False,
|
|
48
|
+
explanation="Not blacklisted"
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
def check_batch(self, values: List[str]) -> List[CheckResult]:
|
|
52
|
+
"""Check multiple values against the blacklist."""
|
|
53
|
+
return [self.check(value) for value in values]
|
|
54
|
+
|
|
55
|
+
def get_status(self) -> StatusInfo:
|
|
56
|
+
"""Get current status of the blacklist service."""
|
|
57
|
+
return StatusInfo(
|
|
58
|
+
entry_count=self.storage.count_entries(),
|
|
59
|
+
last_update=self.storage.get_last_update(),
|
|
60
|
+
sources=self.storage.get_active_sources(),
|
|
61
|
+
server_status="Running (STDIO)"
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
def update(self) -> None:
|
|
65
|
+
"""Force an immediate update of all blacklists."""
|
|
66
|
+
self.updater.force_update()
|
|
67
|
+
|
|
68
|
+
def sample(self, count: int = 10) -> List[str]:
|
|
69
|
+
"""Return a random sample of blacklist entries for testing."""
|
|
70
|
+
return self.storage.sample_entries(count)
|