@rog0x/mcp-seo-tools 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/README.md +105 -0
  2. package/dist/index.d.ts +3 -0
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +175 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/tools/heading-checker.d.ts +15 -0
  7. package/dist/tools/heading-checker.d.ts.map +1 -0
  8. package/dist/tools/heading-checker.js +123 -0
  9. package/dist/tools/heading-checker.js.map +1 -0
  10. package/dist/tools/keyword-density.d.ts +22 -0
  11. package/dist/tools/keyword-density.d.ts.map +1 -0
  12. package/dist/tools/keyword-density.js +176 -0
  13. package/dist/tools/keyword-density.js.map +1 -0
  14. package/dist/tools/link-checker.d.ts +22 -0
  15. package/dist/tools/link-checker.d.ts.map +1 -0
  16. package/dist/tools/link-checker.js +171 -0
  17. package/dist/tools/link-checker.js.map +1 -0
  18. package/dist/tools/meta-analyzer.d.ts +27 -0
  19. package/dist/tools/meta-analyzer.d.ts.map +1 -0
  20. package/dist/tools/meta-analyzer.js +161 -0
  21. package/dist/tools/meta-analyzer.js.map +1 -0
  22. package/dist/tools/page-speed.d.ts +31 -0
  23. package/dist/tools/page-speed.d.ts.map +1 -0
  24. package/dist/tools/page-speed.js +180 -0
  25. package/dist/tools/page-speed.js.map +1 -0
  26. package/dist/tools/sitemap-parser.d.ts +29 -0
  27. package/dist/tools/sitemap-parser.d.ts.map +1 -0
  28. package/dist/tools/sitemap-parser.js +224 -0
  29. package/dist/tools/sitemap-parser.js.map +1 -0
  30. package/package.json +24 -0
  31. package/src/index.ts +199 -0
  32. package/src/tools/heading-checker.ts +109 -0
  33. package/src/tools/keyword-density.ts +180 -0
  34. package/src/tools/link-checker.ts +163 -0
  35. package/src/tools/meta-analyzer.ts +148 -0
  36. package/src/tools/page-speed.ts +190 -0
  37. package/src/tools/sitemap-parser.ts +230 -0
  38. package/tsconfig.json +19 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keyword-density.js","sourceRoot":"","sources":["../../src/tools/keyword-density.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ export interface LinkInfo {
2
+ href: string;
3
+ text: string;
4
+ isExternal: boolean;
5
+ statusCode: number | null;
6
+ status: "ok" | "broken" | "redirect" | "timeout" | "error";
7
+ errorDetail?: string;
8
+ }
9
+ export interface LinkAnalysis {
10
+ url: string;
11
+ totalLinks: number;
12
+ internalLinks: number;
13
+ externalLinks: number;
14
+ brokenLinks: LinkInfo[];
15
+ redirectLinks: LinkInfo[];
16
+ linksWithoutText: number;
17
+ nofollowLinks: number;
18
+ issues: string[];
19
+ summary: string;
20
+ }
21
+ export declare function checkLinks(url: string, maxLinks?: number): Promise<LinkAnalysis>;
22
+ //# sourceMappingURL=link-checker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"link-checker.d.ts","sourceRoot":"","sources":["../../src/tools/link-checker.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,OAAO,CAAC;IACpB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,MAAM,EAAE,IAAI,GAAG,QAAQ,GAAG,UAAU,GAAG,SAAS,GAAG,OAAO,CAAC;IAC3D,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,QAAQ,EAAE,CAAC;IACxB,aAAa,EAAE,QAAQ,EAAE,CAAC;IAC1B,gBAAgB,EAAE,MAAM,CAAC;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AA+CD,wBAAsB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAW,GAAG,OAAO,CAAC,YAAY,CAAC,CA6F1F"}
@@ -0,0 +1,171 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.checkLinks = checkLinks;
37
+ const cheerio = __importStar(require("cheerio"));
38
+ async function probeLink(href) {
39
+ try {
40
+ const controller = new AbortController();
41
+ const timeout = setTimeout(() => controller.abort(), 8000);
42
+ const res = await fetch(href, {
43
+ method: "HEAD",
44
+ headers: { "User-Agent": "MCPSEOTools/1.0 (Link Checker)" },
45
+ redirect: "manual",
46
+ signal: controller.signal,
47
+ });
48
+ clearTimeout(timeout);
49
+ const code = res.status;
50
+ if (code >= 200 && code < 300)
51
+ return { statusCode: code, status: "ok" };
52
+ if (code >= 300 && code < 400)
53
+ return { statusCode: code, status: "redirect" };
54
+ // Some servers reject HEAD, retry with GET
55
+ if (code === 405 || code === 403) {
56
+ const controller2 = new AbortController();
57
+ const timeout2 = setTimeout(() => controller2.abort(), 8000);
58
+ const res2 = await fetch(href, {
59
+ method: "GET",
60
+ headers: { "User-Agent": "MCPSEOTools/1.0 (Link Checker)" },
61
+ redirect: "manual",
62
+ signal: controller2.signal,
63
+ });
64
+ clearTimeout(timeout2);
65
+ const code2 = res2.status;
66
+ if (code2 >= 200 && code2 < 300)
67
+ return { statusCode: code2, status: "ok" };
68
+ if (code2 >= 300 && code2 < 400)
69
+ return { statusCode: code2, status: "redirect" };
70
+ return { statusCode: code2, status: "broken" };
71
+ }
72
+ return { statusCode: code, status: "broken" };
73
+ }
74
+ catch (err) {
75
+ if (err.name === "AbortError")
76
+ return { statusCode: null, status: "timeout", errorDetail: "Request timed out after 8s" };
77
+ return { statusCode: null, status: "error", errorDetail: err.message };
78
+ }
79
+ }
80
+ function resolveUrl(base, href) {
81
+ try {
82
+ return new URL(href, base).href;
83
+ }
84
+ catch {
85
+ return null;
86
+ }
87
+ }
88
+ async function checkLinks(url, maxLinks = 50) {
89
+ const response = await fetch(url, {
90
+ headers: { "User-Agent": "MCPSEOTools/1.0 (Link Checker)" },
91
+ redirect: "follow",
92
+ signal: AbortSignal.timeout(15000),
93
+ });
94
+ const html = await response.text();
95
+ const $ = cheerio.load(html);
96
+ const baseUrl = new URL(url);
97
+ const allAnchors = [];
98
+ $("a[href]").each((_, el) => {
99
+ const href = $(el).attr("href")?.trim() || "";
100
+ const text = $(el).text().trim().replace(/\s+/g, " ");
101
+ const rel = $(el).attr("rel") || "";
102
+ if (href && !href.startsWith("#") && !href.startsWith("mailto:") && !href.startsWith("tel:") && !href.startsWith("javascript:")) {
103
+ allAnchors.push({ href, text, rel });
104
+ }
105
+ });
106
+ const linksWithoutText = allAnchors.filter((a) => a.text.length === 0 && !$(`a[href="${a.href}"] img`).length).length;
107
+ const nofollowLinks = allAnchors.filter((a) => a.rel.includes("nofollow")).length;
108
+ // Deduplicate and resolve URLs
109
+ const uniqueHrefs = new Map();
110
+ for (const anchor of allAnchors) {
111
+ const resolved = resolveUrl(url, anchor.href);
112
+ if (!resolved)
113
+ continue;
114
+ if (uniqueHrefs.has(resolved))
115
+ continue;
116
+ const isExternal = new URL(resolved).hostname !== baseUrl.hostname;
117
+ uniqueHrefs.set(resolved, { text: anchor.text, isExternal });
118
+ }
119
+ const internalCount = [...uniqueHrefs.values()].filter((v) => !v.isExternal).length;
120
+ const externalCount = [...uniqueHrefs.values()].filter((v) => v.isExternal).length;
121
+ // Probe links in batches
122
+ const linksToCheck = [...uniqueHrefs.entries()].slice(0, maxLinks);
123
+ const batchSize = 10;
124
+ const results = [];
125
+ for (let i = 0; i < linksToCheck.length; i += batchSize) {
126
+ const batch = linksToCheck.slice(i, i + batchSize);
127
+ const batchResults = await Promise.all(batch.map(async ([href, info]) => {
128
+ const probe = await probeLink(href);
129
+ return {
130
+ href,
131
+ text: info.text.substring(0, 100),
132
+ isExternal: info.isExternal,
133
+ statusCode: probe.statusCode,
134
+ status: probe.status,
135
+ ...(probe.errorDetail ? { errorDetail: probe.errorDetail } : {}),
136
+ };
137
+ }));
138
+ results.push(...batchResults);
139
+ }
140
+ const brokenLinks = results.filter((l) => l.status === "broken" || l.status === "error" || l.status === "timeout");
141
+ const redirectLinks = results.filter((l) => l.status === "redirect");
142
+ const issues = [];
143
+ if (brokenLinks.length > 0) {
144
+ issues.push(`Found ${brokenLinks.length} broken or unreachable link(s). Fix or remove them to improve crawlability.`);
145
+ }
146
+ if (redirectLinks.length > 0) {
147
+ issues.push(`Found ${redirectLinks.length} redirect(s). Update these to point directly to the final URL.`);
148
+ }
149
+ if (linksWithoutText > 0) {
150
+ issues.push(`${linksWithoutText} link(s) have no anchor text. Add descriptive text for better accessibility and SEO.`);
151
+ }
152
+ if (nofollowLinks > allAnchors.length * 0.5 && allAnchors.length > 5) {
153
+ issues.push("More than half of all links are nofollow. Consider if this is intentional.");
154
+ }
155
+ const checked = results.length;
156
+ const skipped = uniqueHrefs.size - checked;
157
+ const summary = `Checked ${checked} of ${uniqueHrefs.size} unique links (${internalCount} internal, ${externalCount} external). ${brokenLinks.length} broken, ${redirectLinks.length} redirects.${skipped > 0 ? ` ${skipped} links skipped (max ${maxLinks}).` : ""}`;
158
+ return {
159
+ url,
160
+ totalLinks: allAnchors.length,
161
+ internalLinks: internalCount,
162
+ externalLinks: externalCount,
163
+ brokenLinks,
164
+ redirectLinks,
165
+ linksWithoutText,
166
+ nofollowLinks,
167
+ issues,
168
+ summary,
169
+ };
170
+ }
171
+ //# sourceMappingURL=link-checker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"link-checker.js","sourceRoot":"","sources":["../../src/tools/link-checker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ export interface MetaAnalysis {
2
+ url: string;
3
+ title: {
4
+ content: string | null;
5
+ length: number;
6
+ status: "good" | "too_short" | "too_long" | "missing";
7
+ recommendation: string;
8
+ };
9
+ description: {
10
+ content: string | null;
11
+ length: number;
12
+ status: "good" | "too_short" | "too_long" | "missing";
13
+ recommendation: string;
14
+ };
15
+ canonical: string | null;
16
+ robots: string | null;
17
+ viewport: string | null;
18
+ charset: string | null;
19
+ language: string | null;
20
+ openGraph: Record<string, string>;
21
+ twitterCard: Record<string, string>;
22
+ otherMeta: Record<string, string>;
23
+ issues: string[];
24
+ score: number;
25
+ }
26
+ export declare function analyzeMeta(url: string): Promise<MetaAnalysis>;
27
+ //# sourceMappingURL=meta-analyzer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"meta-analyzer.d.ts","sourceRoot":"","sources":["../../src/tools/meta-analyzer.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE;QACL,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;QACvB,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,MAAM,GAAG,WAAW,GAAG,UAAU,GAAG,SAAS,CAAC;QACtD,cAAc,EAAE,MAAM,CAAC;KACxB,CAAC;IACF,WAAW,EAAE;QACX,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;QACvB,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,MAAM,GAAG,WAAW,GAAG,UAAU,GAAG,SAAS,CAAC;QACtD,cAAc,EAAE,MAAM,CAAC;KACxB,CAAC;IACF,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACf;AA8BD,wBAAsB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CA2FpE"}
@@ -0,0 +1,161 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.analyzeMeta = analyzeMeta;
37
+ const cheerio = __importStar(require("cheerio"));
38
+ function assessTitle(title) {
39
+ if (!title) {
40
+ return { content: null, length: 0, status: "missing", recommendation: "Add a title tag between 30-60 characters" };
41
+ }
42
+ const len = title.length;
43
+ if (len < 30) {
44
+ return { content: title, length: len, status: "too_short", recommendation: "Title is under 30 characters. Expand it to improve click-through rates." };
45
+ }
46
+ if (len > 60) {
47
+ return { content: title, length: len, status: "too_long", recommendation: "Title exceeds 60 characters and may be truncated in search results." };
48
+ }
49
+ return { content: title, length: len, status: "good", recommendation: "Title length is within the optimal range." };
50
+ }
51
+ function assessDescription(desc) {
52
+ if (!desc) {
53
+ return { content: null, length: 0, status: "missing", recommendation: "Add a meta description between 120-160 characters" };
54
+ }
55
+ const len = desc.length;
56
+ if (len < 120) {
57
+ return { content: desc, length: len, status: "too_short", recommendation: "Description is under 120 characters. Add more detail to improve CTR." };
58
+ }
59
+ if (len > 160) {
60
+ return { content: desc, length: len, status: "too_long", recommendation: "Description exceeds 160 characters and will be truncated in SERPs." };
61
+ }
62
+ return { content: desc, length: len, status: "good", recommendation: "Description length is within the optimal range." };
63
+ }
64
+ async function analyzeMeta(url) {
65
+ const response = await fetch(url, {
66
+ headers: { "User-Agent": "MCPSEOTools/1.0 (SEO Analyzer)" },
67
+ redirect: "follow",
68
+ signal: AbortSignal.timeout(15000),
69
+ });
70
+ const html = await response.text();
71
+ const $ = cheerio.load(html);
72
+ const issues = [];
73
+ const rawTitle = $("title").first().text().trim() || null;
74
+ const titleAnalysis = assessTitle(rawTitle);
75
+ if (titleAnalysis.status !== "good")
76
+ issues.push(`Title: ${titleAnalysis.recommendation}`);
77
+ const rawDesc = $('meta[name="description"]').attr("content")?.trim() || null;
78
+ const descAnalysis = assessDescription(rawDesc);
79
+ if (descAnalysis.status !== "good")
80
+ issues.push(`Description: ${descAnalysis.recommendation}`);
81
+ const canonical = $('link[rel="canonical"]').attr("href") || null;
82
+ if (!canonical)
83
+ issues.push("Missing canonical URL. Add a <link rel='canonical'> to prevent duplicate content.");
84
+ const robots = $('meta[name="robots"]').attr("content") || null;
85
+ const viewport = $('meta[name="viewport"]').attr("content") || null;
86
+ if (!viewport)
87
+ issues.push("Missing viewport meta tag. Required for mobile-friendly pages.");
88
+ const charset = $('meta[charset]').attr("charset") || $('meta[http-equiv="Content-Type"]').attr("content") || null;
89
+ const language = $("html").attr("lang") || null;
90
+ if (!language)
91
+ issues.push("Missing lang attribute on <html> tag. Important for accessibility and SEO.");
92
+ // Open Graph tags
93
+ const openGraph = {};
94
+ $('meta[property^="og:"]').each((_, el) => {
95
+ const prop = $(el).attr("property")?.replace("og:", "") || "";
96
+ const val = $(el).attr("content") || "";
97
+ if (prop && val)
98
+ openGraph[prop] = val;
99
+ });
100
+ const requiredOg = ["title", "description", "image", "url"];
101
+ const missingOg = requiredOg.filter((p) => !openGraph[p]);
102
+ if (missingOg.length > 0) {
103
+ issues.push(`Missing Open Graph tags: ${missingOg.map((t) => `og:${t}`).join(", ")}`);
104
+ }
105
+ // Twitter Card tags
106
+ const twitterCard = {};
107
+ $('meta[name^="twitter:"], meta[property^="twitter:"]').each((_, el) => {
108
+ const name = ($(el).attr("name") || $(el).attr("property"))?.replace("twitter:", "") || "";
109
+ const val = $(el).attr("content") || "";
110
+ if (name && val)
111
+ twitterCard[name] = val;
112
+ });
113
+ if (!twitterCard["card"]) {
114
+ issues.push("Missing twitter:card meta tag for social sharing.");
115
+ }
116
+ // Other meta tags
117
+ const otherMeta = {};
118
+ $("meta[name]").each((_, el) => {
119
+ const name = $(el).attr("name") || "";
120
+ const content = $(el).attr("content") || "";
121
+ if (name && content && !["description", "robots", "viewport"].includes(name) && !name.startsWith("twitter:")) {
122
+ otherMeta[name] = content;
123
+ }
124
+ });
125
+ // Calculate score out of 100
126
+ let score = 100;
127
+ if (titleAnalysis.status === "missing")
128
+ score -= 20;
129
+ else if (titleAnalysis.status !== "good")
130
+ score -= 10;
131
+ if (descAnalysis.status === "missing")
132
+ score -= 20;
133
+ else if (descAnalysis.status !== "good")
134
+ score -= 10;
135
+ if (!canonical)
136
+ score -= 10;
137
+ if (!viewport)
138
+ score -= 10;
139
+ if (!language)
140
+ score -= 5;
141
+ if (missingOg.length > 0)
142
+ score -= Math.min(missingOg.length * 5, 15);
143
+ if (!twitterCard["card"])
144
+ score -= 10;
145
+ return {
146
+ url,
147
+ title: titleAnalysis,
148
+ description: descAnalysis,
149
+ canonical,
150
+ robots,
151
+ viewport,
152
+ charset,
153
+ language,
154
+ openGraph,
155
+ twitterCard,
156
+ otherMeta,
157
+ issues,
158
+ score: Math.max(0, score),
159
+ };
160
+ }
161
+ //# sourceMappingURL=meta-analyzer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"meta-analyzer.js","sourceRoot":"","sources":["../../src/tools/meta-analyzer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ export interface PageSpeedAnalysis {
2
+ url: string;
3
+ timing: {
4
+ dnsLookupMs: number | null;
5
+ connectionMs: number | null;
6
+ ttfbMs: number;
7
+ downloadMs: number;
8
+ totalMs: number;
9
+ };
10
+ size: {
11
+ htmlBytes: number;
12
+ htmlKB: string;
13
+ compressedBytes: number | null;
14
+ compressedKB: string | null;
15
+ };
16
+ resourceCounts: {
17
+ scripts: number;
18
+ inlineScripts: number;
19
+ stylesheets: number;
20
+ inlineStyles: number;
21
+ images: number;
22
+ imagesWithoutAlt: number;
23
+ imagesWithoutDimensions: number;
24
+ iframes: number;
25
+ };
26
+ issues: string[];
27
+ recommendations: string[];
28
+ score: number;
29
+ }
30
+ export declare function analyzePageSpeed(url: string): Promise<PageSpeedAnalysis>;
31
+ //# sourceMappingURL=page-speed.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"page-speed.d.ts","sourceRoot":"","sources":["../../src/tools/page-speed.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE;QACN,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;QAC3B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;QAC5B,MAAM,EAAE,MAAM,CAAC;QACf,UAAU,EAAE,MAAM,CAAC;QACnB,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,IAAI,EAAE;QACJ,SAAS,EAAE,MAAM,CAAC;QAClB,MAAM,EAAE,MAAM,CAAC;QACf,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;QAC/B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;KAC7B,CAAC;IACF,cAAc,EAAE;QACd,OAAO,EAAE,MAAM,CAAC;QAChB,aAAa,EAAE,MAAM,CAAC;QACtB,WAAW,EAAE,MAAM,CAAC;QACpB,YAAY,EAAE,MAAM,CAAC;QACrB,MAAM,EAAE,MAAM,CAAC;QACf,gBAAgB,EAAE,MAAM,CAAC;QACzB,uBAAuB,EAAE,MAAM,CAAC;QAChC,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;CACf;AAED,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CA6J9E"}
@@ -0,0 +1,180 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.analyzePageSpeed = analyzePageSpeed;
37
+ const cheerio = __importStar(require("cheerio"));
38
+ async function analyzePageSpeed(url) {
39
+ const startTime = performance.now();
40
+ const response = await fetch(url, {
41
+ headers: {
42
+ "User-Agent": "MCPSEOTools/1.0 (Page Speed Analyzer)",
43
+ "Accept-Encoding": "gzip, deflate, br",
44
+ },
45
+ redirect: "follow",
46
+ signal: AbortSignal.timeout(20000),
47
+ });
48
+ const ttfbTime = performance.now();
49
+ const html = await response.text();
50
+ const endTime = performance.now();
51
+ const ttfbMs = Math.round(ttfbTime - startTime);
52
+ const downloadMs = Math.round(endTime - ttfbTime);
53
+ const totalMs = Math.round(endTime - startTime);
54
+ const htmlBytes = new TextEncoder().encode(html).length;
55
+ const contentLength = response.headers.get("content-length");
56
+ const compressedBytes = contentLength ? parseInt(contentLength, 10) : null;
57
+ const $ = cheerio.load(html);
58
+ const scripts = $("script[src]").length;
59
+ const inlineScripts = $("script:not([src])").filter((_, el) => $(el).html()?.trim().length > 0).length;
60
+ const stylesheets = $('link[rel="stylesheet"]').length;
61
+ const inlineStyles = $("style").length;
62
+ const images = $("img").length;
63
+ const imagesWithoutAlt = $("img:not([alt]), img[alt='']").length;
64
+ const imagesWithoutDimensions = $("img:not([width]):not([height])").filter((_, el) => {
65
+ const style = $(el).attr("style") || "";
66
+ return !style.includes("width") && !style.includes("height");
67
+ }).length;
68
+ const iframes = $("iframe").length;
69
+ const issues = [];
70
+ const recommendations = [];
71
+ let score = 100;
72
+ // TTFB analysis
73
+ if (ttfbMs > 800) {
74
+ issues.push(`Slow Time to First Byte: ${ttfbMs}ms. Target is under 800ms.`);
75
+ score -= 15;
76
+ }
77
+ else if (ttfbMs > 400) {
78
+ recommendations.push(`TTFB of ${ttfbMs}ms is acceptable but could be improved. Target under 400ms for best performance.`);
79
+ score -= 5;
80
+ }
81
+ // Total load time
82
+ if (totalMs > 3000) {
83
+ issues.push(`Total load time is ${totalMs}ms. Pages should load within 3 seconds.`);
84
+ score -= 15;
85
+ }
86
+ else if (totalMs > 1500) {
87
+ recommendations.push(`Load time of ${totalMs}ms is acceptable. Aim for under 1.5 seconds.`);
88
+ score -= 5;
89
+ }
90
+ // Page size
91
+ const sizeKB = htmlBytes / 1024;
92
+ if (sizeKB > 500) {
93
+ issues.push(`HTML document is ${sizeKB.toFixed(0)}KB. Large HTML slows initial render. Consider reducing page size.`);
94
+ score -= 10;
95
+ }
96
+ else if (sizeKB > 200) {
97
+ recommendations.push(`HTML is ${sizeKB.toFixed(0)}KB. Consider trimming unnecessary markup.`);
98
+ score -= 3;
99
+ }
100
+ // Compression check
101
+ const encoding = response.headers.get("content-encoding");
102
+ if (!encoding) {
103
+ issues.push("No content compression detected. Enable gzip or Brotli compression on the server.");
104
+ score -= 10;
105
+ }
106
+ // Script analysis
107
+ if (scripts > 15) {
108
+ issues.push(`${scripts} external scripts detected. Too many scripts block rendering. Consider bundling or deferring.`);
109
+ score -= 10;
110
+ }
111
+ else if (scripts > 8) {
112
+ recommendations.push(`${scripts} external scripts found. Consider combining scripts to reduce HTTP requests.`);
113
+ score -= 5;
114
+ }
115
+ if (inlineScripts > 5) {
116
+ recommendations.push(`${inlineScripts} inline scripts found. Move them to external files for better caching.`);
117
+ score -= 3;
118
+ }
119
+ // Check for render-blocking scripts
120
+ const renderBlocking = $("script[src]:not([async]):not([defer])").length;
121
+ if (renderBlocking > 0) {
122
+ issues.push(`${renderBlocking} render-blocking script(s) found. Add async or defer attributes.`);
123
+ score -= renderBlocking * 3;
124
+ }
125
+ // Stylesheet analysis
126
+ if (stylesheets > 8) {
127
+ recommendations.push(`${stylesheets} external stylesheets detected. Consider combining them to reduce requests.`);
128
+ score -= 5;
129
+ }
130
+ // Image analysis
131
+ if (imagesWithoutAlt > 0) {
132
+ issues.push(`${imagesWithoutAlt} image(s) missing alt attributes. Important for accessibility and image SEO.`);
133
+ score -= Math.min(imagesWithoutAlt * 2, 10);
134
+ }
135
+ if (imagesWithoutDimensions > 0) {
136
+ recommendations.push(`${imagesWithoutDimensions} image(s) without explicit dimensions. Set width/height to prevent layout shifts.`);
137
+ score -= Math.min(imagesWithoutDimensions * 2, 8);
138
+ }
139
+ // Check for lazy loading on images
140
+ const lazyImages = $("img[loading='lazy']").length;
141
+ if (images > 5 && lazyImages === 0) {
142
+ recommendations.push("No lazy-loaded images detected. Add loading='lazy' to below-the-fold images.");
143
+ score -= 5;
144
+ }
145
+ // Iframe check
146
+ if (iframes > 0) {
147
+ recommendations.push(`${iframes} iframe(s) found. Iframes add significant load overhead. Use lazy loading or defer if possible.`);
148
+ score -= iframes * 2;
149
+ }
150
+ return {
151
+ url,
152
+ timing: {
153
+ dnsLookupMs: null,
154
+ connectionMs: null,
155
+ ttfbMs,
156
+ downloadMs,
157
+ totalMs,
158
+ },
159
+ size: {
160
+ htmlBytes,
161
+ htmlKB: sizeKB.toFixed(1),
162
+ compressedBytes,
163
+ compressedKB: compressedBytes ? (compressedBytes / 1024).toFixed(1) : null,
164
+ },
165
+ resourceCounts: {
166
+ scripts,
167
+ inlineScripts,
168
+ stylesheets,
169
+ inlineStyles,
170
+ images,
171
+ imagesWithoutAlt,
172
+ imagesWithoutDimensions,
173
+ iframes,
174
+ },
175
+ issues,
176
+ recommendations,
177
+ score: Math.max(0, score),
178
+ };
179
+ }
180
+ //# sourceMappingURL=page-speed.js.map