@@ -743,10 +743,13 @@ export class McpContext implements Context {
743743 let idCounter = 0 ;
744744 const idToNode = new Map < string , TextSnapshotNode > ( ) ;
745745 const seenUniqueIds = new Set < string > ( ) ;
746+ const seenBackendNodeIds = new Set < number > ( ) ;
746747 const assignIds = ( node : SerializedAXNode ) : TextSnapshotNode => {
747748 let id = '' ;
748- // @ts -expect-error untyped loaderId & backendNodeId.
749- const uniqueBackendId = `${ node . loaderId } _${ node . backendNodeId } ` ;
749+ // @ts -expect-error untyped backendNodeId.
750+ const backendNodeId : number = node . backendNodeId ;
751+ // @ts -expect-error untyped loaderId.
752+ const uniqueBackendId = `${ node . loaderId } _${ backendNodeId } ` ;
750753 if ( uniqueBackendNodeIdToMcpId . has ( uniqueBackendId ) ) {
751754 // Re-use MCP exposed ID if the uniqueId is the same.
752755 id = uniqueBackendNodeIdToMcpId . get ( uniqueBackendId ) ! ;
@@ -756,6 +759,7 @@ export class McpContext implements Context {
756759 uniqueBackendNodeIdToMcpId . set ( uniqueBackendId , id ) ;
757760 }
758761 seenUniqueIds . add ( uniqueBackendId ) ;
762+ seenBackendNodeIds . add ( backendNodeId ) ;
759763
760764 const nodeWithId : TextSnapshotNode = {
761765 ...node ,
@@ -780,15 +784,18 @@ export class McpContext implements Context {
780784
781785 const rootNodeWithId = assignIds ( rootNode ) ;
782786
783- await this . #insertExtraNodes(
784- page ,
785- idToNode ,
786- seenUniqueIds ,
787- snapshotId ,
788- idCounter ,
789- rootNodeWithId ,
790- extraHandles ,
791- ) ;
787+ if ( extraHandles ) {
788+ await this . #insertExtraNodes(
789+ page ,
790+ idToNode ,
791+ seenUniqueIds ,
792+ snapshotId ,
793+ idCounter ,
794+ rootNodeWithId ,
795+ seenBackendNodeIds ,
796+ extraHandles ,
797+ ) ;
798+ }
792799
793800 const snapshot : TextSnapshot = {
794801 root : rootNodeWithId ,
@@ -815,7 +822,7 @@ export class McpContext implements Context {
815822 }
816823 }
817824
818- // ExtraHandles represent DOM nodes which are not part of the accessibility tree, e.g. DOM nodes
825+ // ExtraHandles represent DOM nodes which might not be part of the accessibility tree, e.g. DOM nodes
819826 // returned by in-page tools. We insert them into the tree by finding the closest ancestor in the
820827 // tree and inserting the node as a child. The ancestor's child nodes are re-parented if necessary.
821828 async #insertExtraNodes(
@@ -825,21 +832,23 @@ export class McpContext implements Context {
825832 snapshotId : number ,
826833 idCounter : number ,
827834 rootNodeWithId : TextSnapshotNode ,
828- extraHandles ?: ElementHandle [ ] ,
835+ seenBackendNodeIds : Set < number > ,
836+ extraHandles : ElementHandle [ ] ,
829837 ) : Promise < void > {
830838 const { uniqueBackendNodeIdToMcpId} = page ;
831839
832840 const createExtraNode = async (
833841 handle : ElementHandle ,
834842 ) : Promise < TextSnapshotNode | null > => {
835843 const backendNodeId = await handle . backendNodeId ( ) ;
836- if ( ! backendNodeId ) {
844+ if ( ! backendNodeId || seenBackendNodeIds . has ( backendNodeId ) ) {
837845 return null ;
838846 }
839847 const uniqueBackendId = `custom_${ backendNodeId } ` ;
840848 if ( seenUniqueIds . has ( uniqueBackendId ) ) {
841849 return null ;
842850 }
851+ seenBackendNodeIds . add ( backendNodeId ) ;
843852
844853 let id = '' ;
845854 const mcpId = uniqueBackendNodeIdToMcpId . get ( uniqueBackendId ) ;
0 commit comments