@@ -308,24 +308,40 @@ export class MCPClient {
308308 if ( toolName === 'get_embedding_vector_for_text' && this . config . debug ) {
309309 console . log ( `About to parse result for ${ toolName } . Raw result structure:` , JSON . stringify ( result , null , 2 ) ) ;
310310 }
311-
312- // Parse the result content
313- // Log the actual response structure for debugging
314- console . log ( `Result from tool ${ toolName } :` , JSON . stringify ( result , null , 2 ) ) ;
315- if ( ! result [ 'result' ] ) {
316- // Check if the result has a different structure
317- if ( result . hasOwnProperty ( 'content' ) ) {
318- return result [ 'content' ] as unknown as T ;
319- }
320- // For void operations, return undefined
321- if ( toolName === 'create_object_type' || toolName === 'create_relation_type' ||
322- toolName === 'upsert_object' || toolName === 'add_relation' ||
323- toolName === 'delete_object' || toolName === 'delete_relation' ||
324- toolName === 'delete_object_type' || toolName === 'delete_relation_type' ) {
325- return undefined as unknown as T ;
311+
312+ // Handle MCP protocol response format
313+ if ( Array . isArray ( result . content ) && result . content . length > 0 ) {
314+ const content = result . content [ 0 ] ;
315+ if ( content . type === 'text' ) {
316+ try {
317+ const parsedData = JSON . parse ( content . text ) ;
318+ return parsedData ;
319+ } catch ( parseError ) {
320+ if ( this . config . debug ) {
321+ console . log ( `Failed to parse MCP text content for ${ toolName } :` , content . text ) ;
322+ }
323+ throw new Error ( `Failed to parse MCP text response: ${ content . text } ` ) ;
326324 }
327- throw new Error ( `Empty response from tool: ${ toolName } ` ) ;
325+ } else {
326+ throw new Error ( `Unsupported content type: ${ content . type } ` ) ;
328327 }
328+ }
329+
330+ // Legacy response format handling
331+ if ( ! result [ 'result' ] ) {
332+ // Check if the result has a different structure
333+ if ( result . hasOwnProperty ( 'content' ) ) {
334+ return result [ 'content' ] as unknown as T ;
335+ }
336+ // For void operations, return undefined
337+ if ( toolName === 'create_object_type' || toolName === 'create_relation_type' ||
338+ toolName === 'upsert_object' || toolName === 'add_relation' ||
339+ toolName === 'delete_object' || toolName === 'delete_relation' ||
340+ toolName === 'delete_object_type' || toolName === 'delete_relation_type' ) {
341+ return undefined as unknown as T ;
342+ }
343+ throw new Error ( `Empty response from tool: ${ toolName } ` ) ;
344+ }
329345
330346 // If result is already a string, parse it
331347 if ( typeof result [ 'result' ] === 'string' ) {
@@ -449,44 +465,92 @@ export class MCPClient {
449465 * Creates or updates an object instance.
450466 */
451467 async upsertObject ( params : UpsertObjectParams ) : Promise < ObjectInstance > {
452- return await this . callTool < ObjectInstance > ( 'upsert_object' , {
468+ const result = await this . callTool < ObjectInstance > ( 'upsert_object' , {
453469 obj : params . obj ,
454470 } ) ;
471+
472+ // If the server returns undefined (bug in MCP server), try to fetch the object by ID
473+ if ( ! result ) {
474+ if ( this . config . debug ) {
475+ console . warn ( 'upsertObject returned undefined, attempting to fetch object by ID:' , params . obj . id ) ;
476+ }
477+ const fetched = await this . getObjectById ( {
478+ object_id : params . obj . id ,
479+ type_name : params . obj . object_type_name
480+ } ) ;
481+ if ( fetched ) {
482+ return fetched ;
483+ }
484+ throw new Error ( `Failed to upsert and retrieve object ${ params . obj . id } ` ) ;
485+ }
486+
487+ return result ;
455488 }
456489
457490 /**
458491 * Retrieves an object instance by ID and type.
459492 */
460- async getObjectById ( params : GetObjectByIdParams ) : Promise < ObjectInstance | null > {
461- const rawResult = await this . callTool < any > ( 'get_object_by_id' , {
462- object_id : params . object_id ,
463- type_name : params . type_name ,
464- } ) ;
465-
466- // Debug: Log the raw result structure
467- if ( this . config . debug ) {
468- console . log ( 'getObjectById raw result:' , JSON . stringify ( rawResult , null , 2 ) ) ;
469- }
470-
471- let result : ObjectInstance | null ;
493+ async getObjectById ( params : GetObjectByIdParams ) : Promise < ObjectInstance | null > {
494+ const rawResult = await this . callTool < any > ( 'get_object_by_id' , {
495+ object_id : params . object_id ,
496+ type_name : params . type_name ,
497+ } ) ;
498+
499+ // Debug: Log the raw result structure
500+ if ( this . config . debug ) {
501+ console . log ( 'getObjectById raw result:' , JSON . stringify ( rawResult , null , 2 ) ) ;
502+ }
503+
504+ let result : ObjectInstance | null ;
505+
506+ // Handle MCP protocol response format
507+ if ( Array . isArray ( rawResult ) && rawResult . length > 0 && rawResult [ 0 ] . type === 'text' ) {
508+ // MCP protocol format: [{"type":"text","text":"{json_string}" }]
509+ try {
510+ const parsedData = JSON . parse ( rawResult [ 0 ] . text ) ;
511+ result = parsedData ;
512+ } catch ( parseError ) {
513+ throw new Error ( `Failed to parse MCP text response: ${ rawResult [ 0 ] . text } ` ) ;
514+ }
515+ } else if ( rawResult && typeof rawResult === 'object' ) {
516+ // Direct format: {object_instance} or null
517+ result = rawResult as ObjectInstance | null ;
518+ } else {
519+ throw new Error ( `Invalid object by ID response format: ${ JSON . stringify ( rawResult ) } ` ) ;
520+ }
521+
522+ // Deserialize datetime properties
523+ if ( result && result . properties ) {
524+ result . properties = this . deserializeProperties ( result . properties ) ;
525+ }
526+
527+ return result ;
528+ }
472529
473- // Handle MCP protocol response format
474- if ( Array . isArray ( rawResult ) && rawResult . length > 0 && rawResult [ 0 ] . type === 'text' ) {
475- // MCP protocol format: [{"type":"text","text":"{json_string}" }]
476- try {
477- const parsedData = JSON . parse ( rawResult [ 0 ] . text ) ;
478- result = parsedData ;
479- } catch ( parseError ) {
480- throw new Error ( `Failed to parse MCP text response: ${ rawResult [ 0 ] . text } ` ) ;
530+ /**
531+ * Deserializes properties, converting datetime strings to Date objects.
532+ */
533+ private deserializeProperties ( properties : Record < string , any > ) : Record < string , any > {
534+ const deserialized = { ...properties } ;
535+
536+ for ( const [ key , value ] of Object . entries ( deserialized ) ) {
537+ if ( typeof value === 'string' ) {
538+ // Check if it's an ISO 8601 datetime string
539+ const isoRegex = / ^ \d { 4 } - \d { 2 } - \d { 2 } T \d { 2 } : \d { 2 } : \d { 2 } ( \. \d { 3 } ) ? Z ? $ / ;
540+ if ( isoRegex . test ( value ) ) {
541+ try {
542+ deserialized [ key ] = new Date ( value ) ;
543+ } catch ( dateError ) {
544+ // If parsing fails, keep the original string
545+ if ( this . config . debug ) {
546+ console . warn ( `Failed to parse datetime string '${ value } ' for property '${ key } ':` , dateError ) ;
547+ }
548+ }
549+ }
481550 }
482- } else if ( rawResult && typeof rawResult === 'object' ) {
483- // Direct format: {object_instance} or null
484- result = rawResult as ObjectInstance | null ;
485- } else {
486- throw new Error ( `Invalid object by ID response format: ${ JSON . stringify ( rawResult ) } ` ) ;
487551 }
488552
489- return result ;
553+ return deserialized ;
490554 }
491555
492556 /**
0 commit comments