1use super::schema;
4use super::{default_limit, error_text_response, success_text_response, ToolHandler};
5use crate::error::{Error, Result};
6use crate::mcp::protocol::{CallToolResult, Tool};
7use crate::tap_integration::TapIntegration;
8use serde::{Deserialize, Serialize};
9use serde_json::Value;
10use std::sync::Arc;
11use tracing::{debug, error, info};
12
13pub struct CreateAgentTool {
15 tap_integration: Arc<TapIntegration>,
16}
17
18#[derive(Debug, Deserialize)]
20#[serde(deny_unknown_fields)]
21struct CreateAgentParams {
22 #[serde(default)]
23 label: Option<String>,
24}
25
26#[derive(Debug, Serialize)]
28struct CreateAgentResponse {
29 #[serde(rename = "@id")]
30 id: String,
31 #[serde(skip_serializing_if = "Option::is_none")]
32 label: Option<String>,
33 created_at: String,
34}
35
36impl CreateAgentTool {
37 pub fn new(tap_integration: Arc<TapIntegration>) -> Self {
38 Self { tap_integration }
39 }
40
41 fn tap_integration(&self) -> &TapIntegration {
42 &self.tap_integration
43 }
44}
45
46#[async_trait::async_trait]
47impl ToolHandler for CreateAgentTool {
48 async fn handle(&self, arguments: Option<Value>) -> Result<CallToolResult> {
49 let params: CreateAgentParams = match arguments {
50 Some(args) => serde_json::from_value(args)
51 .map_err(|e| Error::invalid_parameter(format!("Invalid parameters: {}", e)))?,
52 None => {
53 return Ok(error_text_response(
54 "Missing required parameters".to_string(),
55 ))
56 }
57 };
58
59 debug!("Creating new agent with auto-generated DID");
60
61 use std::sync::Arc;
63 use tap_agent::storage::KeyStorage;
64 use tap_agent::{
65 did::{DIDGenerationOptions, DIDKeyGenerator, KeyType},
66 TapAgent,
67 };
68
69 let generator = DIDKeyGenerator::new();
71 let generated_key = generator
72 .generate_did(DIDGenerationOptions {
73 key_type: KeyType::Ed25519,
74 })
75 .map_err(|e| Error::tool_execution(format!("Failed to generate DID: {}", e)))?;
76
77 debug!("Generated new DID for agent: {}", generated_key.did);
78
79 let (agent, generated_did) = TapAgent::from_private_key(
81 &generated_key.private_key,
82 generated_key.key_type,
83 false, )
85 .await
86 .map_err(|e| Error::tool_execution(format!("Failed to create agent: {}", e)))?;
87
88 let mut key_storage = match KeyStorage::load_default() {
90 Ok(storage) => storage,
91 Err(e) => {
92 debug!("Could not load existing key storage ({}), creating new", e);
93 KeyStorage::new()
94 }
95 };
96
97 let stored_key = if let Some(ref label) = params.label {
99 tap_agent::storage::KeyStorage::from_generated_key_with_label(&generated_key, label)
100 } else {
101 tap_agent::storage::KeyStorage::from_generated_key(&generated_key)
102 };
103
104 key_storage.add_key(stored_key);
106
107 debug!("Current keys in storage: {}", key_storage.keys.len());
108 for (did, key) in &key_storage.keys {
109 debug!(" - {}: {}", did, key.label);
110 }
111
112 match key_storage.save_default() {
114 Ok(_) => {
115 info!(
116 "Successfully saved agent key to storage with label: {:?}",
117 params.label
118 );
119 }
120 Err(e) => {
121 error!("Failed to save key storage: {}", e);
122 return Err(Error::tool_execution(format!(
123 "Failed to save key storage: {}",
124 e
125 )));
126 }
127 }
128
129 match self
131 .tap_integration()
132 .node()
133 .register_agent(Arc::new(agent))
134 .await
135 {
136 Ok(()) => {
137 info!("Created and registered agent with DID: {}", generated_did);
138
139 let response = CreateAgentResponse {
140 id: generated_did,
141 label: params.label,
142 created_at: chrono::Utc::now().to_rfc3339(),
143 };
144
145 let response_json = serde_json::to_string_pretty(&response).map_err(|e| {
146 Error::tool_execution(format!("Failed to serialize response: {}", e))
147 })?;
148
149 debug!("CreateAgent response JSON: {}", response_json);
150 Ok(success_text_response(response_json))
151 }
152 Err(e) => {
153 error!("Failed to create agent: {}", e);
154 Ok(error_text_response(format!(
155 "Failed to create agent: {}",
156 e
157 )))
158 }
159 }
160 }
161
162 fn get_definition(&self) -> Tool {
163 Tool {
164 name: "tap_create_agent".to_string(),
165 description: "Creates a new TAP agent with auto-generated DID and stores the keys in ~/.tap/keys.json. Returns the generated DID. Roles and party associations are specified per transaction, not during agent creation.".to_string(),
166 input_schema: schema::create_agent_schema(),
167 }
168 }
169}
170
171pub struct ListAgentsTool {
173 tap_integration: Arc<TapIntegration>,
174}
175
176#[derive(Debug, Deserialize)]
178struct ListAgentsParams {
179 #[serde(default = "default_limit")]
180 limit: u32,
181 #[serde(default)]
182 offset: u32,
183}
184
185#[derive(Debug, Serialize)]
187struct ListAgentsResponse {
188 agents: Vec<ListAgentInfo>,
189 total: usize,
190}
191
192#[derive(Debug, Serialize)]
193struct ListAgentInfo {
194 #[serde(rename = "@id")]
195 id: String,
196 #[serde(skip_serializing_if = "Option::is_none")]
197 label: Option<String>,
198 policies: Vec<Value>,
199 metadata: Value,
200}
201
202impl ListAgentsTool {
203 pub fn new(tap_integration: Arc<TapIntegration>) -> Self {
204 Self { tap_integration }
205 }
206
207 fn tap_integration(&self) -> &TapIntegration {
208 &self.tap_integration
209 }
210}
211
212#[async_trait::async_trait]
213impl ToolHandler for ListAgentsTool {
214 async fn handle(&self, arguments: Option<Value>) -> Result<CallToolResult> {
215 let params: ListAgentsParams = match arguments {
216 Some(args) => serde_json::from_value(args)
217 .map_err(|e| Error::invalid_parameter(format!("Invalid parameters: {}", e)))?,
218 None => ListAgentsParams {
219 limit: default_limit(),
220 offset: 0,
221 },
222 };
223
224 debug!(
225 "Listing agents with limit={}, offset={}",
226 params.limit, params.offset
227 );
228
229 match self.tap_integration().list_agents().await {
230 Ok(agents) => {
231 let total = agents.len();
232
233 let paginated_agents: Vec<_> = agents
235 .into_iter()
236 .skip(params.offset as usize)
237 .take(params.limit as usize)
238 .map(|agent| ListAgentInfo {
239 id: agent.id,
240 label: agent.metadata.get("label").cloned(),
241 policies: agent
242 .policies
243 .into_iter()
244 .map(serde_json::Value::String)
245 .collect(),
246 metadata: if agent.metadata.is_empty() {
247 serde_json::Value::Null
248 } else {
249 serde_json::to_value(agent.metadata).unwrap_or(serde_json::Value::Null)
250 },
251 })
252 .collect();
253
254 let response = ListAgentsResponse {
255 agents: paginated_agents,
256 total,
257 };
258
259 let response_json = serde_json::to_string_pretty(&response).map_err(|e| {
260 Error::tool_execution(format!("Failed to serialize response: {}", e))
261 })?;
262
263 Ok(success_text_response(response_json))
264 }
265 Err(e) => {
266 error!("Failed to list agents: {}", e);
267 Ok(error_text_response(format!("Failed to list agents: {}", e)))
268 }
269 }
270 }
271
272 fn get_definition(&self) -> Tool {
273 Tool {
274 name: "tap_list_agents".to_string(),
275 description: "Lists all configured agents from ~/.tap/keys.json. Agents are identified by their DIDs. Roles and party associations are transaction-specific and not stored with agents.".to_string(),
276 input_schema: schema::list_agents_schema(),
277 }
278 }
279}