From 1f33030d0bd0ef705d19c11937d3135aabcbb04e Mon Sep 17 00:00:00 2001 From: Ted Werbel Date: Tue, 11 Mar 2025 00:42:19 +0900 Subject: [PATCH] added audit and debugger mode --- browser-tools-mcp/mcp-server.ts | 760 ++++++++++++++++++++++++++++ browser-tools-mcp/package-lock.json | 126 ++++- 2 files changed, 884 insertions(+), 2 deletions(-) diff --git a/browser-tools-mcp/mcp-server.ts b/browser-tools-mcp/mcp-server.ts index 6eeb585..9916891 100644 --- a/browser-tools-mcp/mcp-server.ts +++ b/browser-tools-mcp/mcp-server.ts @@ -577,6 +577,766 @@ server.tool( } ); +server.tool("runNextJSAudit", {}, async () => ({ + content: [ + { + type: "text", + text: ` + You are an expert in SEO and web development with NextJS. Given the following procedures for analyzing my codebase, please perform a comprehensive - page by page analysis of our NextJS application to identify any issues or areas of improvement for SEO. + + After each iteration of changes, reinvoke this tool to re-fetch our SEO audit procedures and then scan our codebase again to identify additional areas of improvement. + + When no more areas of improvement are found, return "No more areas of improvement found, your NextJS application is optimized for SEO!". + + Start by analyzing each of the following aspects of our codebase: + 1. Meta tags - provides information about your website to search engines and social media platforms. + + Pages should provide the following standard meta tags: + + title + description + keywords + robots + viewport + charSet + Open Graph meta tags: + + og:site_name + og:locale + og:title + og:description + og:type + og:url + og:image + og:image:alt + og:image:type + og:image:width + og:image:height + Article meta tags (actually it's also OpenGraph): + + article:published_time + article:modified_time + article:author + Twitter meta tags: + + twitter:card + twitter:site + twitter:creator + twitter:title + twitter:description + twitter:image + + For applications using the pages router, set up metatags like this in pages/[slug].tsx: + import Head from "next/head"; + + export default function Page() { + return ( + + + Next.js SEO: The Complete Checklist to Boost Your Site Ranking + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); + } + + For applications using the app router, set up metatags like this in layout.tsx: + import type { Viewport, Metadata } from "next"; + + export const viewport: Viewport = { + width: "device-width", + initialScale: 1, + themeColor: "#ffffff" + }; + + export const metadata: Metadata = { + metadataBase: new URL("https://dminhvu.com"), + openGraph: { + siteName: "Blog | Minh Vu", + type: "website", + locale: "en_US" + }, + robots: { + index: true, + follow: true, + "max-image-preview": "large", + "max-snippet": -1, + "max-video-preview": -1, + googleBot: "index, follow" + }, + alternates: { + types: { + "application/rss+xml": "https://dminhvu.com/rss.xml" + } + }, + applicationName: "Blog | Minh Vu", + appleWebApp: { + title: "Blog | Minh Vu", + statusBarStyle: "default", + capable: true + }, + verification: { + google: "YOUR_DATA", + yandex: ["YOUR_DATA"], + other: { + "msvalidate.01": ["YOUR_DATA"], + "facebook-domain-verification": ["YOUR_DATA"] + } + }, + icons: { + icon: [ + { + url: "/favicon.ico", + type: "image/x-icon" + }, + { + url: "/favicon-16x16.png", + sizes: "16x16", + type: "image/png" + } + // add favicon-32x32.png, favicon-96x96.png, android-chrome-192x192.png + ], + shortcut: [ + { + url: "/favicon.ico", + type: "image/x-icon" + } + ], + apple: [ + { + url: "/apple-icon-57x57.png", + sizes: "57x57", + type: "image/png" + }, + { + url: "/apple-icon-60x60.png", + sizes: "60x60", + type: "image/png" + } + // add apple-icon-72x72.png, apple-icon-76x76.png, apple-icon-114x114.png, apple-icon-120x120.png, apple-icon-144x144.png, apple-icon-152x152.png, apple-icon-180x180.png + ] + } + }; + And like this for any page.tsx file: + import { Metadata } from "next"; + + export const metadata: Metadata = { + title: "Elastic Stack, Next.js, Python, JavaScript Tutorials | dminhvu", + description: + "dminhvu.com - Programming blog for everyone to learn Elastic Stack, Next.js, Python, JavaScript, React, Machine Learning, Data Science, and more.", + keywords: [ + "elastic", + "python", + "javascript", + "react", + "machine learning", + "data science" + ], + openGraph: { + url: "https://dminhvu.com", + type: "website", + title: "Elastic Stack, Next.js, Python, JavaScript Tutorials | dminhvu", + description: + "dminhvu.com - Programming blog for everyone to learn Elastic Stack, Next.js, Python, JavaScript, React, Machine Learning, Data Science, and more.", + images: [ + { + url: "https://dminhvu.com/images/home/thumbnail.png", + width: 1200, + height: 630, + alt: "dminhvu" + } + ] + }, + twitter: { + card: "summary_large_image", + title: "Elastic Stack, Next.js, Python, JavaScript Tutorials | dminhvu", + description: + "dminhvu.com - Programming blog for everyone to learn Elastic Stack, Next.js, Python, JavaScript, React, Machine Learning, Data Science, and more.", + creator: "@dminhvu02", + site: "@dminhvu02", + images: [ + { + url: "https://dminhvu.com/images/home/thumbnail.png", + width: 1200, + height: 630, + alt: "dminhvu" + } + ] + }, + alternates: { + canonical: "https://dminhvu.com" + } + }; + + Note that the charSet and viewport are automatically added by Next.js App Router, so you don't need to define them. + + For applications using the app router, dynamic metadata can be defined by using the generateMetadata function, this is useful when you have dynamic pages like [slug]/page.tsx, or [id]/page.tsx: + + import type { Metadata, ResolvingMetadata } from "next"; + + type Params = { + slug: string; + }; + + type Props = { + params: Params; + searchParams: { [key: string]: string | string[] | undefined }; + }; + + export async function generateMetadata( + { params, searchParams }: Props, + parent: ResolvingMetadata + ): Promise { + const { slug } = params; + + const post: Post = await fetch("YOUR_ENDPOINT", { + method: "GET", + next: { + revalidate: 60 * 60 * 24 + } + }).then((res) => res.json()); + + return { + title: "{post.title} | dminhvu", + authors: [ + { + name: post.author || "Minh Vu" + } + ], + description: post.description, + keywords: post.keywords, + openGraph: { + title: "{post.title} | dminhvu", + description: post.description, + type: "article", + url: "https://dminhvu.com/{post.slug}", + publishedTime: post.created_at, + modifiedTime: post.modified_at, + authors: ["https://dminhvu.com/about"], + tags: post.categories, + images: [ + { + url: "https://ik.imagekit.io/dminhvu/assets/{post.slug}/thumbnail.png?tr=f-png", + width: 1024, + height: 576, + alt: post.title, + type: "image/png" + } + ] + }, + twitter: { + card: "summary_large_image", + site: "@dminhvu02", + creator: "@dminhvu02", + title: "{post.title} | dminhvu", + description: post.description, + images: [ + { + url: "https://ik.imagekit.io/dminhvu/assets/{post.slug}/thumbnail.png?tr=f-png", + width: 1024, + height: 576, + alt: post.title + } + ] + }, + alternates: { + canonical: "https://dminhvu.com/{post.slug}" + } + }; + } + + + 2. JSON-LD Schema + + JSON-LD is a format for structured data that can be used by search engines to understand your content. For example, you can use it to describe a person, an event, an organization, a movie, a book, a recipe, and many other types of entities. + + Our current recommendation for JSON-LD is to render structured data as a + + )} + + ); + } + Script Optimization for Common Third-Party Integrations + Next.js App Router introduces a new library called @next/third-parties for: + + Google Tag Manager + Google Analytics + Google Maps Embed + YouTube Embed + To use the @next/third-parties library, you need to install it: + + + npm install @next/third-parties + Then, you can add the following code to your app/layout.tsx: + + app/layout.tsx + + import { GoogleTagManager } from "@next/third-parties/google"; + import { GoogleAnalytics } from "@next/third-parties/google"; + import Head from "next/head"; + + export default function Page() { + return ( + + {process.env.NODE_ENV === "production" && ( + <> + + {/* other scripts */} + + )} + {/* other parts */} + + ); + } + Please note that you don't need to include both GoogleTagManager and GoogleAnalytics if you only use one of them. + 7. Image optimization + Image Optimization + This part can be applied to both Pages Router and App Router. + + Image optimization is also an important part of SEO as it helps your website load faster. + + Faster image rendering speed will contribute to the Google PageSpeed score, which can improve user experience and SEO. + + You can use next/image to optimize images in your Next.js website. + + For example, the following code will optimize this post thumbnail: + + + import Image from "next/image"; + + export default function Page() { + return ( + Next.js SEO + ); + } + Remember to use a CDN to serve your media (images, videos, etc.) to improve the loading speed. + + For the image format, use WebP if possible because it has a smaller size than PNG and JPEG. + `, + }, + ], +})); + +server.tool( + "runDebuggerMode", + "Run debugger mode to debug an issue in our application", + async () => ({ + content: [ + { + type: "text", + text: ` + Please follow this exact sequence to debug an issue in our application: + + 1. Reflect on 5-7 different possible sources of the problem + 2. Distill those down to 1-2 most likely sources + 3. Add additional logs to validate your assumptions and track the transformation of data structures throughout the application control flow before we move onto implementing the actual code fix + 4. Use the "getConsoleLogs", "getConsoleErrors", "getNetworkLogs" & "getNetworkErrors" tools to obtain any newly added web browser logs + 5. Obtain the server logs as well if accessible - otherwise, ask me to copy/paste them into the chat + 6. Deeply reflect on what could be wrong + produce a comprehensive analysis of the issue + 7. Suggest additional logs if the issue persists or if the source is not yet clear + 8. Once a fix is implemented, ask for approval to remove the previously added logs +`, + }, + ], + }) +); + +server.tool( + "runAuditMode", + "Run audit mode to optimize our application for SEO, accessibility and performance", + async () => ({ + content: [ + { + type: "text", + text: ` + I want you to enter "Audit Mode". Use the following MCP tools one after the other in this exact sequence: + + 1. runAccessibilityAudit + 2. runPerformanceAudit + 3. runBestPracticesAudit + 4. runSEOAudit + 5. runNextJSAudit (only if our application is ACTUALLY using NextJS) + + After running all of these tools, return back a comprehensive analysis of the audit results. + + Do NOT use runNextJSAudit tool unless you see that our application is ACTUALLY using NextJS. + + DO NOT use the takeScreenshot tool EVER during audit mode. ONLY use it if I specifically ask you to take a screenshot of something. + + DO NOT check console or network logs to get started - your main priority is to run the audits in the sequence defined above. + + After returning an in-depth analysis, scan through my code and identify various files/parts of my codebase that we want to modify/improve based on the results of our audits. + + After identifying what changes may be needed, do NOT make the actual changes. Instead, return back a comprehensive, step-by-step plan to address all of these changes and ask for approval to execute this plan. If feedback is received, make a new plan and ask for approval again. If approved, execute the ENTIRE plan and after all phases/steps are complete, re-run the auditing tools in the same 4 step sequence again before returning back another analysis for additional changes potentially needed. + + Keep repeating / iterating through this process with the four tools until our application is as optimized as possible for SEO, accessibility and performance. + +`, + }, + ], + }) +); + // Add tool for Best Practices audits, launches a headless browser instance server.tool( "runBestPracticesAudit", diff --git a/browser-tools-mcp/package-lock.json b/browser-tools-mcp/package-lock.json index 262052e..43c2781 100644 --- a/browser-tools-mcp/package-lock.json +++ b/browser-tools-mcp/package-lock.json @@ -1,12 +1,12 @@ { "name": "@agentdeskai/browser-tools-mcp", - "version": "1.0.11", + "version": "1.1.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@agentdeskai/browser-tools-mcp", - "version": "1.0.11", + "version": "1.1.1", "license": "MIT", "dependencies": { "@modelcontextprotocol/sdk": "^1.4.1", @@ -14,6 +14,7 @@ "cors": "^2.8.5", "express": "^4.21.2", "llm-cost": "^1.0.5", + "node-fetch": "^2.7.0", "ws": "^8.18.0" }, "bin": { @@ -24,6 +25,7 @@ "@types/cors": "^2.8.17", "@types/express": "^5.0.0", "@types/node": "^22.13.1", + "@types/node-fetch": "^2.6.11", "@types/ws": "^8.5.14", "typescript": "^5.7.3" } @@ -116,6 +118,16 @@ "undici-types": "~6.20.0" } }, + "node_modules/@types/node-fetch": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.12.tgz", + "integrity": "sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==", + "dev": true, + "dependencies": { + "@types/node": "*", + "form-data": "^4.0.0" + } + }, "node_modules/@types/qs": { "version": "6.9.18", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.18.tgz", @@ -175,6 +187,12 @@ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true + }, "node_modules/body-parser": { "version": "1.20.3", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", @@ -247,6 +265,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -299,6 +329,15 @@ "ms": "2.0.0" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -369,6 +408,21 @@ "node": ">= 0.4" } }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -463,6 +517,21 @@ "node": ">= 0.8" } }, + "node_modules/form-data": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz", + "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -544,6 +613,21 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", @@ -677,6 +761,25 @@ "node": ">= 0.6" } }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -947,6 +1050,11 @@ "node": ">=0.6" } }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, "node_modules/type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", @@ -1002,6 +1110,20 @@ "node": ">= 0.8" } }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/ws": { "version": "8.18.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz",