@vibebrowser/chrome-devtools-mcp 0.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (294) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +873 -0
  3. package/build/src/DevToolsConnectionAdapter.js +70 -0
  4. package/build/src/DevtoolsUtils.js +295 -0
  5. package/build/src/HeapSnapshotManager.js +110 -0
  6. package/build/src/McpContext.js +605 -0
  7. package/build/src/McpPage.js +315 -0
  8. package/build/src/McpResponse.js +858 -0
  9. package/build/src/Mutex.js +38 -0
  10. package/build/src/PageCollector.js +297 -0
  11. package/build/src/SlimMcpResponse.js +19 -0
  12. package/build/src/TextSnapshot.js +236 -0
  13. package/build/src/ToolHandler.js +217 -0
  14. package/build/src/WaitForHelper.js +190 -0
  15. package/build/src/bin/check-latest-version.js +50 -0
  16. package/build/src/bin/chrome-devtools-cli-options.js +840 -0
  17. package/build/src/bin/chrome-devtools-mcp-cli-options.js +350 -0
  18. package/build/src/bin/chrome-devtools-mcp-main.js +94 -0
  19. package/build/src/bin/chrome-devtools-mcp.js +31 -0
  20. package/build/src/bin/chrome-devtools.js +189 -0
  21. package/build/src/bin/install-service.js +246 -0
  22. package/build/src/bin/service/chrome-devtools-mcp.service.template +17 -0
  23. package/build/src/bin/service/com.vibebrowser.chrome-devtools-mcp.plist.template +37 -0
  24. package/build/src/browser.js +204 -0
  25. package/build/src/daemon/client.js +154 -0
  26. package/build/src/daemon/daemon.js +204 -0
  27. package/build/src/daemon/types.js +7 -0
  28. package/build/src/daemon/utils.js +115 -0
  29. package/build/src/formatters/ConsoleFormatter.js +288 -0
  30. package/build/src/formatters/HeapSnapshotFormatter.js +54 -0
  31. package/build/src/formatters/IssueFormatter.js +193 -0
  32. package/build/src/formatters/NetworkFormatter.js +236 -0
  33. package/build/src/formatters/SnapshotFormatter.js +135 -0
  34. package/build/src/index.js +140 -0
  35. package/build/src/issue-descriptions.js +40 -0
  36. package/build/src/logger.js +37 -0
  37. package/build/src/polyfill.js +8 -0
  38. package/build/src/telemetry/ClearcutLogger.js +169 -0
  39. package/build/src/telemetry/WatchdogClient.js +61 -0
  40. package/build/src/telemetry/errors.js +18 -0
  41. package/build/src/telemetry/flagUtils.js +89 -0
  42. package/build/src/telemetry/metricsRegistry.js +89 -0
  43. package/build/src/telemetry/persistence.js +72 -0
  44. package/build/src/telemetry/transformation.js +134 -0
  45. package/build/src/telemetry/types.js +31 -0
  46. package/build/src/telemetry/watchdog/ClearcutSender.js +205 -0
  47. package/build/src/telemetry/watchdog/main.js +128 -0
  48. package/build/src/third_party/devtools-formatter-worker.js +8 -0
  49. package/build/src/third_party/devtools-heap-snapshot-worker.js +8 -0
  50. package/build/src/third_party/index.js +32 -0
  51. package/build/src/third_party/issue-descriptions/CoepCoopSandboxedIframeCannotNavigateToCoopPage.md +4 -0
  52. package/build/src/third_party/issue-descriptions/CoepCorpNotSameOrigin.md +8 -0
  53. package/build/src/third_party/issue-descriptions/CoepCorpNotSameOriginAfterDefaultedToSameOriginByCoep.md +18 -0
  54. package/build/src/third_party/issue-descriptions/CoepCorpNotSameSite.md +7 -0
  55. package/build/src/third_party/issue-descriptions/CoepFrameResourceNeedsCoepHeader.md +10 -0
  56. package/build/src/third_party/issue-descriptions/CompatibilityModeQuirks.md +5 -0
  57. package/build/src/third_party/issue-descriptions/CookieAttributeValueExceedsMaxSize.md +5 -0
  58. package/build/src/third_party/issue-descriptions/LowTextContrast.md +5 -0
  59. package/build/src/third_party/issue-descriptions/SameSiteExcludeContextDowngradeRead.md +8 -0
  60. package/build/src/third_party/issue-descriptions/SameSiteExcludeContextDowngradeSet.md +8 -0
  61. package/build/src/third_party/issue-descriptions/SameSiteExcludeNavigationContextDowngrade.md +8 -0
  62. package/build/src/third_party/issue-descriptions/SameSiteNoneInsecureErrorRead.md +8 -0
  63. package/build/src/third_party/issue-descriptions/SameSiteNoneInsecureErrorSet.md +8 -0
  64. package/build/src/third_party/issue-descriptions/SameSiteNoneInsecureWarnRead.md +8 -0
  65. package/build/src/third_party/issue-descriptions/SameSiteNoneInsecureWarnSet.md +8 -0
  66. package/build/src/third_party/issue-descriptions/SameSiteUnspecifiedLaxAllowUnsafeRead.md +9 -0
  67. package/build/src/third_party/issue-descriptions/SameSiteUnspecifiedLaxAllowUnsafeSet.md +9 -0
  68. package/build/src/third_party/issue-descriptions/SameSiteWarnCrossDowngradeRead.md +8 -0
  69. package/build/src/third_party/issue-descriptions/SameSiteWarnCrossDowngradeSet.md +8 -0
  70. package/build/src/third_party/issue-descriptions/SameSiteWarnStrictLaxDowngradeStrict.md +8 -0
  71. package/build/src/third_party/issue-descriptions/arInsecureContext.md +7 -0
  72. package/build/src/third_party/issue-descriptions/arInvalidInfoHeader.md +5 -0
  73. package/build/src/third_party/issue-descriptions/arInvalidRegisterOsSourceHeader.md +5 -0
  74. package/build/src/third_party/issue-descriptions/arInvalidRegisterOsTriggerHeader.md +5 -0
  75. package/build/src/third_party/issue-descriptions/arInvalidRegisterSourceHeader.md +5 -0
  76. package/build/src/third_party/issue-descriptions/arInvalidRegisterTriggerHeader.md +5 -0
  77. package/build/src/third_party/issue-descriptions/arNavigationRegistrationUniqueScopeAlreadySet.md +5 -0
  78. package/build/src/third_party/issue-descriptions/arNavigationRegistrationWithoutTransientUserActivation.md +6 -0
  79. package/build/src/third_party/issue-descriptions/arNoRegisterOsSourceHeader.md +5 -0
  80. package/build/src/third_party/issue-descriptions/arNoRegisterOsTriggerHeader.md +5 -0
  81. package/build/src/third_party/issue-descriptions/arNoRegisterSourceHeader.md +5 -0
  82. package/build/src/third_party/issue-descriptions/arNoRegisterTriggerHeader.md +5 -0
  83. package/build/src/third_party/issue-descriptions/arNoWebOrOsSupport.md +4 -0
  84. package/build/src/third_party/issue-descriptions/arOsSourceIgnored.md +18 -0
  85. package/build/src/third_party/issue-descriptions/arOsTriggerIgnored.md +19 -0
  86. package/build/src/third_party/issue-descriptions/arPermissionPolicyDisabled.md +8 -0
  87. package/build/src/third_party/issue-descriptions/arSourceAndTriggerHeaders.md +9 -0
  88. package/build/src/third_party/issue-descriptions/arSourceIgnored.md +13 -0
  89. package/build/src/third_party/issue-descriptions/arTriggerIgnored.md +12 -0
  90. package/build/src/third_party/issue-descriptions/arUntrustworthyReportingOrigin.md +10 -0
  91. package/build/src/third_party/issue-descriptions/arWebAndOsHeaders.md +11 -0
  92. package/build/src/third_party/issue-descriptions/bounceTrackingMitigations.md +3 -0
  93. package/build/src/third_party/issue-descriptions/clientHintMetaTagAllowListInvalidOrigin.md +4 -0
  94. package/build/src/third_party/issue-descriptions/clientHintMetaTagModifiedHTML.md +4 -0
  95. package/build/src/third_party/issue-descriptions/connectionAllowlistInvalidAllowlistItemType.md +12 -0
  96. package/build/src/third_party/issue-descriptions/connectionAllowlistInvalidHeader.md +12 -0
  97. package/build/src/third_party/issue-descriptions/connectionAllowlistInvalidUrlPattern.md +8 -0
  98. package/build/src/third_party/issue-descriptions/connectionAllowlistItemNotInnerList.md +12 -0
  99. package/build/src/third_party/issue-descriptions/connectionAllowlistMoreThanOneList.md +7 -0
  100. package/build/src/third_party/issue-descriptions/connectionAllowlistReportingEndpointNotToken.md +10 -0
  101. package/build/src/third_party/issue-descriptions/cookieCrossSiteRedirectDowngrade.md +12 -0
  102. package/build/src/third_party/issue-descriptions/cookieExcludeBlockedWithinRelatedWebsiteSet.md +4 -0
  103. package/build/src/third_party/issue-descriptions/cookieExcludeDomainNonAscii.md +11 -0
  104. package/build/src/third_party/issue-descriptions/cookieExcludePortMismatch.md +8 -0
  105. package/build/src/third_party/issue-descriptions/cookieExcludeSchemeMismatch.md +7 -0
  106. package/build/src/third_party/issue-descriptions/cookieExcludeThirdPartyPhaseoutRead.md +6 -0
  107. package/build/src/third_party/issue-descriptions/cookieExcludeThirdPartyPhaseoutSet.md +6 -0
  108. package/build/src/third_party/issue-descriptions/cookieWarnDomainNonAscii.md +11 -0
  109. package/build/src/third_party/issue-descriptions/cookieWarnMetadataGrantRead.md +4 -0
  110. package/build/src/third_party/issue-descriptions/cookieWarnMetadataGrantSet.md +4 -0
  111. package/build/src/third_party/issue-descriptions/cookieWarnThirdPartyPhaseoutRead.md +6 -0
  112. package/build/src/third_party/issue-descriptions/cookieWarnThirdPartyPhaseoutSet.md +6 -0
  113. package/build/src/third_party/issue-descriptions/corsAllowCredentialsRequired.md +6 -0
  114. package/build/src/third_party/issue-descriptions/corsDisabledScheme.md +7 -0
  115. package/build/src/third_party/issue-descriptions/corsDisallowedByMode.md +7 -0
  116. package/build/src/third_party/issue-descriptions/corsHeaderDisallowedByPreflightResponse.md +5 -0
  117. package/build/src/third_party/issue-descriptions/corsInvalidHeaderValues.md +7 -0
  118. package/build/src/third_party/issue-descriptions/corsLocalNetworkAccessPermissionDenied.md +19 -0
  119. package/build/src/third_party/issue-descriptions/corsMethodDisallowedByPreflightResponse.md +5 -0
  120. package/build/src/third_party/issue-descriptions/corsNoCorsRedirectModeNotFollow.md +5 -0
  121. package/build/src/third_party/issue-descriptions/corsOriginMismatch.md +6 -0
  122. package/build/src/third_party/issue-descriptions/corsPreflightResponseInvalid.md +5 -0
  123. package/build/src/third_party/issue-descriptions/corsRedirectContainsCredentials.md +5 -0
  124. package/build/src/third_party/issue-descriptions/corsWildcardOriginNotAllowed.md +8 -0
  125. package/build/src/third_party/issue-descriptions/cspEvalViolation.md +9 -0
  126. package/build/src/third_party/issue-descriptions/cspInlineViolation.md +10 -0
  127. package/build/src/third_party/issue-descriptions/cspTrustedTypesPolicyViolation.md +5 -0
  128. package/build/src/third_party/issue-descriptions/cspTrustedTypesSinkViolation.md +8 -0
  129. package/build/src/third_party/issue-descriptions/cspURLViolation.md +10 -0
  130. package/build/src/third_party/issue-descriptions/deprecation.md +3 -0
  131. package/build/src/third_party/issue-descriptions/federatedAuthRequestAccountsHttpNotFound.md +1 -0
  132. package/build/src/third_party/issue-descriptions/federatedAuthRequestAccountsInvalidResponse.md +1 -0
  133. package/build/src/third_party/issue-descriptions/federatedAuthRequestAccountsNoResponse.md +1 -0
  134. package/build/src/third_party/issue-descriptions/federatedAuthRequestApprovalDeclined.md +1 -0
  135. package/build/src/third_party/issue-descriptions/federatedAuthRequestCanceled.md +1 -0
  136. package/build/src/third_party/issue-descriptions/federatedAuthRequestErrorFetchingSignin.md +1 -0
  137. package/build/src/third_party/issue-descriptions/federatedAuthRequestErrorIdToken.md +1 -0
  138. package/build/src/third_party/issue-descriptions/federatedAuthRequestIdTokenHttpNotFound.md +1 -0
  139. package/build/src/third_party/issue-descriptions/federatedAuthRequestIdTokenInvalidRequest.md +1 -0
  140. package/build/src/third_party/issue-descriptions/federatedAuthRequestIdTokenInvalidResponse.md +1 -0
  141. package/build/src/third_party/issue-descriptions/federatedAuthRequestIdTokenNoResponse.md +1 -0
  142. package/build/src/third_party/issue-descriptions/federatedAuthRequestInvalidSigninResponse.md +1 -0
  143. package/build/src/third_party/issue-descriptions/federatedAuthRequestManifestHttpNotFound.md +1 -0
  144. package/build/src/third_party/issue-descriptions/federatedAuthRequestManifestInvalidResponse.md +1 -0
  145. package/build/src/third_party/issue-descriptions/federatedAuthRequestManifestNoResponse.md +1 -0
  146. package/build/src/third_party/issue-descriptions/federatedAuthRequestTooManyRequests.md +1 -0
  147. package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestInvalidAccountsResponse.md +1 -0
  148. package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestInvalidConfigOrWellKnown.md +1 -0
  149. package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNoAccountSharingPermission.md +1 -0
  150. package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNoApiPermission.md +1 -0
  151. package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNoReturningUserFromFetchedAccounts.md +1 -0
  152. package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNotIframe.md +1 -0
  153. package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNotPotentiallyTrustworthy.md +1 -0
  154. package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNotSameOrigin.md +1 -0
  155. package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNotSignedInWithIdp.md +1 -0
  156. package/build/src/third_party/issue-descriptions/fetchingPartitionedBlobURL.md +7 -0
  157. package/build/src/third_party/issue-descriptions/genericFormAriaLabelledByToNonExistingIdError.md +8 -0
  158. package/build/src/third_party/issue-descriptions/genericFormAutocompleteAttributeEmptyError.md +5 -0
  159. package/build/src/third_party/issue-descriptions/genericFormDuplicateIdForInputError.md +5 -0
  160. package/build/src/third_party/issue-descriptions/genericFormEmptyIdAndNameAttributesForInputError.md +5 -0
  161. package/build/src/third_party/issue-descriptions/genericFormInputAssignedAutocompleteValueToIdOrNameAttributeError.md +5 -0
  162. package/build/src/third_party/issue-descriptions/genericFormInputHasWrongButWellIntendedAutocompleteValueError.md +5 -0
  163. package/build/src/third_party/issue-descriptions/genericFormInputWithNoLabelError.md +5 -0
  164. package/build/src/third_party/issue-descriptions/genericFormLabelForMatchesNonExistingIdError.md +5 -0
  165. package/build/src/third_party/issue-descriptions/genericFormLabelForNameError.md +5 -0
  166. package/build/src/third_party/issue-descriptions/genericFormLabelHasNeitherForNorNestedInputError.md +5 -0
  167. package/build/src/third_party/issue-descriptions/genericFormModelContextMissingToolDescription.md +5 -0
  168. package/build/src/third_party/issue-descriptions/genericFormModelContextMissingToolName.md +5 -0
  169. package/build/src/third_party/issue-descriptions/genericFormModelContextParameterMissingName.md +5 -0
  170. package/build/src/third_party/issue-descriptions/genericFormModelContextParameterMissingTitleAndDescription.md +5 -0
  171. package/build/src/third_party/issue-descriptions/genericFormModelContextRequiredParameterMissingName.md +5 -0
  172. package/build/src/third_party/issue-descriptions/genericNavigationEntryMarkedSkippable.md +7 -0
  173. package/build/src/third_party/issue-descriptions/genericResponseWasBlockedByORB.md +4 -0
  174. package/build/src/third_party/issue-descriptions/heavyAd.md +10 -0
  175. package/build/src/third_party/issue-descriptions/mixedContent.md +5 -0
  176. package/build/src/third_party/issue-descriptions/navigatingPartitionedBlobURL.md +5 -0
  177. package/build/src/third_party/issue-descriptions/permissionElementActivationDisabled.md +7 -0
  178. package/build/src/third_party/issue-descriptions/permissionElementActivationDisabledWithOccluder.md +9 -0
  179. package/build/src/third_party/issue-descriptions/permissionElementActivationDisabledWithOccluderParent.md +9 -0
  180. package/build/src/third_party/issue-descriptions/permissionElementCspFrameAncestorsMissing.md +5 -0
  181. package/build/src/third_party/issue-descriptions/permissionElementFencedFrameDisallowed.md +5 -0
  182. package/build/src/third_party/issue-descriptions/permissionElementFontSizeTooLarge.md +5 -0
  183. package/build/src/third_party/issue-descriptions/permissionElementFontSizeTooSmall.md +5 -0
  184. package/build/src/third_party/issue-descriptions/permissionElementGeolocationDeprecated.md +5 -0
  185. package/build/src/third_party/issue-descriptions/permissionElementInsetBoxShadowUnsupported.md +5 -0
  186. package/build/src/third_party/issue-descriptions/permissionElementInvalidDisplayStyle.md +5 -0
  187. package/build/src/third_party/issue-descriptions/permissionElementInvalidSizeValue.md +5 -0
  188. package/build/src/third_party/issue-descriptions/permissionElementInvalidType.md +5 -0
  189. package/build/src/third_party/issue-descriptions/permissionElementInvalidTypeActivation.md +5 -0
  190. package/build/src/third_party/issue-descriptions/permissionElementLowContrast.md +5 -0
  191. package/build/src/third_party/issue-descriptions/permissionElementNonOpaqueColor.md +5 -0
  192. package/build/src/third_party/issue-descriptions/permissionElementPaddingBottomUnsupported.md +6 -0
  193. package/build/src/third_party/issue-descriptions/permissionElementPaddingRightUnsupported.md +6 -0
  194. package/build/src/third_party/issue-descriptions/permissionElementPermissionsPolicyBlocked.md +5 -0
  195. package/build/src/third_party/issue-descriptions/permissionElementRegistrationFailed.md +5 -0
  196. package/build/src/third_party/issue-descriptions/permissionElementRequestInProgress.md +5 -0
  197. package/build/src/third_party/issue-descriptions/permissionElementSecurityChecksFailed.md +5 -0
  198. package/build/src/third_party/issue-descriptions/permissionElementTypeNotSupported.md +5 -0
  199. package/build/src/third_party/issue-descriptions/permissionElementUntrustedEvent.md +7 -0
  200. package/build/src/third_party/issue-descriptions/placeholderDescriptionForInvisibleIssues.md +3 -0
  201. package/build/src/third_party/issue-descriptions/propertyRuleInvalidNameIssue.md +3 -0
  202. package/build/src/third_party/issue-descriptions/propertyRuleIssue.md +7 -0
  203. package/build/src/third_party/issue-descriptions/selectElementAccessibilityDisallowedOptGroupChild.md +7 -0
  204. package/build/src/third_party/issue-descriptions/selectElementAccessibilityDisallowedSelectChild.md +7 -0
  205. package/build/src/third_party/issue-descriptions/selectElementAccessibilityInteractiveContentAttributesSelectDescendant.md +3 -0
  206. package/build/src/third_party/issue-descriptions/selectElementAccessibilityInteractiveContentLegendChild.md +3 -0
  207. package/build/src/third_party/issue-descriptions/selectElementAccessibilityInteractiveContentOptionChild.md +3 -0
  208. package/build/src/third_party/issue-descriptions/selectElementAccessibilityNonPhrasingContentOptionChild.md +3 -0
  209. package/build/src/third_party/issue-descriptions/selectivePermissionsIntervention.md +7 -0
  210. package/build/src/third_party/issue-descriptions/sharedArrayBuffer.md +7 -0
  211. package/build/src/third_party/issue-descriptions/sharedDictionaryUseErrorCrossOriginNoCorsRequest.md +1 -0
  212. package/build/src/third_party/issue-descriptions/sharedDictionaryUseErrorDictionaryLoadFailure.md +3 -0
  213. package/build/src/third_party/issue-descriptions/sharedDictionaryUseErrorMatchingDictionaryNotUsed.md +3 -0
  214. package/build/src/third_party/issue-descriptions/sharedDictionaryUseErrorUnexpectedContentDictionaryHeader.md +1 -0
  215. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorCossOriginNoCorsRequest.md +1 -0
  216. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorDisallowedBySettings.md +1 -0
  217. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorExpiredResponse.md +3 -0
  218. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorFeatureDisabled.md +3 -0
  219. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorInsufficientResources.md +1 -0
  220. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorInvalidMatchField.md +1 -0
  221. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorInvalidStructuredHeader.md +1 -0
  222. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorInvalidTTLField.md +1 -0
  223. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNavigationRequest.md +3 -0
  224. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNoMatchField.md +1 -0
  225. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNonIntegerTTLField.md +1 -0
  226. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNonListMatchDestField.md +1 -0
  227. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNonSecureContext.md +3 -0
  228. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNonStringIdField.md +1 -0
  229. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNonStringInMatchDestList.md +1 -0
  230. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNonStringMatchField.md +1 -0
  231. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNonTokenTypeField.md +1 -0
  232. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorRequestAborted.md +1 -0
  233. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorShuttingDown.md +1 -0
  234. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorTooLongIdField.md +3 -0
  235. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorUnsupportedType.md +3 -0
  236. package/build/src/third_party/issue-descriptions/sriInvalidSignatureHeader.md +14 -0
  237. package/build/src/third_party/issue-descriptions/sriInvalidSignatureInputHeader.md +15 -0
  238. package/build/src/third_party/issue-descriptions/sriMissingSignatureHeader.md +8 -0
  239. package/build/src/third_party/issue-descriptions/sriMissingSignatureInputHeader.md +7 -0
  240. package/build/src/third_party/issue-descriptions/sriSignatureHeaderValueIsIncorrectLength.md +11 -0
  241. package/build/src/third_party/issue-descriptions/sriSignatureHeaderValueIsNotByteSequence.md +14 -0
  242. package/build/src/third_party/issue-descriptions/sriSignatureHeaderValueIsParameterized.md +15 -0
  243. package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderInvalidComponentName.md +8 -0
  244. package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderInvalidComponentType.md +13 -0
  245. package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderInvalidDerivedComponentParameter.md +4 -0
  246. package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderInvalidHeaderComponentParameter.md +5 -0
  247. package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderInvalidParameter.md +11 -0
  248. package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderKeyIdLength.md +12 -0
  249. package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderMissingLabel.md +6 -0
  250. package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderMissingRequiredParameters.md +8 -0
  251. package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderValueMissingComponents.md +11 -0
  252. package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderValueNotInnerList.md +11 -0
  253. package/build/src/third_party/issue-descriptions/sriValidationFailedIntegrityMismatch.md +10 -0
  254. package/build/src/third_party/issue-descriptions/sriValidationFailedInvalidLength.md +5 -0
  255. package/build/src/third_party/issue-descriptions/sriValidationFailedSignatureExpired.md +6 -0
  256. package/build/src/third_party/issue-descriptions/sriValidationFailedSignatureMismatch.md +11 -0
  257. package/build/src/third_party/issue-descriptions/stylesheetLateImport.md +4 -0
  258. package/build/src/third_party/issue-descriptions/stylesheetRequestFailed.md +3 -0
  259. package/build/src/third_party/issue-descriptions/summaryElementAccessibilityInteractiveContentSummaryDescendant.md +3 -0
  260. package/build/src/third_party/issue-descriptions/unencodedDigestIncorrectDigestLength.md +12 -0
  261. package/build/src/third_party/issue-descriptions/unencodedDigestIncorrectDigestType.md +17 -0
  262. package/build/src/third_party/issue-descriptions/unencodedDigestMalformedDictionary.md +14 -0
  263. package/build/src/third_party/issue-descriptions/unencodedDigestUnknownAlgorithm.md +15 -0
  264. package/build/src/third_party/lighthouse-devtools-mcp-bundle.js +61598 -0
  265. package/build/src/tools/ToolDefinition.js +73 -0
  266. package/build/src/tools/categories.js +36 -0
  267. package/build/src/tools/console.js +91 -0
  268. package/build/src/tools/emulation.js +57 -0
  269. package/build/src/tools/extensions.js +96 -0
  270. package/build/src/tools/input.js +461 -0
  271. package/build/src/tools/lighthouse.js +131 -0
  272. package/build/src/tools/memory.js +106 -0
  273. package/build/src/tools/network.js +125 -0
  274. package/build/src/tools/pages.js +411 -0
  275. package/build/src/tools/performance.js +196 -0
  276. package/build/src/tools/screencast.js +95 -0
  277. package/build/src/tools/screenshot.js +87 -0
  278. package/build/src/tools/script.js +151 -0
  279. package/build/src/tools/slim/tools.js +85 -0
  280. package/build/src/tools/snapshot.js +60 -0
  281. package/build/src/tools/thirdPartyDeveloper.js +75 -0
  282. package/build/src/tools/tools.js +56 -0
  283. package/build/src/tools/webmcp.js +64 -0
  284. package/build/src/trace-processing/parse.js +85 -0
  285. package/build/src/types.js +7 -0
  286. package/build/src/utils/check-for-updates.js +74 -0
  287. package/build/src/utils/files.js +18 -0
  288. package/build/src/utils/id.js +16 -0
  289. package/build/src/utils/keyboard.js +297 -0
  290. package/build/src/utils/pagination.js +50 -0
  291. package/build/src/utils/string.js +37 -0
  292. package/build/src/utils/types.js +7 -0
  293. package/build/src/version.js +10 -0
  294. package/package.json +93 -0
@@ -0,0 +1,193 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { ISSUE_UTILS } from '../issue-descriptions.js';
7
+ import { logger } from '../logger.js';
8
+ import { DevTools } from '../third_party/index.js';
9
+ export class IssueFormatter {
10
+ #issue;
11
+ #options;
12
+ constructor(issue, options) {
13
+ this.#issue = issue;
14
+ this.#options = options;
15
+ }
16
+ toString() {
17
+ return convertIssueConciseToString(this.toJSON());
18
+ }
19
+ toStringDetailed() {
20
+ return convertIssueDetailedToString(this.toJSONDetailed());
21
+ }
22
+ toJSON() {
23
+ return {
24
+ type: 'issue',
25
+ title: this.#getTitle(),
26
+ count: this.#issue.getAggregatedIssuesCount(),
27
+ id: this.#options.id,
28
+ };
29
+ }
30
+ toJSONDetailed() {
31
+ return {
32
+ id: this.#options.id,
33
+ type: 'issue',
34
+ count: this.#issue.getAggregatedIssuesCount(),
35
+ title: this.#getTitle(),
36
+ description: this.#getDescription(),
37
+ links: this.#issue.getDescription()?.links,
38
+ affectedResources: this.#getAffectedResources(),
39
+ };
40
+ }
41
+ #getAffectedResources() {
42
+ const issues = this.#issue.getAllIssues();
43
+ const affectedResources = [];
44
+ for (const singleIssue of issues) {
45
+ const details = singleIssue.details();
46
+ if (!details) {
47
+ continue;
48
+ }
49
+ // We send the remaining details as untyped JSON because the DevTools
50
+ // frontend code is currently not re-usable.
51
+ const data = structuredClone(details);
52
+ let uid;
53
+ let request;
54
+ if ('violatingNodeId' in details &&
55
+ details.violatingNodeId &&
56
+ this.#options.elementIdResolver) {
57
+ uid = this.#options.elementIdResolver(details.violatingNodeId);
58
+ delete data.violatingNodeId;
59
+ }
60
+ if ('nodeId' in details &&
61
+ details.nodeId &&
62
+ this.#options.elementIdResolver) {
63
+ uid = this.#options.elementIdResolver(details.nodeId);
64
+ delete data.nodeId;
65
+ }
66
+ if ('documentNodeId' in details &&
67
+ details.documentNodeId &&
68
+ this.#options.elementIdResolver) {
69
+ uid = this.#options.elementIdResolver(details.documentNodeId);
70
+ delete data.documentNodeId;
71
+ }
72
+ if ('request' in details && details.request) {
73
+ request = details.request.url;
74
+ if (details.request.requestId && this.#options.requestIdResolver) {
75
+ const resolvedId = this.#options.requestIdResolver(details.request.requestId);
76
+ if (resolvedId) {
77
+ request = resolvedId;
78
+ const requestData = data.request;
79
+ delete requestData.requestId;
80
+ }
81
+ }
82
+ }
83
+ // These fields has no use for the MCP client (redundant or irrelevant).
84
+ delete data.errorType;
85
+ delete data.frameId;
86
+ affectedResources.push({
87
+ uid,
88
+ data: data,
89
+ request,
90
+ });
91
+ }
92
+ return affectedResources;
93
+ }
94
+ isValid() {
95
+ return this.#getTitle() !== undefined;
96
+ }
97
+ // Helper to extract title
98
+ #getTitle() {
99
+ const markdownDescription = this.#issue.getDescription();
100
+ const filename = markdownDescription?.file;
101
+ if (!filename) {
102
+ logger(`no description found for issue:` + this.#issue.code());
103
+ return undefined;
104
+ }
105
+ // We already have the description logic in #getDescription, but title extraction is separate
106
+ // We can reuse the logic or cache it.
107
+ // Ideally we should process markdown once.
108
+ const rawMarkdown = ISSUE_UTILS.getIssueDescription(filename);
109
+ if (!rawMarkdown) {
110
+ logger(`no markdown ${filename} found for issue:` + this.#issue.code());
111
+ return undefined;
112
+ }
113
+ try {
114
+ const processedMarkdown = DevTools.MarkdownIssueDescription.substitutePlaceholders(rawMarkdown, markdownDescription?.substitutions);
115
+ const markdownAst = DevTools.Marked.Marked.lexer(processedMarkdown);
116
+ const title = DevTools.MarkdownIssueDescription.findTitleFromMarkdownAst(markdownAst);
117
+ if (!title) {
118
+ logger('cannot read issue title from ' + filename);
119
+ return undefined;
120
+ }
121
+ return title;
122
+ }
123
+ catch {
124
+ logger('error parsing markdown for issue ' + this.#issue.code());
125
+ return undefined;
126
+ }
127
+ }
128
+ #getDescription() {
129
+ const markdownDescription = this.#issue.getDescription();
130
+ const filename = markdownDescription?.file;
131
+ if (!filename) {
132
+ return undefined;
133
+ }
134
+ const rawMarkdown = ISSUE_UTILS.getIssueDescription(filename);
135
+ if (!rawMarkdown) {
136
+ return undefined;
137
+ }
138
+ try {
139
+ return DevTools.MarkdownIssueDescription.substitutePlaceholders(rawMarkdown, markdownDescription?.substitutions);
140
+ }
141
+ catch {
142
+ return undefined;
143
+ }
144
+ }
145
+ }
146
+ function convertIssueConciseToString(issue) {
147
+ return `msgid=${issue.id} [issue] ${issue.title} (count: ${issue.count})`;
148
+ }
149
+ function convertIssueDetailedToString(issue) {
150
+ const result = [];
151
+ result.push(`ID: ${issue.id}`);
152
+ const bodyParts = [];
153
+ const description = issue.description;
154
+ let processedMarkdown = description?.trim();
155
+ // Remove heading in order not to conflict with the whole console message response markdown
156
+ if (processedMarkdown?.startsWith('# ')) {
157
+ processedMarkdown = processedMarkdown.substring(2).trimStart();
158
+ }
159
+ if (processedMarkdown) {
160
+ bodyParts.push(processedMarkdown);
161
+ }
162
+ else {
163
+ bodyParts.push(issue.title ?? 'Unknown Issue');
164
+ }
165
+ const links = issue.links;
166
+ if (links && links.length > 0) {
167
+ bodyParts.push('Learn more:');
168
+ for (const link of links) {
169
+ bodyParts.push(`[${link.linkTitle}](${link.link})`);
170
+ }
171
+ }
172
+ const affectedResources = issue.affectedResources;
173
+ if (affectedResources.length) {
174
+ bodyParts.push('### Affected resources');
175
+ bodyParts.push(...affectedResources.map(item => {
176
+ const details = [];
177
+ if (item.uid) {
178
+ details.push(`uid=${item.uid}`);
179
+ }
180
+ if (item.request) {
181
+ details.push((typeof item.request === 'number' ? `reqid=` : 'url=') +
182
+ item.request);
183
+ }
184
+ if (item.data) {
185
+ details.push(`data=${JSON.stringify(item.data)}`);
186
+ }
187
+ return details.join(' ');
188
+ }));
189
+ }
190
+ result.push(`Message: issue> ${bodyParts.join('\n')}`);
191
+ return result.join('\n');
192
+ }
193
+ //# sourceMappingURL=IssueFormatter.js.map
@@ -0,0 +1,236 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ * */
6
+ import { isUtf8 } from 'node:buffer';
7
+ import { DevTools, } from '../third_party/index.js';
8
+ const BODY_CONTEXT_SIZE_LIMIT = 10000;
9
+ export class NetworkFormatter {
10
+ #request;
11
+ #options;
12
+ #requestBody;
13
+ #responseBody;
14
+ #requestBodyFilePath;
15
+ #responseBodyFilePath;
16
+ constructor(request, options) {
17
+ this.#request = request;
18
+ this.#options = options;
19
+ }
20
+ static async from(request, options) {
21
+ const instance = new NetworkFormatter(request, options);
22
+ if (options.fetchData) {
23
+ await instance.#loadDetailedData();
24
+ }
25
+ return instance;
26
+ }
27
+ async #loadDetailedData() {
28
+ // Load Request Body
29
+ if (this.#request.hasPostData()) {
30
+ let data;
31
+ try {
32
+ data =
33
+ this.#request.postData() ?? (await this.#request.fetchPostData());
34
+ }
35
+ catch {
36
+ // Ignore parsing errors
37
+ }
38
+ const requestBodyNotAvailableMessage = '<Request body not available anymore>';
39
+ if (this.#options.requestFilePath) {
40
+ if (!this.#options.saveFile) {
41
+ throw new Error('saveFile is not provided');
42
+ }
43
+ if (data) {
44
+ const result = await this.#options.saveFile(Buffer.from(data), this.#options.requestFilePath, '.network-request');
45
+ this.#requestBodyFilePath = result.filename;
46
+ }
47
+ else {
48
+ this.#requestBody = requestBodyNotAvailableMessage;
49
+ }
50
+ }
51
+ else {
52
+ if (data) {
53
+ this.#requestBody = getSizeLimitedString(data, BODY_CONTEXT_SIZE_LIMIT);
54
+ }
55
+ else {
56
+ this.#requestBody = requestBodyNotAvailableMessage;
57
+ }
58
+ }
59
+ }
60
+ // Load Response Body
61
+ const response = this.#request.response();
62
+ if (response) {
63
+ const responseBodyNotAvailableMessage = '<Response body not available anymore>';
64
+ if (this.#options.responseFilePath) {
65
+ try {
66
+ const buffer = await response.buffer();
67
+ if (!this.#options.saveFile) {
68
+ throw new Error('saveFile is not provided');
69
+ }
70
+ const result = await this.#options.saveFile(buffer, this.#options.responseFilePath, '.network-response');
71
+ this.#responseBodyFilePath = result.filename;
72
+ }
73
+ catch {
74
+ // Flatten error handling for buffer() failure and save failure
75
+ }
76
+ if (!this.#responseBodyFilePath) {
77
+ this.#responseBody = responseBodyNotAvailableMessage;
78
+ }
79
+ }
80
+ else {
81
+ this.#responseBody = await this.#getFormattedResponseBody(response, BODY_CONTEXT_SIZE_LIMIT);
82
+ }
83
+ }
84
+ }
85
+ toString() {
86
+ return convertNetworkRequestConciseToString(this.toJSON());
87
+ }
88
+ toStringDetailed() {
89
+ return converNetworkRequestDetailedToStringDetailed(this.toJSONDetailed());
90
+ }
91
+ toJSON() {
92
+ return {
93
+ requestId: this.#options.requestId,
94
+ method: this.#request.method(),
95
+ url: this.#request.url(),
96
+ status: this.#getStatusFromRequest(this.#request),
97
+ selectedInDevToolsUI: this.#options.selectedInDevToolsUI,
98
+ };
99
+ }
100
+ #redactNetworkHeaders(headers) {
101
+ const headersList = Object.entries(headers).map(item => {
102
+ return { name: item[0], value: item[1] };
103
+ });
104
+ const redacted = DevTools.NetworkRequestFormatter.sanitizeHeaders(headersList);
105
+ return redacted.reduce((acc, item) => {
106
+ acc[item.name] = item.value;
107
+ return acc;
108
+ }, {});
109
+ }
110
+ toJSONDetailed() {
111
+ const redirectChain = this.#request.redirectChain();
112
+ const formattedRedirectChain = redirectChain.reverse().map(request => {
113
+ const id = this.#options.requestIdResolver
114
+ ? this.#options.requestIdResolver(request)
115
+ : undefined;
116
+ const formatter = new NetworkFormatter(request, {
117
+ requestId: id,
118
+ saveFile: this.#options.saveFile,
119
+ redactNetworkHeaders: this.#options.redactNetworkHeaders,
120
+ });
121
+ return formatter.toJSON();
122
+ });
123
+ const responseHeaders = this.#request.response()?.headers();
124
+ return {
125
+ ...this.toJSON(),
126
+ requestHeaders: this.#options.redactNetworkHeaders
127
+ ? this.#redactNetworkHeaders(this.#request.headers())
128
+ : this.#request.headers(),
129
+ requestBody: this.#requestBody,
130
+ requestBodyFilePath: this.#requestBodyFilePath,
131
+ responseHeaders: this.#options.redactNetworkHeaders && responseHeaders
132
+ ? this.#redactNetworkHeaders(responseHeaders)
133
+ : this.#request.response()?.headers(),
134
+ responseBody: this.#responseBody,
135
+ responseBodyFilePath: this.#responseBodyFilePath,
136
+ failure: this.#request.failure()?.errorText,
137
+ redirectChain: formattedRedirectChain.length
138
+ ? formattedRedirectChain
139
+ : undefined,
140
+ };
141
+ }
142
+ #getStatusFromRequest(request) {
143
+ const httpResponse = request.response();
144
+ const failure = request.failure();
145
+ let status;
146
+ if (httpResponse) {
147
+ status = httpResponse.status().toString();
148
+ }
149
+ else if (failure) {
150
+ status = failure.errorText;
151
+ }
152
+ else {
153
+ status = 'pending';
154
+ }
155
+ return status;
156
+ }
157
+ async #getFormattedResponseBody(httpResponse, sizeLimit = BODY_CONTEXT_SIZE_LIMIT) {
158
+ try {
159
+ const responseBuffer = await httpResponse.buffer();
160
+ if (isUtf8(responseBuffer)) {
161
+ const responseAsTest = responseBuffer.toString('utf-8');
162
+ if (responseAsTest.length === 0) {
163
+ return '<empty response>';
164
+ }
165
+ return getSizeLimitedString(responseAsTest, sizeLimit);
166
+ }
167
+ return '<binary data>';
168
+ }
169
+ catch {
170
+ return '<not available anymore>';
171
+ }
172
+ }
173
+ }
174
+ function getSizeLimitedString(text, sizeLimit) {
175
+ if (text.length > sizeLimit) {
176
+ return text.substring(0, sizeLimit) + '... <truncated>';
177
+ }
178
+ return text;
179
+ }
180
+ function convertNetworkRequestConciseToString(data) {
181
+ // TODO truncate the URL
182
+ return `reqid=${data.requestId} ${data.method} ${data.url} [${data.status}]${data.selectedInDevToolsUI ? ` [selected in the DevTools Network panel]` : ''}`;
183
+ }
184
+ function formatHeadlers(headers) {
185
+ const response = [];
186
+ for (const [name, value] of Object.entries(headers)) {
187
+ response.push(`- ${name}:${value}`);
188
+ }
189
+ return response;
190
+ }
191
+ function converNetworkRequestDetailedToStringDetailed(data) {
192
+ const response = [];
193
+ response.push(`## Request ${data.url}`);
194
+ response.push(`Status: ${data.status}`);
195
+ response.push(`### Request Headers`);
196
+ for (const line of formatHeadlers(data.requestHeaders)) {
197
+ response.push(line);
198
+ }
199
+ if (data.requestBody) {
200
+ response.push(`### Request Body`);
201
+ response.push(data.requestBody);
202
+ }
203
+ else if (data.requestBodyFilePath) {
204
+ response.push(`### Request Body`);
205
+ response.push(`Saved to ${data.requestBodyFilePath}.`);
206
+ }
207
+ if (data.responseHeaders) {
208
+ response.push(`### Response Headers`);
209
+ for (const line of formatHeadlers(data.responseHeaders)) {
210
+ response.push(line);
211
+ }
212
+ }
213
+ if (data.responseBody) {
214
+ response.push(`### Response Body`);
215
+ response.push(data.responseBody);
216
+ }
217
+ else if (data.responseBodyFilePath) {
218
+ response.push(`### Response Body`);
219
+ response.push(`Saved to ${data.responseBodyFilePath}.`);
220
+ }
221
+ if (data.failure) {
222
+ response.push(`### Request failed with`);
223
+ response.push(data.failure);
224
+ }
225
+ const redirectChain = data.redirectChain;
226
+ if (redirectChain?.length) {
227
+ response.push(`### Redirect chain`);
228
+ let indent = 0;
229
+ for (const request of redirectChain.reverse()) {
230
+ response.push(`${' '.repeat(indent)}${convertNetworkRequestConciseToString(request)}`);
231
+ indent++;
232
+ }
233
+ }
234
+ return response.join('\n');
235
+ }
236
+ //# sourceMappingURL=NetworkFormatter.js.map
@@ -0,0 +1,135 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ export class SnapshotFormatter {
7
+ #snapshot;
8
+ constructor(snapshot) {
9
+ this.#snapshot = snapshot;
10
+ }
11
+ toString() {
12
+ const chunks = [];
13
+ const root = this.#snapshot.root;
14
+ // Top-level content of the snapshot.
15
+ if (!this.#snapshot.verbose &&
16
+ this.#snapshot.hasSelectedElement &&
17
+ !this.#snapshot.selectedElementUid) {
18
+ chunks.push(`Note: there is a selected element in the DevTools Elements panel but it is not included into the current a11y tree snapshot.
19
+ Get a verbose snapshot to include all elements if you are interested in the selected element.\n\n`);
20
+ }
21
+ chunks.push(this.#formatNode(root, 0));
22
+ return chunks.join('');
23
+ }
24
+ toJSON() {
25
+ return this.#nodeToJSON(this.#snapshot.root);
26
+ }
27
+ #formatNode(node, depth = 0) {
28
+ const chunks = [];
29
+ const attributes = this.#getAttributes(node);
30
+ const line = ' '.repeat(depth * 2) +
31
+ attributes.join(' ') +
32
+ (node.id === this.#snapshot.selectedElementUid
33
+ ? ' [selected in the DevTools Elements panel]'
34
+ : '') +
35
+ '\n';
36
+ chunks.push(line);
37
+ for (const child of node.children) {
38
+ chunks.push(this.#formatNode(child, depth + 1));
39
+ }
40
+ return chunks.join('');
41
+ }
42
+ #nodeToJSON(node) {
43
+ const rawAttrs = this.#getAttributesMap(node);
44
+ const children = node.children.map(child => this.#nodeToJSON(child));
45
+ const result = structuredClone(rawAttrs);
46
+ if (children.length > 0) {
47
+ result.children = children;
48
+ }
49
+ return result;
50
+ }
51
+ #getAttributes(serializedAXNodeRoot) {
52
+ const attributes = [`uid=${serializedAXNodeRoot.id}`];
53
+ if (serializedAXNodeRoot.role) {
54
+ attributes.push(serializedAXNodeRoot.role === 'none'
55
+ ? 'ignored'
56
+ : serializedAXNodeRoot.role);
57
+ }
58
+ if (serializedAXNodeRoot.name) {
59
+ attributes.push(`"${serializedAXNodeRoot.name}"`);
60
+ }
61
+ const simpleAttrs = this.#getAttributesMap(serializedAXNodeRoot,
62
+ /* excludeSpecial */ true);
63
+ for (const attr of Object.keys(serializedAXNodeRoot).sort()) {
64
+ if (excludedAttributes.has(attr)) {
65
+ continue;
66
+ }
67
+ const mapped = booleanPropertyMap[attr];
68
+ if (mapped && simpleAttrs[mapped]) {
69
+ attributes.push(mapped);
70
+ }
71
+ const val = simpleAttrs[attr];
72
+ if (val === true) {
73
+ attributes.push(attr);
74
+ }
75
+ else if (typeof val === 'string' || typeof val === 'number') {
76
+ attributes.push(`${attr}="${val}"`);
77
+ }
78
+ }
79
+ return attributes;
80
+ }
81
+ #getAttributesMap(node, excludeSpecial = false) {
82
+ const result = {};
83
+ if (!excludeSpecial) {
84
+ result.id = node.id;
85
+ if (node.role) {
86
+ result.role = node.role;
87
+ }
88
+ if (node.name) {
89
+ result.name = node.name;
90
+ }
91
+ }
92
+ // Re-implementing the exact logic from original function for #getAttributes to be safe:
93
+ return {
94
+ ...result,
95
+ ...this.#extractedAttributes(node),
96
+ };
97
+ }
98
+ #extractedAttributes(node) {
99
+ const result = {};
100
+ for (const attr of Object.keys(node).sort()) {
101
+ if (excludedAttributes.has(attr)) {
102
+ continue;
103
+ }
104
+ const value = node[attr];
105
+ if (typeof value === 'boolean') {
106
+ if (booleanPropertyMap[attr]) {
107
+ result[booleanPropertyMap[attr]] = true;
108
+ }
109
+ if (value) {
110
+ result[attr] = true;
111
+ }
112
+ }
113
+ else if (typeof value === 'string' || typeof value === 'number') {
114
+ result[attr] = value;
115
+ }
116
+ }
117
+ return result;
118
+ }
119
+ }
120
+ const booleanPropertyMap = {
121
+ disabled: 'disableable',
122
+ expanded: 'expandable',
123
+ focused: 'focusable',
124
+ selected: 'selectable',
125
+ };
126
+ const excludedAttributes = new Set([
127
+ 'id',
128
+ 'role',
129
+ 'name',
130
+ 'elementHandle',
131
+ 'children',
132
+ 'backendNodeId',
133
+ 'loaderId',
134
+ ]);
135
+ //# sourceMappingURL=SnapshotFormatter.js.map
@@ -0,0 +1,140 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { ensureBrowserConnected, ensureBrowserLaunched } from './browser.js';
7
+ import { loadIssueDescriptions } from './issue-descriptions.js';
8
+ import { logger } from './logger.js';
9
+ import { McpContext } from './McpContext.js';
10
+ import { Mutex } from './Mutex.js';
11
+ import { ClearcutLogger } from './telemetry/ClearcutLogger.js';
12
+ import { FilePersistence } from './telemetry/persistence.js';
13
+ import { McpServer, SetLevelRequestSchema, ListRootsResultSchema, RootsListChangedNotificationSchema, } from './third_party/index.js';
14
+ import { ToolHandler } from './ToolHandler.js';
15
+ import { createTools } from './tools/tools.js';
16
+ import { VERSION } from './version.js';
17
+ export { buildFlag } from './ToolHandler.js';
18
+ export async function createMcpServer(serverArgs, options) {
19
+ if (serverArgs.usageStatistics) {
20
+ ClearcutLogger.initialize({
21
+ persistence: new FilePersistence(),
22
+ logFile: serverArgs.logFile,
23
+ appVersion: VERSION,
24
+ clearcutEndpoint: serverArgs.clearcutEndpoint,
25
+ clearcutForceFlushIntervalMs: serverArgs.clearcutForceFlushIntervalMs,
26
+ clearcutIncludePidHeader: serverArgs.clearcutIncludePidHeader,
27
+ });
28
+ }
29
+ const server = new McpServer({
30
+ name: 'chrome_devtools',
31
+ title: 'Chrome DevTools MCP server',
32
+ version: VERSION,
33
+ }, { capabilities: { logging: {} } });
34
+ server.server.setRequestHandler(SetLevelRequestSchema, () => {
35
+ return {};
36
+ });
37
+ const updateRoots = async () => {
38
+ if (!server.server.getClientCapabilities()?.roots) {
39
+ return;
40
+ }
41
+ try {
42
+ const roots = await server.server.request({ method: 'roots/list' }, ListRootsResultSchema);
43
+ context?.setRoots(roots.roots);
44
+ }
45
+ catch (e) {
46
+ logger('Failed to list roots', e);
47
+ }
48
+ };
49
+ server.server.oninitialized = () => {
50
+ const clientName = server.server.getClientVersion()?.name;
51
+ if (clientName) {
52
+ ClearcutLogger.get()?.setClientName(clientName);
53
+ }
54
+ if (server.server.getClientCapabilities()?.roots) {
55
+ void updateRoots();
56
+ server.server.setNotificationHandler(RootsListChangedNotificationSchema, () => {
57
+ void updateRoots();
58
+ });
59
+ }
60
+ };
61
+ let context;
62
+ async function getContext() {
63
+ const chromeArgs = (serverArgs.chromeArg ?? []).map(String);
64
+ const ignoreDefaultChromeArgs = (serverArgs.ignoreDefaultChromeArg ?? []).map(String);
65
+ if (serverArgs.proxyServer) {
66
+ chromeArgs.push(`--proxy-server=${serverArgs.proxyServer}`);
67
+ }
68
+ const devtools = serverArgs.experimentalDevtools ?? false;
69
+ const browser = serverArgs.browserUrl || serverArgs.wsEndpoint || serverArgs.autoConnect
70
+ ? await ensureBrowserConnected({
71
+ browserURL: serverArgs.browserUrl,
72
+ wsEndpoint: serverArgs.wsEndpoint,
73
+ wsHeaders: serverArgs.wsHeaders,
74
+ // Important: only pass channel, if autoConnect is true.
75
+ channel: serverArgs.autoConnect
76
+ ? serverArgs.channel
77
+ : undefined,
78
+ userDataDir: serverArgs.userDataDir,
79
+ devtools,
80
+ })
81
+ : await ensureBrowserLaunched({
82
+ headless: serverArgs.headless,
83
+ executablePath: serverArgs.executablePath,
84
+ channel: serverArgs.channel,
85
+ isolated: serverArgs.isolated ?? false,
86
+ userDataDir: serverArgs.userDataDir,
87
+ logFile: options.logFile,
88
+ viewport: serverArgs.viewport,
89
+ chromeArgs,
90
+ ignoreDefaultChromeArgs,
91
+ acceptInsecureCerts: serverArgs.acceptInsecureCerts,
92
+ devtools,
93
+ enableExtensions: serverArgs.categoryExtensions,
94
+ viaCli: serverArgs.viaCli,
95
+ });
96
+ if (context?.browser !== browser) {
97
+ context = await McpContext.from(browser, logger, {
98
+ experimentalDevToolsDebugging: devtools,
99
+ experimentalIncludeAllPages: serverArgs.experimentalIncludeAllPages,
100
+ performanceCrux: serverArgs.performanceCrux,
101
+ });
102
+ await updateRoots();
103
+ }
104
+ return context;
105
+ }
106
+ const toolMutex = new Mutex();
107
+ function registerTool(tool) {
108
+ const toolHandler = new ToolHandler(tool, serverArgs, getContext, toolMutex);
109
+ if (!toolHandler.shouldRegister) {
110
+ return;
111
+ }
112
+ server.registerTool(tool.name, {
113
+ description: tool.description,
114
+ inputSchema: toolHandler.registeredInputSchema,
115
+ annotations: tool.annotations,
116
+ }, async (params) => {
117
+ return await toolHandler.handle(params);
118
+ });
119
+ }
120
+ const tools = createTools(serverArgs);
121
+ for (const tool of tools) {
122
+ registerTool(tool);
123
+ }
124
+ await loadIssueDescriptions();
125
+ return { server };
126
+ }
127
+ export const logDisclaimers = (args) => {
128
+ console.error(`chrome-devtools-mcp exposes content of the browser instance to the MCP clients allowing them to inspect,
129
+ debug, and modify any data in the browser or DevTools.
130
+ Avoid sharing sensitive or personal information that you do not want to share with MCP clients.`);
131
+ if (!args.slim && args.performanceCrux) {
132
+ console.error(`Performance tools may send trace URLs to the Google CrUX API to fetch real-user experience data. To disable, run with --no-performance-crux.`);
133
+ }
134
+ if (!args.slim && args.usageStatistics) {
135
+ console.error(`
136
+ Google collects usage statistics to improve Chrome DevTools MCP. To opt-out, run with --no-usage-statistics.
137
+ For more details, visit: https://github.com/ChromeDevTools/chrome-devtools-mcp#usage-statistics`);
138
+ }
139
+ };
140
+ //# sourceMappingURL=index.js.map