Mini MCP Client
November 18, 2025 · View on GitHub
A simple, standalone Python client demonstrating how to integrate with the mitre-mcp server via HTTP/JSON-RPC. This client serves as both a practical tool and a reference implementation for building your own integrations.
⚡ Quick Reference
Critical requirement for MCP HTTP integration:
import httpx
async def call_mcp_tool(tool_name: str, arguments: dict):
"""Call an MCP tool via HTTP/JSON-RPC."""
async with httpx.AsyncClient() as client:
response = await client.post(
"http://localhost:8000/mcp",
json={
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {"name": tool_name, "arguments": arguments}
},
headers={
"Content-Type": "application/json",
"Accept": "application/json, text/event-stream" # ⚠️ BOTH required!
}
)
return response.json()
# Example usage
result = await call_mcp_tool("get_tactics", {"domain": "enterprise-attack"})
Key point: The MCP server requires Accept: application/json, text/event-stream - omitting either will result in 406 errors.
Features
- ✅ Complete CLI - Command-line interface for all mitre-mcp tools
- ✅ HTTP/JSON-RPC - Uses the recommended HTTP transport mode with proper MCP headers
- ✅ Error Handling - Proper error messages and connection troubleshooting
- ✅ Pretty Output - JSON formatting with optional pretty-printing
- ✅ All Tools Supported - Covers all 9 MCP tools
- ✅ Configurable - Customize host, port, and domain
- ✅ Lightweight - Only requires
httpxand Python 3.10+ - ✅ Debug Mode - Detailed request/response logging for troubleshooting
Prerequisites
- Python 3.10 or higher
- The
httpxlibrary - A running mitre-mcp server in HTTP mode
Installation
# Install httpx if not already installed
pip install httpx
# Make the script executable (optional)
chmod +x mini-mcp-client.py
Quick Start
Step 1: Start the mitre-mcp server in HTTP mode:
mitre-mcp --http --port 8000
Step 2: Run the mini-mcp-client:
# Get help
python mini-mcp-client.py --help
# Get all tactics
python mini-mcp-client.py tactics
# Get techniques for initial-access tactic
python mini-mcp-client.py techniques --tactic initial-access
Available Commands
1. tactics - Get all tactics
python mini-mcp-client.py tactics
python mini-mcp-client.py tactics --domain mobile-attack
2. techniques - Get techniques (all or by tactic)
# Get all techniques (paginated)
python mini-mcp-client.py techniques
# Get techniques with subtechniques
python mini-mcp-client.py techniques --subtechniques
# Get techniques with descriptions
python mini-mcp-client.py techniques --descriptions
# Get techniques for a specific tactic
python mini-mcp-client.py techniques --tactic initial-access
# Pagination
python mini-mcp-client.py techniques --limit 50 --offset 100
# Exclude revoked/deprecated
python mini-mcp-client.py techniques --no-revoked
3. technique - Get details for a specific technique
python mini-mcp-client.py technique --id T1059.001
python mini-mcp-client.py technique --id T1003 --domain enterprise-attack
4. groups - Get all threat groups
python mini-mcp-client.py groups
python mini-mcp-client.py groups --no-revoked
5. group - Get techniques used by a threat group
python mini-mcp-client.py group --name APT29
python mini-mcp-client.py group --name "Lazarus Group"
python mini-mcp-client.py group --name APT41 --domain enterprise-attack
6. software - Get software (malware/tools)
# Get all software
python mini-mcp-client.py software
# Get only malware
python mini-mcp-client.py software --malware
# Get only tools
python mini-mcp-client.py software --tools
# Exclude revoked
python mini-mcp-client.py software --no-revoked
7. mitigations - Get mitigations
# Get all mitigations
python mini-mcp-client.py mitigations
# Get techniques mitigated by a specific mitigation
python mini-mcp-client.py mitigations --name "Multi-factor Authentication"
python mini-mcp-client.py mitigations --name "Network Segmentation"
Global Options
All commands support these global options:
--host HOST- Server host (default: localhost)--port PORT- Server port (default: 8000)--no-pretty- Disable pretty JSON formatting--domain DOMAIN- ATT&CK domain (enterprise-attack, mobile-attack, ics-attack)--no-revoked- Exclude revoked/deprecated items
Examples
Example 1: Threat Intelligence Workflow
# 1. Get all threat groups
python mini-mcp-client.py groups --no-revoked
# 2. Get techniques used by APT29
python mini-mcp-client.py group --name APT29
# 3. Get details for a specific technique
python mini-mcp-client.py technique --id T1059.001
Example 2: Detection Engineering
# 1. Get all persistence techniques
python mini-mcp-client.py techniques --tactic persistence --no-revoked
# 2. Get all mitigations
python mini-mcp-client.py mitigations
# 3. Check what a specific mitigation addresses
python mini-mcp-client.py mitigations --name "Application Developer Guidance"
Example 3: Red Team Planning
# 1. Get techniques for lateral movement
python mini-mcp-client.py techniques --tactic lateral-movement --descriptions
# 2. Get tools available
python mini-mcp-client.py software --tools
# 3. Check what a specific group uses
python mini-mcp-client.py group --name FIN7
Example 4: Using Different Server Configuration
# Connect to remote server
python mini-mcp-client.py --host 192.168.1.100 --port 8080 tactics
# Use mobile domain
python mini-mcp-client.py techniques --domain mobile-attack
# Disable pretty printing (for piping to jq)
python mini-mcp-client.py tactics --no-pretty | jq '.result'
Integration Examples
Using as a Library
You can import and use the MitreMCPClient class in your own scripts:
import asyncio
from mini_mcp_client import MitreMCPClient
async def my_analysis():
client = MitreMCPClient(host="localhost", port=8000)
# Get tactics
tactics = await client.call_tool("get_tactics", {
"domain": "enterprise-attack"
})
# Get techniques for a tactic
techniques = await client.call_tool("get_techniques_by_tactic", {
"tactic_shortname": "initial-access",
"domain": "enterprise-attack"
})
print(client.format_output(tactics))
print(client.format_output(techniques))
asyncio.run(my_analysis())
Building Custom Workflows
import asyncio
from mini_mcp_client import MitreMCPClient
async def analyze_apt_group(group_name: str):
"""Analyze techniques used by an APT group."""
client = MitreMCPClient()
# Get group's techniques
result = await client.call_tool("get_techniques_used_by_group", {
"group_name": group_name,
"domain": "enterprise-attack"
})
# Process results
if "result" in result:
techniques = result["result"]["content"][0]["text"]
print(f"Techniques used by {group_name}:")
print(techniques)
return result
# Run analysis
asyncio.run(analyze_apt_group("APT29"))
Troubleshooting
406 Not Acceptable Error
If you see this error:
❌ HTTP Error: Client error '406 Not Acceptable'
Cause: The MCP HTTP server requires the Accept header to include both application/json and text/event-stream.
Solution: This is already fixed in the current version. The client now sends:
headers = {
"Content-Type": "application/json",
"Accept": "application/json, text/event-stream"
}
If you're implementing your own client, make sure to include both MIME types in the Accept header.
Server Connection Issues
If you see connection errors:
❌ HTTP Error: ConnectError
Make sure mitre-mcp server is running: mitre-mcp --http --port 8000
Solution:
- Check if the mitre-mcp server is running
- Verify the host and port match your server configuration
- Ensure no firewall is blocking the connection
- Run the diagnostic script:
python test-mcp-connection.py localhost 8000
JSON-RPC Errors
If you see JSON-RPC errors:
❌ Error: JSON-RPC Error -32602: Invalid params
Solution:
- Check your command syntax with
--help - Verify technique IDs follow the format
T####orT####.### - Ensure group names and mitigation names are correct
Timeout Issues
If requests timeout:
❌ HTTP Error: TimeoutException
Solution:
- The server might be downloading data (first run)
- Increase timeout in the code (currently 30 seconds)
- Check server logs for issues
Code Structure
mini-mcp-client.py
├── MitreMCPClient # HTTP client class
│ ├── __init__() # Initialize with host/port
│ ├── call_tool() # Call MCP tools via JSON-RPC
│ └── format_output() # Format JSON output
│
├── Command Functions # One per MCP tool
│ ├── cmd_tactics()
│ ├── cmd_techniques()
│ ├── cmd_technique()
│ ├── cmd_groups()
│ ├── cmd_group()
│ ├── cmd_software()
│ └── cmd_mitigations()
│
└── main() # CLI argument parsing & execution
Best Practices
- Error Handling: Always wrap calls in try/except blocks
- Timeouts: Set appropriate timeouts for your use case
- Pagination: Use --limit and --offset for large datasets
- Filtering: Use --no-revoked to exclude outdated entries
- Caching: Consider caching results for frequently accessed data
- Async: Use async/await for concurrent requests
Extending the Client
Adding a New Command
async def cmd_my_command(
client: MitreMCPClient, args: argparse.Namespace
) -> Dict[str, Any]:
"""Your custom command."""
return await client.call_tool(
"your_tool_name",
{
"param1": args.param1,
"param2": args.param2
}
)
# Add to argparse subparsers in main()
my_parser = subparsers.add_parser("mycommand", help="My custom command")
my_parser.add_argument("--param1", required=True)
my_parser.set_defaults(func=cmd_my_command)
Adding Response Processing
def format_output(self, result: Dict[str, Any], pretty: bool = True) -> str:
"""Enhanced output formatting."""
if pretty:
# Extract specific fields
if "result" in result:
content = result["result"].get("content", [])
if content:
text = content[0].get("text", "")
# Custom formatting here
return self.format_custom(text)
return json.dumps(result, indent=2)
return json.dumps(result)
Performance Tips
- Use --no-pretty when piping to other tools
- Set appropriate --limit to reduce response size
- Use --no-revoked to filter out deprecated entries
- Cache frequently accessed data in your application
- Run server and client on same machine for lowest latency
Security Considerations
-
HTTP Transport: Not encrypted by default
- For production, use HTTPS or run on localhost only
- Don't expose the server to untrusted networks
-
Input Validation: The client validates inputs
- Server also validates for defense in depth
- Don't disable client-side validation
-
Credentials: Currently no authentication
- Add authentication if exposing over network
- Use firewall rules to restrict access
Contributing
To improve this client:
- Add more output formatting options
- Implement response caching
- Add batch processing capabilities
- Create interactive mode
- Add progress bars for large requests
License
This mini-mcp-client is part of the mitre-mcp project and follows the same MIT license.
Support
For issues or questions:
- Check the main mitre-mcp README
- Review the Playbook for usage examples
- Open an issue on the GitHub repository
Related Documentation
- Main README - mitre-mcp server documentation
- Playbook - Advanced usage scenarios
- Beginner's Guide - Getting started guide