feat(tools): VEX, SBOM, Komponenten, Policy-Verstoesse + Projekt-Lookup als MCP-Tools
CI / test (push) Failing after 5m24s
CI / test (push) Failing after 5m24s
This commit is contained in:
@@ -40,10 +40,20 @@ pub struct DtrackServer {
|
|||||||
/// Argument fuer projektbezogene Tools.
|
/// Argument fuer projektbezogene Tools.
|
||||||
#[derive(Debug, Deserialize, JsonSchema)]
|
#[derive(Debug, Deserialize, JsonSchema)]
|
||||||
pub struct ProjectArg {
|
pub struct ProjectArg {
|
||||||
/// UUID des Projekts (aus `list_projects`).
|
/// UUID des Projekts (aus `list_projects` oder `lookup_project`).
|
||||||
pub uuid: String,
|
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]
|
#[tool_router]
|
||||||
impl DtrackServer {
|
impl DtrackServer {
|
||||||
pub fn new(client: SharedClient) -> Self {
|
pub fn new(client: SharedClient) -> Self {
|
||||||
@@ -63,6 +73,32 @@ impl DtrackServer {
|
|||||||
Ok(CallToolResult::success(vec![Content::text(body)]))
|
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.")]
|
#[tool(description = "Findings (Schwachstellen) eines Projekts anhand seiner UUID.")]
|
||||||
async fn project_findings(
|
async fn project_findings(
|
||||||
&self,
|
&self,
|
||||||
@@ -88,6 +124,45 @@ impl DtrackServer {
|
|||||||
.map_err(|e| McpError::internal_error(e.to_string(), None))?;
|
.map_err(|e| McpError::internal_error(e.to_string(), None))?;
|
||||||
Ok(CallToolResult::success(vec![Content::text(body)]))
|
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]
|
#[tool_handler]
|
||||||
@@ -98,7 +173,8 @@ impl ServerHandler for DtrackServer {
|
|||||||
capabilities: ServerCapabilities::builder().enable_tools().build(),
|
capabilities: ServerCapabilities::builder().enable_tools().build(),
|
||||||
server_info: Implementation::from_build_env(),
|
server_info: Implementation::from_build_env(),
|
||||||
instructions: Some(
|
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(),
|
.to_string(),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user