pagesight 0.14.0 → 0.14.1
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/README.md +24 -18
- package/package.json +1 -1
- package/src/tools/ai.ts +13 -0
- package/src/tools/page.ts +1 -1
- package/src/tools/search.ts +10 -4
- package/src/tools/speed.ts +4 -4
package/README.md
CHANGED
|
@@ -8,34 +8,40 @@ See your site the way search engines and AI see it.
|
|
|
8
8
|
npm install pagesight
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
Your AI assistant can write your code. Now it can see your site. Index status, performance, real-user metrics, search traffic, meta tags, structured data, AI crawler access — one package, one call.
|
|
11
|
+
Your AI assistant can write your code. Now it can see your site. Index status, performance, real-user metrics, search traffic, meta tags, structured data, AI crawler access, link health — one package, one call.
|
|
12
12
|
|
|
13
13
|
```
|
|
14
14
|
=== Site Audit: https://example.com ===
|
|
15
15
|
|
|
16
|
+
2 checks failed — results below are partial:
|
|
17
|
+
|
|
18
|
+
FAIL PageSpeed: quota exceeded
|
|
19
|
+
FAIL Sitemaps: permission denied
|
|
20
|
+
|
|
21
|
+
5 findings:
|
|
22
|
+
|
|
16
23
|
HIGH Missing canonical URL
|
|
17
|
-
HIGH
|
|
24
|
+
HIGH 22 sitemap URLs submitted, 0 indexed
|
|
25
|
+
Auto-inspected 5 URLs:
|
|
26
|
+
- 2/5 indexed
|
|
27
|
+
- 3/5 Discovered - currently not indexed: /docs/, /pricing/, /about/
|
|
18
28
|
MEDIUM Missing og:image — no social preview image
|
|
19
|
-
MEDIUM Accessibility score: 89/100
|
|
20
29
|
LOW Missing Twitter Card tags
|
|
21
|
-
LOW
|
|
30
|
+
LOW 6/139 AI crawlers blocked
|
|
22
31
|
```
|
|
23
32
|
|
|
24
33
|
## Tools
|
|
25
34
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
|
29
|
-
|
|
30
|
-
| `
|
|
31
|
-
| `
|
|
32
|
-
| `
|
|
33
|
-
| `
|
|
34
|
-
| `
|
|
35
|
-
| `
|
|
36
|
-
| `robots` | robots.txt validation (RFC 9309) + AI crawler audit (139+ bots). |
|
|
37
|
-
| `sitemaps` | Search Console properties and sitemaps with submitted/indexed counts. |
|
|
38
|
-
| `setup` | Auth status and OAuth setup. |
|
|
35
|
+
6 tools organized by intent:
|
|
36
|
+
|
|
37
|
+
| Tool | Intent | What it does |
|
|
38
|
+
|------|--------|-------------|
|
|
39
|
+
| `audit` | How's my site? | One-call site audit. Runs all checks in parallel. Prioritized findings with auto-drill-down on indexing issues. |
|
|
40
|
+
| `page` | What's on this URL? | Meta tags, OG, Twitter Card, JSON-LD validation (19 schema types), internal link health, redirect chains, WCAG contrast checker. Batch mode for multiple URLs. |
|
|
41
|
+
| `speed` | How fast is it? | PageSpeed single/batch/compare with Lighthouse scores and opportunities. CrUX real-user metrics (snapshot + history trends). |
|
|
42
|
+
| `search` | How's Google seeing me? | URL inspection, sample-inspect from sitemaps, sitemap management, search analytics with period-over-period comparison. |
|
|
43
|
+
| `ai` | How's AI seeing me? | AI crawler audit (139+ bots by category), robots.txt validation (RFC 9309), llms.txt detection, path access checks. |
|
|
44
|
+
| `setup` | Auth config | Auth status check and OAuth setup flow. |
|
|
39
45
|
|
|
40
46
|
## Setup
|
|
41
47
|
|
|
@@ -58,7 +64,7 @@ Add to your MCP config:
|
|
|
58
64
|
}
|
|
59
65
|
```
|
|
60
66
|
|
|
61
|
-
`
|
|
67
|
+
`page`, `speed`, and `ai` work without credentials. `search` and `audit` (for GSC checks) require OAuth or a service account.
|
|
62
68
|
|
|
63
69
|
### Full setup
|
|
64
70
|
|
package/package.json
CHANGED
package/src/tools/ai.ts
CHANGED
|
@@ -12,12 +12,24 @@ interface LlmsTxtResult {
|
|
|
12
12
|
|
|
13
13
|
async function checkLlmsTxt(origin: string, path: string): Promise<LlmsTxtResult> {
|
|
14
14
|
try {
|
|
15
|
+
const controller = new AbortController();
|
|
16
|
+
const timeout = setTimeout(() => controller.abort(), 10_000);
|
|
15
17
|
const res = await fetch(`${origin}${path}`, {
|
|
16
18
|
headers: { "User-Agent": "Pagesight/1.0" },
|
|
17
19
|
redirect: "follow",
|
|
20
|
+
signal: controller.signal,
|
|
18
21
|
});
|
|
22
|
+
clearTimeout(timeout);
|
|
19
23
|
if (!res.ok) return { exists: false, size: null, firstLine: null };
|
|
24
|
+
// Cap at 1MB to avoid OOM on large responses
|
|
25
|
+
const contentLength = Number(res.headers.get("content-length") ?? 0);
|
|
26
|
+
if (contentLength > 1_048_576) {
|
|
27
|
+
return { exists: true, size: contentLength, firstLine: "(file too large to preview)" };
|
|
28
|
+
}
|
|
20
29
|
const text = await res.text();
|
|
30
|
+
if (text.length > 1_048_576) {
|
|
31
|
+
return { exists: true, size: text.length, firstLine: "(file too large to preview)" };
|
|
32
|
+
}
|
|
21
33
|
const firstLine =
|
|
22
34
|
text
|
|
23
35
|
.split("\n")
|
|
@@ -215,6 +227,7 @@ export function registerAiTool(server: McpServer): void {
|
|
|
215
227
|
{
|
|
216
228
|
url: z
|
|
217
229
|
.string()
|
|
230
|
+
.url()
|
|
218
231
|
.describe("Site URL or origin (e.g., 'https://example.com'). Fetches /robots.txt from this origin."),
|
|
219
232
|
check_path: z
|
|
220
233
|
.string()
|
package/src/tools/page.ts
CHANGED
|
@@ -615,7 +615,7 @@ async function checkLink(href: string): Promise<LinkResult> {
|
|
|
615
615
|
try {
|
|
616
616
|
for (let i = 0; i < 10; i++) {
|
|
617
617
|
const res = await fetch(current, {
|
|
618
|
-
method: "
|
|
618
|
+
method: "HEAD",
|
|
619
619
|
headers: { "User-Agent": "Mozilla/5.0 (compatible; Googlebot/2.1)", Accept: "text/html" },
|
|
620
620
|
redirect: "manual",
|
|
621
621
|
});
|
package/src/tools/search.ts
CHANGED
|
@@ -430,10 +430,16 @@ function formatComparison(
|
|
|
430
430
|
}
|
|
431
431
|
|
|
432
432
|
function daysAgo(n: number): string {
|
|
433
|
-
// GSC dates are in
|
|
434
|
-
const
|
|
435
|
-
|
|
436
|
-
|
|
433
|
+
// GSC dates are in Pacific Time. Use Intl to handle DST correctly.
|
|
434
|
+
const d = new Date();
|
|
435
|
+
d.setDate(d.getDate() - n);
|
|
436
|
+
const parts = new Intl.DateTimeFormat("en-CA", {
|
|
437
|
+
timeZone: "America/Los_Angeles",
|
|
438
|
+
year: "numeric",
|
|
439
|
+
month: "2-digit",
|
|
440
|
+
day: "2-digit",
|
|
441
|
+
}).format(d);
|
|
442
|
+
return parts; // en-CA formats as YYYY-MM-DD
|
|
437
443
|
}
|
|
438
444
|
|
|
439
445
|
// ── Tool registration ──
|
package/src/tools/speed.ts
CHANGED
|
@@ -813,10 +813,10 @@ export function registerSpeedTool(server: McpServer): void {
|
|
|
813
813
|
const cruxOrigin = origin;
|
|
814
814
|
|
|
815
815
|
if (!cruxUrl && !cruxOrigin) {
|
|
816
|
-
return { content: [{ type: "text" as const, text: "Error: provide
|
|
816
|
+
return { content: [{ type: "text" as const, text: "Error: provide url or origin for CrUX data." }] };
|
|
817
817
|
}
|
|
818
818
|
if (cruxUrl && cruxOrigin) {
|
|
819
|
-
return { content: [{ type: "text" as const, text: "Error: provide
|
|
819
|
+
return { content: [{ type: "text" as const, text: "Error: provide url or origin, not both." }] };
|
|
820
820
|
}
|
|
821
821
|
|
|
822
822
|
try {
|
|
@@ -860,10 +860,10 @@ export function registerSpeedTool(server: McpServer): void {
|
|
|
860
860
|
const histOrigin = origin;
|
|
861
861
|
|
|
862
862
|
if (!histUrl && !histOrigin) {
|
|
863
|
-
return { content: [{ type: "text" as const, text: "Error: provide
|
|
863
|
+
return { content: [{ type: "text" as const, text: "Error: provide url or origin for CrUX history." }] };
|
|
864
864
|
}
|
|
865
865
|
if (histUrl && histOrigin) {
|
|
866
|
-
return { content: [{ type: "text" as const, text: "Error: provide
|
|
866
|
+
return { content: [{ type: "text" as const, text: "Error: provide url or origin, not both." }] };
|
|
867
867
|
}
|
|
868
868
|
|
|
869
869
|
try {
|