mcp-scraper 0.3.16 → 0.3.17
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/dist/bin/api-server.cjs +133 -5
- package/dist/bin/api-server.cjs.map +1 -1
- package/dist/bin/api-server.js +1 -1
- package/dist/bin/browser-agent-stdio-server.cjs +1 -1
- package/dist/bin/browser-agent-stdio-server.cjs.map +1 -1
- package/dist/bin/browser-agent-stdio-server.js +2 -2
- package/dist/bin/mcp-scraper-cli.cjs +1 -1
- package/dist/bin/mcp-scraper-cli.cjs.map +1 -1
- package/dist/bin/mcp-scraper-cli.js +1 -1
- package/dist/bin/mcp-scraper-combined-stdio-server.cjs +121 -4
- package/dist/bin/mcp-scraper-combined-stdio-server.cjs.map +1 -1
- package/dist/bin/mcp-scraper-combined-stdio-server.js +3 -3
- package/dist/bin/mcp-scraper-install.cjs +1 -1
- package/dist/bin/mcp-scraper-install.cjs.map +1 -1
- package/dist/bin/mcp-scraper-install.js +1 -1
- package/dist/bin/mcp-stdio-server.cjs +121 -4
- package/dist/bin/mcp-stdio-server.cjs.map +1 -1
- package/dist/bin/mcp-stdio-server.js +2 -2
- package/dist/{chunk-7XARJHS6.js → chunk-N33YEY6W.js} +124 -5
- package/dist/chunk-N33YEY6W.js.map +1 -0
- package/dist/chunk-PVWWY5NV.js +7 -0
- package/dist/chunk-PVWWY5NV.js.map +1 -0
- package/dist/{chunk-ISZWGIWL.js → chunk-UFD7N36R.js} +2 -2
- package/dist/{server-LPVBSE2E.js → server-TKWY47JA.js} +11 -5
- package/dist/server-TKWY47JA.js.map +1 -0
- package/docs/mcp-tool-manifest.generated.json +1 -1
- package/package.json +1 -1
- package/dist/chunk-7XARJHS6.js.map +0 -1
- package/dist/chunk-SOMBZK3V.js +0 -7
- package/dist/chunk-SOMBZK3V.js.map +0 -1
- package/dist/server-LPVBSE2E.js.map +0 -1
- /package/dist/{chunk-ISZWGIWL.js.map → chunk-UFD7N36R.js.map} +0 -0
|
@@ -456,7 +456,7 @@ render();
|
|
|
456
456
|
}
|
|
457
457
|
|
|
458
458
|
// src/version.ts
|
|
459
|
-
var PACKAGE_VERSION = "0.3.
|
|
459
|
+
var PACKAGE_VERSION = "0.3.17";
|
|
460
460
|
|
|
461
461
|
// src/mcp/browser-agent-tool-schemas.ts
|
|
462
462
|
var import_zod = require("zod");
|
|
@@ -1970,6 +1970,99 @@ function buildLinkGraph(pages, startUrl) {
|
|
|
1970
1970
|
return { edges, metrics };
|
|
1971
1971
|
}
|
|
1972
1972
|
|
|
1973
|
+
// src/api/seo-link-report.ts
|
|
1974
|
+
function registrableDomain(host) {
|
|
1975
|
+
const h = host.replace(/^www\./, "").toLowerCase();
|
|
1976
|
+
const parts = h.split(".");
|
|
1977
|
+
return parts.length <= 2 ? h : parts.slice(-2).join(".");
|
|
1978
|
+
}
|
|
1979
|
+
function buildLinkReport(edges, metrics, siteUrl) {
|
|
1980
|
+
let siteReg = "";
|
|
1981
|
+
try {
|
|
1982
|
+
siteReg = registrableDomain(new URL(siteUrl).hostname);
|
|
1983
|
+
} catch {
|
|
1984
|
+
siteReg = "";
|
|
1985
|
+
}
|
|
1986
|
+
const internalEdges = edges.filter((e) => e.internal);
|
|
1987
|
+
const pages = metrics.length;
|
|
1988
|
+
const orphans = metrics.filter((m) => m.orphan).length;
|
|
1989
|
+
const brokenInternal = internalEdges.filter((e) => e.targetStatus != null && e.targetStatus >= 400).length;
|
|
1990
|
+
const sumInlinks = metrics.reduce((a, m) => a + m.inlinks, 0);
|
|
1991
|
+
const sumOutlinks = metrics.reduce((a, m) => a + m.outlinksInternal + m.outlinksExternal, 0);
|
|
1992
|
+
const distribution = { zero: 0, oneToTwo: 0, threeToTen: 0, elevenPlus: 0 };
|
|
1993
|
+
for (const m of metrics) {
|
|
1994
|
+
if (m.inlinks === 0) distribution.zero++;
|
|
1995
|
+
else if (m.inlinks <= 2) distribution.oneToTwo++;
|
|
1996
|
+
else if (m.inlinks <= 10) distribution.threeToTen++;
|
|
1997
|
+
else distribution.elevenPlus++;
|
|
1998
|
+
}
|
|
1999
|
+
const topByInlinks = [...metrics].sort((a, b) => b.inlinks - a.inlinks).slice(0, 20).map((m) => ({ url: m.url, inlinks: m.inlinks, outlinksInternal: m.outlinksInternal, outlinksExternal: m.outlinksExternal }));
|
|
2000
|
+
const domMap = /* @__PURE__ */ new Map();
|
|
2001
|
+
let externalTotal = 0;
|
|
2002
|
+
for (const e of edges) {
|
|
2003
|
+
let domain;
|
|
2004
|
+
try {
|
|
2005
|
+
domain = registrableDomain(new URL(e.to).hostname);
|
|
2006
|
+
} catch {
|
|
2007
|
+
continue;
|
|
2008
|
+
}
|
|
2009
|
+
if (!domain || domain === siteReg) continue;
|
|
2010
|
+
externalTotal++;
|
|
2011
|
+
const d = domMap.get(domain) ?? { links: 0, nofollow: 0, pages: /* @__PURE__ */ new Set() };
|
|
2012
|
+
d.links++;
|
|
2013
|
+
if (e.nofollow) d.nofollow++;
|
|
2014
|
+
d.pages.add(e.from);
|
|
2015
|
+
domMap.set(domain, d);
|
|
2016
|
+
}
|
|
2017
|
+
const externalDomains = [...domMap.entries()].map(([domain, d]) => ({ domain, links: d.links, nofollow: d.nofollow, pages: d.pages.size })).sort((a, b) => b.links - a.links);
|
|
2018
|
+
const round = (n) => Math.round(n * 10) / 10;
|
|
2019
|
+
return {
|
|
2020
|
+
summary: {
|
|
2021
|
+
internal: {
|
|
2022
|
+
totalLinks: internalEdges.length,
|
|
2023
|
+
pages,
|
|
2024
|
+
orphans,
|
|
2025
|
+
brokenInternal,
|
|
2026
|
+
avgInlinks: pages ? round(sumInlinks / pages) : 0,
|
|
2027
|
+
avgOutlinks: pages ? round(sumOutlinks / pages) : 0,
|
|
2028
|
+
distribution,
|
|
2029
|
+
topByInlinks
|
|
2030
|
+
},
|
|
2031
|
+
external: {
|
|
2032
|
+
totalLinks: externalTotal,
|
|
2033
|
+
uniqueDomains: externalDomains.length,
|
|
2034
|
+
topDomains: externalDomains.slice(0, 20)
|
|
2035
|
+
}
|
|
2036
|
+
},
|
|
2037
|
+
externalDomains
|
|
2038
|
+
};
|
|
2039
|
+
}
|
|
2040
|
+
function renderLinkReport(r) {
|
|
2041
|
+
const s = r.summary;
|
|
2042
|
+
const lines = [
|
|
2043
|
+
`## Link analysis`,
|
|
2044
|
+
`**Internal:** ${s.internal.totalLinks} links \xB7 ${s.internal.pages} pages \xB7 avg ${s.internal.avgInlinks} inlinks/page \xB7 ${s.internal.orphans} orphans \xB7 ${s.internal.brokenInternal} broken`,
|
|
2045
|
+
`**External:** ${s.external.totalLinks} links to ${s.external.uniqueDomains} domains`,
|
|
2046
|
+
``,
|
|
2047
|
+
`### Inlink distribution`,
|
|
2048
|
+
`- 0 inlinks (orphans): ${s.internal.distribution.zero}`,
|
|
2049
|
+
`- 1\u20132: ${s.internal.distribution.oneToTwo}`,
|
|
2050
|
+
`- 3\u201310: ${s.internal.distribution.threeToTen}`,
|
|
2051
|
+
`- 11+: ${s.internal.distribution.elevenPlus}`,
|
|
2052
|
+
``,
|
|
2053
|
+
`### Top 20 internal pages by inlinks`,
|
|
2054
|
+
`| inlinks | out (int/ext) | URL |`,
|
|
2055
|
+
`|---|---|---|`,
|
|
2056
|
+
...s.internal.topByInlinks.map((p) => `| ${p.inlinks} | ${p.outlinksInternal}/${p.outlinksExternal} | ${p.url} |`),
|
|
2057
|
+
``,
|
|
2058
|
+
`### Top 20 external domains by links`,
|
|
2059
|
+
`| links | nofollow | from pages | domain |`,
|
|
2060
|
+
`|---|---|---|---|`,
|
|
2061
|
+
...s.external.topDomains.map((d) => `| ${d.links} | ${d.nofollow} | ${d.pages} | ${d.domain} |`)
|
|
2062
|
+
];
|
|
2063
|
+
return lines.join("\n");
|
|
2064
|
+
}
|
|
2065
|
+
|
|
1973
2066
|
// src/api/seo-issues.ts
|
|
1974
2067
|
var THIN_WORDS = 200;
|
|
1975
2068
|
var TITLE_MAX = 60;
|
|
@@ -2275,6 +2368,9 @@ function saveBulkSite(siteUrl, pages, seo, imageAudit) {
|
|
|
2275
2368
|
`- \`pages.jsonl\` \u2014 per-page SEO fields, one JSON object per page`,
|
|
2276
2369
|
`- \`links.jsonl\` \u2014 internal/external link edges (anchor, rel, target status)`,
|
|
2277
2370
|
`- \`link-metrics.jsonl\` \u2014 inlinks, crawl depth, orphan flags per page`,
|
|
2371
|
+
`- \`link-report.md\` \u2014 link analysis: top internal pages by inlinks, top external domains, distribution`,
|
|
2372
|
+
`- \`links-summary.json\` \u2014 link totals + top-20 internal pages + top-20 external domains`,
|
|
2373
|
+
`- \`external-domains.json\` \u2014 every external domain linked to, ordered by link count`,
|
|
2278
2374
|
...imageAudit ? [
|
|
2279
2375
|
`- \`images.jsonl\` \u2014 every image with byte size, format, over-100KB and legacy-format flags`,
|
|
2280
2376
|
`- \`images-summary.json\` \u2014 image totals (count, total weight, over-100KB, legacy)`
|
|
@@ -2310,7 +2406,13 @@ ${indexRows.join("\n")}`
|
|
|
2310
2406
|
(0, import_node_fs3.writeFileSync)(reportFile, seo.reportMd + (imageAudit ? `
|
|
2311
2407
|
|
|
2312
2408
|
${renderImageSection(imageAudit)}` : ""), "utf8");
|
|
2313
|
-
|
|
2409
|
+
const linkReportFile = (0, import_node_path4.join)(dir, "link-report.md");
|
|
2410
|
+
const linksSummaryFile = (0, import_node_path4.join)(dir, "links-summary.json");
|
|
2411
|
+
const externalDomainsFile = (0, import_node_path4.join)(dir, "external-domains.json");
|
|
2412
|
+
(0, import_node_fs3.writeFileSync)(linkReportFile, renderLinkReport(seo.linkReport), "utf8");
|
|
2413
|
+
(0, import_node_fs3.writeFileSync)(linksSummaryFile, JSON.stringify(seo.linkReport.summary, null, 2), "utf8");
|
|
2414
|
+
(0, import_node_fs3.writeFileSync)(externalDomainsFile, JSON.stringify(seo.linkReport.externalDomains, null, 2), "utf8");
|
|
2415
|
+
seoFiles = [pagesJsonl, linksJsonl, metricsJsonl, issuesFile, reportFile, linkReportFile, linksSummaryFile, externalDomainsFile];
|
|
2314
2416
|
if (imageAudit) {
|
|
2315
2417
|
const imagesJsonl = (0, import_node_path4.join)(dir, "images.jsonl");
|
|
2316
2418
|
const imagesSummary = (0, import_node_path4.join)(dir, "images-summary.json");
|
|
@@ -2762,6 +2864,7 @@ function buildSeoExport(siteUrl, pages, branding) {
|
|
|
2762
2864
|
metrics: [...metrics.values()],
|
|
2763
2865
|
issues,
|
|
2764
2866
|
reportMd: renderIssueReport(siteUrl, pages, issues, metrics),
|
|
2867
|
+
linkReport: buildLinkReport(edges, [...metrics.values()], siteUrl),
|
|
2765
2868
|
branding: branding ?? void 0
|
|
2766
2869
|
};
|
|
2767
2870
|
}
|
|
@@ -2870,6 +2973,9 @@ async function formatAuditSite(raw, input) {
|
|
|
2870
2973
|
const topIssues = Object.entries(seo.issues).sort((a, b) => b[1].count - a[1].count).slice(0, 8).map(([k, v]) => `- \`${k}\` \u2014 ${v.count}`).join("\n");
|
|
2871
2974
|
const img = imageAudit.summary;
|
|
2872
2975
|
const imgLine = `${img.unique} images \xB7 ${img.totalSize} total \xB7 ${img.over100kb} over 100 KB \xB7 ${img.legacyFormat} legacy format`;
|
|
2976
|
+
const lr = seo.linkReport.summary;
|
|
2977
|
+
const topExt = lr.external.topDomains.slice(0, 3).map((dm) => `${dm.domain} (${dm.links})`).join(", ") || "\u2014";
|
|
2978
|
+
const linkLine = `${lr.internal.totalLinks} internal / ${lr.external.totalLinks} external links \xB7 ${lr.internal.orphans} orphans \xB7 ${lr.internal.brokenInternal} broken \xB7 avg ${lr.internal.avgInlinks} inlinks/page \xB7 top external: ${topExt}`;
|
|
2873
2979
|
const durationLine = `**${pages.length} pages** \xB7 ${((d.durationMs ?? 0) / 1e3).toFixed(1)}s`;
|
|
2874
2980
|
const structuredContent = {
|
|
2875
2981
|
url: input.url,
|
|
@@ -2877,7 +2983,8 @@ async function formatAuditSite(raw, input) {
|
|
|
2877
2983
|
durationMs: d.durationMs ?? 0,
|
|
2878
2984
|
bulkFolder: bulk?.dir ?? null,
|
|
2879
2985
|
issues: Object.fromEntries(Object.entries(seo.issues).map(([k, v]) => [k, v.count])),
|
|
2880
|
-
images: { unique: img.unique, totalBytes: img.totalBytes, over100kb: img.over100kb, legacyFormat: img.legacyFormat }
|
|
2986
|
+
images: { unique: img.unique, totalBytes: img.totalBytes, over100kb: img.over100kb, legacyFormat: img.legacyFormat },
|
|
2987
|
+
links: { internal: lr.internal.totalLinks, external: lr.external.totalLinks, orphans: lr.internal.orphans, brokenInternal: lr.internal.brokenInternal, externalDomains: lr.external.uniqueDomains }
|
|
2881
2988
|
};
|
|
2882
2989
|
const location = bulk ? `
|
|
2883
2990
|
## \u{1F4C1} Technical audit saved
|
|
@@ -2896,6 +3003,9 @@ Report saving is disabled in this environment. Enable \`MCP_SCRAPER_SAVE_REPORTS
|
|
|
2896
3003
|
## Top issues
|
|
2897
3004
|
${topIssues || "_none found_"}`,
|
|
2898
3005
|
`
|
|
3006
|
+
## Links
|
|
3007
|
+
${linkLine}`,
|
|
3008
|
+
`
|
|
2899
3009
|
## Images
|
|
2900
3010
|
${imgLine}`
|
|
2901
3011
|
].join("\n");
|
|
@@ -4463,6 +4573,13 @@ var AuditSiteOutputSchema = {
|
|
|
4463
4573
|
totalBytes: import_zod3.z.number().min(0),
|
|
4464
4574
|
over100kb: import_zod3.z.number().int().min(0),
|
|
4465
4575
|
legacyFormat: import_zod3.z.number().int().min(0)
|
|
4576
|
+
}),
|
|
4577
|
+
links: import_zod3.z.object({
|
|
4578
|
+
internal: import_zod3.z.number().int().min(0),
|
|
4579
|
+
external: import_zod3.z.number().int().min(0),
|
|
4580
|
+
orphans: import_zod3.z.number().int().min(0),
|
|
4581
|
+
brokenInternal: import_zod3.z.number().int().min(0),
|
|
4582
|
+
externalDomains: import_zod3.z.number().int().min(0)
|
|
4466
4583
|
})
|
|
4467
4584
|
};
|
|
4468
4585
|
var MapsPlaceIntelOutputSchema = {
|
|
@@ -5309,7 +5426,7 @@ function registerPaaExtractorMcpTools(server2, executor, options = {}) {
|
|
|
5309
5426
|
}, async (input) => formatExtractSite(await executor.extractSite(input), input));
|
|
5310
5427
|
server2.registerTool("audit_site", {
|
|
5311
5428
|
title: "Technical SEO Audit",
|
|
5312
|
-
description: withReportNote("Run a full technical SEO audit (Screaming-Frog-style) on a public website. Crawls up to maxPages and produces a complete on-page + crawl analysis: per-page title/meta lengths, heading breakdown, indexability and canonical status, schema, an internal link graph
|
|
5429
|
+
description: withReportNote("Run a full technical SEO audit (Screaming-Frog-style) on a public website. Crawls up to maxPages and produces a complete on-page + crawl analysis: per-page title/meta lengths, heading breakdown, indexability and canonical status, schema, an internal link graph (inlinks/orphans/crawl-depth), a link analysis (top internal pages by inlinks, top external domains by link count, broken/orphan counts), an issues report, and an image audit (byte size, format, over-100KB and legacy-format flags). Writes everything to a local folder (report.md, issues.json, pages.jsonl, links.jsonl, link-metrics.jsonl, link-report.md, links-summary.json, external-domains.json, images.jsonl) plus per-page content, and returns a headline summary plus the folder path. Use this when the user wants an audit or analysis; use extract_site when they just want page content."),
|
|
5313
5430
|
inputSchema: AuditSiteInputSchema,
|
|
5314
5431
|
outputSchema: AuditSiteOutputSchema,
|
|
5315
5432
|
annotations: liveWebToolAnnotations("Technical SEO Audit")
|