mcpscore 0.3.0__tar.gz → 0.4.0__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.
- {mcpscore-0.3.0 → mcpscore-0.4.0}/PKG-INFO +56 -19
- {mcpscore-0.3.0 → mcpscore-0.4.0}/README.md +44 -12
- {mcpscore-0.3.0 → mcpscore-0.4.0}/mcpscore/__init__.py +2 -2
- {mcpscore-0.3.0 → mcpscore-0.4.0}/mcpscore/cli.py +10 -9
- {mcpscore-0.3.0 → mcpscore-0.4.0}/mcpscore/enums.py +11 -4
- {mcpscore-0.3.0 → mcpscore-0.4.0}/mcpscore/mcp_auditor.py +47 -7
- {mcpscore-0.3.0 → mcpscore-0.4.0}/mcpscore/mcp_client.py +116 -32
- {mcpscore-0.3.0 → mcpscore-0.4.0}/mcpscore/rules/__init__.py +8 -2
- {mcpscore-0.3.0 → mcpscore-0.4.0}/mcpscore/rules/base.py +3 -1
- {mcpscore-0.3.0 → mcpscore-0.4.0}/mcpscore/rules/protocol_version.py +8 -7
- {mcpscore-0.3.0 → mcpscore-0.4.0}/mcpscore/rules/registry.py +2 -2
- {mcpscore-0.3.0 → mcpscore-0.4.0}/mcpscore/rules/security.py +3 -2
- {mcpscore-0.3.0 → mcpscore-0.4.0}/mcpscore/rules/tools.py +36 -32
- {mcpscore-0.3.0 → mcpscore-0.4.0}/mcpscore/rules/transport.py +21 -18
- mcpscore-0.4.0/pyproject.toml +274 -0
- {mcpscore-0.3.0 → mcpscore-0.4.0}/tests/test_auditor.py +161 -135
- {mcpscore-0.3.0 → mcpscore-0.4.0}/tests/test_cli.py +70 -63
- mcpscore-0.4.0/tests/test_mcp_client_handshake.py +182 -0
- {mcpscore-0.3.0 → mcpscore-0.4.0}/tests/test_mcp_client_http.py +0 -11
- {mcpscore-0.3.0 → mcpscore-0.4.0}/tests/test_mcp_client_session.py +0 -15
- {mcpscore-0.3.0 → mcpscore-0.4.0}/tests/test_mcp_client_sse.py +0 -11
- {mcpscore-0.3.0 → mcpscore-0.4.0}/tests/test_mcp_client_stdio.py +0 -8
- {mcpscore-0.3.0 → mcpscore-0.4.0}/tests/test_protocol_version_rules.py +13 -0
- {mcpscore-0.3.0 → mcpscore-0.4.0}/tests/test_security_rules.py +7 -5
- {mcpscore-0.3.0 → mcpscore-0.4.0}/tests/test_tools_rules.py +41 -30
- mcpscore-0.4.0/tests/test_transport_rules.py +66 -0
- mcpscore-0.3.0/pyproject.toml +0 -118
- mcpscore-0.3.0/tests/test_transport_rules.py +0 -64
- {mcpscore-0.3.0 → mcpscore-0.4.0}/.gitignore +0 -0
- {mcpscore-0.3.0 → mcpscore-0.4.0}/LICENSE +0 -0
- {mcpscore-0.3.0 → mcpscore-0.4.0}/mcpscore/py.typed +0 -0
- {mcpscore-0.3.0 → mcpscore-0.4.0}/mcpscore/rules/capabilities.py +0 -0
- {mcpscore-0.3.0 → mcpscore-0.4.0}/mcpscore/rules/server_info.py +0 -0
- {mcpscore-0.3.0 → mcpscore-0.4.0}/tests/__init__.py +0 -0
- {mcpscore-0.3.0 → mcpscore-0.4.0}/tests/conftest.py +0 -0
- {mcpscore-0.3.0 → mcpscore-0.4.0}/tests/test_capabilities_rules.py +0 -0
- {mcpscore-0.3.0 → mcpscore-0.4.0}/tests/test_registry.py +0 -0
- {mcpscore-0.3.0 → mcpscore-0.4.0}/tests/test_server_info_rules.py +0 -0
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mcpscore
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: CLI tool to analyze your MCP server and get a comprehensive report on its quality
|
|
5
|
-
Project-URL: Homepage, https://
|
|
5
|
+
Project-URL: Homepage, https://mcpaudit.dev
|
|
6
6
|
Project-URL: Repository, https://github.com/mcp-box/mcpscore
|
|
7
7
|
Project-URL: Issues, https://github.com/mcp-box/mcpscore/issues
|
|
8
|
+
Project-URL: Documentation, https://github.com/mcp-box/mcpscore#readme
|
|
9
|
+
Project-URL: Changelog, https://github.com/mcp-box/mcpscore/blob/main/CHANGELOG.md
|
|
8
10
|
Author: Alex Akimov
|
|
9
11
|
License-Expression: MIT
|
|
10
12
|
License-File: LICENSE
|
|
11
|
-
Keywords: ai,audit,cli,developer-tools,llm,mcp,mcp-server,model-context-protocol,quality
|
|
13
|
+
Keywords: ai,audit,cli,compliance,developer-tools,llm,mcp,mcp-audit,mcp-server,model-context-protocol,protocol,quality,validation
|
|
12
14
|
Classifier: Development Status :: 4 - Beta
|
|
13
15
|
Classifier: Environment :: Console
|
|
14
16
|
Classifier: Intended Audience :: Developers
|
|
@@ -16,29 +18,61 @@ Classifier: License :: OSI Approved :: MIT License
|
|
|
16
18
|
Classifier: Operating System :: OS Independent
|
|
17
19
|
Classifier: Programming Language :: Python
|
|
18
20
|
Classifier: Programming Language :: Python :: 3
|
|
21
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
24
|
Classifier: Programming Language :: Python :: 3.13
|
|
20
25
|
Classifier: Topic :: Software Development
|
|
21
26
|
Classifier: Topic :: Software Development :: Libraries
|
|
22
27
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
28
|
Classifier: Topic :: Software Development :: Quality Assurance
|
|
24
29
|
Classifier: Typing :: Typed
|
|
25
|
-
Requires-Python: >=3.
|
|
26
|
-
Requires-Dist: httpx-sse>=0.4.
|
|
27
|
-
Requires-Dist: httpx>=0.28.
|
|
28
|
-
Requires-Dist: mcp>=1.
|
|
30
|
+
Requires-Python: >=3.11
|
|
31
|
+
Requires-Dist: httpx-sse>=0.4.3
|
|
32
|
+
Requires-Dist: httpx>=0.28.1
|
|
33
|
+
Requires-Dist: mcp>=1.27.2
|
|
29
34
|
Description-Content-Type: text/markdown
|
|
30
35
|
|
|
31
36
|
# MCPScore
|
|
32
37
|
|
|
38
|
+
[](https://github.com/mcp-box/mcpscore/actions/workflows/ci.yml)
|
|
39
|
+
[](https://codecov.io/gh/mcp-box/mcpscore)
|
|
40
|
+
[](https://pypi.org/project/mcpscore/)
|
|
41
|
+
[](https://pypi.org/project/mcpscore/)
|
|
42
|
+
[](LICENSE)
|
|
43
|
+
|
|
33
44
|
A command-line tool for auditing MCP (Model Context Protocol) servers. MCPScore connects to your server, runs a comprehensive set of validation rules against it, and produces a severity-based report showing what's compliant and what needs attention.
|
|
34
45
|
|
|
46
|
+
## Why MCPScore?
|
|
47
|
+
|
|
48
|
+
MCP servers that violate the spec fail silently in the worst place: inside someone else's AI agent. A missing tool description, an outdated protocol version, or an unencrypted endpoint won't crash your server — it will just make agents pick the wrong tool, drop your server from their registry, or leak traffic. MCPScore catches these issues in seconds, before your users do.
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
pip install mcpscore
|
|
52
|
+
mcpscore https://your-server.example/mcp
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## How scoring works
|
|
56
|
+
|
|
57
|
+
Every rule has a severity, and each passing rule contributes its weight to the score:
|
|
58
|
+
|
|
59
|
+
| Severity | Points | Meaning |
|
|
60
|
+
|----------|--------|---------|
|
|
61
|
+
| CRITICAL | 5 | Spec violations that break interoperability (protocol version, server name, TLS) |
|
|
62
|
+
| HIGH | 3 | Strong spec expectations (server version, valid tool schemas) |
|
|
63
|
+
| MEDIUM | 2 | Recommendations that improve agent UX (titles, descriptions, error hygiene) |
|
|
64
|
+
| LOW | 1 | Nice-to-haves (capability extras, transport recommendations) |
|
|
65
|
+
|
|
66
|
+
The final score is reported as `earned/maximum` — higher means better MCP compliance.
|
|
67
|
+
|
|
35
68
|
## Features
|
|
36
69
|
|
|
37
70
|
- **Multiple transports**: STDIO (local servers), Streamable HTTP, and SSE (remote servers)
|
|
38
71
|
- **Auto-detection**: Picks the right transport automatically — tries Streamable HTTP first, falls back to SSE for URLs
|
|
72
|
+
- **Real handshake verification**: A connection only counts once the server completes the MCP `initialize` handshake — pointing it at a non-MCP endpoint fails cleanly
|
|
39
73
|
- **Multi-language**: Audits both Python (`.py`) and Node.js (`.js`) MCP servers via STDIO
|
|
40
74
|
- **Severity-based reporting**: Rules categorized as CRITICAL, HIGH, MEDIUM, or LOW
|
|
41
|
-
- **
|
|
75
|
+
- **Library-friendly**: Fully typed (`py.typed`); use `MCPClient` + `MCPAuditor` programmatically
|
|
42
76
|
|
|
43
77
|
## What it audits
|
|
44
78
|
|
|
@@ -54,16 +88,19 @@ A command-line tool for auditing MCP (Model Context Protocol) servers. MCPScore
|
|
|
54
88
|
|
|
55
89
|
- **Capabilities**: Tools, resources, prompts, logging, and subscription support
|
|
56
90
|
|
|
91
|
+
- **Tools**: Names (presence, uniqueness, format), titles, descriptions, and JSON Schema validity of input/output schemas
|
|
92
|
+
|
|
57
93
|
- **Security**:
|
|
58
|
-
- ✅ HTTPS/TLS usage
|
|
94
|
+
- ✅ HTTPS/TLS usage with the actually negotiated TLS version
|
|
59
95
|
- ✅ Valid certificate checks
|
|
96
|
+
- ✅ Error responses checked for data leaks
|
|
60
97
|
|
|
61
98
|
- **Transport**:
|
|
62
|
-
- ✅ SSE
|
|
99
|
+
- ✅ Streamable HTTP usage (the current MCP standard; SSE-only servers get migration advice)
|
|
63
100
|
|
|
64
101
|
## Requirements
|
|
65
102
|
|
|
66
|
-
- Python 3.
|
|
103
|
+
- Python 3.11+
|
|
67
104
|
- Node.js on `PATH` if auditing a Node.js MCP server
|
|
68
105
|
- A Python interpreter on `PATH` if auditing a Python MCP server
|
|
69
106
|
|
|
@@ -101,9 +138,9 @@ Welcome to MCPScore!
|
|
|
101
138
|
Connected to the MCP server: /path/to/server.py
|
|
102
139
|
Transport: stdio
|
|
103
140
|
Starting the audit...
|
|
104
|
-
✅ Protocol version '2025-
|
|
105
|
-
✅ Protocol version '2025-
|
|
106
|
-
✅ Protocol version '2025-
|
|
141
|
+
✅ Protocol version '2025-11-25' is one of the allowed versions
|
|
142
|
+
✅ Protocol version '2025-11-25' is not deprecated
|
|
143
|
+
✅ Protocol version '2025-11-25' is the latest version
|
|
107
144
|
✅ Server name is present: 'weather'
|
|
108
145
|
✅ Server version is present: '1.17.0'
|
|
109
146
|
❌ Server title is not present in server info
|
|
@@ -124,23 +161,23 @@ Starting the audit...
|
|
|
124
161
|
Audit finished. Final score: 55/71
|
|
125
162
|
```
|
|
126
163
|
|
|
127
|
-
### Understanding the score
|
|
128
|
-
|
|
129
|
-
Each passing rule contributes points equal to its severity weight: **CRITICAL = 5, HIGH = 3, MEDIUM = 2, LOW = 1**. Higher scores indicate better compliance with MCP standards.
|
|
130
|
-
|
|
131
164
|
## Troubleshooting
|
|
132
165
|
|
|
133
166
|
**Connection fails**
|
|
134
167
|
|
|
135
168
|
- Check the path or URL is correct and reachable
|
|
136
169
|
- For local servers, make sure Python or Node.js is on `PATH`
|
|
137
|
-
-
|
|
170
|
+
- "Not a valid MCP server (handshake failed)" means the endpoint responded but did not complete the MCP `initialize` handshake — verify the URL points at an actual MCP endpoint (often `/mcp`)
|
|
138
171
|
|
|
139
172
|
**Protocol version errors**
|
|
140
173
|
|
|
141
174
|
- Confirm your server uses a currently supported MCP protocol version
|
|
142
175
|
- If your server uses a newer version that MCPScore doesn't yet recognize, please [open an issue](https://github.com/mcp-box/mcpscore/issues)
|
|
143
176
|
|
|
177
|
+
## Contributing
|
|
178
|
+
|
|
179
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup and how to add audit rules. Security reports: [SECURITY.md](SECURITY.md). Release history: [CHANGELOG.md](CHANGELOG.md).
|
|
180
|
+
|
|
144
181
|
## Feedback
|
|
145
182
|
|
|
146
183
|
Bug reports, feature requests, and general feedback are welcome at <https://github.com/mcp-box/mcpscore/issues>.
|
|
@@ -1,14 +1,43 @@
|
|
|
1
1
|
# MCPScore
|
|
2
2
|
|
|
3
|
+
[](https://github.com/mcp-box/mcpscore/actions/workflows/ci.yml)
|
|
4
|
+
[](https://codecov.io/gh/mcp-box/mcpscore)
|
|
5
|
+
[](https://pypi.org/project/mcpscore/)
|
|
6
|
+
[](https://pypi.org/project/mcpscore/)
|
|
7
|
+
[](LICENSE)
|
|
8
|
+
|
|
3
9
|
A command-line tool for auditing MCP (Model Context Protocol) servers. MCPScore connects to your server, runs a comprehensive set of validation rules against it, and produces a severity-based report showing what's compliant and what needs attention.
|
|
4
10
|
|
|
11
|
+
## Why MCPScore?
|
|
12
|
+
|
|
13
|
+
MCP servers that violate the spec fail silently in the worst place: inside someone else's AI agent. A missing tool description, an outdated protocol version, or an unencrypted endpoint won't crash your server — it will just make agents pick the wrong tool, drop your server from their registry, or leak traffic. MCPScore catches these issues in seconds, before your users do.
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pip install mcpscore
|
|
17
|
+
mcpscore https://your-server.example/mcp
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## How scoring works
|
|
21
|
+
|
|
22
|
+
Every rule has a severity, and each passing rule contributes its weight to the score:
|
|
23
|
+
|
|
24
|
+
| Severity | Points | Meaning |
|
|
25
|
+
|----------|--------|---------|
|
|
26
|
+
| CRITICAL | 5 | Spec violations that break interoperability (protocol version, server name, TLS) |
|
|
27
|
+
| HIGH | 3 | Strong spec expectations (server version, valid tool schemas) |
|
|
28
|
+
| MEDIUM | 2 | Recommendations that improve agent UX (titles, descriptions, error hygiene) |
|
|
29
|
+
| LOW | 1 | Nice-to-haves (capability extras, transport recommendations) |
|
|
30
|
+
|
|
31
|
+
The final score is reported as `earned/maximum` — higher means better MCP compliance.
|
|
32
|
+
|
|
5
33
|
## Features
|
|
6
34
|
|
|
7
35
|
- **Multiple transports**: STDIO (local servers), Streamable HTTP, and SSE (remote servers)
|
|
8
36
|
- **Auto-detection**: Picks the right transport automatically — tries Streamable HTTP first, falls back to SSE for URLs
|
|
37
|
+
- **Real handshake verification**: A connection only counts once the server completes the MCP `initialize` handshake — pointing it at a non-MCP endpoint fails cleanly
|
|
9
38
|
- **Multi-language**: Audits both Python (`.py`) and Node.js (`.js`) MCP servers via STDIO
|
|
10
39
|
- **Severity-based reporting**: Rules categorized as CRITICAL, HIGH, MEDIUM, or LOW
|
|
11
|
-
- **
|
|
40
|
+
- **Library-friendly**: Fully typed (`py.typed`); use `MCPClient` + `MCPAuditor` programmatically
|
|
12
41
|
|
|
13
42
|
## What it audits
|
|
14
43
|
|
|
@@ -24,16 +53,19 @@ A command-line tool for auditing MCP (Model Context Protocol) servers. MCPScore
|
|
|
24
53
|
|
|
25
54
|
- **Capabilities**: Tools, resources, prompts, logging, and subscription support
|
|
26
55
|
|
|
56
|
+
- **Tools**: Names (presence, uniqueness, format), titles, descriptions, and JSON Schema validity of input/output schemas
|
|
57
|
+
|
|
27
58
|
- **Security**:
|
|
28
|
-
- ✅ HTTPS/TLS usage
|
|
59
|
+
- ✅ HTTPS/TLS usage with the actually negotiated TLS version
|
|
29
60
|
- ✅ Valid certificate checks
|
|
61
|
+
- ✅ Error responses checked for data leaks
|
|
30
62
|
|
|
31
63
|
- **Transport**:
|
|
32
|
-
- ✅ SSE
|
|
64
|
+
- ✅ Streamable HTTP usage (the current MCP standard; SSE-only servers get migration advice)
|
|
33
65
|
|
|
34
66
|
## Requirements
|
|
35
67
|
|
|
36
|
-
- Python 3.
|
|
68
|
+
- Python 3.11+
|
|
37
69
|
- Node.js on `PATH` if auditing a Node.js MCP server
|
|
38
70
|
- A Python interpreter on `PATH` if auditing a Python MCP server
|
|
39
71
|
|
|
@@ -71,9 +103,9 @@ Welcome to MCPScore!
|
|
|
71
103
|
Connected to the MCP server: /path/to/server.py
|
|
72
104
|
Transport: stdio
|
|
73
105
|
Starting the audit...
|
|
74
|
-
✅ Protocol version '2025-
|
|
75
|
-
✅ Protocol version '2025-
|
|
76
|
-
✅ Protocol version '2025-
|
|
106
|
+
✅ Protocol version '2025-11-25' is one of the allowed versions
|
|
107
|
+
✅ Protocol version '2025-11-25' is not deprecated
|
|
108
|
+
✅ Protocol version '2025-11-25' is the latest version
|
|
77
109
|
✅ Server name is present: 'weather'
|
|
78
110
|
✅ Server version is present: '1.17.0'
|
|
79
111
|
❌ Server title is not present in server info
|
|
@@ -94,23 +126,23 @@ Starting the audit...
|
|
|
94
126
|
Audit finished. Final score: 55/71
|
|
95
127
|
```
|
|
96
128
|
|
|
97
|
-
### Understanding the score
|
|
98
|
-
|
|
99
|
-
Each passing rule contributes points equal to its severity weight: **CRITICAL = 5, HIGH = 3, MEDIUM = 2, LOW = 1**. Higher scores indicate better compliance with MCP standards.
|
|
100
|
-
|
|
101
129
|
## Troubleshooting
|
|
102
130
|
|
|
103
131
|
**Connection fails**
|
|
104
132
|
|
|
105
133
|
- Check the path or URL is correct and reachable
|
|
106
134
|
- For local servers, make sure Python or Node.js is on `PATH`
|
|
107
|
-
-
|
|
135
|
+
- "Not a valid MCP server (handshake failed)" means the endpoint responded but did not complete the MCP `initialize` handshake — verify the URL points at an actual MCP endpoint (often `/mcp`)
|
|
108
136
|
|
|
109
137
|
**Protocol version errors**
|
|
110
138
|
|
|
111
139
|
- Confirm your server uses a currently supported MCP protocol version
|
|
112
140
|
- If your server uses a newer version that MCPScore doesn't yet recognize, please [open an issue](https://github.com/mcp-box/mcpscore/issues)
|
|
113
141
|
|
|
142
|
+
## Contributing
|
|
143
|
+
|
|
144
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup and how to add audit rules. Security reports: [SECURITY.md](SECURITY.md). Release history: [CHANGELOG.md](CHANGELOG.md).
|
|
145
|
+
|
|
114
146
|
## Feedback
|
|
115
147
|
|
|
116
148
|
Bug reports, feature requests, and general feedback are welcome at <https://github.com/mcp-box/mcpscore/issues>.
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""MCPScore - A comprehensive auditing tool for MCP (Model Context Protocol) servers.
|
|
2
2
|
|
|
3
3
|
This package provides tools for auditing MCP servers to ensure compliance with
|
|
4
4
|
protocol standards and best practices. It includes:
|
|
5
5
|
|
|
6
|
+
- MCPAuditor: For orchestrating the audit process
|
|
6
7
|
- MCPClient: For connecting to and communicating with MCP servers
|
|
7
|
-
- MCPDoctor: For orchestrating the audit process
|
|
8
8
|
- Rule system: Extensible framework for implementing audit checks
|
|
9
9
|
- Enums: Protocol versions and transport types
|
|
10
10
|
|
|
@@ -32,22 +32,23 @@ async def async_main() -> None:
|
|
|
32
32
|
|
|
33
33
|
target: str = sys.argv[1]
|
|
34
34
|
client: MCPClient = MCPClient()
|
|
35
|
-
|
|
35
|
+
auditor: MCPAuditor = MCPAuditor()
|
|
36
36
|
|
|
37
37
|
success, transport = await client.detect_and_connect(target)
|
|
38
38
|
|
|
39
|
-
if success:
|
|
40
|
-
logger.info("Connected to the MCP server: %s", target)
|
|
41
|
-
logger.info("Transport: %s", transport)
|
|
42
|
-
else:
|
|
39
|
+
if not success:
|
|
43
40
|
logger.error("Error connecting to the MCP server: %s", target)
|
|
44
41
|
sys.exit(2)
|
|
45
42
|
|
|
46
|
-
logger.info("
|
|
47
|
-
|
|
48
|
-
logger.info("Audit finished. Final score: %s/%s", final_score, max_score)
|
|
43
|
+
logger.info("Connected to the MCP server: %s", target)
|
|
44
|
+
logger.info("Transport: %s", transport)
|
|
49
45
|
|
|
50
|
-
|
|
46
|
+
try:
|
|
47
|
+
logger.info("Starting the audit...")
|
|
48
|
+
final_score, max_score = await auditor.audit(client)
|
|
49
|
+
logger.info("Audit finished. Final score: %s/%s", final_score, max_score)
|
|
50
|
+
finally:
|
|
51
|
+
await client.cleanup()
|
|
51
52
|
|
|
52
53
|
|
|
53
54
|
def main() -> None:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""Enumerations and constants for MCP (Model Context Protocol) auditing.
|
|
2
2
|
|
|
3
|
-
This module defines the core enumerations used throughout the
|
|
3
|
+
This module defines the core enumerations used throughout the MCPScore system:
|
|
4
4
|
|
|
5
5
|
- MCPTransportType: Supported transport methods for MCP communication
|
|
6
6
|
- MCPProtocolVersion: Supported versions of the MCP protocol
|
|
@@ -38,7 +38,14 @@ class MCPProtocolVersion(StrEnum):
|
|
|
38
38
|
"""MCP protocol version from March 26, 2025."""
|
|
39
39
|
|
|
40
40
|
v2025_06_18 = "2025-06-18"
|
|
41
|
-
"""
|
|
41
|
+
"""MCP protocol version from June 18, 2025."""
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
"""
|
|
43
|
+
v2025_11_25 = "2025-11-25"
|
|
44
|
+
"""Latest MCP protocol version (November 25, 2025)."""
|
|
45
|
+
|
|
46
|
+
Latest = v2025_11_25
|
|
47
|
+
"""Alias for the latest protocol version.
|
|
48
|
+
|
|
49
|
+
This is an enum alias, not a distinct member: it does not appear in
|
|
50
|
+
`list(MCPProtocolVersion)` or in iteration-derived version lists.
|
|
51
|
+
"""
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
import asyncio
|
|
1
2
|
import logging
|
|
3
|
+
import ssl
|
|
2
4
|
from typing import TYPE_CHECKING
|
|
5
|
+
from urllib.parse import urlparse
|
|
3
6
|
|
|
4
7
|
if TYPE_CHECKING:
|
|
5
8
|
from mcp.types import InitializeResult, Prompt, Resource, Tool
|
|
@@ -9,6 +12,9 @@ from .rules import AuditData, BaseRule, RuleResult, RuleSeverity, create_all_rul
|
|
|
9
12
|
|
|
10
13
|
logger = logging.getLogger(__name__)
|
|
11
14
|
|
|
15
|
+
TLS_PROBE_TIMEOUT_S = 10
|
|
16
|
+
"""Timeout for probing the negotiated TLS version of an HTTPS server."""
|
|
17
|
+
|
|
12
18
|
|
|
13
19
|
class MCPAuditor:
|
|
14
20
|
"""Orchestrates the MCP server audit process.
|
|
@@ -19,14 +25,14 @@ class MCPAuditor:
|
|
|
19
25
|
- Tracks audit results and scoring
|
|
20
26
|
- Provides audit summary and reporting
|
|
21
27
|
|
|
22
|
-
The
|
|
28
|
+
The auditor uses a rule-based system where each rule checks specific
|
|
23
29
|
aspects of MCP compliance and contributes to an overall audit score.
|
|
24
30
|
"""
|
|
25
31
|
|
|
26
32
|
def __init__(self) -> None:
|
|
27
|
-
"""Initialize a new
|
|
33
|
+
"""Initialize a new MCPAuditor instance.
|
|
28
34
|
|
|
29
|
-
Sets up the
|
|
35
|
+
Sets up the auditor with:
|
|
30
36
|
- Empty audit data container
|
|
31
37
|
- All registered audit rules
|
|
32
38
|
- Zero initial score
|
|
@@ -68,11 +74,11 @@ class MCPAuditor:
|
|
|
68
74
|
await self._collect_resources()
|
|
69
75
|
if self.audit_data.capabilities.prompts is not None:
|
|
70
76
|
await self._collect_prompts()
|
|
71
|
-
|
|
77
|
+
self._run_all_rules()
|
|
72
78
|
|
|
73
79
|
return self.score, self.max_score
|
|
74
80
|
|
|
75
|
-
|
|
81
|
+
def _run_all_rules(self) -> None:
|
|
76
82
|
"""Execute all registered audit rules and update the audit score.
|
|
77
83
|
|
|
78
84
|
Iterates through all rules, executes each one, logs the results,
|
|
@@ -110,14 +116,48 @@ class MCPAuditor:
|
|
|
110
116
|
|
|
111
117
|
# For HTTPS connections, check TLS
|
|
112
118
|
if self.mcp_client.url and self.mcp_client.url.startswith("https://"):
|
|
113
|
-
# If we successfully connected via HTTPS,
|
|
119
|
+
# If we successfully connected via HTTPS, TLS is verified
|
|
114
120
|
# (httpx would have failed the connection if cert validation failed)
|
|
115
121
|
self.audit_data.tls_verified = True
|
|
116
|
-
self.audit_data.tls_version =
|
|
122
|
+
self.audit_data.tls_version = await self._probe_tls_version(self.mcp_client.url)
|
|
117
123
|
elif self.mcp_client.url and self.mcp_client.url.startswith("http://"):
|
|
118
124
|
self.audit_data.tls_verified = False
|
|
119
125
|
self.audit_data.tls_version = None
|
|
120
126
|
|
|
127
|
+
@staticmethod
|
|
128
|
+
async def _probe_tls_version(url: str) -> str | None:
|
|
129
|
+
"""Probe the TLS version negotiated with an HTTPS server.
|
|
130
|
+
|
|
131
|
+
Opens a short-lived TLS connection to the server and reads the
|
|
132
|
+
negotiated protocol version (e.g. "TLSv1.3") from the SSL object.
|
|
133
|
+
|
|
134
|
+
Returns:
|
|
135
|
+
The negotiated TLS version string, or None if it could not be
|
|
136
|
+
determined (the TLS rules treat an unknown version leniently).
|
|
137
|
+
|
|
138
|
+
"""
|
|
139
|
+
parsed = urlparse(url)
|
|
140
|
+
host = parsed.hostname
|
|
141
|
+
if host is None:
|
|
142
|
+
return None
|
|
143
|
+
port = parsed.port or 443
|
|
144
|
+
|
|
145
|
+
writer = None
|
|
146
|
+
try:
|
|
147
|
+
context = ssl.create_default_context()
|
|
148
|
+
_reader, writer = await asyncio.wait_for(
|
|
149
|
+
asyncio.open_connection(host, port, ssl=context),
|
|
150
|
+
timeout=TLS_PROBE_TIMEOUT_S,
|
|
151
|
+
)
|
|
152
|
+
ssl_object = writer.get_extra_info("ssl_object")
|
|
153
|
+
return ssl_object.version() if ssl_object is not None else None
|
|
154
|
+
except Exception as e: # noqa: BLE001 — probe failure must not abort the audit
|
|
155
|
+
logger.info("Could not probe TLS version for %s: %s", url, e)
|
|
156
|
+
return None
|
|
157
|
+
finally:
|
|
158
|
+
if writer is not None:
|
|
159
|
+
writer.close()
|
|
160
|
+
|
|
121
161
|
async def _collect_init_result(self) -> None:
|
|
122
162
|
"""Collect initialization data from the MCP server.
|
|
123
163
|
|