drake-mcp 0.1.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.
- drake_mcp-0.1.0/PKG-INFO +30 -0
- drake_mcp-0.1.0/README.md +400 -0
- drake_mcp-0.1.0/pyproject.toml +71 -0
- drake_mcp-0.1.0/setup.cfg +4 -0
- drake_mcp-0.1.0/src/drake/__init__.py +0 -0
- drake_mcp-0.1.0/src/drake/ai_clustering/__init__.py +0 -0
- drake_mcp-0.1.0/src/drake/ai_clustering/dependency_matcher.py +160 -0
- drake_mcp-0.1.0/src/drake/ai_clustering/embedding_service.py +154 -0
- drake_mcp-0.1.0/src/drake/ai_clustering/explain.py +29 -0
- drake_mcp-0.1.0/src/drake/ai_clustering/graph_clustering.py +570 -0
- drake_mcp-0.1.0/src/drake/ai_clustering/nl_compiler.py +36 -0
- drake_mcp-0.1.0/src/drake/ai_clustering/ollama_service.py +96 -0
- drake_mcp-0.1.0/src/drake/ai_clustering/schemas/workflow.py +69 -0
- drake_mcp-0.1.0/src/drake/ai_clustering/workflow_naming.py +106 -0
- drake_mcp-0.1.0/src/drake/cli/__init__.py +3 -0
- drake_mcp-0.1.0/src/drake/cli/commands/__init__.py +1 -0
- drake_mcp-0.1.0/src/drake/cli/commands/ansible.py +63 -0
- drake_mcp-0.1.0/src/drake/cli/commands/audit.py +86 -0
- drake_mcp-0.1.0/src/drake/cli/commands/cluster.py +52 -0
- drake_mcp-0.1.0/src/drake/cli/commands/compatibility.py +133 -0
- drake_mcp-0.1.0/src/drake/cli/commands/config.py +74 -0
- drake_mcp-0.1.0/src/drake/cli/commands/diagnostics.py +119 -0
- drake_mcp-0.1.0/src/drake/cli/commands/governance.py +112 -0
- drake_mcp-0.1.0/src/drake/cli/commands/pipeline.py +50 -0
- drake_mcp-0.1.0/src/drake/cli/commands/runtime.py +108 -0
- drake_mcp-0.1.0/src/drake/cli/commands/server.py +36 -0
- drake_mcp-0.1.0/src/drake/cli/commands/system.py +45 -0
- drake_mcp-0.1.0/src/drake/cli/components.py +321 -0
- drake_mcp-0.1.0/src/drake/cli/container.py +52 -0
- drake_mcp-0.1.0/src/drake/cli/context.py +8 -0
- drake_mcp-0.1.0/src/drake/cli/exceptions.py +12 -0
- drake_mcp-0.1.0/src/drake/cli/main.py +179 -0
- drake_mcp-0.1.0/src/drake/cli/plugins/__init__.py +48 -0
- drake_mcp-0.1.0/src/drake/cli/services/__init__.py +23 -0
- drake_mcp-0.1.0/src/drake/cli/services/ansible.py +50 -0
- drake_mcp-0.1.0/src/drake/cli/services/audit.py +59 -0
- drake_mcp-0.1.0/src/drake/cli/services/bridge.py +20 -0
- drake_mcp-0.1.0/src/drake/cli/services/cluster.py +121 -0
- drake_mcp-0.1.0/src/drake/cli/services/compatibility.py +140 -0
- drake_mcp-0.1.0/src/drake/cli/services/config.py +94 -0
- drake_mcp-0.1.0/src/drake/cli/services/diagnostics.py +148 -0
- drake_mcp-0.1.0/src/drake/cli/services/governance.py +142 -0
- drake_mcp-0.1.0/src/drake/cli/services/runtime.py +75 -0
- drake_mcp-0.1.0/src/drake/cli/services/system.py +77 -0
- drake_mcp-0.1.0/src/drake/cli/theme.py +170 -0
- drake_mcp-0.1.0/src/drake/core/__init__.py +33 -0
- drake_mcp-0.1.0/src/drake/core/compatibility/ansible_enricher.py +167 -0
- drake_mcp-0.1.0/src/drake/core/compatibility/engine.py +664 -0
- drake_mcp-0.1.0/src/drake/core/compatibility/models.py +201 -0
- drake_mcp-0.1.0/src/drake/core/compatibility/orchestrator.py +250 -0
- drake_mcp-0.1.0/src/drake/core/compatibility/repository.py +386 -0
- drake_mcp-0.1.0/src/drake/core/compatibility/sources.py +219 -0
- drake_mcp-0.1.0/src/drake/core/compression.py +136 -0
- drake_mcp-0.1.0/src/drake/core/config.py +110 -0
- drake_mcp-0.1.0/src/drake/core/database.py +1064 -0
- drake_mcp-0.1.0/src/drake/core/env_config.py +72 -0
- drake_mcp-0.1.0/src/drake/core/exceptions.py +120 -0
- drake_mcp-0.1.0/src/drake/core/models.py +245 -0
- drake_mcp-0.1.0/src/drake/governance/__init__.py +1 -0
- drake_mcp-0.1.0/src/drake/governance/core/__init__.py +1 -0
- drake_mcp-0.1.0/src/drake/governance/core/policy.py +89 -0
- drake_mcp-0.1.0/src/drake/governance/core/risk.py +88 -0
- drake_mcp-0.1.0/src/drake/governance/core/validator.py +58 -0
- drake_mcp-0.1.0/src/drake/governance/middleware.py +89 -0
- drake_mcp-0.1.0/src/drake/governance/runtime/__init__.py +1 -0
- drake_mcp-0.1.0/src/drake/governance/runtime/interceptor.py +62 -0
- drake_mcp-0.1.0/src/drake/parser/__init__.py +9 -0
- drake_mcp-0.1.0/src/drake/parser/asyncapi_parser.py +61 -0
- drake_mcp-0.1.0/src/drake/parser/graphql_parser.py +65 -0
- drake_mcp-0.1.0/src/drake/parser/grpc_parser.py +57 -0
- drake_mcp-0.1.0/src/drake/parser/openapi_parser.py +378 -0
- drake_mcp-0.1.0/src/drake/proxy/__init__.py +0 -0
- drake_mcp-0.1.0/src/drake/proxy/api.py +1143 -0
- drake_mcp-0.1.0/src/drake/proxy/executors/__init__.py +11 -0
- drake_mcp-0.1.0/src/drake/proxy/executors/base.py +52 -0
- drake_mcp-0.1.0/src/drake/proxy/executors/dell_omsdk_executor.py +69 -0
- drake_mcp-0.1.0/src/drake/proxy/executors/httpx_executor.py +299 -0
- drake_mcp-0.1.0/src/drake/proxy/executors/workflow_execution_service.py +243 -0
- drake_mcp-0.1.0/src/drake/proxy/server.py +813 -0
- drake_mcp-0.1.0/src/drake/proxy/stdio_server.py +37 -0
- drake_mcp-0.1.0/src/drake_mcp.egg-info/PKG-INFO +30 -0
- drake_mcp-0.1.0/src/drake_mcp.egg-info/SOURCES.txt +102 -0
- drake_mcp-0.1.0/src/drake_mcp.egg-info/dependency_links.txt +1 -0
- drake_mcp-0.1.0/src/drake_mcp.egg-info/entry_points.txt +2 -0
- drake_mcp-0.1.0/src/drake_mcp.egg-info/requires.txt +25 -0
- drake_mcp-0.1.0/src/drake_mcp.egg-info/top_level.txt +1 -0
- drake_mcp-0.1.0/tests/test_caching_optimizer.py +130 -0
- drake_mcp-0.1.0/tests/test_clustering_quality.py +78 -0
- drake_mcp-0.1.0/tests/test_edge_concurrency.py +97 -0
- drake_mcp-0.1.0/tests/test_edge_resilience.py +94 -0
- drake_mcp-0.1.0/tests/test_edge_security.py +96 -0
- drake_mcp-0.1.0/tests/test_generator_bootstrap.py +97 -0
- drake_mcp-0.1.0/tests/test_governance_api.py +283 -0
- drake_mcp-0.1.0/tests/test_hierarchical_exposure.py +111 -0
- drake_mcp-0.1.0/tests/test_hierarchical_exposure_comprehensive.py +155 -0
- drake_mcp-0.1.0/tests/test_microservice.py +137 -0
- drake_mcp-0.1.0/tests/test_mock_api.py +34 -0
- drake_mcp-0.1.0/tests/test_multi_api_ingestion.py +164 -0
- drake_mcp-0.1.0/tests/test_nl_compiler.py +89 -0
- drake_mcp-0.1.0/tests/test_parser.py +61 -0
- drake_mcp-0.1.0/tests/test_real_world_specs.py +68 -0
- drake_mcp-0.1.0/tests/test_security_hardening.py +73 -0
- drake_mcp-0.1.0/tests/test_server.py +28 -0
- drake_mcp-0.1.0/tests/test_workflow_lifecycle_patterns.py +182 -0
drake_mcp-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: drake-mcp
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Dell Enterprise MCP Workflow Proxy
|
|
5
|
+
Requires-Python: >=3.10
|
|
6
|
+
Requires-Dist: fastmcp>=3.4.2
|
|
7
|
+
Requires-Dist: httpx>=0.28.1
|
|
8
|
+
Requires-Dist: instructor>=1.15.3
|
|
9
|
+
Requires-Dist: ollama>=0.6.2
|
|
10
|
+
Requires-Dist: openapi-core>=0.23.1
|
|
11
|
+
Requires-Dist: pydantic>=2.13.4
|
|
12
|
+
Requires-Dist: fastapi>=0.110.0
|
|
13
|
+
Requires-Dist: uvicorn>=0.30.0
|
|
14
|
+
Requires-Dist: networkx>=3.0
|
|
15
|
+
Requires-Dist: sentence-transformers>=3.0.0
|
|
16
|
+
Requires-Dist: scikit-learn>=1.5.0
|
|
17
|
+
Requires-Dist: leidenalg>=0.10.2
|
|
18
|
+
Requires-Dist: igraph>=0.11.0
|
|
19
|
+
Requires-Dist: tenacity>=9.1.4
|
|
20
|
+
Requires-Dist: sqlalchemy>=2.0.51
|
|
21
|
+
Requires-Dist: aiosqlite>=0.22.1
|
|
22
|
+
Requires-Dist: PyYAML>=6.0.1
|
|
23
|
+
Requires-Dist: mcp>=0.1.0
|
|
24
|
+
Requires-Dist: python-dotenv>=1.1.0
|
|
25
|
+
Requires-Dist: PyJWT>=2.10.0
|
|
26
|
+
Requires-Dist: click>=8.2.1
|
|
27
|
+
Requires-Dist: rich>=14.0.0
|
|
28
|
+
Requires-Dist: numpy>=2.0.0
|
|
29
|
+
Requires-Dist: typer>=0.16.0
|
|
30
|
+
Requires-Dist: openai>=1.84.0
|
|
@@ -0,0 +1,400 @@
|
|
|
1
|
+
# Dell Enterprise MCP Proxy - Infrastructure Command Center CLI (`drake`)
|
|
2
|
+
|
|
3
|
+
The **Infrastructure Command Center CLI (`drake`)** is the primary operational control plane and administration utility for the Dell Enterprise MCP Proxy platform.
|
|
4
|
+
|
|
5
|
+
It is designed for:
|
|
6
|
+
* **Infrastructure Engineers** managing bare-metal systems and server topologies.
|
|
7
|
+
* **Platform Reliability Engineers (PRE)** monitoring runtime states and API availability.
|
|
8
|
+
* **Dell PowerEdge Administrators** validating hardware compliance and firmware inventories.
|
|
9
|
+
* **Governance & Compliance Teams** auditing AI-generated workflows and reviewing action ledgers.
|
|
10
|
+
|
|
11
|
+
The CLI acts as a thin presentation and orchestration layer over the underlying Dell MCP services, presenting a high-performance, unified, and resilient command center experience.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Architecture Diagram
|
|
16
|
+
|
|
17
|
+
The CLI is decoupled from the core business engines and repositories using a strict presentation layer design:
|
|
18
|
+
|
|
19
|
+
```mermaid
|
|
20
|
+
flowchart TD
|
|
21
|
+
subgraph Presentation Layer
|
|
22
|
+
A[Operator Console / shell] -->|drake CLI| B[Typer Main Router src/cli/main.py]
|
|
23
|
+
B -->|Command Group Router src/cli/commands/*| C[CLIContainer src/cli/container.py]
|
|
24
|
+
C -->|Lazy Resolution| D[CLI Service Adapter src/cli/services/*]
|
|
25
|
+
end
|
|
26
|
+
subgraph Core Platform Services
|
|
27
|
+
D -->|Database Sync / Async Session| E[(SQLite governance.db)]
|
|
28
|
+
D -->|Pre-flight Verification| F[Compatibility Engine]
|
|
29
|
+
D -->|Playbook Enrichment| G[Ansible Exporter]
|
|
30
|
+
D -->|FastMCP Runtime State| H[Execution Manager]
|
|
31
|
+
end
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Dependency Rules
|
|
35
|
+
* Commands **must never** directly instantiate SQLite connections, SQLAlchemy sessions, HTTPX clients, or core logic engines.
|
|
36
|
+
* All operations must flow through service adapters resolved via the centralized **CLIContainer**.
|
|
37
|
+
* Console visual structures are decoupled from business logic.
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Installation & Requirements
|
|
42
|
+
|
|
43
|
+
### System Requirements
|
|
44
|
+
* Python 3.10 or higher.
|
|
45
|
+
* `uv` (fast Python package installer).
|
|
46
|
+
* Stateful access to `data/governance.db` (seeded and active).
|
|
47
|
+
|
|
48
|
+
### Editable Development Installation
|
|
49
|
+
Install the project dependencies and wire the executable script locally using `uv`:
|
|
50
|
+
|
|
51
|
+
#### 1. Install uv
|
|
52
|
+
```bash
|
|
53
|
+
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
#### 2. Install Local LLM Engine (Ollama)
|
|
57
|
+
You must also install and start the local LLM engine Ollama and pull/run the Llama3 model:
|
|
58
|
+
```bash
|
|
59
|
+
# Run Ollama with Llama3 model
|
|
60
|
+
ollama run llama3
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
#### 3. Environment Setup
|
|
64
|
+
Initialize the virtual environment and install all dependencies:
|
|
65
|
+
```bash
|
|
66
|
+
# Sync all platform virtual environment dependencies
|
|
67
|
+
uv sync
|
|
68
|
+
|
|
69
|
+
# Install the drake package in editable mode
|
|
70
|
+
uv pip install -e .
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
#### 4. Activate the Virtual Environment
|
|
74
|
+
Activate the `uv`-managed virtual environment so that `drake` resolves to the correct venv binary:
|
|
75
|
+
```powershell
|
|
76
|
+
# Windows (PowerShell) — run once per terminal session
|
|
77
|
+
.venv\Scripts\Activate.ps1
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
After activation, run bare `drake` commands directly:
|
|
81
|
+
```bash
|
|
82
|
+
drake --help
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
> **Alternative (no activation needed):** Prefix every command with `uv run`:
|
|
86
|
+
> ```bash
|
|
87
|
+
> uv run drake --help
|
|
88
|
+
> uv run drake overview
|
|
89
|
+
> ```
|
|
90
|
+
|
|
91
|
+
> **Environment Variable:** Ensure the following variable is defined in your `.env` file:
|
|
92
|
+
> `DELL_MCP_API_KEY` — used in `src/proxy/api.py` to authenticate proxy calls and administration endpoints.
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## Quick Start (Automated Launch)
|
|
97
|
+
|
|
98
|
+
You can launch all required services—including environment validation, package sync, the backend FastMCP/FastAPI server, the Next.js frontend console, and checking Ollama models—with a single command:
|
|
99
|
+
|
|
100
|
+
```powershell
|
|
101
|
+
# Run the PowerShell launcher script
|
|
102
|
+
.\start.ps1
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Or simply double-click the `start.bat` file in Windows Explorer, or run:
|
|
106
|
+
```cmd
|
|
107
|
+
start.bat
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
The launcher will verify your dependencies and launch the backend and frontend services in dedicated terminal windows.
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## Quick Start (Manual Setup)
|
|
115
|
+
|
|
116
|
+
Activate the virtual environment first, then run commands:
|
|
117
|
+
|
|
118
|
+
```powershell
|
|
119
|
+
# 1. Activate venv (once per terminal session)
|
|
120
|
+
.venv\Scripts\Activate.ps1
|
|
121
|
+
|
|
122
|
+
# 2. Print global help instructions and subcommand catalog
|
|
123
|
+
drake --help
|
|
124
|
+
|
|
125
|
+
# 3. Render the executive control plane dashboard overview
|
|
126
|
+
drake overview
|
|
127
|
+
|
|
128
|
+
# 4. Verify subsystem readiness and health assessment matrix
|
|
129
|
+
drake health
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
> **Or without activation:** prefix every command with `uv run drake ...`
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## Command Reference
|
|
137
|
+
|
|
138
|
+
The Command Center organizes operational tasks into specialized command groups:
|
|
139
|
+
|
|
140
|
+
### 1. `cluster`
|
|
141
|
+
Manages AI clustering, OpenAPI integrations, and spec parsing.
|
|
142
|
+
* **`summary`**
|
|
143
|
+
* *Purpose*: Render clustering metrics and distribution data.
|
|
144
|
+
* *Syntax*: `drake cluster summary`
|
|
145
|
+
* *Example Output*: Prints total endpoints, Leiden clusters, and average confidence levels.
|
|
146
|
+
* **`graph`**
|
|
147
|
+
* *Purpose*: Display active relationship graphs of endpoints.
|
|
148
|
+
* *Syntax*: `drake cluster graph`
|
|
149
|
+
* **`run --spec <path>`**
|
|
150
|
+
* *Purpose*: Parse an OpenAPI specification file and regenerate workflow clusters.
|
|
151
|
+
* *Syntax*: `drake cluster run --spec openapi.json`
|
|
152
|
+
|
|
153
|
+
### 2. `governance`
|
|
154
|
+
Enforces human-in-the-loop review cycles for LLM-generated workflows.
|
|
155
|
+
* **`pending`**
|
|
156
|
+
* *Purpose*: List all workflows awaiting human approval.
|
|
157
|
+
* *Syntax*: `drake governance pending`
|
|
158
|
+
* **`approved`**
|
|
159
|
+
* *Purpose*: List all certified/approved operational workflows.
|
|
160
|
+
* *Syntax*: `drake governance approved`
|
|
161
|
+
* **`rejected`**
|
|
162
|
+
* *Purpose*: List workflows blocked or rejected by operators.
|
|
163
|
+
* *Syntax*: `drake governance rejected`
|
|
164
|
+
* **`review <workflow_id>`**
|
|
165
|
+
* *Purpose*: Inspect a workflow's details and constituent API steps.
|
|
166
|
+
* *Syntax*: `drake governance review test_wf_1`
|
|
167
|
+
* **`approve <workflow_id>`**
|
|
168
|
+
* *Purpose*: Approve a pending workflow, promoting it to an executable FastMCP tool.
|
|
169
|
+
* *Syntax*: `drake governance approve test_wf_1`
|
|
170
|
+
* **`reject <workflow_id> --reason <text>`**
|
|
171
|
+
* *Purpose*: Reject a workflow and document the audit reason.
|
|
172
|
+
* *Syntax*: `drake governance reject test_wf_1 --reason "Security validation failed"`
|
|
173
|
+
|
|
174
|
+
### 3. `compatibility`
|
|
175
|
+
Pre-flight verification intelligence.
|
|
176
|
+
* **`validate <workflow_id> --target-ip <ip>`**
|
|
177
|
+
* *Purpose*: Validate workflow steps against target hardware.
|
|
178
|
+
* *Syntax*: `drake compatibility validate test_wf_1 --target-ip 192.168.0.120`
|
|
179
|
+
* **`explain <workflow_id>`**
|
|
180
|
+
* *Purpose*: Render the DAG rules tree that evaluates the workflow.
|
|
181
|
+
* *Syntax*: `drake compatibility explain test_wf_1`
|
|
182
|
+
* **`dashboard <workflow_id> --target-ip <ip>`**
|
|
183
|
+
* *Purpose*: Renders the decision cockpit (see flagship section below).
|
|
184
|
+
* *Syntax*: `drake compatibility dashboard test_wf_1 --target-ip 192.168.0.120`
|
|
185
|
+
* **`rules`**
|
|
186
|
+
* *Purpose*: Print the active policies and compatibility rules catalog.
|
|
187
|
+
* *Syntax*: `drake compatibility rules`
|
|
188
|
+
* **`device <ip>`**
|
|
189
|
+
* *Purpose*: Query stateful cached specifications for a datacenter node.
|
|
190
|
+
* *Syntax*: `drake compatibility device 192.168.0.120`
|
|
191
|
+
|
|
192
|
+
### 4. `runtime`
|
|
193
|
+
Controls the FastMCP integration hooks.
|
|
194
|
+
* **`tools`**
|
|
195
|
+
* *Purpose*: List currently exposed FastMCP tools ready for client consumption.
|
|
196
|
+
* *Syntax*: `drake runtime tools`
|
|
197
|
+
* **`reload`**
|
|
198
|
+
* *Purpose*: Trigger hot-reloads to refresh tool mappings from database states.
|
|
199
|
+
* *Syntax*: `drake runtime reload`
|
|
200
|
+
* **`execute <tool_name> --params <json>`**
|
|
201
|
+
* *Purpose*: Manually invoke a registered workflow.
|
|
202
|
+
* *Syntax*: `drake runtime execute test_workflow --params '{"sys_id": 1}'`
|
|
203
|
+
|
|
204
|
+
### 5. `ansible`
|
|
205
|
+
Exports workflow logic to infrastructure-as-code files.
|
|
206
|
+
* **`preview <workflow_id>`**
|
|
207
|
+
* *Purpose*: Render syntax-highlighted playbook configurations directly on the console.
|
|
208
|
+
* *Syntax*: `drake ansible preview test_wf_1`
|
|
209
|
+
* **`export <workflow_id> --output <path>`**
|
|
210
|
+
* *Purpose*: Export enriched playbooks directly to files.
|
|
211
|
+
* *Syntax*: `drake ansible export test_wf_1 --output playbooks/deploy.yml`
|
|
212
|
+
|
|
213
|
+
### 6. `audit`
|
|
214
|
+
Exposes the compliance history ledger.
|
|
215
|
+
* **`events`**
|
|
216
|
+
* *Purpose*: List administrative events, modifications, and approvals.
|
|
217
|
+
* *Syntax*: `drake audit events`
|
|
218
|
+
* **`executions`**
|
|
219
|
+
* *Purpose*: Print workflow runs, durations, status codes, and targets.
|
|
220
|
+
* *Syntax*: `drake audit executions`
|
|
221
|
+
* **`summary`**
|
|
222
|
+
* *Purpose*: Present compliance summaries and error trends.
|
|
223
|
+
* *Syntax*: `drake audit summary`
|
|
224
|
+
|
|
225
|
+
### 7. `system`
|
|
226
|
+
Prints operational topology data.
|
|
227
|
+
* **`topology`**
|
|
228
|
+
* *Purpose*: Display the system dependencies tree.
|
|
229
|
+
* *Syntax*: `drake system topology`
|
|
230
|
+
|
|
231
|
+
### 8. `diagnostics`
|
|
232
|
+
Evaluates internal health checks.
|
|
233
|
+
* **`db`** / **`api`** / **`compatibility`** / **`runtime`**
|
|
234
|
+
* *Purpose*: Troubleshoot connections to database files, REST endpoints, and facts caches.
|
|
235
|
+
* *Syntax*: `drake diagnostics db`
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
## Flagship Feature: Compatibility Cockpit
|
|
240
|
+
|
|
241
|
+
The **Compatibility Cockpit** provides a single Go/No-Go verdict before executing any workflow on target hardware:
|
|
242
|
+
|
|
243
|
+
```bash
|
|
244
|
+
drake compatibility dashboard <workflow_id> --target-ip <ip>
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### Cockpit Panels
|
|
248
|
+
|
|
249
|
+
1. **Target Device**: Displays model, BIOS version, Lifecycle Controller version, and scan time.
|
|
250
|
+
2. **Validation Scores**:
|
|
251
|
+
* *Compatibility Score*: Measures compliance with active rules catalog (0-100%).
|
|
252
|
+
* *Risk Score*: Computes operational risk coefficients (0-100).
|
|
253
|
+
* *Blast Radius*: Outlines impact boundary (e.g. `NODE`, `CHASSIS`, `RACK`, `DATACENTER`).
|
|
254
|
+
* *Confidence*: Quality indicator of cached/retrieved device specifications.
|
|
255
|
+
3. **Violations**: Lists check failures, expected vs actual properties, and corrective remediation actions.
|
|
256
|
+
4. **Prerequisites Dependencies**: Structured tree showing parent-child dependency checks.
|
|
257
|
+
5. **Final Execution Verdict**: Bold colored indicator marking either `✓ SAFE TO EXECUTE` or `✗ BLOCK EXECUTION`.
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
## Universal JSON Mode
|
|
262
|
+
|
|
263
|
+
To support scripting, automation pipeline runs, and DevOps integration, every CLI command supports the `--json` flag:
|
|
264
|
+
|
|
265
|
+
```bash
|
|
266
|
+
drake --json compatibility dashboard test_wf_1 --target-ip 192.168.0.120
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
When `--json` is enabled:
|
|
270
|
+
* All styled panels, colors, tables, trees, and interactive spinners are **bypassed**.
|
|
271
|
+
* Only valid machine-readable JSON is written to `stdout`.
|
|
272
|
+
* Standard logs and non-critical warnings are redirected to `stderr`.
|
|
273
|
+
|
|
274
|
+
---
|
|
275
|
+
|
|
276
|
+
## Watch Mode
|
|
277
|
+
|
|
278
|
+
Monitor executive statuses or health assessment matrices in real-time using watch flags:
|
|
279
|
+
|
|
280
|
+
```bash
|
|
281
|
+
drake overview --watch --interval 2
|
|
282
|
+
drake health --watch
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
* **`--watch`**: Toggles live loop.
|
|
286
|
+
* **`--interval` (`-i`)**: Defines update frequency in seconds (default: 5).
|
|
287
|
+
* *Exit*: Cleanly intercepts `Ctrl+C` to terminate the loops without locking SQLite files.
|
|
288
|
+
|
|
289
|
+
---
|
|
290
|
+
|
|
291
|
+
## Plugin System
|
|
292
|
+
|
|
293
|
+
The Command Center includes a self-discovering plugin mechanism located in **`src/cli/plugins/`**.
|
|
294
|
+
|
|
295
|
+
### How Plugin Discovery Works
|
|
296
|
+
* The CLI scans the `src/cli/plugins/` directory at startup.
|
|
297
|
+
* It dynamically loads modules that do not start with an underscore (`_`).
|
|
298
|
+
* It registers subcommands if they expose a `register_plugin(app)` function or expose a `typer.Typer()` application named `app`.
|
|
299
|
+
|
|
300
|
+
### Authoring Custom Plugins
|
|
301
|
+
Create a Python module in `src/cli/plugins/network_config.py`:
|
|
302
|
+
```python
|
|
303
|
+
import typer
|
|
304
|
+
|
|
305
|
+
app = typer.Typer(help="Manage switch network configurations")
|
|
306
|
+
|
|
307
|
+
@app.command("show")
|
|
308
|
+
def show_switch_status():
|
|
309
|
+
print("Switch connections operational.")
|
|
310
|
+
```
|
|
311
|
+
The CLI automatically loads this, making the command `drake network_config show` immediately available.
|
|
312
|
+
|
|
313
|
+
### Failure Isolation
|
|
314
|
+
If a plugin raises an exception during import or initialization:
|
|
315
|
+
* The exception is caught and printed as a warning (`⚠ WARNING: Plugin load failed`).
|
|
316
|
+
* The core CLI continues to boot successfully, preserving primary operations.
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
320
|
+
## Security Features
|
|
321
|
+
|
|
322
|
+
### Secrets Masking Shield
|
|
323
|
+
To ensure security, the CLI scans outputs for sensitive keys (e.g. `password`, `token`, `key`, `secret`, `authorization`, `ssn`) and masks them recursively:
|
|
324
|
+
* **Console Output**: Masked with `********` inside tables and panels.
|
|
325
|
+
* **JSON Mode**: Formatted structure replaces sensitive strings with `********`, preventing data leaks in automation logs.
|
|
326
|
+
|
|
327
|
+
### Access Trails
|
|
328
|
+
Operations that alter states (e.g. `governance approve`, `governance reject`) write audit records to the local governance ledger, documenting administrative actor and time.
|
|
329
|
+
|
|
330
|
+
---
|
|
331
|
+
|
|
332
|
+
## Troubleshooting
|
|
333
|
+
|
|
334
|
+
### Legacy Windows Output Crash (`UnicodeEncodeError`)
|
|
335
|
+
* *Symptom*: Commands crash printing `UnicodeEncodeError: 'charmap' codec can't encode character...`
|
|
336
|
+
* *Cause*: Legacy Windows terminal character set (e.g. CP-1252) cannot print unicode symbols (`⚠`, `✓`).
|
|
337
|
+
* *Resolution*: Force the environment to use UTF-8 encoding:
|
|
338
|
+
```powershell
|
|
339
|
+
$env:PYTHONIOENCODING="utf-8"
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
### Packaging Script Location Error (`ModuleNotFoundError`)
|
|
343
|
+
* *Symptom*: Running `drake` raises `ModuleNotFoundError: No module named 'src'`.
|
|
344
|
+
* *Cause*: The bare `drake` command resolves to a system-level Python install that does not have access to the project source tree. This happens when the virtual environment is not activated.
|
|
345
|
+
* *Resolution (preferred)*: Activate the `uv` virtual environment before running any commands:
|
|
346
|
+
```powershell
|
|
347
|
+
.venv\Scripts\Activate.ps1
|
|
348
|
+
drake --help
|
|
349
|
+
```
|
|
350
|
+
* *Resolution (alternative)*: Use `uv run` to automatically route through the correct venv:
|
|
351
|
+
```bash
|
|
352
|
+
uv run drake --help
|
|
353
|
+
uv run drake health
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
### SQLite Database Locks
|
|
357
|
+
* *Symptom*: Actions time out or fail with database locks.
|
|
358
|
+
* *Cause*: Concurrent operations on SQLite files during long-running tasks.
|
|
359
|
+
* *Resolution*: Run `drake diagnostics db` to check connection status. Ensure the microservice FastAPI server is running with WAL journal modes.
|
|
360
|
+
|
|
361
|
+
---
|
|
362
|
+
|
|
363
|
+
## Operator Workflows
|
|
364
|
+
|
|
365
|
+
### Workflow 1: Platform Monitoring
|
|
366
|
+
Verify global status and watch for changes during maintenance windows:
|
|
367
|
+
```bash
|
|
368
|
+
$env:PYTHONIOENCODING="utf-8"
|
|
369
|
+
drake health
|
|
370
|
+
drake overview --watch --interval 10
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
### Workflow 2: Safe Pre-Flight Validation & Approval
|
|
374
|
+
Review a workflow generated by clustering, validate it against target hardware, and approve it:
|
|
375
|
+
```bash
|
|
376
|
+
# 1. List pending LLM workflows
|
|
377
|
+
drake governance pending
|
|
378
|
+
|
|
379
|
+
# 2. Inspect step details
|
|
380
|
+
drake governance review test_wf_1
|
|
381
|
+
|
|
382
|
+
# 3. Perform pre-flight compatibility evaluation cockpit
|
|
383
|
+
drake compatibility dashboard test_wf_1 --target-ip 192.168.0.120
|
|
384
|
+
|
|
385
|
+
# 4. Approve workflow
|
|
386
|
+
drake governance approve test_wf_1
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
### Workflow 3: IaC Automation Export
|
|
390
|
+
Validate a workflow and export it to an enriched Ansible playbook for target datacenter node setups:
|
|
391
|
+
```bash
|
|
392
|
+
# 1. Verify compatibility
|
|
393
|
+
drake compatibility validate test_wf_1 --target-ip 192.168.0.120
|
|
394
|
+
|
|
395
|
+
# 2. Preview playbooks syntax
|
|
396
|
+
drake ansible preview test_wf_1
|
|
397
|
+
|
|
398
|
+
# 3. Export playbook to target directory
|
|
399
|
+
drake ansible export test_wf_1 --output playbooks/idrac_setup.yml
|
|
400
|
+
```
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "drake-mcp"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Dell Enterprise MCP Workflow Proxy"
|
|
5
|
+
requires-python = ">=3.10"
|
|
6
|
+
dependencies = [
|
|
7
|
+
"fastmcp>=3.4.2",
|
|
8
|
+
"httpx>=0.28.1",
|
|
9
|
+
"instructor>=1.15.3",
|
|
10
|
+
"ollama>=0.6.2",
|
|
11
|
+
"openapi-core>=0.23.1",
|
|
12
|
+
"pydantic>=2.13.4",
|
|
13
|
+
"fastapi>=0.110.0",
|
|
14
|
+
"uvicorn>=0.30.0",
|
|
15
|
+
"networkx>=3.0",
|
|
16
|
+
"sentence-transformers>=3.0.0",
|
|
17
|
+
"scikit-learn>=1.5.0",
|
|
18
|
+
"leidenalg>=0.10.2",
|
|
19
|
+
"igraph>=0.11.0",
|
|
20
|
+
"tenacity>=9.1.4",
|
|
21
|
+
"sqlalchemy>=2.0.51",
|
|
22
|
+
"aiosqlite>=0.22.1",
|
|
23
|
+
"PyYAML>=6.0.1",
|
|
24
|
+
"mcp>=0.1.0",
|
|
25
|
+
"python-dotenv>=1.1.0",
|
|
26
|
+
"PyJWT>=2.10.0",
|
|
27
|
+
"click>=8.2.1",
|
|
28
|
+
"rich>=14.0.0",
|
|
29
|
+
"numpy>=2.0.0",
|
|
30
|
+
"typer>=0.16.0",
|
|
31
|
+
"openai>=1.84.0",
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
[project.scripts]
|
|
35
|
+
drake = "drake.cli.main:main"
|
|
36
|
+
|
|
37
|
+
[dependency-groups]
|
|
38
|
+
dev = [
|
|
39
|
+
"black>=26.5.1",
|
|
40
|
+
"flake8>=7.3.0",
|
|
41
|
+
"mypy>=2.1.0",
|
|
42
|
+
"pytest>=9.1.0",
|
|
43
|
+
"pytest-asyncio>=0.23.5",
|
|
44
|
+
"pytest-xdist>=3.8.0",
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
[tool.black]
|
|
48
|
+
line-length = 88
|
|
49
|
+
target-version = ["py311"]
|
|
50
|
+
include = '\.pyi?$'
|
|
51
|
+
|
|
52
|
+
[tool.mypy]
|
|
53
|
+
python_version = "3.11"
|
|
54
|
+
strict = true
|
|
55
|
+
disallow_untyped_defs = true
|
|
56
|
+
ignore_missing_imports = true
|
|
57
|
+
|
|
58
|
+
[tool.pytest.ini_options]
|
|
59
|
+
testpaths = ["tests"]
|
|
60
|
+
norecursedirs = ["generated"]
|
|
61
|
+
asyncio_mode = "auto"
|
|
62
|
+
addopts = "-n 2 --ignore=tests/generated"
|
|
63
|
+
|
|
64
|
+
[build-system]
|
|
65
|
+
requires = ["setuptools>=61.0.0", "wheel"]
|
|
66
|
+
build-backend = "setuptools.build_meta"
|
|
67
|
+
|
|
68
|
+
[tool.setuptools.packages.find]
|
|
69
|
+
where = ["src"]
|
|
70
|
+
include = ["drake*"]
|
|
71
|
+
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import logging
|
|
3
|
+
import networkx as nx
|
|
4
|
+
from typing import List, Dict, Any
|
|
5
|
+
|
|
6
|
+
logger = logging.getLogger(__name__)
|
|
7
|
+
|
|
8
|
+
def extract_schema_fields_typed(schema_str: Any) -> Dict[str, str]:
|
|
9
|
+
"""Extracts property names and types from a JSON schema string recursively."""
|
|
10
|
+
fields = {}
|
|
11
|
+
if not schema_str:
|
|
12
|
+
return fields
|
|
13
|
+
try:
|
|
14
|
+
schema = json.loads(schema_str) if isinstance(schema_str, str) else schema_str
|
|
15
|
+
if not isinstance(schema, dict):
|
|
16
|
+
return fields
|
|
17
|
+
def recurse(obj):
|
|
18
|
+
if isinstance(obj, dict):
|
|
19
|
+
if "properties" in obj and isinstance(obj["properties"], dict):
|
|
20
|
+
for k, v in obj["properties"].items():
|
|
21
|
+
t = v.get("type", "string") if isinstance(v, dict) else "unknown"
|
|
22
|
+
fields[k] = t
|
|
23
|
+
recurse(v)
|
|
24
|
+
for k, v in obj.items():
|
|
25
|
+
if k != "properties":
|
|
26
|
+
recurse(v)
|
|
27
|
+
elif isinstance(obj, list):
|
|
28
|
+
for item in obj:
|
|
29
|
+
recurse(item)
|
|
30
|
+
recurse(schema)
|
|
31
|
+
except Exception as e:
|
|
32
|
+
logger.warning(f"Failed to parse schema for dependency matching: {e}")
|
|
33
|
+
return fields
|
|
34
|
+
|
|
35
|
+
def extract_required_params_typed(params_str: Any) -> Dict[str, str]:
|
|
36
|
+
fields = {}
|
|
37
|
+
if not params_str:
|
|
38
|
+
return fields
|
|
39
|
+
try:
|
|
40
|
+
params = json.loads(params_str) if isinstance(params_str, str) else params_str
|
|
41
|
+
for p in params:
|
|
42
|
+
if isinstance(p, dict) and "name" in p:
|
|
43
|
+
t = p.get("schema", {}).get("type", "string")
|
|
44
|
+
fields[p["name"]] = t
|
|
45
|
+
except Exception:
|
|
46
|
+
pass
|
|
47
|
+
return fields
|
|
48
|
+
|
|
49
|
+
def build_execution_dag(endpoints: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
|
|
50
|
+
"""
|
|
51
|
+
Takes a list of endpoints within a community.
|
|
52
|
+
Builds a Directed Acyclic Graph (DAG) based on data dependencies.
|
|
53
|
+
Resolves Cycles automatically.
|
|
54
|
+
Returns the endpoints ordered by topological sort with variable_bindings injected.
|
|
55
|
+
"""
|
|
56
|
+
if not endpoints:
|
|
57
|
+
return []
|
|
58
|
+
if len(endpoints) == 1:
|
|
59
|
+
endpoints[0]["variable_bindings"] = json.dumps({})
|
|
60
|
+
return endpoints
|
|
61
|
+
|
|
62
|
+
G = nx.DiGraph()
|
|
63
|
+
bindings = {ep["operation_id"]: {} for ep in endpoints}
|
|
64
|
+
|
|
65
|
+
for ep in endpoints:
|
|
66
|
+
G.add_node(ep["operation_id"], data=ep)
|
|
67
|
+
|
|
68
|
+
common_fields = {"id", "name", "description", "status", "message", "error", "type"}
|
|
69
|
+
|
|
70
|
+
for ep_a in endpoints:
|
|
71
|
+
a_id = ep_a["operation_id"]
|
|
72
|
+
a_method = ep_a["method"].upper()
|
|
73
|
+
a_path = ep_a["url"]
|
|
74
|
+
a_outputs = extract_schema_fields_typed(ep_a.get("response_schema"))
|
|
75
|
+
|
|
76
|
+
for ep_b in endpoints:
|
|
77
|
+
b_id = ep_b["operation_id"]
|
|
78
|
+
if a_id == b_id:
|
|
79
|
+
continue
|
|
80
|
+
b_method = ep_b["method"].upper()
|
|
81
|
+
b_path = ep_b["url"]
|
|
82
|
+
b_inputs = extract_schema_fields_typed(ep_b.get("request_schema"))
|
|
83
|
+
b_inputs.update(extract_required_params_typed(ep_b.get("required_params")))
|
|
84
|
+
|
|
85
|
+
edge_weight = 0
|
|
86
|
+
mapped_fields = []
|
|
87
|
+
|
|
88
|
+
# Rule 1: Type-Aware Schema Intersection
|
|
89
|
+
for a_key, a_type in a_outputs.items():
|
|
90
|
+
if a_key.lower() in common_fields:
|
|
91
|
+
continue
|
|
92
|
+
for b_key, b_type in b_inputs.items():
|
|
93
|
+
if a_key.lower() == b_key.lower() and a_type == b_type:
|
|
94
|
+
edge_weight += 5
|
|
95
|
+
mapped_fields.append((b_key, a_key))
|
|
96
|
+
|
|
97
|
+
# Rule 2: Path Hierarchy (RESTful dependency)
|
|
98
|
+
if a_path in b_path and len(a_path) < len(b_path):
|
|
99
|
+
edge_weight += 10
|
|
100
|
+
|
|
101
|
+
# Rule 3: CRUD Semantics on the exact same path
|
|
102
|
+
if a_path == b_path:
|
|
103
|
+
crud_order = {"POST": 1, "GET": 2, "PUT": 3, "PATCH": 4, "DELETE": 5}
|
|
104
|
+
a_order = crud_order.get(a_method, 99)
|
|
105
|
+
b_order = crud_order.get(b_method, 99)
|
|
106
|
+
if a_order < b_order:
|
|
107
|
+
edge_weight += 3
|
|
108
|
+
|
|
109
|
+
if edge_weight > 0:
|
|
110
|
+
G.add_edge(a_id, b_id, weight=edge_weight)
|
|
111
|
+
for b_key, a_key in mapped_fields:
|
|
112
|
+
if b_key not in bindings[b_id]:
|
|
113
|
+
bindings[b_id][b_key] = f"{{{{{a_id}.{a_key}}}}}"
|
|
114
|
+
|
|
115
|
+
# Cycle Management Engine
|
|
116
|
+
try:
|
|
117
|
+
sorted_ids = list(nx.lexicographical_topological_sort(G))
|
|
118
|
+
except nx.NetworkXUnfeasible:
|
|
119
|
+
logger.warning("Cycle detected in DAG. Initializing Cycle Management Engine.")
|
|
120
|
+
while True:
|
|
121
|
+
try:
|
|
122
|
+
cycles = list(nx.simple_cycles(G))
|
|
123
|
+
if not cycles:
|
|
124
|
+
break
|
|
125
|
+
for cycle in cycles:
|
|
126
|
+
min_weight = float('inf')
|
|
127
|
+
weakest_edge = None
|
|
128
|
+
for i in range(len(cycle)):
|
|
129
|
+
u = cycle[i]
|
|
130
|
+
v = cycle[(i + 1) % len(cycle)]
|
|
131
|
+
if G.has_edge(u, v):
|
|
132
|
+
w = G[u][v]["weight"]
|
|
133
|
+
if w < min_weight:
|
|
134
|
+
min_weight = w
|
|
135
|
+
weakest_edge = (u, v)
|
|
136
|
+
if weakest_edge:
|
|
137
|
+
G.remove_edge(*weakest_edge)
|
|
138
|
+
logger.info(f"Cycle Management: Removed weakest edge {weakest_edge} (weight {min_weight})")
|
|
139
|
+
# Also remove the binding that caused this edge
|
|
140
|
+
target_id = weakest_edge[1]
|
|
141
|
+
bindings[target_id] = {k: v for k, v in bindings[target_id].items() if not v.startswith(f"{{{{{weakest_edge[0]}.")}
|
|
142
|
+
sorted_ids = list(nx.lexicographical_topological_sort(G))
|
|
143
|
+
break
|
|
144
|
+
except nx.NetworkXUnfeasible:
|
|
145
|
+
continue
|
|
146
|
+
|
|
147
|
+
ep_map = {ep["operation_id"]: ep for ep in endpoints}
|
|
148
|
+
sorted_endpoints = []
|
|
149
|
+
|
|
150
|
+
# Handle disconnected nodes gracefully
|
|
151
|
+
all_nodes = set(ep_map.keys())
|
|
152
|
+
sorted_set = set(sorted_ids)
|
|
153
|
+
missing = all_nodes - sorted_set
|
|
154
|
+
|
|
155
|
+
for op_id in sorted_ids + list(missing):
|
|
156
|
+
ep = ep_map[op_id]
|
|
157
|
+
ep["variable_bindings"] = json.dumps(bindings.get(op_id, {}))
|
|
158
|
+
sorted_endpoints.append(ep)
|
|
159
|
+
|
|
160
|
+
return sorted_endpoints
|