@@ -6,11 +6,12 @@ use crate::error::{Error, Result};
66use crate :: mcp:: protocol:: { CallToolResult , Tool } ;
77use crate :: tap_integration:: TapIntegration ;
88use serde:: { Deserialize , Serialize } ;
9- use serde_json:: Value ;
9+ use serde_json:: { json , Value } ;
1010use std:: collections:: { HashMap , HashSet } ;
1111use std:: sync:: Arc ;
1212use tap_msg:: message:: TapMessage ;
1313use tap_node:: customer:: CustomerManager ;
14+ use tap_node:: storage:: models:: { Customer , SchemaType } ;
1415use tracing:: { debug, error} ;
1516
1617/// Tool for listing customers (parties that an agent acts for)
@@ -740,6 +741,229 @@ impl ToolHandler for UpdateCustomerProfileTool {
740741 }
741742}
742743
744+ /// Tool for creating a new customer
745+ pub struct CreateCustomerTool {
746+ tap_integration : Arc < TapIntegration > ,
747+ }
748+
749+ /// Parameters for creating a customer
750+ #[ derive( Debug , Deserialize ) ]
751+ struct CreateCustomerParams {
752+ agent_did : String ,
753+ customer_id : String ,
754+ profile_data : Value ,
755+ }
756+
757+ impl CreateCustomerTool {
758+ pub fn new ( tap_integration : Arc < TapIntegration > ) -> Self {
759+ Self { tap_integration }
760+ }
761+
762+ fn tap_integration ( & self ) -> & TapIntegration {
763+ & self . tap_integration
764+ }
765+ }
766+
767+ #[ async_trait:: async_trait]
768+ impl ToolHandler for CreateCustomerTool {
769+ async fn handle ( & self , arguments : Option < Value > ) -> Result < CallToolResult > {
770+ let params: CreateCustomerParams = match arguments {
771+ Some ( args) => serde_json:: from_value ( args)
772+ . map_err ( |e| Error :: invalid_parameter ( format ! ( "Invalid parameters: {}" , e) ) ) ?,
773+ None => {
774+ return Ok ( error_text_response (
775+ "Missing required parameters" . to_string ( ) ,
776+ ) )
777+ }
778+ } ;
779+
780+ debug ! (
781+ "Creating customer {} via agent {}" ,
782+ params. customer_id, params. agent_did
783+ ) ;
784+
785+ // Get storage for the agent
786+ let storage = match self
787+ . tap_integration ( )
788+ . storage_for_agent ( & params. agent_did )
789+ . await
790+ {
791+ Ok ( storage) => storage,
792+ Err ( e) => {
793+ error ! (
794+ "Failed to get storage for agent {}: {}" ,
795+ params. agent_did, e
796+ ) ;
797+ return Ok ( error_text_response ( format ! (
798+ "Failed to get storage for agent {}: {}" ,
799+ params. agent_did, e
800+ ) ) ) ;
801+ }
802+ } ;
803+
804+ // Create customer manager
805+ let customer_manager = CustomerManager :: new ( storage. clone ( ) ) ;
806+
807+ // Check if customer already exists
808+ let existing = match storage. get_customer ( & params. customer_id ) . await {
809+ Ok ( existing) => existing,
810+ Err ( e) => {
811+ error ! ( "Failed to check existing customer: {}" , e) ;
812+ return Ok ( error_text_response ( format ! (
813+ "Failed to check existing customer: {}" ,
814+ e
815+ ) ) ) ;
816+ }
817+ } ;
818+
819+ if existing. is_none ( ) {
820+ // Create new customer
821+ let display_name = params
822+ . profile_data
823+ . get ( "givenName" )
824+ . and_then ( |v| v. as_str ( ) )
825+ . map ( |given| {
826+ if let Some ( family) = params
827+ . profile_data
828+ . get ( "familyName" )
829+ . and_then ( |v| v. as_str ( ) )
830+ {
831+ format ! ( "{} {}" , given, family)
832+ } else {
833+ given. to_string ( )
834+ }
835+ } ) ;
836+
837+ // Create customer profile from schema.org data
838+ let mut profile = json ! ( {
839+ "@context" : "https://schema.org" ,
840+ "@type" : "Person" ,
841+ "identifier" : params. customer_id. clone( ) ,
842+ } ) ;
843+
844+ // Merge provided profile data
845+ if let Value :: Object ( profile_obj) = & mut profile {
846+ if let Value :: Object ( data_obj) = & params. profile_data {
847+ for ( key, value) in data_obj {
848+ profile_obj. insert ( key. clone ( ) , value. clone ( ) ) ;
849+ }
850+ }
851+ }
852+
853+ // Determine schema type based on provided data
854+ let schema_type = if params. profile_data . get ( "@type" ) . and_then ( |v| v. as_str ( ) )
855+ == Some ( "Organization" )
856+ {
857+ SchemaType :: Organization
858+ } else {
859+ SchemaType :: Person
860+ } ;
861+
862+ // Create Customer struct
863+ let customer = Customer {
864+ id : params. customer_id . clone ( ) ,
865+ agent_did : params. agent_did . clone ( ) ,
866+ schema_type,
867+ given_name : params
868+ . profile_data
869+ . get ( "givenName" )
870+ . and_then ( |v| v. as_str ( ) )
871+ . map ( String :: from) ,
872+ family_name : params
873+ . profile_data
874+ . get ( "familyName" )
875+ . and_then ( |v| v. as_str ( ) )
876+ . map ( String :: from) ,
877+ display_name,
878+ legal_name : params
879+ . profile_data
880+ . get ( "legalName" )
881+ . and_then ( |v| v. as_str ( ) )
882+ . map ( String :: from) ,
883+ lei_code : params
884+ . profile_data
885+ . get ( "leiCode" )
886+ . and_then ( |v| v. as_str ( ) )
887+ . map ( String :: from) ,
888+ mcc_code : params
889+ . profile_data
890+ . get ( "mccCode" )
891+ . and_then ( |v| v. as_str ( ) )
892+ . map ( String :: from) ,
893+ address_country : params
894+ . profile_data
895+ . get ( "addressCountry" )
896+ . and_then ( |v| v. as_str ( ) )
897+ . map ( String :: from) ,
898+ address_locality : params
899+ . profile_data
900+ . get ( "addressLocality" )
901+ . and_then ( |v| v. as_str ( ) )
902+ . map ( String :: from) ,
903+ postal_code : params
904+ . profile_data
905+ . get ( "postalCode" )
906+ . and_then ( |v| v. as_str ( ) )
907+ . map ( String :: from) ,
908+ street_address : params
909+ . profile_data
910+ . get ( "streetAddress" )
911+ . and_then ( |v| v. as_str ( ) )
912+ . map ( String :: from) ,
913+ profile,
914+ ivms101_data : None ,
915+ verified_at : None ,
916+ created_at : chrono:: Utc :: now ( ) . to_rfc3339 ( ) ,
917+ updated_at : chrono:: Utc :: now ( ) . to_rfc3339 ( ) ,
918+ } ;
919+
920+ // Create the customer
921+ match storage. upsert_customer ( & customer) . await {
922+ Ok ( _) => {
923+ debug ! ( "Created new customer {}" , params. customer_id) ;
924+ Ok ( success_text_response ( format ! (
925+ "Successfully created customer {}" ,
926+ params. customer_id
927+ ) ) )
928+ }
929+ Err ( e) => {
930+ error ! ( "Failed to create customer: {}" , e) ;
931+ Ok ( error_text_response ( format ! (
932+ "Failed to create customer: {}" ,
933+ e
934+ ) ) )
935+ }
936+ }
937+ } else {
938+ // Update existing customer
939+ match customer_manager
940+ . update_customer_profile ( & params. customer_id , params. profile_data )
941+ . await
942+ {
943+ Ok ( _) => Ok ( success_text_response ( format ! (
944+ "Successfully updated existing customer {}" ,
945+ params. customer_id
946+ ) ) ) ,
947+ Err ( e) => {
948+ error ! ( "Failed to update customer: {}" , e) ;
949+ Ok ( error_text_response ( format ! (
950+ "Failed to update customer: {}" ,
951+ e
952+ ) ) )
953+ }
954+ }
955+ }
956+ }
957+
958+ fn get_definition ( & self ) -> Tool {
959+ Tool {
960+ name : "tap_create_customer" . to_string ( ) ,
961+ description : "Creates a new customer profile for an agent. The customer_id should be a DID or unique identifier. The profile_data should be a JSON object with schema.org fields (e.g., givenName, familyName, addressCountry). If a customer with the same ID already exists, their profile will be updated." . to_string ( ) ,
962+ input_schema : schema:: create_customer_schema ( ) ,
963+ }
964+ }
965+ }
966+
743967/// Tool for updating customer from IVMS101 data
744968pub struct UpdateCustomerFromIvms101Tool {
745969 tap_integration : Arc < TapIntegration > ,
0 commit comments