feat(tools): VEX, SBOM, Komponenten, Policy-Verstoesse + Projekt-Lookup als MCP-Tools
CI / test (push) Failing after 5m24s

This commit is contained in:
2026-06-25 06:44:38 +00:00
parent df99a46f95
commit 9be73422bb
+78 -2
View File
@@ -40,10 +40,20 @@ pub struct DtrackServer {
/// Argument fuer projektbezogene Tools.
#[derive(Debug, Deserialize, JsonSchema)]
pub struct ProjectArg {
/// UUID des Projekts (aus `list_projects`).
/// UUID des Projekts (aus `list_projects` oder `lookup_project`).
pub uuid: String,
}
/// Argument fuer die Projekt-Suche per Name.
#[derive(Debug, Deserialize, JsonSchema)]
pub struct LookupArg {
/// Projektname (exakt).
pub name: String,
/// Optional: Projektversion. Weglassen sucht ohne Versionsfilter.
#[serde(default)]
pub version: Option<String>,
}
#[tool_router]
impl DtrackServer {
pub fn new(client: SharedClient) -> Self {
@@ -63,6 +73,32 @@ impl DtrackServer {
Ok(CallToolResult::success(vec![Content::text(body)]))
}
#[tool(description = "Findet ein Projekt per Name (optional Version) und liefert u.a. dessen UUID.")]
async fn lookup_project(
&self,
Parameters(arg): Parameters<LookupArg>,
) -> Result<CallToolResult, McpError> {
let client = self.client.read().await.clone();
let body = client
.lookup_project(&arg.name, arg.version.as_deref())
.await
.map_err(|e| McpError::internal_error(e.to_string(), None))?;
Ok(CallToolResult::success(vec![Content::text(body)]))
}
#[tool(description = "Komponenten/Abhaengigkeiten eines Projekts anhand seiner UUID.")]
async fn project_components(
&self,
Parameters(arg): Parameters<ProjectArg>,
) -> Result<CallToolResult, McpError> {
let client = self.client.read().await.clone();
let body = client
.project_components(&arg.uuid)
.await
.map_err(|e| McpError::internal_error(e.to_string(), None))?;
Ok(CallToolResult::success(vec![Content::text(body)]))
}
#[tool(description = "Findings (Schwachstellen) eines Projekts anhand seiner UUID.")]
async fn project_findings(
&self,
@@ -88,6 +124,45 @@ impl DtrackServer {
.map_err(|e| McpError::internal_error(e.to_string(), None))?;
Ok(CallToolResult::success(vec![Content::text(body)]))
}
#[tool(description = "Policy-Verstoesse eines Projekts (UUID). Braucht das DT-Recht VIEW_POLICY_VIOLATION.")]
async fn project_violations(
&self,
Parameters(arg): Parameters<ProjectArg>,
) -> Result<CallToolResult, McpError> {
let client = self.client.read().await.clone();
let body = client
.project_violations(&arg.uuid)
.await
.map_err(|e| McpError::internal_error(e.to_string(), None))?;
Ok(CallToolResult::success(vec![Content::text(body)]))
}
#[tool(description = "VEX (CycloneDX) eines Projekts (UUID): Exploitability-/Analyse-Status der Schwachstellen.")]
async fn project_vex(
&self,
Parameters(arg): Parameters<ProjectArg>,
) -> Result<CallToolResult, McpError> {
let client = self.client.read().await.clone();
let body = client
.project_vex(&arg.uuid)
.await
.map_err(|e| McpError::internal_error(e.to_string(), None))?;
Ok(CallToolResult::success(vec![Content::text(body)]))
}
#[tool(description = "SBOM (CycloneDX, JSON) eines Projekts anhand seiner UUID.")]
async fn project_bom(
&self,
Parameters(arg): Parameters<ProjectArg>,
) -> Result<CallToolResult, McpError> {
let client = self.client.read().await.clone();
let body = client
.project_bom(&arg.uuid)
.await
.map_err(|e| McpError::internal_error(e.to_string(), None))?;
Ok(CallToolResult::success(vec![Content::text(body)]))
}
}
#[tool_handler]
@@ -98,7 +173,8 @@ impl ServerHandler for DtrackServer {
capabilities: ServerCapabilities::builder().enable_tools().build(),
server_info: Implementation::from_build_env(),
instructions: Some(
"Read-only Zugriff auf Dependency-Track (Projekte, Findings, Metriken)."
"Read-only Zugriff auf Dependency-Track: Projekte (Liste/Lookup), \
Komponenten, Findings, Metriken, Policy-Verstoesse, VEX und SBOM (CycloneDX)."
.to_string(),
),
}