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