Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file removed .DS_Store
Binary file not shown.
101 changes: 68 additions & 33 deletions browser-tools-mcp/mcp-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -264,14 +264,49 @@ server.tool(
const result = await response.json();

if (response.ok) {
return {
content: [
{
type: "text",
text: "Successfully saved screenshot",
},
],
};
// If we have a file path, read the image directly from disk
if (result.path && typeof result.path === 'string') {
try {
const fs = await import('fs');
const imageBuffer = fs.readFileSync(result.path);
const base64Data = imageBuffer.toString('base64');

return {
content: [
{
type: "image",
data: base64Data,
mimeType: "image/png",
},
{
type: "text",
text: `Screenshot captured successfully and saved to: ${result.path}`,
},
],
};
} catch (fileError) {
// If we can't read the file, fall back to text response
console.error("Failed to read screenshot file:", fileError);
return {
content: [
{
type: "text",
text: `Screenshot saved to: ${result.path} (but couldn't load image data)`,
},
],
};
}
} else {
// Fallback to text response if no path
return {
content: [
{
type: "text",
text: "Successfully saved screenshot",
},
],
};
}
} else {
return {
content: [
Expand Down Expand Up @@ -584,7 +619,7 @@ server.tool("runNextJSAudit", {}, async () => ({
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.
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!".

Expand Down Expand Up @@ -706,7 +741,7 @@ server.tool("runNextJSAudit", {}, async () => ({
initialScale: 1,
themeColor: "#ffffff"
};

export const metadata: Metadata = {
metadataBase: new URL("https://dminhvu.com"),
openGraph: {
Expand Down Expand Up @@ -835,25 +870,25 @@ server.tool("runNextJSAudit", {}, async () => ({
type Params = {
slug: string;
};

type Props = {
params: Params;
searchParams: { [key: string]: string | string[] | undefined };
};

export async function generateMetadata(
{ params, searchParams }: Props,
parent: ResolvingMetadata
): Promise<Metadata> {
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: [
Expand Down Expand Up @@ -903,7 +938,7 @@ server.tool("runNextJSAudit", {}, async () => ({
};
}


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.
Expand All @@ -912,15 +947,15 @@ server.tool("runNextJSAudit", {}, async () => ({
export default async function Page({ params }) {
const { id } = await params
const product = await getProduct(id)

const jsonLd = {
'@context': 'https://schema.org',
'@type': 'Product',
name: product.name,
image: product.image,
description: product.description,
}

return (
<section>
{/* Add JSON-LD to your page */}
Expand All @@ -932,12 +967,12 @@ server.tool("runNextJSAudit", {}, async () => ({
</section>
)
}

You can type your JSON-LD with TypeScript using community packages like schema-dts:


import { Product, WithContext } from 'schema-dts'

const jsonLd: WithContext<Product> = {
'@context': 'https://schema.org',
'@type': 'Product',
Expand Down Expand Up @@ -981,7 +1016,7 @@ server.tool("runNextJSAudit", {}, async () => ({
getAllPostSlugsWithModifyTime
} from "@/utils/getData";
import { MetadataRoute } from "next";

export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
const defaultPages = [
{
Expand All @@ -1004,10 +1039,10 @@ server.tool("runNextJSAudit", {}, async () => ({
}
// other pages
];

const postSlugs = await getAllPostSlugsWithModifyTime();
const categorySlugs = await getAllCategories();

const sitemap = [
...defaultPages,
...postSlugs.map((e: any) => ({
Expand All @@ -1023,7 +1058,7 @@ server.tool("runNextJSAudit", {}, async () => ({
priority: 0.7
}))
];

return sitemap;
}
With this sitemap.ts file created, you can access the sitemap at https://dminhvu.com/sitemap.xml.
Expand Down Expand Up @@ -1062,7 +1097,7 @@ server.tool("runNextJSAudit", {}, async () => ({
app/robots.ts

import { MetadataRoute } from "next";

export default function robots(): MetadataRoute.Robots {
return {
rules: {
Expand All @@ -1080,7 +1115,7 @@ server.tool("runNextJSAudit", {}, async () => ({
Allow: /
Disallow: /search?q=
Disallow: /admin

Sitemap: https://dminhvu.com/sitemap.xml
5. Link tags
Link Tags for Next.js Pages Router
Expand All @@ -1089,7 +1124,7 @@ server.tool("runNextJSAudit", {}, async () => ({
pages/_app.tsx

import Head from "next/head";

export default function Page() {
return (
<Head>
Expand All @@ -1116,7 +1151,7 @@ server.tool("runNextJSAudit", {}, async () => ({
pages/[slug].tsx

import Head from "next/head";

export default function Page() {
return (
<Head>
Expand Down Expand Up @@ -1191,7 +1226,7 @@ server.tool("runNextJSAudit", {}, async () => ({

import Head from "next/head";
import Script from "next/script";

export default function Page() {
return (
<Head>
Expand Down Expand Up @@ -1229,7 +1264,7 @@ server.tool("runNextJSAudit", {}, async () => ({
import { GoogleTagManager } from "@next/third-parties/google";
import { GoogleAnalytics } from "@next/third-parties/google";
import Head from "next/head";

export default function Page() {
return (
<html lang="en" className="scroll-smooth" suppressHydrationWarning>
Expand Down Expand Up @@ -1258,7 +1293,7 @@ server.tool("runNextJSAudit", {}, async () => ({


import Image from "next/image";

export default function Page() {
return (
<Image
Expand Down Expand Up @@ -1293,7 +1328,7 @@ server.tool(
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
Expand All @@ -1319,7 +1354,7 @@ server.tool(
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
Expand All @@ -1333,7 +1368,7 @@ server.tool(
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.
Expand Down
4 changes: 2 additions & 2 deletions browser-tools-mcp/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

29 changes: 16 additions & 13 deletions browser-tools-server/browser-connector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1076,15 +1076,15 @@ export class BrowserConnector {
const appleScript = `
-- Set path to the screenshot
set imagePath to "${fullPath}"

-- Copy the image to clipboard
try
set the clipboard to (read (POSIX file imagePath) as «class PNGf»)
on error errMsg
log "Error copying image to clipboard: " & errMsg
return "Failed to copy image to clipboard: " & errMsg
end try

-- Activate Cursor application
try
tell application "Cursor"
Expand All @@ -1094,10 +1094,10 @@ export class BrowserConnector {
log "Error activating Cursor: " & errMsg
return "Failed to activate Cursor: " & errMsg
end try

-- Wait for the application to fully activate
delay 3

-- Try to interact with Cursor
try
tell application "System Events"
Expand All @@ -1106,12 +1106,12 @@ export class BrowserConnector {
if (count of windows) is 0 then
return "No windows found in Cursor"
end if

set cursorWindow to window 1

-- Try Method 1: Look for elements of class "Text Area"
set foundElements to {}

-- Try different selectors to find the text input area
try
-- Try with class
Expand All @@ -1120,7 +1120,7 @@ export class BrowserConnector {
set foundElements to textAreas
end if
end try

if (count of foundElements) is 0 then
try
-- Try with AXTextField role
Expand All @@ -1130,7 +1130,7 @@ export class BrowserConnector {
end if
end try
end if

if (count of foundElements) is 0 then
try
-- Try with AXTextArea role in nested elements
Expand All @@ -1149,7 +1149,7 @@ export class BrowserConnector {
end repeat
end try
end if

-- If no elements found with specific attributes, try a broader approach
if (count of foundElements) is 0 then
-- Just try to use the Command+V shortcut on the active window
Expand All @@ -1166,16 +1166,16 @@ export class BrowserConnector {
else
-- We found a potential text input element
set inputElement to item 1 of foundElements

-- Try to focus and paste
try
set focused of inputElement to true
delay 0.5

-- Paste the image
keystroke "v" using command down
delay 1

-- Type the text
keystroke "here is the screenshot"
delay 1
Expand Down Expand Up @@ -1232,8 +1232,11 @@ export class BrowserConnector {
}

res.json({
success: true,
path: fullPath,
filename: filename,
data: base64Data, // Include the original base64 data with data URL prefix
message: "Screenshot captured and saved successfully",
});
} catch (error) {
const errorMessage =
Expand Down
Loading