@mcp-b/chrome-devtools-mcp 2.2.0 → 2.3.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.
- package/README.md +1 -4
- package/build/src/DevToolsConnectionAdapter.js +5 -4
- package/build/src/DevtoolsUtils.js +8 -12
- package/build/src/McpContext.js +34 -39
- package/build/src/McpResponse.js +19 -45
- package/build/src/PageCollector.js +10 -11
- package/build/src/WaitForHelper.js +7 -11
- package/build/src/bin/chrome-devtools-cli-options.js +616 -665
- package/build/src/bin/chrome-devtools-mcp-cli-options.js +5 -5
- package/build/src/bin/chrome-devtools.js +2 -24
- package/build/src/bin/cliDefinitions.js +615 -0
- package/build/src/browser.js +5 -10
- package/build/src/daemon/client.js +10 -34
- package/build/src/formatters/{consoleFormatter.js → ConsoleFormatter.js} +10 -17
- package/build/src/formatters/{networkFormatter.js → NetworkFormatter.js} +3 -6
- package/build/src/formatters/{snapshotFormatter.js → SnapshotFormatter.js} +3 -6
- package/build/src/index.js +6 -16
- package/build/src/tools/ToolDefinition.js +1 -1
- package/build/src/tools/emulation.js +1 -1
- package/build/src/tools/input.js +5 -11
- package/build/src/tools/pages.js +7 -19
- package/build/src/tools/performance.js +3 -3
- package/build/src/tools/script.js +4 -6
- package/build/src/tools/tools.js +0 -1
- package/build/src/version.js +1 -1
- package/package.json +9 -9
- package/build/src/third_party/issue-descriptions/CoepCoopSandboxedIframeCannotNavigateToCoopPage.md +0 -4
- package/build/src/third_party/issue-descriptions/CoepCorpNotSameOrigin.md +0 -8
- package/build/src/third_party/issue-descriptions/CoepCorpNotSameOriginAfterDefaultedToSameOriginByCoep.md +0 -18
- package/build/src/third_party/issue-descriptions/CoepCorpNotSameSite.md +0 -7
- package/build/src/third_party/issue-descriptions/CoepFrameResourceNeedsCoepHeader.md +0 -10
- package/build/src/third_party/issue-descriptions/CompatibilityModeQuirks.md +0 -5
- package/build/src/third_party/issue-descriptions/CookieAttributeValueExceedsMaxSize.md +0 -5
- package/build/src/third_party/issue-descriptions/LowTextContrast.md +0 -5
- package/build/src/third_party/issue-descriptions/SameSiteExcludeContextDowngradeRead.md +0 -8
- package/build/src/third_party/issue-descriptions/SameSiteExcludeContextDowngradeSet.md +0 -8
- package/build/src/third_party/issue-descriptions/SameSiteExcludeNavigationContextDowngrade.md +0 -8
- package/build/src/third_party/issue-descriptions/SameSiteNoneInsecureErrorRead.md +0 -8
- package/build/src/third_party/issue-descriptions/SameSiteNoneInsecureErrorSet.md +0 -8
- package/build/src/third_party/issue-descriptions/SameSiteNoneInsecureWarnRead.md +0 -8
- package/build/src/third_party/issue-descriptions/SameSiteNoneInsecureWarnSet.md +0 -8
- package/build/src/third_party/issue-descriptions/SameSiteUnspecifiedLaxAllowUnsafeRead.md +0 -9
- package/build/src/third_party/issue-descriptions/SameSiteUnspecifiedLaxAllowUnsafeSet.md +0 -9
- package/build/src/third_party/issue-descriptions/SameSiteWarnCrossDowngradeRead.md +0 -8
- package/build/src/third_party/issue-descriptions/SameSiteWarnCrossDowngradeSet.md +0 -8
- package/build/src/third_party/issue-descriptions/SameSiteWarnStrictLaxDowngradeStrict.md +0 -8
- package/build/src/third_party/issue-descriptions/arInsecureContext.md +0 -7
- package/build/src/third_party/issue-descriptions/arInvalidInfoHeader.md +0 -5
- package/build/src/third_party/issue-descriptions/arInvalidRegisterOsSourceHeader.md +0 -5
- package/build/src/third_party/issue-descriptions/arInvalidRegisterOsTriggerHeader.md +0 -5
- package/build/src/third_party/issue-descriptions/arInvalidRegisterSourceHeader.md +0 -5
- package/build/src/third_party/issue-descriptions/arInvalidRegisterTriggerHeader.md +0 -5
- package/build/src/third_party/issue-descriptions/arNavigationRegistrationUniqueScopeAlreadySet.md +0 -5
- package/build/src/third_party/issue-descriptions/arNavigationRegistrationWithoutTransientUserActivation.md +0 -6
- package/build/src/third_party/issue-descriptions/arNoRegisterOsSourceHeader.md +0 -5
- package/build/src/third_party/issue-descriptions/arNoRegisterOsTriggerHeader.md +0 -5
- package/build/src/third_party/issue-descriptions/arNoRegisterSourceHeader.md +0 -5
- package/build/src/third_party/issue-descriptions/arNoRegisterTriggerHeader.md +0 -5
- package/build/src/third_party/issue-descriptions/arNoWebOrOsSupport.md +0 -4
- package/build/src/third_party/issue-descriptions/arOsSourceIgnored.md +0 -18
- package/build/src/third_party/issue-descriptions/arOsTriggerIgnored.md +0 -19
- package/build/src/third_party/issue-descriptions/arPermissionPolicyDisabled.md +0 -8
- package/build/src/third_party/issue-descriptions/arSourceAndTriggerHeaders.md +0 -9
- package/build/src/third_party/issue-descriptions/arSourceIgnored.md +0 -13
- package/build/src/third_party/issue-descriptions/arTriggerIgnored.md +0 -12
- package/build/src/third_party/issue-descriptions/arUntrustworthyReportingOrigin.md +0 -10
- package/build/src/third_party/issue-descriptions/arWebAndOsHeaders.md +0 -11
- package/build/src/third_party/issue-descriptions/bounceTrackingMitigations.md +0 -3
- package/build/src/third_party/issue-descriptions/clientHintMetaTagAllowListInvalidOrigin.md +0 -4
- package/build/src/third_party/issue-descriptions/clientHintMetaTagModifiedHTML.md +0 -4
- package/build/src/third_party/issue-descriptions/connectionAllowlistInvalidAllowlistItemType.md +0 -12
- package/build/src/third_party/issue-descriptions/connectionAllowlistInvalidHeader.md +0 -12
- package/build/src/third_party/issue-descriptions/connectionAllowlistInvalidUrlPattern.md +0 -8
- package/build/src/third_party/issue-descriptions/connectionAllowlistItemNotInnerList.md +0 -12
- package/build/src/third_party/issue-descriptions/connectionAllowlistMoreThanOneList.md +0 -7
- package/build/src/third_party/issue-descriptions/connectionAllowlistReportingEndpointNotToken.md +0 -10
- package/build/src/third_party/issue-descriptions/cookieCrossSiteRedirectDowngrade.md +0 -12
- package/build/src/third_party/issue-descriptions/cookieExcludeBlockedWithinRelatedWebsiteSet.md +0 -4
- package/build/src/third_party/issue-descriptions/cookieExcludeDomainNonAscii.md +0 -11
- package/build/src/third_party/issue-descriptions/cookieExcludePortMismatch.md +0 -8
- package/build/src/third_party/issue-descriptions/cookieExcludeSchemeMismatch.md +0 -7
- package/build/src/third_party/issue-descriptions/cookieExcludeThirdPartyPhaseoutRead.md +0 -6
- package/build/src/third_party/issue-descriptions/cookieExcludeThirdPartyPhaseoutSet.md +0 -6
- package/build/src/third_party/issue-descriptions/cookieWarnDomainNonAscii.md +0 -11
- package/build/src/third_party/issue-descriptions/cookieWarnMetadataGrantRead.md +0 -4
- package/build/src/third_party/issue-descriptions/cookieWarnMetadataGrantSet.md +0 -4
- package/build/src/third_party/issue-descriptions/cookieWarnThirdPartyPhaseoutRead.md +0 -6
- package/build/src/third_party/issue-descriptions/cookieWarnThirdPartyPhaseoutSet.md +0 -6
- package/build/src/third_party/issue-descriptions/corsAllowCredentialsRequired.md +0 -6
- package/build/src/third_party/issue-descriptions/corsDisabledScheme.md +0 -7
- package/build/src/third_party/issue-descriptions/corsDisallowedByMode.md +0 -7
- package/build/src/third_party/issue-descriptions/corsHeaderDisallowedByPreflightResponse.md +0 -5
- package/build/src/third_party/issue-descriptions/corsInvalidHeaderValues.md +0 -7
- package/build/src/third_party/issue-descriptions/corsLocalNetworkAccessPermissionDenied.md +0 -19
- package/build/src/third_party/issue-descriptions/corsMethodDisallowedByPreflightResponse.md +0 -5
- package/build/src/third_party/issue-descriptions/corsNoCorsRedirectModeNotFollow.md +0 -5
- package/build/src/third_party/issue-descriptions/corsOriginMismatch.md +0 -6
- package/build/src/third_party/issue-descriptions/corsPreflightResponseInvalid.md +0 -5
- package/build/src/third_party/issue-descriptions/corsRedirectContainsCredentials.md +0 -5
- package/build/src/third_party/issue-descriptions/corsWildcardOriginNotAllowed.md +0 -8
- package/build/src/third_party/issue-descriptions/cspEvalViolation.md +0 -9
- package/build/src/third_party/issue-descriptions/cspInlineViolation.md +0 -10
- package/build/src/third_party/issue-descriptions/cspTrustedTypesPolicyViolation.md +0 -5
- package/build/src/third_party/issue-descriptions/cspTrustedTypesSinkViolation.md +0 -8
- package/build/src/third_party/issue-descriptions/cspURLViolation.md +0 -10
- package/build/src/third_party/issue-descriptions/deprecation.md +0 -3
- package/build/src/third_party/issue-descriptions/federatedAuthRequestAccountsHttpNotFound.md +0 -1
- package/build/src/third_party/issue-descriptions/federatedAuthRequestAccountsInvalidResponse.md +0 -1
- package/build/src/third_party/issue-descriptions/federatedAuthRequestAccountsNoResponse.md +0 -1
- package/build/src/third_party/issue-descriptions/federatedAuthRequestApprovalDeclined.md +0 -1
- package/build/src/third_party/issue-descriptions/federatedAuthRequestCanceled.md +0 -1
- package/build/src/third_party/issue-descriptions/federatedAuthRequestErrorFetchingSignin.md +0 -1
- package/build/src/third_party/issue-descriptions/federatedAuthRequestErrorIdToken.md +0 -1
- package/build/src/third_party/issue-descriptions/federatedAuthRequestIdTokenHttpNotFound.md +0 -1
- package/build/src/third_party/issue-descriptions/federatedAuthRequestIdTokenInvalidRequest.md +0 -1
- package/build/src/third_party/issue-descriptions/federatedAuthRequestIdTokenInvalidResponse.md +0 -1
- package/build/src/third_party/issue-descriptions/federatedAuthRequestIdTokenNoResponse.md +0 -1
- package/build/src/third_party/issue-descriptions/federatedAuthRequestInvalidSigninResponse.md +0 -1
- package/build/src/third_party/issue-descriptions/federatedAuthRequestManifestHttpNotFound.md +0 -1
- package/build/src/third_party/issue-descriptions/federatedAuthRequestManifestInvalidResponse.md +0 -1
- package/build/src/third_party/issue-descriptions/federatedAuthRequestManifestNoResponse.md +0 -1
- package/build/src/third_party/issue-descriptions/federatedAuthRequestTooManyRequests.md +0 -1
- package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestInvalidAccountsResponse.md +0 -1
- package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestInvalidConfigOrWellKnown.md +0 -1
- package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNoAccountSharingPermission.md +0 -1
- package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNoApiPermission.md +0 -1
- package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNoReturningUserFromFetchedAccounts.md +0 -1
- package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNotIframe.md +0 -1
- package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNotPotentiallyTrustworthy.md +0 -1
- package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNotSameOrigin.md +0 -1
- package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNotSignedInWithIdp.md +0 -1
- package/build/src/third_party/issue-descriptions/fetchingPartitionedBlobURL.md +0 -7
- package/build/src/third_party/issue-descriptions/genericFormAriaLabelledByToNonExistingIdError.md +0 -8
- package/build/src/third_party/issue-descriptions/genericFormAutocompleteAttributeEmptyError.md +0 -5
- package/build/src/third_party/issue-descriptions/genericFormDuplicateIdForInputError.md +0 -5
- package/build/src/third_party/issue-descriptions/genericFormEmptyIdAndNameAttributesForInputError.md +0 -5
- package/build/src/third_party/issue-descriptions/genericFormInputAssignedAutocompleteValueToIdOrNameAttributeError.md +0 -5
- package/build/src/third_party/issue-descriptions/genericFormInputHasWrongButWellIntendedAutocompleteValueError.md +0 -5
- package/build/src/third_party/issue-descriptions/genericFormInputWithNoLabelError.md +0 -5
- package/build/src/third_party/issue-descriptions/genericFormLabelForMatchesNonExistingIdError.md +0 -5
- package/build/src/third_party/issue-descriptions/genericFormLabelForNameError.md +0 -5
- package/build/src/third_party/issue-descriptions/genericFormLabelHasNeitherForNorNestedInputError.md +0 -5
- package/build/src/third_party/issue-descriptions/genericNavigationEntryMarkedSkippable.md +0 -7
- package/build/src/third_party/issue-descriptions/genericResponseWasBlockedByORB.md +0 -4
- package/build/src/third_party/issue-descriptions/heavyAd.md +0 -10
- package/build/src/third_party/issue-descriptions/mixedContent.md +0 -5
- package/build/src/third_party/issue-descriptions/navigatingPartitionedBlobURL.md +0 -5
- package/build/src/third_party/issue-descriptions/permissionElementActivationDisabled.md +0 -7
- package/build/src/third_party/issue-descriptions/permissionElementActivationDisabledWithOccluder.md +0 -9
- package/build/src/third_party/issue-descriptions/permissionElementActivationDisabledWithOccluderParent.md +0 -9
- package/build/src/third_party/issue-descriptions/permissionElementCspFrameAncestorsMissing.md +0 -5
- package/build/src/third_party/issue-descriptions/permissionElementFencedFrameDisallowed.md +0 -5
- package/build/src/third_party/issue-descriptions/permissionElementFontSizeTooLarge.md +0 -5
- package/build/src/third_party/issue-descriptions/permissionElementFontSizeTooSmall.md +0 -5
- package/build/src/third_party/issue-descriptions/permissionElementGeolocationDeprecated.md +0 -5
- package/build/src/third_party/issue-descriptions/permissionElementInsetBoxShadowUnsupported.md +0 -5
- package/build/src/third_party/issue-descriptions/permissionElementInvalidDisplayStyle.md +0 -5
- package/build/src/third_party/issue-descriptions/permissionElementInvalidSizeValue.md +0 -5
- package/build/src/third_party/issue-descriptions/permissionElementInvalidType.md +0 -5
- package/build/src/third_party/issue-descriptions/permissionElementInvalidTypeActivation.md +0 -5
- package/build/src/third_party/issue-descriptions/permissionElementLowContrast.md +0 -5
- package/build/src/third_party/issue-descriptions/permissionElementNonOpaqueColor.md +0 -5
- package/build/src/third_party/issue-descriptions/permissionElementPaddingBottomUnsupported.md +0 -6
- package/build/src/third_party/issue-descriptions/permissionElementPaddingRightUnsupported.md +0 -6
- package/build/src/third_party/issue-descriptions/permissionElementPermissionsPolicyBlocked.md +0 -5
- package/build/src/third_party/issue-descriptions/permissionElementRegistrationFailed.md +0 -5
- package/build/src/third_party/issue-descriptions/permissionElementRequestInProgress.md +0 -5
- package/build/src/third_party/issue-descriptions/permissionElementSecurityChecksFailed.md +0 -5
- package/build/src/third_party/issue-descriptions/permissionElementTypeNotSupported.md +0 -5
- package/build/src/third_party/issue-descriptions/permissionElementUntrustedEvent.md +0 -7
- package/build/src/third_party/issue-descriptions/placeholderDescriptionForInvisibleIssues.md +0 -3
- package/build/src/third_party/issue-descriptions/propertyRuleInvalidNameIssue.md +0 -3
- package/build/src/third_party/issue-descriptions/propertyRuleIssue.md +0 -7
- package/build/src/third_party/issue-descriptions/selectElementAccessibilityDisallowedOptGroupChild.md +0 -7
- package/build/src/third_party/issue-descriptions/selectElementAccessibilityDisallowedSelectChild.md +0 -7
- package/build/src/third_party/issue-descriptions/selectElementAccessibilityInteractiveContentAttributesSelectDescendant.md +0 -3
- package/build/src/third_party/issue-descriptions/selectElementAccessibilityInteractiveContentLegendChild.md +0 -3
- package/build/src/third_party/issue-descriptions/selectElementAccessibilityInteractiveContentOptionChild.md +0 -3
- package/build/src/third_party/issue-descriptions/selectElementAccessibilityNonPhrasingContentOptionChild.md +0 -3
- package/build/src/third_party/issue-descriptions/selectivePermissionsIntervention.md +0 -7
- package/build/src/third_party/issue-descriptions/sharedArrayBuffer.md +0 -7
- package/build/src/third_party/issue-descriptions/sharedDictionaryUseErrorCrossOriginNoCorsRequest.md +0 -1
- package/build/src/third_party/issue-descriptions/sharedDictionaryUseErrorDictionaryLoadFailure.md +0 -3
- package/build/src/third_party/issue-descriptions/sharedDictionaryUseErrorMatchingDictionaryNotUsed.md +0 -3
- package/build/src/third_party/issue-descriptions/sharedDictionaryUseErrorUnexpectedContentDictionaryHeader.md +0 -1
- package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorCossOriginNoCorsRequest.md +0 -1
- package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorDisallowedBySettings.md +0 -1
- package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorExpiredResponse.md +0 -3
- package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorFeatureDisabled.md +0 -3
- package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorInsufficientResources.md +0 -1
- package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorInvalidMatchField.md +0 -1
- package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorInvalidStructuredHeader.md +0 -1
- package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorInvalidTTLField.md +0 -1
- package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNavigationRequest.md +0 -3
- package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNoMatchField.md +0 -1
- package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNonIntegerTTLField.md +0 -1
- package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNonListMatchDestField.md +0 -1
- package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNonSecureContext.md +0 -3
- package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNonStringIdField.md +0 -1
- package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNonStringInMatchDestList.md +0 -1
- package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNonStringMatchField.md +0 -1
- package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNonTokenTypeField.md +0 -1
- package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorRequestAborted.md +0 -1
- package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorShuttingDown.md +0 -1
- package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorTooLongIdField.md +0 -3
- package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorUnsupportedType.md +0 -3
- package/build/src/third_party/issue-descriptions/sriInvalidSignatureHeader.md +0 -14
- package/build/src/third_party/issue-descriptions/sriInvalidSignatureInputHeader.md +0 -15
- package/build/src/third_party/issue-descriptions/sriMissingSignatureHeader.md +0 -8
- package/build/src/third_party/issue-descriptions/sriMissingSignatureInputHeader.md +0 -7
- package/build/src/third_party/issue-descriptions/sriSignatureHeaderValueIsIncorrectLength.md +0 -11
- package/build/src/third_party/issue-descriptions/sriSignatureHeaderValueIsNotByteSequence.md +0 -14
- package/build/src/third_party/issue-descriptions/sriSignatureHeaderValueIsParameterized.md +0 -15
- package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderInvalidComponentName.md +0 -8
- package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderInvalidComponentType.md +0 -13
- package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderInvalidDerivedComponentParameter.md +0 -4
- package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderInvalidHeaderComponentParameter.md +0 -5
- package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderInvalidParameter.md +0 -11
- package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderKeyIdLength.md +0 -12
- package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderMissingLabel.md +0 -6
- package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderMissingRequiredParameters.md +0 -8
- package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderValueMissingComponents.md +0 -11
- package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderValueNotInnerList.md +0 -11
- package/build/src/third_party/issue-descriptions/sriValidationFailedIntegrityMismatch.md +0 -10
- package/build/src/third_party/issue-descriptions/sriValidationFailedInvalidLength.md +0 -5
- package/build/src/third_party/issue-descriptions/sriValidationFailedSignatureExpired.md +0 -6
- package/build/src/third_party/issue-descriptions/sriValidationFailedSignatureMismatch.md +0 -11
- package/build/src/third_party/issue-descriptions/stylesheetLateImport.md +0 -4
- package/build/src/third_party/issue-descriptions/stylesheetRequestFailed.md +0 -3
- package/build/src/third_party/issue-descriptions/summaryElementAccessibilityInteractiveContentSummaryDescendant.md +0 -3
- package/build/src/third_party/issue-descriptions/unencodedDigestIncorrectDigestLength.md +0 -12
- package/build/src/third_party/issue-descriptions/unencodedDigestIncorrectDigestType.md +0 -17
- package/build/src/third_party/issue-descriptions/unencodedDigestMalformedDictionary.md +0 -14
- package/build/src/third_party/issue-descriptions/unencodedDigestUnknownAlgorithm.md +0 -15
package/build/src/browser.js
CHANGED
|
@@ -61,10 +61,10 @@ export async function ensureBrowserConnected(options) {
|
|
|
61
61
|
const fileContent = await fs.promises.readFile(portPath, 'utf8');
|
|
62
62
|
const [rawPort, rawPath] = fileContent
|
|
63
63
|
.split('\n')
|
|
64
|
-
.map(line => {
|
|
64
|
+
.map((line) => {
|
|
65
65
|
return line.trim();
|
|
66
66
|
})
|
|
67
|
-
.filter(line => {
|
|
67
|
+
.filter((line) => {
|
|
68
68
|
return !!line;
|
|
69
69
|
});
|
|
70
70
|
if (!rawPort || !rawPath) {
|
|
@@ -123,9 +123,7 @@ export function detectDisplay() {
|
|
|
123
123
|
}
|
|
124
124
|
export async function launch(options) {
|
|
125
125
|
const { channel, executablePath, headless, isolated } = options;
|
|
126
|
-
const profileDirName = channel && channel !== 'stable'
|
|
127
|
-
? `chrome-profile-${channel}`
|
|
128
|
-
: 'chrome-profile';
|
|
126
|
+
const profileDirName = channel && channel !== 'stable' ? `chrome-profile-${channel}` : 'chrome-profile';
|
|
129
127
|
let userDataDir = options.userDataDir;
|
|
130
128
|
if (!isolated && !userDataDir) {
|
|
131
129
|
userDataDir = path.join(os.homedir(), '.cache', options.viaCli ? 'chrome-devtools-mcp-cli' : 'chrome-devtools-mcp', profileDirName);
|
|
@@ -147,9 +145,7 @@ export async function launch(options) {
|
|
|
147
145
|
}
|
|
148
146
|
if (!executablePath) {
|
|
149
147
|
puppeteerChannel =
|
|
150
|
-
channel && channel !== 'stable'
|
|
151
|
-
? `chrome-${channel}`
|
|
152
|
-
: 'chrome';
|
|
148
|
+
channel && channel !== 'stable' ? `chrome-${channel}` : 'chrome';
|
|
153
149
|
}
|
|
154
150
|
if (!headless) {
|
|
155
151
|
detectDisplay();
|
|
@@ -185,8 +181,7 @@ export async function launch(options) {
|
|
|
185
181
|
return browser;
|
|
186
182
|
}
|
|
187
183
|
catch (error) {
|
|
188
|
-
if (userDataDir &&
|
|
189
|
-
error.message.includes('The browser is already running')) {
|
|
184
|
+
if (userDataDir && error.message.includes('The browser is already running')) {
|
|
190
185
|
throw new Error(`The browser is already running for ${userDataDir}. Use --isolated to run multiple browser instances.`, {
|
|
191
186
|
cause: error,
|
|
192
187
|
});
|
|
@@ -11,23 +11,6 @@ import { PipeTransport } from '../third_party/index.js';
|
|
|
11
11
|
import { saveTemporaryFile } from '../utils/files.js';
|
|
12
12
|
import { DAEMON_SCRIPT_PATH, getSocketPath, getPidFilePath, isDaemonRunning, } from './utils.js';
|
|
13
13
|
const FILE_TIMEOUT = 10_000;
|
|
14
|
-
function fileExtensionForMimeType(mimeType) {
|
|
15
|
-
switch (mimeType) {
|
|
16
|
-
case 'image/png':
|
|
17
|
-
return '.png';
|
|
18
|
-
case 'image/jpg':
|
|
19
|
-
case 'image/jpeg':
|
|
20
|
-
return '.jpeg';
|
|
21
|
-
case 'image/webp':
|
|
22
|
-
return '.webp';
|
|
23
|
-
case 'text/plain':
|
|
24
|
-
return '.txt';
|
|
25
|
-
case 'application/json':
|
|
26
|
-
return '.json';
|
|
27
|
-
default:
|
|
28
|
-
return '.bin';
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
14
|
/**
|
|
32
15
|
* Waits for a file to be created and populated (removed = false) or removed (removed = true).
|
|
33
16
|
*/
|
|
@@ -146,28 +129,21 @@ export async function handleResponse(response, format) {
|
|
|
146
129
|
else if (content.type === 'image') {
|
|
147
130
|
const imageData = content.data;
|
|
148
131
|
const mimeType = content.mimeType;
|
|
149
|
-
|
|
132
|
+
let extension = '.png';
|
|
133
|
+
switch (mimeType) {
|
|
134
|
+
case 'image/jpg':
|
|
135
|
+
case 'image/jpeg':
|
|
136
|
+
extension = '.jpeg';
|
|
137
|
+
break;
|
|
138
|
+
case 'webp':
|
|
139
|
+
extension = '.webp';
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
150
142
|
const data = Buffer.from(imageData, 'base64');
|
|
151
143
|
const name = crypto.randomUUID();
|
|
152
144
|
const { filepath } = await saveTemporaryFile(data, `${name}${extension}`);
|
|
153
145
|
chunks.push(`Saved to ${filepath}.`);
|
|
154
146
|
}
|
|
155
|
-
else if (content.type === 'resource') {
|
|
156
|
-
const resource = content.resource;
|
|
157
|
-
if ('text' in resource && typeof resource.text === 'string') {
|
|
158
|
-
chunks.push(resource.text);
|
|
159
|
-
continue;
|
|
160
|
-
}
|
|
161
|
-
if ('blob' in resource && typeof resource.blob === 'string') {
|
|
162
|
-
const extension = fileExtensionForMimeType(resource.mimeType);
|
|
163
|
-
const data = Buffer.from(resource.blob, 'base64');
|
|
164
|
-
const name = crypto.randomUUID();
|
|
165
|
-
const { filepath } = await saveTemporaryFile(data, `${name}${extension}`);
|
|
166
|
-
chunks.push(`Saved resource ${resource.uri} to ${filepath}.`);
|
|
167
|
-
continue;
|
|
168
|
-
}
|
|
169
|
-
chunks.push(resource.uri);
|
|
170
|
-
}
|
|
171
147
|
else {
|
|
172
148
|
throw new Error('Not supported response content type');
|
|
173
149
|
}
|
|
@@ -28,7 +28,7 @@ export class ConsoleFormatter {
|
|
|
28
28
|
static async from(msg, options) {
|
|
29
29
|
const ignoreListManager = options?.devTools?.universe.context.get(DevTools.DevTools.IgnoreListManager);
|
|
30
30
|
const isIgnored = options.isIgnoredForTesting ||
|
|
31
|
-
(frame => {
|
|
31
|
+
((frame) => {
|
|
32
32
|
if (!ignoreListManager) {
|
|
33
33
|
return false;
|
|
34
34
|
}
|
|
@@ -66,8 +66,7 @@ export class ConsoleFormatter {
|
|
|
66
66
|
resolvedArgs = await Promise.all(msg.args().map(async (arg, i) => {
|
|
67
67
|
try {
|
|
68
68
|
const remoteObject = arg.remoteObject();
|
|
69
|
-
if (remoteObject.type === 'object' &&
|
|
70
|
-
remoteObject.subtype === 'error') {
|
|
69
|
+
if (remoteObject.type === 'object' && remoteObject.subtype === 'error') {
|
|
71
70
|
return await SymbolizedError.fromError({
|
|
72
71
|
devTools: options.devTools,
|
|
73
72
|
error: remoteObject,
|
|
@@ -137,10 +136,8 @@ export class ConsoleFormatter {
|
|
|
137
136
|
type: this.#type,
|
|
138
137
|
text: this.#text,
|
|
139
138
|
argsCount: this.#argCount,
|
|
140
|
-
args: this.#getArgs().map(arg => formatArg(arg, this)),
|
|
141
|
-
stackTrace: this.#stack
|
|
142
|
-
? formatStackTrace(this.#stack, this.#cause, this)
|
|
143
|
-
: undefined,
|
|
139
|
+
args: this.#getArgs().map((arg) => formatArg(arg, this)),
|
|
140
|
+
stackTrace: this.#stack ? formatStackTrace(this.#stack, this.#cause, this) : undefined,
|
|
144
141
|
};
|
|
145
142
|
}
|
|
146
143
|
}
|
|
@@ -153,7 +150,7 @@ function convertConsoleMessageConciseDetailedToString(msg) {
|
|
|
153
150
|
`Message: ${msg.type}> ${msg.text}`,
|
|
154
151
|
formatArgs(msg),
|
|
155
152
|
...(msg.stackTrace ? ['### Stack trace', msg.stackTrace] : []),
|
|
156
|
-
].filter(line => !!line);
|
|
153
|
+
].filter((line) => !!line);
|
|
157
154
|
return result.join('\n');
|
|
158
155
|
}
|
|
159
156
|
function formatArgs(msg) {
|
|
@@ -171,11 +168,9 @@ function formatArg(arg, formatter) {
|
|
|
171
168
|
if (arg instanceof SymbolizedError) {
|
|
172
169
|
return [
|
|
173
170
|
arg.message,
|
|
174
|
-
arg.stackTrace
|
|
175
|
-
? formatStackTrace(arg.stackTrace, arg.cause, formatter)
|
|
176
|
-
: undefined,
|
|
171
|
+
arg.stackTrace ? formatStackTrace(arg.stackTrace, arg.cause, formatter) : undefined,
|
|
177
172
|
]
|
|
178
|
-
.filter(line => !!line)
|
|
173
|
+
.filter((line) => !!line)
|
|
179
174
|
.join('\n');
|
|
180
175
|
}
|
|
181
176
|
return typeof arg === 'object' ? JSON.stringify(arg) : String(arg);
|
|
@@ -190,7 +185,7 @@ function formatStackTrace(stackTrace, cause, formatter) {
|
|
|
190
185
|
reminderCount > 0 ? `... and ${reminderCount} more frames` : '',
|
|
191
186
|
'Note: line and column numbers use 1-based indexing',
|
|
192
187
|
]
|
|
193
|
-
.filter(line => !!line)
|
|
188
|
+
.filter((line) => !!line)
|
|
194
189
|
.join('\n');
|
|
195
190
|
}
|
|
196
191
|
function formatStackTraceInner(stackTrace, cause, formatter) {
|
|
@@ -199,14 +194,12 @@ function formatStackTraceInner(stackTrace, cause, formatter) {
|
|
|
199
194
|
}
|
|
200
195
|
return [
|
|
201
196
|
...formatFragment(stackTrace.syncFragment, formatter),
|
|
202
|
-
...stackTrace.asyncFragments
|
|
203
|
-
.map(item => formatAsyncFragment(item, formatter))
|
|
204
|
-
.flat(),
|
|
197
|
+
...stackTrace.asyncFragments.map((item) => formatAsyncFragment(item, formatter)).flat(),
|
|
205
198
|
...formatCause(cause, formatter),
|
|
206
199
|
];
|
|
207
200
|
}
|
|
208
201
|
function formatFragment(fragment, formatter) {
|
|
209
|
-
const frames = fragment.frames.filter(frame => !formatter.isIgnored(frame));
|
|
202
|
+
const frames = fragment.frames.filter((frame) => !formatter.isIgnored(frame));
|
|
210
203
|
return frames.map(formatFrame);
|
|
211
204
|
}
|
|
212
205
|
function formatAsyncFragment(fragment, formatter) {
|
|
@@ -28,8 +28,7 @@ export class NetworkFormatter {
|
|
|
28
28
|
if (this.#request.hasPostData()) {
|
|
29
29
|
let data;
|
|
30
30
|
try {
|
|
31
|
-
data =
|
|
32
|
-
this.#request.postData() ?? (await this.#request.fetchPostData());
|
|
31
|
+
data = this.#request.postData() ?? (await this.#request.fetchPostData());
|
|
33
32
|
}
|
|
34
33
|
catch {
|
|
35
34
|
// Ignore parsing errors
|
|
@@ -98,7 +97,7 @@ export class NetworkFormatter {
|
|
|
98
97
|
}
|
|
99
98
|
toJSONDetailed() {
|
|
100
99
|
const redirectChain = this.#request.redirectChain();
|
|
101
|
-
const formattedRedirectChain = redirectChain.reverse().map(request => {
|
|
100
|
+
const formattedRedirectChain = redirectChain.reverse().map((request) => {
|
|
102
101
|
const id = this.#options.requestIdResolver
|
|
103
102
|
? this.#options.requestIdResolver(request)
|
|
104
103
|
: undefined;
|
|
@@ -117,9 +116,7 @@ export class NetworkFormatter {
|
|
|
117
116
|
responseBody: this.#responseBody,
|
|
118
117
|
responseBodyFilePath: this.#responseBodyFilePath,
|
|
119
118
|
failure: this.#request.failure()?.errorText,
|
|
120
|
-
redirectChain: formattedRedirectChain.length
|
|
121
|
-
? formattedRedirectChain
|
|
122
|
-
: undefined,
|
|
119
|
+
redirectChain: formattedRedirectChain.length ? formattedRedirectChain : undefined,
|
|
123
120
|
};
|
|
124
121
|
}
|
|
125
122
|
#getStatusFromRequest(request) {
|
|
@@ -41,7 +41,7 @@ Get a verbose snapshot to include all elements if you are interested in the sele
|
|
|
41
41
|
}
|
|
42
42
|
#nodeToJSON(node) {
|
|
43
43
|
const rawAttrs = this.#getAttributesMap(node);
|
|
44
|
-
const children = node.children.map(child => this.#nodeToJSON(child));
|
|
44
|
+
const children = node.children.map((child) => this.#nodeToJSON(child));
|
|
45
45
|
const result = structuredClone(rawAttrs);
|
|
46
46
|
if (children.length > 0) {
|
|
47
47
|
result.children = children;
|
|
@@ -51,15 +51,12 @@ Get a verbose snapshot to include all elements if you are interested in the sele
|
|
|
51
51
|
#getAttributes(serializedAXNodeRoot) {
|
|
52
52
|
const attributes = [`uid=${serializedAXNodeRoot.id}`];
|
|
53
53
|
if (serializedAXNodeRoot.role) {
|
|
54
|
-
attributes.push(serializedAXNodeRoot.role === 'none'
|
|
55
|
-
? 'ignored'
|
|
56
|
-
: serializedAXNodeRoot.role);
|
|
54
|
+
attributes.push(serializedAXNodeRoot.role === 'none' ? 'ignored' : serializedAXNodeRoot.role);
|
|
57
55
|
}
|
|
58
56
|
if (serializedAXNodeRoot.name) {
|
|
59
57
|
attributes.push(`"${serializedAXNodeRoot.name}"`);
|
|
60
58
|
}
|
|
61
|
-
const simpleAttrs = this.#getAttributesMap(serializedAXNodeRoot,
|
|
62
|
-
/* excludeSpecial */ true);
|
|
59
|
+
const simpleAttrs = this.#getAttributesMap(serializedAXNodeRoot, /* excludeSpecial */ true);
|
|
63
60
|
for (const attr of Object.keys(serializedAXNodeRoot).sort()) {
|
|
64
61
|
if (excludedAttributes.has(attr)) {
|
|
65
62
|
continue;
|
package/build/src/index.js
CHANGED
|
@@ -12,7 +12,7 @@ import { Mutex } from './Mutex.js';
|
|
|
12
12
|
import { SlimMcpResponse } from './SlimMcpResponse.js';
|
|
13
13
|
import { ClearcutLogger } from './telemetry/ClearcutLogger.js';
|
|
14
14
|
import { bucketizeLatency } from './telemetry/metricUtils.js';
|
|
15
|
-
import { McpServer, SetLevelRequestSchema
|
|
15
|
+
import { McpServer, SetLevelRequestSchema } from './third_party/index.js';
|
|
16
16
|
import { ToolCategory } from './tools/categories.js';
|
|
17
17
|
import { pageIdSchema } from './tools/ToolDefinition.js';
|
|
18
18
|
import { createTools } from './tools/tools.js';
|
|
@@ -50,9 +50,7 @@ export async function createMcpServer(serverArgs, options) {
|
|
|
50
50
|
wsEndpoint: serverArgs.wsEndpoint,
|
|
51
51
|
wsHeaders: serverArgs.wsHeaders,
|
|
52
52
|
// Important: only pass channel, if autoConnect is true.
|
|
53
|
-
channel: serverArgs.autoConnect
|
|
54
|
-
? serverArgs.channel
|
|
55
|
-
: undefined,
|
|
53
|
+
channel: serverArgs.autoConnect ? serverArgs.channel : undefined,
|
|
56
54
|
userDataDir: serverArgs.userDataDir,
|
|
57
55
|
devtools,
|
|
58
56
|
})
|
|
@@ -94,20 +92,17 @@ export async function createMcpServer(serverArgs, options) {
|
|
|
94
92
|
serverArgs.categoryNetwork === false) {
|
|
95
93
|
return;
|
|
96
94
|
}
|
|
97
|
-
if (tool.annotations.category === ToolCategory.EXTENSIONS &&
|
|
98
|
-
serverArgs.categoryExtensions === false) {
|
|
95
|
+
if (tool.annotations.category === ToolCategory.EXTENSIONS && !serverArgs.categoryExtensions) {
|
|
99
96
|
return;
|
|
100
97
|
}
|
|
101
|
-
if (tool.annotations.conditions?.includes('computerVision') &&
|
|
102
|
-
!serverArgs.experimentalVision) {
|
|
98
|
+
if (tool.annotations.conditions?.includes('computerVision') && !serverArgs.experimentalVision) {
|
|
103
99
|
return;
|
|
104
100
|
}
|
|
105
101
|
if (tool.annotations.conditions?.includes('experimentalInteropTools') &&
|
|
106
102
|
!serverArgs.experimentalInteropTools) {
|
|
107
103
|
return;
|
|
108
104
|
}
|
|
109
|
-
if (tool.annotations.conditions?.includes('screencast') &&
|
|
110
|
-
!serverArgs.experimentalScreencast) {
|
|
105
|
+
if (tool.annotations.conditions?.includes('screencast') && !serverArgs.experimentalScreencast) {
|
|
111
106
|
return;
|
|
112
107
|
}
|
|
113
108
|
const schema = 'pageScoped' in tool &&
|
|
@@ -133,9 +128,7 @@ export async function createMcpServer(serverArgs, options) {
|
|
|
133
128
|
? new SlimMcpResponse(serverArgs)
|
|
134
129
|
: new McpResponse(serverArgs);
|
|
135
130
|
if ('pageScoped' in tool && tool.pageScoped) {
|
|
136
|
-
const page = serverArgs.experimentalPageIdRouting &&
|
|
137
|
-
params.pageId &&
|
|
138
|
-
!serverArgs.slim
|
|
131
|
+
const page = serverArgs.experimentalPageIdRouting && params.pageId && !serverArgs.slim
|
|
139
132
|
? context.getPageById(params.pageId)
|
|
140
133
|
: context.getSelectedMcpPage();
|
|
141
134
|
response.setPage(page);
|
|
@@ -155,9 +148,6 @@ export async function createMcpServer(serverArgs, options) {
|
|
|
155
148
|
const result = {
|
|
156
149
|
content,
|
|
157
150
|
};
|
|
158
|
-
if (response.isError) {
|
|
159
|
-
result.isError = true;
|
|
160
|
-
}
|
|
161
151
|
success = true;
|
|
162
152
|
if (serverArgs.experimentalStructuredContent) {
|
|
163
153
|
result.structuredContent = structuredContent;
|
|
@@ -38,7 +38,7 @@ export const timeoutSchema = {
|
|
|
38
38
|
.int()
|
|
39
39
|
.optional()
|
|
40
40
|
.describe(`Maximum wait time in milliseconds. If set to 0, the default timeout will be used.`)
|
|
41
|
-
.transform(value => {
|
|
41
|
+
.transform((value) => {
|
|
42
42
|
return value && value <= 0 ? undefined : value;
|
|
43
43
|
}),
|
|
44
44
|
};
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { zod, PredefinedNetworkConditions } from '../third_party/index.js';
|
|
8
8
|
import { ToolCategory } from './categories.js';
|
|
9
|
-
import { definePageTool, geolocationTransform, viewportTransform
|
|
9
|
+
import { definePageTool, geolocationTransform, viewportTransform } from './ToolDefinition.js';
|
|
10
10
|
const throttlingOptions = [
|
|
11
11
|
'Offline',
|
|
12
12
|
...Object.keys(PredefinedNetworkConditions),
|
package/build/src/tools/input.js
CHANGED
|
@@ -34,9 +34,7 @@ export const click = definePageTool({
|
|
|
34
34
|
readOnlyHint: false,
|
|
35
35
|
},
|
|
36
36
|
schema: {
|
|
37
|
-
uid: zod
|
|
38
|
-
.string()
|
|
39
|
-
.describe('The uid of an element on the page from the page content snapshot'),
|
|
37
|
+
uid: zod.string().describe('The uid of an element on the page from the page content snapshot'),
|
|
40
38
|
dblClick: dblClickSchema,
|
|
41
39
|
includeSnapshot: includeSnapshotSchema,
|
|
42
40
|
},
|
|
@@ -101,9 +99,7 @@ export const hover = definePageTool({
|
|
|
101
99
|
readOnlyHint: false,
|
|
102
100
|
},
|
|
103
101
|
schema: {
|
|
104
|
-
uid: zod
|
|
105
|
-
.string()
|
|
106
|
-
.describe('The uid of an element on the page from the page content snapshot'),
|
|
102
|
+
uid: zod.string().describe('The uid of an element on the page from the page content snapshot'),
|
|
107
103
|
includeSnapshot: includeSnapshotSchema,
|
|
108
104
|
},
|
|
109
105
|
handler: async (request, response, context) => {
|
|
@@ -161,7 +157,7 @@ async function selectOption(handle, aXNode, value) {
|
|
|
161
157
|
}
|
|
162
158
|
}
|
|
163
159
|
function hasOptionChildren(aXNode) {
|
|
164
|
-
return aXNode.children.some(child => child.role === 'option');
|
|
160
|
+
return aXNode.children.some((child) => child.role === 'option');
|
|
165
161
|
}
|
|
166
162
|
async function fillFormElement(uid, value, context, page) {
|
|
167
163
|
const handle = await page.getElementByUid(uid);
|
|
@@ -194,9 +190,7 @@ export const fill = definePageTool({
|
|
|
194
190
|
readOnlyHint: false,
|
|
195
191
|
},
|
|
196
192
|
schema: {
|
|
197
|
-
uid: zod
|
|
198
|
-
.string()
|
|
199
|
-
.describe('The uid of an element on the page from the page content snapshot'),
|
|
193
|
+
uid: zod.string().describe('The uid of an element on the page from the page content snapshot'),
|
|
200
194
|
value: zod.string().describe('The value to fill in'),
|
|
201
195
|
includeSnapshot: includeSnapshotSchema,
|
|
202
196
|
},
|
|
@@ -251,7 +245,7 @@ export const drag = definePageTool({
|
|
|
251
245
|
try {
|
|
252
246
|
await context.waitForEventsAfterAction(async () => {
|
|
253
247
|
await fromHandle.drag(toHandle);
|
|
254
|
-
await new Promise(resolve => setTimeout(resolve, 50));
|
|
248
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
255
249
|
await toHandle.drop(fromHandle);
|
|
256
250
|
});
|
|
257
251
|
response.appendResponseLine(`Successfully dragged an element`);
|
package/build/src/tools/pages.js
CHANGED
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
import { logger } from '../logger.js';
|
|
7
7
|
import { zod } from '../third_party/index.js';
|
|
8
8
|
import { ToolCategory } from './categories.js';
|
|
9
|
-
import { CLOSE_PAGE_ERROR, definePageTool, defineTool, timeoutSchema
|
|
10
|
-
export const listPages = definePageTool(args => {
|
|
9
|
+
import { CLOSE_PAGE_ERROR, definePageTool, defineTool, timeoutSchema } from './ToolDefinition.js';
|
|
10
|
+
export const listPages = definePageTool((args) => {
|
|
11
11
|
return {
|
|
12
12
|
name: 'list_pages',
|
|
13
13
|
description: `Get a list of pages ${args?.categoryExtensions ? 'including extension service workers' : ''} open in the browser.`,
|
|
@@ -54,9 +54,7 @@ export const closePage = defineTool({
|
|
|
54
54
|
readOnlyHint: false,
|
|
55
55
|
},
|
|
56
56
|
schema: {
|
|
57
|
-
pageId: zod
|
|
58
|
-
.number()
|
|
59
|
-
.describe('The ID of the page to close. Call list_pages to list pages.'),
|
|
57
|
+
pageId: zod.number().describe('The ID of the page to close. Call list_pages to list pages.'),
|
|
60
58
|
},
|
|
61
59
|
handler: async (request, response, context) => {
|
|
62
60
|
try {
|
|
@@ -117,10 +115,7 @@ export const navigatePage = definePageTool({
|
|
|
117
115
|
.optional()
|
|
118
116
|
.describe('Navigate the page by URL, back or forward in history, or reload.'),
|
|
119
117
|
url: zod.string().optional().describe('Target URL (only type=url)'),
|
|
120
|
-
ignoreCache: zod
|
|
121
|
-
.boolean()
|
|
122
|
-
.optional()
|
|
123
|
-
.describe('Whether to ignore cache on reload.'),
|
|
118
|
+
ignoreCache: zod.boolean().optional().describe('Whether to ignore cache on reload.'),
|
|
124
119
|
handleBeforeUnload: zod
|
|
125
120
|
.enum(['accept', 'decline'])
|
|
126
121
|
.optional()
|
|
@@ -214,9 +209,7 @@ export const navigatePage = definePageTool({
|
|
|
214
209
|
finally {
|
|
215
210
|
page.pptrPage.off('dialog', dialogHandler);
|
|
216
211
|
if (initScriptId) {
|
|
217
|
-
await page.pptrPage
|
|
218
|
-
.removeScriptToEvaluateOnNewDocument(initScriptId)
|
|
219
|
-
.catch(error => {
|
|
212
|
+
await page.pptrPage.removeScriptToEvaluateOnNewDocument(initScriptId).catch((error) => {
|
|
220
213
|
logger(`Failed to remove init script`, error);
|
|
221
214
|
});
|
|
222
215
|
}
|
|
@@ -268,13 +261,8 @@ export const handleDialog = definePageTool({
|
|
|
268
261
|
readOnlyHint: false,
|
|
269
262
|
},
|
|
270
263
|
schema: {
|
|
271
|
-
action: zod
|
|
272
|
-
|
|
273
|
-
.describe('Whether to dismiss or accept the dialog'),
|
|
274
|
-
promptText: zod
|
|
275
|
-
.string()
|
|
276
|
-
.optional()
|
|
277
|
-
.describe('Optional prompt text to enter into the dialog.'),
|
|
264
|
+
action: zod.enum(['accept', 'dismiss']).describe('Whether to dismiss or accept the dialog'),
|
|
265
|
+
promptText: zod.string().optional().describe('Optional prompt text to enter into the dialog.'),
|
|
278
266
|
},
|
|
279
267
|
handler: async (request, response, _context) => {
|
|
280
268
|
const page = request.page;
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import zlib from 'node:zlib';
|
|
7
7
|
import { logger } from '../logger.js';
|
|
8
8
|
import { zod, DevTools } from '../third_party/index.js';
|
|
9
|
-
import { parseRawTraceBuffer, traceResultIsSuccess
|
|
9
|
+
import { parseRawTraceBuffer, traceResultIsSuccess } from '../trace-processing/parse.js';
|
|
10
10
|
import { ToolCategory } from './categories.js';
|
|
11
11
|
import { definePageTool } from './ToolDefinition.js';
|
|
12
12
|
const filePathSchema = zod
|
|
@@ -75,7 +75,7 @@ export const startTrace = definePageTool({
|
|
|
75
75
|
});
|
|
76
76
|
}
|
|
77
77
|
if (request.params.autoStop) {
|
|
78
|
-
await new Promise(resolve => setTimeout(resolve, 5_000));
|
|
78
|
+
await new Promise((resolve) => setTimeout(resolve, 5_000));
|
|
79
79
|
await stopTracingAndAppendOutput(page.pptrPage, response, context, request.params.filePath);
|
|
80
80
|
}
|
|
81
81
|
else {
|
|
@@ -173,7 +173,7 @@ async function populateCruxData(result) {
|
|
|
173
173
|
});
|
|
174
174
|
cruxSetting.set({ enabled: true });
|
|
175
175
|
// Gather URLs to fetch CrUX data for
|
|
176
|
-
const urls = [...(result.parsedTrace.insights?.values() ?? [])].map(c => c.url.toString());
|
|
176
|
+
const urls = [...(result.parsedTrace.insights?.values() ?? [])].map((c) => c.url.toString());
|
|
177
177
|
urls.push(result.parsedTrace.data.Meta.mainFrameURL);
|
|
178
178
|
const urlSet = new Set(urls);
|
|
179
179
|
if (urlSet.size === 0) {
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import { zod } from '../third_party/index.js';
|
|
7
7
|
import { ToolCategory } from './categories.js';
|
|
8
8
|
import { defineTool, pageIdSchema } from './ToolDefinition.js';
|
|
9
|
-
export const evaluateScript = defineTool(cliArgs => {
|
|
9
|
+
export const evaluateScript = defineTool((cliArgs) => {
|
|
10
10
|
return {
|
|
11
11
|
name: 'evaluate_script',
|
|
12
12
|
description: `Evaluate a JavaScript function inside the currently selected page. Returns the response as JSON,
|
|
@@ -27,9 +27,7 @@ Example with arguments: \`(el) => {
|
|
|
27
27
|
}\`
|
|
28
28
|
`),
|
|
29
29
|
args: zod
|
|
30
|
-
.array(zod
|
|
31
|
-
.string()
|
|
32
|
-
.describe('The uid of an element on the page from the page content snapshot'))
|
|
30
|
+
.array(zod.string().describe('The uid of an element on the page from the page content snapshot'))
|
|
33
31
|
.optional()
|
|
34
32
|
.describe(`An optional list of arguments to pass to the function.`),
|
|
35
33
|
...(cliArgs?.experimentalPageIdRouting ? pageIdSchema : {}),
|
|
@@ -43,7 +41,7 @@ Example with arguments: \`(el) => {
|
|
|
43
41
|
: {}),
|
|
44
42
|
},
|
|
45
43
|
handler: async (request, response, context) => {
|
|
46
|
-
const { serviceWorkerId, args: uidArgs, function: fnString, pageId
|
|
44
|
+
const { serviceWorkerId, args: uidArgs, function: fnString, pageId } = request.params;
|
|
47
45
|
if (cliArgs?.categoryExtensions && serviceWorkerId) {
|
|
48
46
|
if (uidArgs && uidArgs.length > 0) {
|
|
49
47
|
throw new Error('args (element uids) cannot be used when evaluating in a service worker.');
|
|
@@ -71,7 +69,7 @@ Example with arguments: \`(el) => {
|
|
|
71
69
|
await performEvaluation(evaluatable, fnString, args, response, context);
|
|
72
70
|
}
|
|
73
71
|
finally {
|
|
74
|
-
void Promise.allSettled(args.map(arg => arg.dispose()));
|
|
72
|
+
void Promise.allSettled(args.map((arg) => arg.dispose()));
|
|
75
73
|
}
|
|
76
74
|
},
|
|
77
75
|
};
|
package/build/src/tools/tools.js
CHANGED
|
@@ -17,7 +17,6 @@ import * as screenshotTools from './screenshot.js';
|
|
|
17
17
|
import * as scriptTools from './script.js';
|
|
18
18
|
import * as slimTools from './slim/tools.js';
|
|
19
19
|
import * as snapshotTools from './snapshot.js';
|
|
20
|
-
import * as webmcpTools from './webmcp.js';
|
|
21
20
|
export const createTools = (args) => {
|
|
22
21
|
const rawTools = args.slim
|
|
23
22
|
? Object.values(slimTools)
|
package/build/src/version.js
CHANGED
package/package.json
CHANGED
|
@@ -1,20 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mcp-b/chrome-devtools-mcp",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.0",
|
|
4
4
|
"description": "MCP server for Chrome DevTools",
|
|
5
5
|
"homepage": "https://github.com/WebMCP-org/npm-packages/tree/main/packages/chrome-devtools-mcp#readme",
|
|
6
6
|
"bugs": {
|
|
7
7
|
"url": "https://github.com/WebMCP-org/npm-packages/issues"
|
|
8
8
|
},
|
|
9
|
+
"license": "Apache-2.0",
|
|
10
|
+
"author": "Google LLC",
|
|
9
11
|
"repository": {
|
|
10
12
|
"type": "git",
|
|
11
13
|
"url": "git+https://github.com/WebMCP-org/npm-packages.git",
|
|
12
14
|
"directory": "packages/chrome-devtools-mcp"
|
|
13
15
|
},
|
|
14
|
-
"license": "Apache-2.0",
|
|
15
|
-
"author": "Google LLC",
|
|
16
|
-
"type": "module",
|
|
17
|
-
"main": "./build/src/index.js",
|
|
18
16
|
"bin": {
|
|
19
17
|
"chrome-devtools": "./build/src/bin/chrome-devtools.js",
|
|
20
18
|
"chrome-devtools-mcp": "./build/src/bin/chrome-devtools-mcp.js"
|
|
@@ -24,6 +22,12 @@
|
|
|
24
22
|
"LICENSE",
|
|
25
23
|
"!*.tsbuildinfo"
|
|
26
24
|
],
|
|
25
|
+
"type": "module",
|
|
26
|
+
"main": "./build/src/index.js",
|
|
27
|
+
"publishConfig": {
|
|
28
|
+
"access": "public",
|
|
29
|
+
"registry": "https://registry.npmjs.org/"
|
|
30
|
+
},
|
|
27
31
|
"devDependencies": {
|
|
28
32
|
"@eslint/js": "^9.35.0",
|
|
29
33
|
"@google/genai": "^1.37.0",
|
|
@@ -64,10 +68,6 @@
|
|
|
64
68
|
"engines": {
|
|
65
69
|
"node": "^20.19.0 || ^22.12.0 || >=23"
|
|
66
70
|
},
|
|
67
|
-
"publishConfig": {
|
|
68
|
-
"access": "public",
|
|
69
|
-
"registry": "https://registry.npmjs.org/"
|
|
70
|
-
},
|
|
71
71
|
"mcpName": "@mcp-b/chrome-devtools-mcp",
|
|
72
72
|
"upstream": {
|
|
73
73
|
"repository": "https://github.com/ChromeDevTools/chrome-devtools-mcp",
|
package/build/src/third_party/issue-descriptions/CoepCoopSandboxedIframeCannotNavigateToCoopPage.md
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
# An iframe navigation to a document with a Cross-Origin Opener Policy was blocked
|
|
2
|
-
|
|
3
|
-
A document with a Cross-Origin Opener Policy (COOP) was blocked from loading in an iframe, because the iframe specifies a sandbox attribute.
|
|
4
|
-
This protects COOP-enabled documents from inheriting properties from its opener.
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
# Specify a more permissive Cross-Origin Resource Policy to prevent a resource from being blocked
|
|
2
|
-
|
|
3
|
-
Your site tries to access an external resource that only allows same-origin usage.
|
|
4
|
-
This behavior prevents a document from loading any non-same-origin resources which don’t explicitly grant permission to be loaded.
|
|
5
|
-
|
|
6
|
-
To solve this, add the following to the resource’s HTML response header:
|
|
7
|
-
* `Cross-Origin-Resource-Policy: same-site` if the resource and your site are served from the same site.
|
|
8
|
-
* `Cross-Origin-Resource-Policy: cross-origin` if the resource is served from another location than your website. ⚠️If you set this header, any website can embed this resource.
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
# Specify a Cross-Origin Resource Policy to prevent a resource from being blocked
|
|
2
|
-
|
|
3
|
-
Because your site has the Cross-Origin Embedder Policy (COEP) enabled, each
|
|
4
|
-
resource must specify a suitable Cross-Origin Resource Policy (CORP). This
|
|
5
|
-
behavior prevents a document from loading cross-origin resources which don’t
|
|
6
|
-
explicitly grant permission to be loaded.
|
|
7
|
-
|
|
8
|
-
To solve this, add the following to the resource’ response header:
|
|
9
|
-
* `Cross-Origin-Resource-Policy: same-site` if the resource and your site are
|
|
10
|
-
served from the same site.
|
|
11
|
-
* `Cross-Origin-Resource-Policy: cross-origin` if the resource is served from
|
|
12
|
-
another location than your website. ⚠️If you set this header, any website can
|
|
13
|
-
embed this resource.
|
|
14
|
-
|
|
15
|
-
Alternatively, the document can use the variant: `Cross-Origin-Embedder-Policy:
|
|
16
|
-
credentialless` instead of `require-corp`. It allows loading the resource,
|
|
17
|
-
despite the missing CORP header, at the cost of requesting it without
|
|
18
|
-
credentials like Cookies.
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
# Specify a more permissive Cross-Origin Resource Policy to prevent a resource from being blocked
|
|
2
|
-
|
|
3
|
-
Your site tries to access an external resource that only allows same-site usage.
|
|
4
|
-
This behavior prevents a document from loading any non-same-site resources which don’t explicitly grant permission to be loaded.
|
|
5
|
-
|
|
6
|
-
To solve this, add the following to the resource’s HTML response header: `Cross-Origin-Resource-Policy: cross-origin`
|
|
7
|
-
⚠️If you set this header, any website can embed this resource.
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
# Specify a Cross-Origin Embedder Policy to prevent this frame from being blocked
|
|
2
|
-
|
|
3
|
-
Because your site has the Cross-Origin Embedder Policy (COEP) enabled, each
|
|
4
|
-
embedded iframe must also specify this policy. This behavior protects private
|
|
5
|
-
data from being exposed to untrusted third party sites.
|
|
6
|
-
|
|
7
|
-
To solve this, add one of following to the embedded frame’s HTML response
|
|
8
|
-
header:
|
|
9
|
-
* `Cross-Origin-Embedder-Policy: require-corp`
|
|
10
|
-
* `Cross-Origin-Embedder-Policy: credentialless` (Chrome > 96)
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
# Page layout may be unexpected due to Quirks Mode
|
|
2
|
-
|
|
3
|
-
One or more documents in this page is in Quirks Mode, which will render the affected document(s) with quirks incompatible with the current HTML and CSS specifications.
|
|
4
|
-
|
|
5
|
-
Quirks Mode exists mostly due to historical reasons. If this is not intentional, you can [add or modify the DOCTYPE to be `<!DOCTYPE html>`](issueQuirksModeDoctype) to render the page in No Quirks Mode.
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
# Ensure cookie attribute values don’t exceed 1024 characters
|
|
2
|
-
|
|
3
|
-
Cookie attribute values exceeding 1024 characters in size will result in the attribute being ignored. This could lead to unexpected behavior since the cookie will be processed as if the offending attribute / attribute value pair were not present.
|
|
4
|
-
|
|
5
|
-
Resolve this issue by ensuring that cookie attribute values don’t exceed 1024 characters.
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
# Users may have difficulties reading text content due to insufficient color contrast
|
|
2
|
-
|
|
3
|
-
Low-contrast text is difficult or impossible for users to read. A [minimum contrast ratio (AA) of 4.5](issuesContrastWCAG21AA) is recommended for all text. Since font size and weight affect color perception, an exception is made for very large or bold text — in this case, a contrast ratio of 3.0 is allowed. The [enhanced conformance level (AAA)](issuesContrastWCAG21AAA) requires the contrast ratio to be above 7.0 for regular text and 4.5 for large text.
|
|
4
|
-
|
|
5
|
-
Update colors or change the font size or weight to achieve sufficient contrast. You can use the [“Suggest color” feature](issuesContrastSuggestColor) in the DevTools color picker to automatically select a better text color.
|