# Directory Structure ``` ├── .gitignore ├── index.ts ├── LICENSE ├── package copy.json ├── package-lock.json ├── package.json ├── README.md └── tsconfig.json ``` # Files -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- ``` node_modules/ build/ .env *.log .DS_Store .idea/ .vscode/ ``` -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- ```markdown # @enemyrr/mcp-server-pagespeed A Model Context Protocol server that provides Google PageSpeed Insights analysis. This server enables AI models to analyze webpage performance through a standardized interface. <a href="https://glama.ai/mcp/servers/wes81w8il2"><img width="380" height="200" src="https://glama.ai/mcp/servers/wes81w8il2/badge" alt="Server Pagespeed MCP server" /></a> ## Installation & Setup for Cursor IDE 1. Clone and build the project: ```bash git clone https://github.com/enemyrr/mcp-server-pagespeed.git cd mcp-server-pagespeed npm install npm run build ``` 2. Add the server in Cursor IDE settings: - Open Command Palette (Cmd/Ctrl + Shift + P) - Search for "MCP: Add Server" - Fill in the fields: - Name: `pagespeed` - Type: `command` - Command: `node /absolute/path/to/mcp-server-pagespeed/build/index.js` > **Note**: Replace `/absolute/path/to/` with the actual path where you cloned and built the project. ## Command-line Usage Just run: ```bash npx mcp-server-pagespeed ``` ## Available Tools ### analyze_pagespeed Analyze a webpage using Google PageSpeed Insights API. ```typescript use_mcp_tool({ server_name: "pagespeed", tool_name: "analyze_pagespeed", arguments: { url: "https://example.com" } }); ``` The tool returns: - Overall performance score (0-100) - Loading experience metrics - First Contentful Paint - First Input Delay - Top 5 improvement suggestions with: - Title - Description - Potential impact - Current value ## Features - Real-time webpage performance analysis - Detailed loading experience metrics - Prioritized improvement suggestions - Comprehensive error handling - TypeScript support ## Error Handling The server provides detailed error messages for: - Invalid URLs - API request failures - Connection issues - Invalid tool calls ## Contributing Contributions are welcome! Please feel free to submit a Pull Request to https://github.com/enemyrr/mcp-server-pagespeed ## License MIT ``` -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- ```json { "compilerOptions": { "target": "es2020", "module": "es2020", "moduleResolution": "node", "outDir": "./build", "rootDir": "./", "strict": true, "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true }, "include": [ "*.ts" ], "exclude": [ "node_modules" ] } ``` -------------------------------------------------------------------------------- /package copy.json: -------------------------------------------------------------------------------- ```json { "name": "@enemyrr/mcp-mysql-server", "version": "0.1.0", "description": "A Model Context Protocol server for MySQL database operations", "type": "module", "bin": { "mcp-mysql": "./build/index.js" }, "files": [ "build" ], "scripts": { "build": "tsc && node -e \"require('fs').chmodSync('build/index.js', '755')\"", "prepare": "npm run build", "watch": "tsc --watch", "inspector": "npx @modelcontextprotocol/inspector build/index.js" }, "keywords": [ "mcp", "model-context-protocol", "mysql", "database", "claude", "anthropic" ], "author": "enemyrr", "license": "MIT", "dependencies": { "@modelcontextprotocol/sdk": "0.6.0", "dotenv": "^16.4.7", "mysql2": "^3.11.5" }, "devDependencies": { "@types/node": "^20.11.24", "typescript": "^5.3.3" }, "repository": { "type": "git", "url": "https://github.com/enemyrr/mcp-mysql-server" }, "publishConfig": { "access": "public" } } ``` -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- ```json { "name": "mcp-server-pagespeed", "version": "1.0.0", "description": "A Model Context Protocol server for Google PageSpeed Insights", "type": "module", "bin": { "mcp-pagespeed": "./build/index.js" }, "files": [ "build" ], "main": "build/index.js", "scripts": { "build": "tsc && node -e \"require('fs').chmodSync('build/index.js', '755')\"", "prepare": "npm run build", "watch": "tsc --watch", "start": "node build/index.js", "dev": "ts-node --esm index.ts", "inspector": "npx @modelcontextprotocol/inspector build/index.js" }, "keywords": [ "mcp", "model-context-protocol", "pagespeed", "google", "performance" ], "author": "@enemyrr", "license": "MIT", "dependencies": { "@modelcontextprotocol/sdk": "0.6.0", "axios": "^1.6.7" }, "devDependencies": { "@types/node": "^20.11.19", "ts-node": "^10.9.2", "typescript": "^5.3.3" }, "repository": { "type": "git", "url": "https://github.com/enemyrr/mcp-server-pagespeed" }, "publishConfig": { "access": "public" } } ``` -------------------------------------------------------------------------------- /index.ts: -------------------------------------------------------------------------------- ```typescript #!/usr/bin/env node import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { ErrorCode, ListToolsRequestSchema, CallToolRequestSchema } from '@modelcontextprotocol/sdk/types.js'; import axios from 'axios'; interface PageSpeedInsight { score: number; title: string; description: string; displayValue?: string; } interface ProcessedPageSpeedResult { performanceScore: number; insights: PageSpeedInsight[]; loadingExperience: { firstContentfulPaint: { category: string; percentile: number; }; firstInputDelay: { category: string; percentile: number; }; }; } class PageSpeedServer { private server: Server; constructor() { this.server = new Server( { name: 'pagespeed-server', version: '1.0.0', }, { capabilities: { tools: {}, }, } ); this.setupToolHandlers(); this.server.onerror = (error) => console.error('[MCP Error]', error); } private setupToolHandlers() { this.server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: [ { name: 'analyze_pagespeed', description: 'Analyzes a webpage using Google PageSpeed Insights API', inputSchema: { type: 'object', properties: { url: { type: 'string', description: 'The URL to analyze' } }, required: ['url'] } } ] })); this.server.setRequestHandler(CallToolRequestSchema, async (request) => { if (request.params.name === 'analyze_pagespeed') { const { url } = request.params.arguments as { url: string }; try { const response = await axios.get<any>( `https://www.googleapis.com/pagespeedonline/v5/runPagespeed?url=${encodeURIComponent(url)}` ); const result = response.data; const processedResult: ProcessedPageSpeedResult = { performanceScore: Math.round(result.lighthouseResult.categories.performance.score * 100), insights: [], loadingExperience: { firstContentfulPaint: { category: result.loadingExperience?.metrics?.FIRST_CONTENTFUL_PAINT_MS?.category || 'N/A', percentile: result.loadingExperience?.metrics?.FIRST_CONTENTFUL_PAINT_MS?.percentile || 0 }, firstInputDelay: { category: result.loadingExperience?.metrics?.FIRST_INPUT_DELAY_MS?.category || 'N/A', percentile: result.loadingExperience?.metrics?.FIRST_INPUT_DELAY_MS?.percentile || 0 } } }; // Process audits and extract insights const audits = result.lighthouseResult.audits; for (const [key, audit] of Object.entries(audits)) { const typedAudit = audit as any; if (typedAudit.score !== null && typedAudit.score < 1) { processedResult.insights.push({ score: typedAudit.score, title: typedAudit.title, description: typedAudit.description, displayValue: typedAudit.displayValue }); } } // Sort insights by score (lowest first) processedResult.insights.sort((a, b) => a.score - b.score); return { content: [ { type: 'text', text: JSON.stringify({ summary: `Your page performance score is ${processedResult.performanceScore}/100`, loadingExperience: { firstContentfulPaint: `${processedResult.loadingExperience.firstContentfulPaint.category} (${processedResult.loadingExperience.firstContentfulPaint.percentile}ms)`, firstInputDelay: `${processedResult.loadingExperience.firstInputDelay.category} (${processedResult.loadingExperience.firstInputDelay.percentile}ms)` }, topImprovements: processedResult.insights.slice(0, 5).map(insight => ({ title: insight.title, description: insight.description, impact: Math.round((1 - insight.score) * 100) + '% improvement possible', currentValue: insight.displayValue })) }, null, 2) } ] }; } catch (error) { console.error('Error analyzing URL:', error); throw { code: ErrorCode.InternalError, message: 'Failed to analyze URL', details: error instanceof Error ? error.message : 'Unknown error' }; } } throw { code: ErrorCode.MethodNotFound, message: `Unknown tool: ${request.params.name}` }; }); } async run() { const transport = new StdioServerTransport(); await this.server.connect(transport); console.error('PageSpeed MCP server running on stdio'); } } const server = new PageSpeedServer(); server.run().catch(console.error); ```