loading…
Search for a command to run...
loading…
Bridges Tufin SecureTrack and SecureChange APIs with AI development workflows, providing a secure REST API with RBAC for ticketing, device management, and topol
Bridges Tufin SecureTrack and SecureChange APIs with AI development workflows, providing a secure REST API with RBAC for ticketing, device management, and topology queries.
Welcome to the Tufin MCP (Multi-Controller Protocol) Server project! This open-source initiative aims to provide Tufin users with a powerful tool to bridge the gap between Tufin's robust APIs (SecureTrack and SecureChange) and modern AI development workflows.
By exposing Tufin functionalities through a secure, standardized REST API with Role-Based Access Control (RBAC), this server allows you to easily integrate Tufin data and actions into your custom scripts, applications, and AI agents (like those running in Cursor, ChatGPT Actions, Ollama, etc.).
This is a community-driven project. We encourage contributions! Whether it's adding new endpoint coverage, improving security, enhancing the client libraries, or fixing bugs, your input is valuable. Please check the Contributing section for more details.
Find the project repository on GitHub: https://github.com/stonecircle82/tufin-mcp
This server acts as a secure proxy and abstraction layer for Tufin APIs (v25.1 targeted).
Key Features:
Clone the repository:
git clone https://github.com/<your-username>/tufin-mcp.git # ** Replace URL **
cd tufin-mcp
Create and activate a virtual environment:
python -m venv venv
source venv/bin/activate # On Windows use `venv\Scripts\activate`
Install dependencies:
pip install -r requirements.txt
Configuration is managed via environment variables or a .env file in the project root.
Create .env file: Copy .env.example (if provided) or create .env manually.
Set required variables:
# Server Settings
MCP_PORT=8000
LOG_LEVEL="INFO" # DEBUG, INFO, WARNING, ERROR
# Tufin Connection (REPLACE with your details)
TUFIN_SECURETRACK_URL="https://your-securetrack-host"
TUFIN_SECURECHANGE_URL="https://your-securechange-host"
TUFIN_USERNAME="your_tufin_username"
TUFIN_PASSWORD="your_tufin_password"
TUFIN_SSL_VERIFY="True" # Set to False only if absolutely necessary (insecure!)
TUFIN_API_TIMEOUT="30.0" # Timeout for Tufin API calls in seconds
# --- Development API Keys (Insecure - For Dev/Test Only!) ---
# For the default In-Memory secure store, provide initial RAW keys and roles via this JSON string.
# The server will HASH the keys on startup and store them in memory.
# DO NOT USE PRODUCTION KEYS HERE.
DEV_API_KEYS='[{"key":"admin_key_abc", "role":"admin"}, {"key":"manager_key_xyz", "role":"ticket_manager"}, {"key":"user_key_123", "role":"user"}]'
SSL Verification Note (TUFIN_SSL_VERIFY): By default, the server attempts to verify the SSL certificates of your Tufin instances (TUFIN_SSL_VERIFY="True"). Setting this to "False" disables verification, which can be necessary for environments using self-signed certificates, but it is highly insecure for production as it exposes the connection to man-in-the-middle attacks. If using internal CAs, consider configuring the underlying system or providing a custom CA bundle path (requires code modification).
Production Security Note: API Keys are hashed using bcrypt. The default InMemorySecureStore loads raw keys from DEV_API_KEYS only for development. For production, you MUST:
InMemorySecureStore in src/app/core/secure_store.py with an implementation using a secure database or secrets manager (e.g., HashiCorp Vault).DEV_API_KEYS in production.# From the project root directory
uvicorn src.app.main:app --reload --port ${MCP_PORT:-8000}
--reload flag enables auto-reloading on code changes..env or defaults to 8000.Build the image:
# From the project root directory
docker build -t tufin-mcp-server:latest .
Run the container:
docker run --rm -d \
--name tufin-mcp \
--env-file .env \
-p ${MCP_PORT:-8000}:${MCP_PORT:-8000} \
tufin-mcp-server:latest
.env file.MCP_PORT or default 8000).Accessing: http://localhost:${MCP_PORT:-8000}
Logs: docker logs tufin-mcp (-f to follow)
Stopping: docker stop tufin-mcp
This project uses pytest for testing.
Install test dependencies:
pip install -r requirements-dev.txt
Run tests:
# From the project root directory
pytest
pytest tests/api/v1/test_endpoints.py-v for verbose output: pytest -v-k to filter tests by name: pytest -k list_devicesTest Coverage (Optional):
Install pytest-cov (pip install pytest-cov) and run:
pytest --cov=src/app --cov-report=term-missing
Pass your generated API key in the X-API-Key HTTP header for all requests except /health.
Access is controlled by roles assigned to API keys during key creation (using a secure production process or via DEV_API_KEYS for development). Allowed roles for each endpoint are configured in src/app/core/config.py under ENDPOINT_PERMISSIONS.
admin, ticket_manager, user.403 Forbidden.Configuring Endpoint Permissions:
The ENDPOINT_PERMISSIONS dictionary in src/app/core/config.py defines which roles can access which logical action (permission ID). Example:
# src/app/core/config.py
ENDPOINT_PERMISSIONS: Dict[str, List[UserRole]] = {
"list_devices": [UserRole.ADMIN, UserRole.TICKET_MANAGER, UserRole.USER],
"get_device": [UserRole.ADMIN, UserRole.TICKET_MANAGER, UserRole.USER],
"create_ticket": [UserRole.ADMIN, UserRole.TICKET_MANAGER],
# ... other permissions ...
}
require_permission("permission_id") dependency. This dependency checks if the role associated with the user's validated API key is present in the list defined for that specific permission_id in the ENDPOINT_PERMISSIONS dictionary.UserRole enums for any given permission ID directly within config.py. Add new permission IDs as you add new endpoints.IP-based rate limits apply (default: 60/minute). Exceeding limits results in 429 Too Many Requests.
The API structure is defined in openapi.yaml. You can explore this file directly or use tools like Swagger UI if the spec is served by the application (requires adding static file serving to main.py).
Current Endpoint Summary:
GET /health: Health check.POST /api/v1/tickets: Create SecureChange ticket.GET /api/v1/tickets: List SecureChange tickets (Supports filtering by status).GET /api/v1/tickets/{ticket_id}: Get a specific SecureChange ticket.PUT /api/v1/tickets/{ticket_id}: Update a SecureChange ticket.GET /api/v1/devices: List SecureTrack devices (Supports filtering by status, name, vendor).GET /api/v1/devices/{device_id}: Get SecureTrack device details.POST /api/v1/devices/bulk: Add one or more devices (requires vendor-specific device_data in request body).POST /api/v1/devices/bulk/import: Import managed devices (DGs, ADOMs, contexts, etc.) into existing management devices.GET /api/v1/topology/map: Get SecureTrack topology map.POST /api/v1/topology/query: Run a SecureTrack topology query.GET /api/v1/topology/path: Run a SecureTrack topology path query. Returns a summarized result including traffic_allowed, is_fully_routed, and path_device_names (if allowed/routed).GET /api/v1/topology/path/image: Get the topology path as an image (e.g., PNG).POST /api/v1/graphql/rules: Query SecureTrack rules using GraphQL and TQL filter.Note: Implementation requires verification against Tufin 25.1 REST API docs. Filter implementation needs checking against specific Tufin API syntax.
curl)# Set environment variables for convenience
export MCP_URL="http://localhost:8000"
export MCP_API_KEY="your_api_key_here"
# Health Check
curl "$MCP_URL/health"
# List Devices
curl -H "X-API-Key: $MCP_API_KEY" "$MCP_URL/api/v1/devices?limit=5"
# Create Ticket (Requires appropriate role for the key)
curl -X POST -H "X-API-Key: $MCP_API_KEY" -H "Content-Type: application/json" \
-d '{"subject": "API: Allow Port 443", "description": "...details..."}' \
"$MCP_URL/api/v1/tickets"
# Example Topology Path Query
curl -G -H "X-API-Key: $MCP_API_KEY" "$MCP_URL/api/v1/topology/path" \
--data-urlencode "src=1.1.1.1" \
--data-urlencode "dst=8.8.8.8" \
--data-urlencode "service=tcp:443"
# Example Topology Path Image Request (save to file)
curl -H "X-API-Key: $MCP_API_KEY" "$MCP_URL/api/v1/topology/path/image?src=1.1.1.1&dst=8.8.8.8&service=tcp:443" -o topology_path.png
# Example Add Device (Cisco ASA - requires ADMIN role & correct device_data)
curl -X POST -H "X-API-Key: $MCP_API_KEY" -H "Content-Type: application/json" \
-d '{
"devices": [
{
"display_name": "MCP-ASA-Test",
"ip_address": "10.1.2.3",
"vendor": "Cisco",
"model": "ASA",
"securetrack_domain": "Default",
"enable_topology": true,
"device_data": {
"user_name": "tufin-api-user",
"password": "tufin-api-password",
"enable_password": "tufin-enable-password"
# Add other ASA specific fields from Tufin docs here
}
}
]
}' \
"$MCP_URL/api/v1/devices/bulk"
# Example Import Managed Devices (Panorama DG)
curl -X POST -H "X-API-Key: $MCP_API_KEY" -H "Content-Type: application/json" \
-d '{
"devices": [
{
"device_id": "1",
"device_data": {
"import_all": false,
"import_devices": [
{"name": "DG1", "import_all": false, "managed_devices": ["fw1"]}
]
}
}
]
}' \
"$MCP_URL/api/v1/devices/bulk/import"
# Example GraphQL Rule Query (using curl and jq for readability)
# Find firewall rules allowing any source to 8.8.8.8
export TQL_FILTER="destination.ip 8.8.8.8"
curl -X POST -H "X-API-Key: $MCP_API_KEY" -H "Content-Type: application/json" \
-d "{\"tql_filter\": \"$TQL_FILTER\"}" \
"$MCP_URL/api/v1/graphql/rules" | jq
An OpenAPI 3.0 specification file (openapi.yaml) is included in the root directory. This file formally describes the API, including endpoints, parameters, request/response schemas, and security requirements. It can be used with various tools:
(Optional Enhancement): Consider configuring FastAPI to serve this specification automatically at /openapi.yaml and interactive documentation (Swagger UI/Redoc).
A basic Python client library structure is provided in client_libs/python/.
# From the project root directory
cd client_libs/python
pip install .
from tufin_mcp_client import TufinMCPClient, TufinMCPClientError
SERVER_URL = "http://localhost:8000"
API_KEY = "your_api_key_here"
# Use as a context manager (recommended)
with TufinMCPClient(base_url=SERVER_URL, api_key=API_KEY) as client:
try:
health = client.get_health()
print(f"Health: {health}")
devices = client.list_devices()
print(f"Devices Found: {devices.total}")
# Example: Get first device if list is not empty
if devices.devices:
first_device_id = devices.devices[0].id
device_details = client.get_device(first_device_id)
print(f"Device {first_device_id}: {device_details.name} ({device_details.vendor})")
# Example: Create Ticket
ticket_data = {
"workflow_name": "Example Firewall Workflow", # Check configured workflows
"subject": "Client Lib Test",
"details": { # Workflow specific fields go here
"description": "Testing ticket creation via client",
"priority": "Medium"
# Add other fields required by the specific workflow
}
}
created_ticket = client.create_ticket(ticket_data)
print(f"Created Ticket ID: {created_ticket.id}, Status: {created_ticket.status}")
ticket_id = created_ticket.id
if ticket_id:
retrieved_ticket = client.get_ticket(ticket_id)
print(f"Retrieved Ticket {ticket_id}: Subject: {retrieved_ticket.subject}")
updated_data = {"status": "In Progress"} # Check actual updatable fields
updated_ticket = client.update_ticket(ticket_id, updated_data)
print(f"Updated Ticket {ticket_id}: Status: {updated_ticket.status}")
# Example Add Device
asa_device = {
"display_name": "MCP-ASA-Test-Client",
"ip_address": "10.1.2.4",
"vendor": "Cisco",
"model": "ASA",
"securetrack_domain": "Default",
"enable_topology": True,
"device_data": {
"user_name": "tufin-api-user",
"password": "tufin-api-password",
"enable_password": "tufin-enable-password"
}
}
client.add_devices([asa_device]) # Pass as a list
print("Device add request accepted.")
# Example Import Managed Device
import_details = {
"devices": [
{
"device_id": "1", # Panorama ID
"device_data": {
"import_all": False,
"import_devices": [
{"name": "DG_CLIENT", "import_all": True}
]
}
}
]
}
client.import_managed_devices(import_details)
print("Managed device import request accepted.")
# Example GraphQL Rule Query
rule_filter = "action accept and source.ip 192.168.1.0/24"
rules_response = client.query_rules_graphql(tql_filter=rule_filter)
print(f"\nFound {rules_response.rules.count} rules matching filter:")
for rule in rules_response.rules.values:
print(f" - ID: {rule.id}, Name: {rule.name}, Action: {rule.action}")
except TufinMCPClientError as e:
print(f"MCP Client Error: {e}")
if e.status_code:
print(f" Status Code: {e.status_code}")
if e.response_text:
print(f" Response: {e.response_text}")
except Exception as e:
print(f"An unexpected error occurred: {e}")
Note: The client library provides basic functionality, error handling (TufinMCPClientError), and returns Pydantic models for responses. Further enhancements are planned (see Roadmap).
A basic TypeScript client library structure for interacting with the MCP Server API is provided in client_libs/javascript/.
# From your JS/TS project directory
npm install <path_to_client_libs/javascript>
# or link for local development
# cd client_libs/javascript && npm link && cd ../../ && npm link tufin-mcp-client-js
# Or if published to npm:
# npm install tufin-mcp-client-js
Make sure to build the client first if installing from source: cd client_libs/javascript && npm run build && cd ../..
import { TufinMCPClient, TufinMCPClientError } from 'tufin-mcp-client-js'; // Adjust import path
const SERVER_URL = 'http://localhost:8000'; // Your MCP Server URL
const API_KEY = 'your_api_key_here';
const client = new TufinMCPClient(SERVER_URL, API_KEY);
async function runClient() {
try {
const health = await client.getHealth();
console.log('Health:', health);
const devices = await client.listDevices({ limit: 5 }); // Example param
console.log(`Devices Found: ${devices.total}`);
console.log('First device:', devices.devices[0]);
// Example: Create Ticket
const ticketData = {
workflow_name: 'Example Firewall Workflow', // Check configured workflows
subject: 'TS Client Test',
details: {
description: 'Testing ticket from TS client',
priority: 'Low'
// Add other workflow-specific fields
}
};
const createdTicket = await client.createTicket(ticketData);
console.log(`Created Ticket ID: ${createdTicket.id}, Status: ${createdTicket.status}`);
// Example Add Device
const asaDevice = {
display_name: "MCP-ASA-Test-JS",
ip_address: "10.1.2.5",
vendor: "Cisco",
model: "ASA",
securetrack_domain: "Default",
enable_topology: true,
device_data: {
user_name: "tufin-api-user",
password: "tufin-api-password",
enable_password: "tufin-enable-password"
}
};
await client.addDevices([asaDevice]); // Pass as an array
console.log("Device add request accepted.");
// Example Import Managed Device
const importDetails = {
devices: [
{
device_id: "1", // Panorama ID
device_data: {
import_all: false,
import_devices: [
{ name: "DG_JS_CLIENT", import_all: true }
]
}
}
]
};
await client.importManagedDevices(importDetails);
console.log("Managed device import request accepted.");
// Example GraphQL Rule Query
const ruleFilter = "disabled true";
const rulesResponse = await client.queryRulesGraphQL({tql_filter: ruleFilter});
console.log(`\nFound ${rulesResponse.rules.count} disabled rules:`);
rulesResponse.rules.values.forEach(rule => {
console.log(` - ID: ${rule.id}, Name: ${rule.name}`);
});
} catch (error) {
if (error instanceof TufinMCPClientError) {
console.error('MCP Client Error:', error.message);
if (error.status) {
console.error(' Status Code:', error.status);
}
if (error.data) {
console.error(' Response Data:', error.data);
}
} else {
console.error('An unexpected error occurred:', error);
}
}
}
runClient();
Note: This client is basic. It needs further development for comprehensive error handling, potential model parsing (if not relying on any), and more robust type safety.
For scenarios where you need to bypass the MCP Server and connect directly to the Tufin APIs using basic authentication, a separate, simpler JS/TS client library is available in client_libs/javascript_direct/. See the README within that directory for details.
openapi.yaml), Copilot (via code context), Ollama/OpenRouter (via intermediary script).Contributions are welcome! Please see the Contributing Guidelines for details on how to get involved, report bugs, suggest features, and submit pull requests.
We also adhere to a Code of Conduct.
This list reflects known TODOs and potential future improvements:
src/app/clients/tufin.py against the official Tufin 25.1 REST documentation.src/app/models/ accurately parse the verified Tufin REST API responses.InMemorySecureStore with a production-ready solution (Database, Vault) and implement secure API key management (generation, revocation).src/app/core/logging_config.py.TUFIN_SSL_VERIFY) is configured for production deployments.httpx client in src/app/clients/tufin.py.openapi.yaml and interactive docs (Swagger UI/Redoc).This project is licensed under the MIT License - see the LICENSE file for details.
Выполни в терминале:
claude mcp add tufin-mcp-server -- npx Безопасность
Низкий рискАвтоматическая эвристика по публичным данным — не гарантия безопасности.