-
Notifications
You must be signed in to change notification settings - Fork 73
Expand file tree
/
Copy pathlist_dsc_resources.rs
More file actions
82 lines (76 loc) · 3.52 KB
/
Copy pathlist_dsc_resources.rs
File metadata and controls
82 lines (76 loc) · 3.52 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
use crate::server::mcp_server::McpServer;
use dsc_lib::{
DscManager, discovery::{
command_discovery::ImportedManifest::Resource,
discovery_trait::{DiscoveryFilter, DiscoveryKind},
}, dscresources::resource_manifest::Kind, progress::ProgressFormat, types::{FullyQualifiedTypeName, TypeNameFilter}
};
use rmcp::{ErrorData as McpError, Json, tool, tool_router, handler::server::wrapper::Parameters};
use rust_i18n::t;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use tokio::task;
#[derive(Serialize, JsonSchema)]
pub struct ResourceListResult {
pub resources: Vec<ResourceSummary>,
}
#[derive(Serialize, JsonSchema)]
pub struct ResourceSummary {
pub r#type: FullyQualifiedTypeName,
pub kind: Kind,
pub description: Option<String>,
#[serde(rename = "requireAdapter")]
pub require_adapter: Option<FullyQualifiedTypeName>,
}
#[derive(Deserialize, JsonSchema)]
pub struct ListResourcesRequest {
#[schemars(description = "Filter adapted resources to only those requiring the specified adapter type. If not specified, all non-adapted resources are returned.")]
pub adapter: Option<FullyQualifiedTypeName>,
}
#[tool_router(router = list_dsc_resources_router, vis = "pub")]
impl McpServer {
#[tool(
description = "List summary of all DSC resources available on the local machine",
annotations(
title = "Enumerate all available DSC resources on the local machine returning name, kind, and description.",
read_only_hint = true,
destructive_hint = false,
idempotent_hint = true,
open_world_hint = true,
)
)]
pub async fn list_dsc_resources(&self, Parameters(ListResourcesRequest { adapter }): Parameters<ListResourcesRequest>) -> Result<Json<ResourceListResult>, McpError> {
let result = task::spawn_blocking(move || {
let mut dsc = DscManager::new();
let adapter_filter = match adapter {
Some(adapter) => {
if let Some(resource) = dsc.find_resource(&DiscoveryFilter::new(&adapter, None, None)).unwrap_or(None) {
if resource.kind != Kind::Adapter {
return Err(McpError::invalid_params(t!("server.list_dsc_resources.resourceNotAdapter", adapter = adapter), None));
}
Some(&TypeNameFilter::Literal(resource.type_name.clone()))
} else {
return Err(McpError::invalid_params(t!("server.list_dsc_resources.adapterNotFound", adapter = adapter), None));
}
},
None => None,
};
let mut resources = Vec::<ResourceSummary>::new();
for resource in dsc.list_available(&DiscoveryKind::Resource, &TypeNameFilter::default(), adapter_filter, ProgressFormat::None) {
if let Resource(resource) = resource {
let summary = ResourceSummary {
r#type: resource.type_name.clone(),
kind: resource.kind.clone(),
description: resource.description.clone(),
require_adapter: resource.require_adapter,
};
resources.push(summary);
}
}
Ok(ResourceListResult { resources })
}).await.map_err(|e| McpError::internal_error(e.to_string(), None))??;
Ok(Json(result))
}
}