@@ -778,6 +778,55 @@ export class McpContext implements Context {
778778
779779 const rootNodeWithId = assignIds ( rootNode ) ;
780780
781+ await this . #insertExtraNodes(
782+ page ,
783+ idToNode ,
784+ seenUniqueIds ,
785+ snapshotId ,
786+ idCounter ,
787+ rootNodeWithId ,
788+ extraHandles ,
789+ ) ;
790+
791+ const snapshot : TextSnapshot = {
792+ root : rootNodeWithId ,
793+ snapshotId : String ( snapshotId ) ,
794+ idToNode,
795+ hasSelectedElement : false ,
796+ verbose,
797+ } ;
798+ page . setSnapshot ( snapshot ) ;
799+ const data = devtoolsData ?? ( await this . getDevToolsData ( page ) ) ;
800+ if ( data ?. cdpBackendNodeId ) {
801+ snapshot . hasSelectedElement = true ;
802+ snapshot . selectedElementUid = this . resolveCdpElementId (
803+ page ,
804+ data ?. cdpBackendNodeId ,
805+ ) ;
806+ }
807+
808+ // Clean up unique IDs that we did not see anymore.
809+ for ( const key of uniqueBackendNodeIdToMcpId . keys ( ) ) {
810+ if ( ! seenUniqueIds . has ( key ) ) {
811+ uniqueBackendNodeIdToMcpId . delete ( key ) ;
812+ }
813+ }
814+ }
815+
816+ // ExtraHandles represent DOM nodes which are not part of the accessibility tree, e.g. DOM nodes
817+ // returned by in-page tools. We insert them into the tree by finding the closest ancestor in the
818+ // tree and inserting the node as a child. The ancestor's child nodes are re-parented if necessary.
819+ async #insertExtraNodes(
820+ page : ContextPage ,
821+ idToNode : Map < string , TextSnapshotNode > ,
822+ seenUniqueIds : Set < string > ,
823+ snapshotId : number ,
824+ idCounter : number ,
825+ rootNodeWithId : TextSnapshotNode ,
826+ extraHandles ?: ElementHandle [ ] ,
827+ ) : Promise < void > {
828+ const { uniqueBackendNodeIdToMcpId} = page ;
829+
781830 const createExtraNode = async (
782831 handle : ElementHandle ,
783832 ) : Promise < TextSnapshotNode | null > => {
@@ -791,8 +840,9 @@ export class McpContext implements Context {
791840 }
792841
793842 let id = '' ;
794- if ( uniqueBackendNodeIdToMcpId . has ( uniqueBackendId ) ) {
795- id = uniqueBackendNodeIdToMcpId . get ( uniqueBackendId ) ! ;
843+ const mcpId = uniqueBackendNodeIdToMcpId . get ( uniqueBackendId ) ;
844+ if ( mcpId !== undefined ) {
845+ id = mcpId ;
796846 } else {
797847 id = `${ snapshotId } _${ idCounter ++ } ` ;
798848 uniqueBackendNodeIdToMcpId . set ( uniqueBackendId , id ) ;
@@ -917,32 +967,10 @@ export class McpContext implements Context {
917967 }
918968 idToNode . set ( extraNode . id , extraNode ) ;
919969 const attachTarget = ( await findAncestorNode ( handle ) ) || rootNodeWithId ;
920- const descendantIds = await findDescendantNodes ( extraNode . backendNodeId ! ) ;
921- const index = moveChildNodes ( attachTarget , extraNode , descendantIds ) ;
922- attachTarget . children . splice ( index , 0 , extraNode ) ;
923- }
924-
925- const snapshot : TextSnapshot = {
926- root : rootNodeWithId ,
927- snapshotId : String ( snapshotId ) ,
928- idToNode,
929- hasSelectedElement : false ,
930- verbose,
931- } ;
932- page . setSnapshot ( snapshot ) ;
933- const data = devtoolsData ?? ( await this . getDevToolsData ( page ) ) ;
934- if ( data ?. cdpBackendNodeId ) {
935- snapshot . hasSelectedElement = true ;
936- snapshot . selectedElementUid = this . resolveCdpElementId (
937- page ,
938- data ?. cdpBackendNodeId ,
939- ) ;
940- }
941-
942- // Clean up unique IDs that we did not see anymore.
943- for ( const key of uniqueBackendNodeIdToMcpId . keys ( ) ) {
944- if ( ! seenUniqueIds . has ( key ) ) {
945- uniqueBackendNodeIdToMcpId . delete ( key ) ;
970+ if ( extraNode . backendNodeId !== undefined ) {
971+ const descendantIds = await findDescendantNodes ( extraNode . backendNodeId ) ;
972+ const index = moveChildNodes ( attachTarget , extraNode , descendantIds ) ;
973+ attachTarget . children . splice ( index , 0 , extraNode ) ;
946974 }
947975 }
948976 }
0 commit comments