Skip to main content

tap_mcp/
tap_integration.rs

1//! Integration layer with TAP ecosystem components
2
3use crate::error::{Error, Result};
4use std::path::PathBuf;
5use std::sync::Arc;
6use tap_agent::TapAgent;
7use tap_node::{NodeConfig, TapNode};
8use tracing::{debug, error, info};
9
10/// TAP ecosystem integration - thin wrapper around TapNode
11pub struct TapIntegration {
12    node: Arc<TapNode>,
13    /// Custom storage path for testing (if set, overrides default ~/.tap)
14    storage_path: Option<PathBuf>,
15}
16
17impl TapIntegration {
18    /// Create new TAP integration using TapNode with agent registration
19    pub async fn new(
20        agent_did: Option<&str>,
21        tap_root: Option<&str>,
22        agent: Option<Arc<TapAgent>>,
23    ) -> Result<Self> {
24        // Create node configuration
25        let mut config = NodeConfig::default();
26
27        // Set agent DID for proper storage organization
28        if let Some(did) = agent_did {
29            config.agent_did = Some(did.to_string());
30        }
31
32        // Set custom TAP root if provided
33        if let Some(root) = tap_root {
34            config.tap_root = Some(PathBuf::from(root));
35        }
36
37        // Enable storage features
38        config.enable_message_logging = true;
39        config.log_message_content = true;
40
41        // Create the node
42        let mut node = TapNode::new(config);
43
44        // Initialize storage with DID-based structure
45        node.init_storage().await.map_err(|e| {
46            Error::configuration(format!("Failed to initialize TAP node storage: {}", e))
47        })?;
48
49        info!("Initialized TAP integration with DID-based storage");
50
51        let node_arc = Arc::new(node);
52
53        // Register the primary agent if provided
54        if let Some(agent) = agent {
55            node_arc
56                .register_agent(agent)
57                .await
58                .map_err(|e| Error::configuration(format!("Failed to register agent: {}", e)))?;
59            info!("Registered primary agent with TAP Node");
60        }
61
62        // Load and register all additional agents from storage
63        match tap_agent::storage::KeyStorage::load_default() {
64            Ok(storage) => {
65                let stored_dids: Vec<String> = storage.keys.keys().cloned().collect();
66                info!("Found {} total keys in storage", stored_dids.len());
67
68                for stored_did in &stored_dids {
69                    // Skip the primary agent if it's already registered
70                    if agent_did.is_some_and(|did| stored_did == did) {
71                        continue;
72                    }
73
74                    info!("Registering additional agent: {}", stored_did);
75                    match TapAgent::from_stored_keys(Some(stored_did.clone()), true).await {
76                        Ok(additional_agent) => {
77                            let additional_agent_arc = Arc::new(additional_agent);
78                            if let Err(e) = node_arc.register_agent(additional_agent_arc).await {
79                                error!("Failed to register additional agent {}: {}", stored_did, e);
80                            } else {
81                                info!("Successfully registered additional agent: {}", stored_did);
82                            }
83                        }
84                        Err(e) => {
85                            error!("Failed to load additional agent {}: {}", stored_did, e);
86                        }
87                    }
88                }
89            }
90            Err(e) => {
91                debug!("Could not load additional keys from storage: {}", e);
92            }
93        }
94
95        Ok(Self {
96            node: node_arc,
97            storage_path: None,
98        })
99    }
100
101    /// Create new TAP integration for testing with custom paths
102    #[allow(dead_code)]
103    pub async fn new_for_testing(tap_root: Option<&str>, agent_did: &str) -> Result<Self> {
104        let mut config = NodeConfig::default();
105
106        // Set custom TAP root for testing
107        if let Some(root) = tap_root {
108            config.tap_root = Some(PathBuf::from(root));
109        }
110
111        // Set agent DID
112        config.agent_did = Some(agent_did.to_string());
113        config.enable_message_logging = true;
114        config.log_message_content = true;
115
116        let mut node = TapNode::new(config);
117        node.init_storage().await.map_err(|e| {
118            Error::configuration(format!("Failed to initialize TAP node storage: {}", e))
119        })?;
120
121        debug!(
122            "Created TAP integration for testing with DID: {}",
123            agent_did
124        );
125
126        // For testing, use the keys.json file in the TAP root
127        let storage_path = tap_root.map(|root| PathBuf::from(root).join("keys.json"));
128
129        // Create a test agent for testing
130        let (test_agent, _) = TapAgent::from_ephemeral_key()
131            .await
132            .map_err(|e| Error::configuration(format!("Failed to create test agent: {}", e)))?;
133
134        let node_arc = Arc::new(node);
135        node_arc
136            .register_agent(Arc::new(test_agent))
137            .await
138            .map_err(|e| Error::configuration(format!("Failed to register test agent: {}", e)))?;
139
140        Ok(Self {
141            node: node_arc,
142            storage_path,
143        })
144    }
145
146    /// Get reference to underlying TapNode
147    #[allow(dead_code)]
148    pub fn node(&self) -> &Arc<TapNode> {
149        &self.node
150    }
151
152    /// Get storage path (if available)
153    #[allow(dead_code)]
154    pub fn storage_path(&self) -> Option<&PathBuf> {
155        self.storage_path.as_ref()
156    }
157
158    /// Get storage reference (if available) - uses the primary node storage
159    pub fn storage(&self) -> Option<&Arc<tap_node::storage::Storage>> {
160        self.node.storage()
161    }
162
163    /// Get storage for a specific agent DID
164    /// This delegates to TAP Node's AgentStorageManager for proper agent isolation
165    pub async fn storage_for_agent(
166        &self,
167        agent_did: &str,
168    ) -> Result<Arc<tap_node::storage::Storage>> {
169        // Use TAP Node's agent storage manager for consistent storage access
170        if let Some(storage_manager) = self.node.agent_storage_manager() {
171            storage_manager
172                .get_agent_storage(agent_did)
173                .await
174                .map_err(|e| {
175                    Error::configuration(format!(
176                        "Failed to get storage for agent {}: {}",
177                        agent_did, e
178                    ))
179                })
180        } else {
181            Err(Error::configuration(
182                "Agent storage manager not available".to_string(),
183            ))
184        }
185    }
186
187    /// List all registered agents (from storage and in-memory registry)
188    pub async fn list_agents(&self) -> Result<Vec<AgentInfo>> {
189        let mut agents = Vec::new();
190
191        // Load agents directly from KeyStorage to get labels
192        use tap_agent::storage::KeyStorage;
193        let key_storage = if let Some(ref storage_path) = self.storage_path {
194            KeyStorage::load_from_path(storage_path)
195        } else {
196            KeyStorage::load_default()
197        };
198
199        match key_storage {
200            Ok(storage) => {
201                // Process each stored key
202                for (did, stored_key) in &storage.keys {
203                    let mut metadata = std::collections::HashMap::new();
204
205                    // Include the label from the stored key
206                    if !stored_key.label.is_empty() {
207                        metadata.insert("label".to_string(), stored_key.label.clone());
208                    }
209
210                    // Also include any additional metadata from the stored key
211                    for (key, value) in &stored_key.metadata {
212                        metadata.insert(key.clone(), value.clone());
213                    }
214
215                    // Try to load policies for this agent
216                    let policies = storage.load_agent_policies(did).unwrap_or_default();
217
218                    agents.push(AgentInfo {
219                        id: did.clone(),
220                        role: "Agent".to_string(), // Default role, will be determined per transaction
221                        for_party: did.clone(), // Default to self, will be determined per transaction
222                        policies,
223                        metadata,
224                    });
225                }
226            }
227            Err(e) => {
228                debug!("Could not load key storage: {}", e);
229            }
230        }
231
232        // Also include any agents only registered in TapNode (for backward compatibility)
233        let node_agent_dids = self.node.list_agents();
234        for did in node_agent_dids {
235            // Check if we already have this agent from key storage
236            if !agents.iter().any(|a| a.id == did) {
237                agents.push(AgentInfo {
238                    id: did.clone(),
239                    role: "Agent".to_string(),
240                    for_party: did,
241                    policies: vec![],
242                    metadata: std::collections::HashMap::new(),
243                });
244            }
245        }
246
247        Ok(agents)
248    }
249}
250
251/// Agent information for MCP interface
252#[derive(Debug, Clone)]
253pub struct AgentInfo {
254    pub id: String,
255    pub role: String,
256    pub for_party: String,
257    pub policies: Vec<String>,
258    pub metadata: std::collections::HashMap<String, String>,
259}