seo-gravity-mcp 1.0.2 → 1.2.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 (67) hide show
  1. package/README.md +118 -105
  2. package/dist/adapters/adapterRegistry.d.ts +7 -0
  3. package/dist/adapters/adapterRegistry.js +30 -0
  4. package/dist/adapters/astroAdapter.d.ts +17 -0
  5. package/dist/adapters/astroAdapter.js +191 -0
  6. package/dist/adapters/nextAppAdapter.d.ts +17 -0
  7. package/dist/adapters/nextAppAdapter.js +265 -0
  8. package/dist/adapters/nextPagesAdapter.d.ts +17 -0
  9. package/dist/adapters/nextPagesAdapter.js +209 -0
  10. package/dist/adapters/remixAdapter.d.ts +16 -0
  11. package/dist/adapters/remixAdapter.js +118 -0
  12. package/dist/adapters/staticAdapter.d.ts +16 -0
  13. package/dist/adapters/staticAdapter.js +117 -0
  14. package/dist/adapters/svelteKitAdapter.d.ts +16 -0
  15. package/dist/adapters/svelteKitAdapter.js +122 -0
  16. package/dist/adapters/types.d.ts +39 -0
  17. package/dist/adapters/types.js +1 -0
  18. package/dist/adapters/viteReactAdapter.d.ts +16 -0
  19. package/dist/adapters/viteReactAdapter.js +189 -0
  20. package/dist/benchmark/correlationBenchmark.d.ts +1 -0
  21. package/dist/benchmark/correlationBenchmark.js +96 -0
  22. package/dist/benchmark/invariantBenchmark.d.ts +1 -0
  23. package/dist/benchmark/invariantBenchmark.js +47 -0
  24. package/dist/cli.d.ts +8 -0
  25. package/dist/cli.js +162 -0
  26. package/dist/index.d.ts +3 -1
  27. package/dist/index.js +8 -646
  28. package/dist/invariants/registry.d.ts +12 -0
  29. package/dist/invariants/registry.js +178 -0
  30. package/dist/invariants/types.d.ts +38 -0
  31. package/dist/invariants/types.js +1 -0
  32. package/dist/providers/providerRegistry.d.ts +65 -0
  33. package/dist/providers/providerRegistry.js +64 -0
  34. package/dist/providers/types.d.ts +22 -0
  35. package/dist/providers/types.js +1 -0
  36. package/dist/server/registry.d.ts +3 -0
  37. package/dist/server/registry.js +559 -0
  38. package/dist/server/server.d.ts +70 -0
  39. package/dist/server/server.js +53 -0
  40. package/dist/server/types.d.ts +7 -0
  41. package/dist/server/types.js +1 -0
  42. package/dist/test.js +108 -138
  43. package/dist/tools/orchestration.js +23 -21
  44. package/dist/types/canonical.d.ts +64 -0
  45. package/dist/types/canonical.js +1 -0
  46. package/dist/types/findings.d.ts +22 -0
  47. package/dist/types/findings.js +1 -1
  48. package/dist/types/seo.d.ts +24 -0
  49. package/dist/utils/astLocator.d.ts +14 -0
  50. package/dist/utils/astLocator.js +137 -0
  51. package/dist/utils/cacheManager.d.ts +29 -0
  52. package/dist/utils/cacheManager.js +60 -0
  53. package/dist/utils/experimentEngine.d.ts +26 -0
  54. package/dist/utils/experimentEngine.js +41 -0
  55. package/dist/utils/findingEngine.d.ts +2 -1
  56. package/dist/utils/findingEngine.js +1 -0
  57. package/dist/utils/gitDiffEngine.d.ts +28 -0
  58. package/dist/utils/gitDiffEngine.js +109 -0
  59. package/dist/utils/opportunityEngine.d.ts +19 -0
  60. package/dist/utils/opportunityEngine.js +61 -0
  61. package/dist/utils/projectScanner.d.ts +4 -2
  62. package/dist/utils/projectScanner.js +14 -346
  63. package/dist/utils/sarifExporter.d.ts +64 -0
  64. package/dist/utils/sarifExporter.js +81 -0
  65. package/dist/utils/snapshotEngine.d.ts +3 -1
  66. package/dist/utils/snapshotEngine.js +232 -94
  67. package/package.json +8 -5
package/dist/index.js CHANGED
@@ -1,651 +1,13 @@
1
1
  #!/usr/bin/env node
2
- import { Server } from '@modelcontextprotocol/sdk/server/index.js';
3
- import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
4
- import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
5
- // Import Tool Handlers
6
- import { analyzeSerp, profileCompetitor, analyzeCompetitorContentGap, diffCompetitor, analyzeForumDiscussions } from './tools/serp.js';
7
- import { auditGeoAiReadiness, generateLlmsTxt, auditAiBotsRobots } from './tools/geo.js';
8
- import { scoreInformationGain, auditEeat } from './tools/eeat.js';
9
- import { auditOnPage, generateContentBrief, scoreReadability } from './tools/onpage.js';
10
- import { auditTechnical, diffJsRendering, validateRobotsTxt, inspectSitemap, analyzeInternalLinks } from './tools/technical.js';
11
- import { getKeywordSuggestions, findQuestions, clusterKeywords, classifySearchIntent } from './tools/keywords.js';
12
- import { mapEntitySalience, generateSchemaMarkup, validateSchema } from './tools/schema.js';
13
- import { auditPageSpeed, submitIndexNow, auditContentDecay } from './tools/performance.js';
14
- import { auditProject, diagnoseSeo, prioritizeFindings, generateFixPlan, createSnapshotTool, compareSnapshotsTool, checkRegression } from './tools/orchestration.js';
15
- // Define the 35 MCP Tools
16
- const TOOLS = [
17
- // ==========================================
18
- // Layer 0. Agent Orchestration & Remediation
19
- // ==========================================
20
- {
21
- name: 'seo_project_audit',
22
- description: 'Flagship project audit: scans codebase for framework (Next.js, Astro, Vite, Remix), maps discovered routes to source files, builds crawl graph, and computes multidimensional SEO scores (Technical, Content, AI Readiness, Discoverability, Entity).',
23
- inputSchema: {
24
- type: 'object',
25
- properties: {
26
- project_path: { type: 'string', description: 'Absolute or relative path to project workspace root' },
27
- base_url: { type: 'string', description: 'Optional live or dev server URL (e.g. "http://localhost:3000")' },
28
- crawl_depth: { type: 'number', description: 'Crawl depth for internal link graph analysis (default 2)' }
29
- },
30
- required: ['project_path']
31
- }
32
- },
33
- {
34
- name: 'seo_diagnose',
35
- description: 'Deep root-cause diagnostic: correlates an observed SEO issue or URL back to specific source code files, components, and line numbers with actionable code fix blueprints.',
36
- inputSchema: {
37
- type: 'object',
38
- properties: {
39
- project_path: { type: 'string', description: 'Path to project workspace root' },
40
- target_url_or_file: { type: 'string', description: 'URL, route path (e.g. "/blog/[slug]"), or file path to diagnose' },
41
- focus_issue_id: { type: 'string', description: 'Optional specific finding ID (e.g. "SEO-CANONICAL-001")' }
42
- },
43
- required: ['project_path', 'target_url_or_file']
44
- }
45
- },
46
- {
47
- name: 'seo_prioritize',
48
- description: 'Ranks and groups project SEO findings into actionable sprints (Quick Wins, Critical Blockers, Architectural Improvements) using the (Impact × Confidence × Reach) / Effort formula.',
49
- inputSchema: {
50
- type: 'object',
51
- properties: {
52
- project_path: { type: 'string', description: 'Project path or raw findings array' },
53
- max_count: { type: 'number', description: 'Max items per sprint category (default 20)' }
54
- },
55
- required: ['project_path']
56
- }
57
- },
58
- {
59
- name: 'seo_fix_plan',
60
- description: 'Generates a structured, step-by-step code modification and verification plan for AI coding agents to remediate project SEO issues.',
61
- inputSchema: {
62
- type: 'object',
63
- properties: {
64
- project_path: { type: 'string', description: 'Path to project workspace root' },
65
- finding_ids: { type: 'array', items: { type: 'string' }, description: 'Optional subset of finding IDs to plan fixes for' }
66
- },
67
- required: ['project_path']
68
- }
69
- },
70
- {
71
- name: 'seo_snapshot_create',
72
- description: 'Creates a baseline or milestone project SEO snapshot adhering to canonical schema `seo.gravity/v1`, optionally exporting to a JSON file.',
73
- inputSchema: {
74
- type: 'object',
75
- properties: {
76
- project_path: { type: 'string', description: 'Path to project workspace root' },
77
- base_url: { type: 'string', description: 'Optional live or dev server URL' },
78
- output_path: { type: 'string', description: 'Optional destination file path to save snapshot JSON' }
79
- },
80
- required: ['project_path']
81
- }
82
- },
83
- {
84
- name: 'seo_snapshot_compare',
85
- description: 'Compares two SEO project snapshots (e.g. baseline vs current) to compute exact resolved issues, new regressions, and multidimensional score deltas.',
86
- inputSchema: {
87
- type: 'object',
88
- properties: {
89
- baseline_snapshot: { type: 'object', description: 'Baseline ProjectSnapshot object or file path' },
90
- current_snapshot: { type: 'object', description: 'Current ProjectSnapshot object or file path' }
91
- },
92
- required: ['baseline_snapshot', 'current_snapshot']
93
- }
94
- },
95
- {
96
- name: 'seo_regression_check',
97
- description: 'Automated CI/PR regression check: compares current project state against a baseline snapshot and returns a pass/fail verdict with regression alerts.',
98
- inputSchema: {
99
- type: 'object',
100
- properties: {
101
- project_path: { type: 'string', description: 'Path to project workspace root' },
102
- baseline_snapshot: { type: 'object', description: 'Baseline ProjectSnapshot object or file path' },
103
- base_url: { type: 'string', description: 'Optional live or dev server URL' }
104
- },
105
- required: ['project_path', 'baseline_snapshot']
106
- }
107
- },
108
- // ==========================================
109
- // Layer 1. SERP & Competitor Intelligence
110
- // ==========================================
111
- {
112
- name: 'seo_serp_analyze',
113
- description: 'Scrapes live Google SERP for any keyword. Returns top ranking URLs, snippets, People Also Ask (PAA), Related Searches, and rich SERP features.',
114
- inputSchema: {
115
- type: 'object',
116
- properties: {
117
- query: { type: 'string', description: 'Search keyword / phrase' },
118
- country: { type: 'string', description: 'Two-letter country code (default "us")' },
119
- language: { type: 'string', description: 'Language code (default "en")' },
120
- num_results: { type: 'number', description: 'Number of results to fetch (default 10)' }
121
- },
122
- required: ['query']
123
- }
124
- },
125
- {
126
- name: 'seo_competitor_content_gap',
127
- description: 'Compares your page URL or draft text against top 3-5 ranking competitor pages to identify missing TF-IDF semantic entities, heading subtopics, and content depth gaps.',
128
- inputSchema: {
129
- type: 'object',
130
- properties: {
131
- target_url_or_text: { type: 'string', description: 'Your page URL, local file path, or draft content' },
132
- target_keyword: { type: 'string', description: 'Target keyword to rank for' },
133
- competitor_urls: { type: 'array', items: { type: 'string' }, description: 'Optional list of competitor URLs (auto-scraped if omitted)' }
134
- },
135
- required: ['target_url_or_text', 'target_keyword']
136
- }
137
- },
138
- {
139
- name: 'seo_competitor_profile',
140
- description: 'Deep extraction of a single competitor URL: heading tree (H1-H4), schema types, word count, reading grade, meta tags, and internal/external link ratio.',
141
- inputSchema: {
142
- type: 'object',
143
- properties: {
144
- url: { type: 'string', description: 'Competitor page URL' }
145
- },
146
- required: ['url']
147
- }
148
- },
149
- {
150
- name: 'seo_competitor_diff',
151
- description: 'Side-by-side scorecard comparing your page vs a competitor across 25+ ranking signals (title, H1, keyword density, schema, image alt, etc.).',
152
- inputSchema: {
153
- type: 'object',
154
- properties: {
155
- my_url: { type: 'string', description: 'Your page URL or local server URL' },
156
- competitor_url: { type: 'string', description: 'Competitor URL' },
157
- focus_keyword: { type: 'string', description: 'Primary keyword to evaluate' }
158
- },
159
- required: ['my_url', 'competitor_url', 'focus_keyword']
160
- }
161
- },
162
- {
163
- name: 'seo_forum_discussions_pulse',
164
- description: 'Scrapes Reddit, Quora, and forum discussions currently ranking on Google for a topic. Extracts real user problems, sentiments, and consensus.',
165
- inputSchema: {
166
- type: 'object',
167
- properties: {
168
- topic_or_keyword: { type: 'string', description: 'Topic or keyword to query' }
169
- },
170
- required: ['topic_or_keyword']
171
- }
172
- },
173
- // ==========================================
174
- // Layer 2. GEO & AI Search (AEO)
175
- // ==========================================
176
- {
177
- name: 'seo_geo_ai_readiness_audit',
178
- description: 'Evaluates content for citation readiness in Google AI Overviews, Perplexity.ai, and ChatGPT Search (checks direct definitions, semantic chunking, tables, and stats).',
179
- inputSchema: {
180
- type: 'object',
181
- properties: {
182
- url_or_text: { type: 'string', description: 'Page URL, raw HTML, or text draft' },
183
- target_query: { type: 'string', description: 'Search query to test' }
184
- },
185
- required: ['url_or_text', 'target_query']
186
- }
187
- },
188
- {
189
- name: 'seo_llms_txt_generate',
190
- description: 'Generates standard /llms.txt and /llms-full.txt markdown files to provide clean, structured context for AI search bots.',
191
- inputSchema: {
192
- type: 'object',
193
- properties: {
194
- site_name: { type: 'string', description: 'Site or project name' },
195
- site_description: { type: 'string', description: 'Concise summary of site purpose' },
196
- key_pages: {
197
- type: 'array',
198
- items: {
199
- type: 'object',
200
- properties: {
201
- title: { type: 'string' },
202
- url: { type: 'string' },
203
- description: { type: 'string' }
204
- },
205
- required: ['title', 'url', 'description']
206
- },
207
- description: 'Key pages to index for LLMs'
208
- }
209
- },
210
- required: ['site_name', 'site_description', 'key_pages']
211
- }
212
- },
213
- {
214
- name: 'seo_ai_bots_robots_audit',
215
- description: 'Audits robots.txt permissions specifically for generative AI crawlers (GPTBot, ClaudeBot, PerplexityBot, Google-Extended, Bytespider).',
216
- inputSchema: {
217
- type: 'object',
218
- properties: {
219
- domain_or_url: { type: 'string', description: 'Website domain or URL' }
220
- },
221
- required: ['domain_or_url']
222
- }
223
- },
224
- // ==========================================
225
- // Layer 3. Information Gain & E-E-A-T
226
- // ==========================================
227
- {
228
- name: 'seo_information_gain_score',
229
- description: 'Quantifies content novelty vs top 10 Google results (Google Information Gain Patent) to detect and fix generic AI fluff.',
230
- inputSchema: {
231
- type: 'object',
232
- properties: {
233
- my_content_or_url: { type: 'string', description: 'Your content draft, local file, or live URL' },
234
- keyword: { type: 'string', description: 'Target search query' }
235
- },
236
- required: ['my_content_or_url', 'keyword']
237
- }
238
- },
239
- {
240
- name: 'seo_eeat_audit',
241
- description: 'Audits Google E-E-A-T trust signals (Person schema, author bylines, sameAs Wikidata/LinkedIn links, editorial policies, update dates).',
242
- inputSchema: {
243
- type: 'object',
244
- properties: {
245
- url_or_html: { type: 'string', description: 'Page URL or raw HTML' }
246
- },
247
- required: ['url_or_html']
248
- }
249
- },
250
- // ==========================================
251
- // Layer 4. On-Page & Content Strategy
252
- // ==========================================
253
- {
254
- name: 'seo_onpage_audit',
255
- description: 'Comprehensive on-page audit of a URL, local file, or raw HTML (title pixel width, meta CTR, heading hierarchy, image alt, and slug).',
256
- inputSchema: {
257
- type: 'object',
258
- properties: {
259
- url_or_html: { type: 'string', description: 'URL, local file path, or raw HTML string' },
260
- focus_keyword: { type: 'string', description: 'Optional primary keyword to verify' }
261
- },
262
- required: ['url_or_html']
263
- }
264
- },
265
- {
266
- name: 'seo_content_brief_generate',
267
- description: 'Generates a data-backed Content Outline & Brief with target word count, H1/H2/H3 structure, semantic entities, and PAA FAQs.',
268
- inputSchema: {
269
- type: 'object',
270
- properties: {
271
- primary_keyword: { type: 'string', description: 'Primary keyword to target' },
272
- secondary_keywords: { type: 'array', items: { type: 'string' }, description: 'Supporting secondary keywords' },
273
- search_intent: {
274
- type: 'string',
275
- enum: ['Informational', 'Transactional', 'Commercial Investigation', 'Navigational'],
276
- description: 'Optional intent classification'
277
- }
278
- },
279
- required: ['primary_keyword']
280
- }
281
- },
282
- {
283
- name: 'seo_readability_score',
284
- description: 'Computes Flesch Reading Ease, Flesch-Kincaid Grade Level, Gunning Fog index, passive voice %, and complex sentence breakdowns.',
285
- inputSchema: {
286
- type: 'object',
287
- properties: {
288
- text_or_url: { type: 'string', description: 'Text, markdown, or URL to score' }
289
- },
290
- required: ['text_or_url']
291
- }
292
- },
293
- // ==========================================
294
- // Layer 5. Technical SEO & JS Hydration
295
- // ==========================================
296
- {
297
- name: 'seo_technical_audit',
298
- description: 'Inspects HTTP status code, redirect chains, canonical consistency, meta robots (noindex/nofollow), hreflang, SSL, and OpenGraph tags.',
299
- inputSchema: {
300
- type: 'object',
301
- properties: {
302
- url: { type: 'string', description: 'URL to audit' }
303
- },
304
- required: ['url']
305
- }
306
- },
307
- {
308
- name: 'seo_js_rendering_diff',
309
- description: 'Compares raw server HTML response against the hydrated client DOM (JavaScript SEO) to spot hidden content or broken tags.',
310
- inputSchema: {
311
- type: 'object',
312
- properties: {
313
- url: { type: 'string', description: 'URL to diff (supports localhost or live sites)' }
314
- },
315
- required: ['url']
316
- }
317
- },
318
- {
319
- name: 'seo_robots_txt_validate',
320
- description: 'Tests if specific URLs or paths are crawlable by search engine bots (Googlebot, Bingbot, GPTBot) based on robots.txt rules.',
321
- inputSchema: {
322
- type: 'object',
323
- properties: {
324
- domain_or_url: { type: 'string', description: 'Website domain or URL' },
325
- test_path: { type: 'string', description: 'Subpath to test (default "/")' },
326
- user_agent: { type: 'string', description: 'Bot name to test (default "Googlebot")' }
327
- },
328
- required: ['domain_or_url']
329
- }
330
- },
331
- {
332
- name: 'seo_sitemap_inspect',
333
- description: 'Parses and validates XML sitemaps or sitemap index files, verifies lastmod tags, and checks URL limits.',
334
- inputSchema: {
335
- type: 'object',
336
- properties: {
337
- sitemap_url: { type: 'string', description: 'URL of sitemap.xml or sitemap_index.xml' }
338
- },
339
- required: ['sitemap_url']
340
- }
341
- },
342
- {
343
- name: 'seo_internal_links_analyze',
344
- description: 'Analyzes internal links, anchor text distribution, generic anchor alerts, and nofollow internal flags.',
345
- inputSchema: {
346
- type: 'object',
347
- properties: {
348
- url: { type: 'string', description: 'Page URL to analyze' }
349
- },
350
- required: ['url']
351
- }
352
- },
353
- // ==========================================
354
- // Layer 6. Keyword Research & Intent
355
- // ==========================================
356
- {
357
- name: 'seo_keyword_suggestions',
358
- description: 'Extracts keyword suggestions and long-tail variations using Google Autocomplete and the Alphabet Soup method.',
359
- inputSchema: {
360
- type: 'object',
361
- properties: {
362
- seed_keyword: { type: 'string', description: 'Seed keyword' },
363
- include_alphabet_soup: { type: 'boolean', description: 'Generate a-z suggestions (default true)' }
364
- },
365
- required: ['seed_keyword']
366
- }
367
- },
368
- {
369
- name: 'seo_questions_find',
370
- description: 'Finds question queries asked by users across Google (Who, What, Where, When, Why, How, Can, Is).',
371
- inputSchema: {
372
- type: 'object',
373
- properties: {
374
- topic: { type: 'string', description: 'Topic or keyword' }
375
- },
376
- required: ['topic']
377
- }
378
- },
379
- {
380
- name: 'seo_keyword_cluster',
381
- description: 'Clusters a list of keywords into distinct Topic Pillars and Supporting Articles using semantic similarity.',
382
- inputSchema: {
383
- type: 'object',
384
- properties: {
385
- keywords: { type: 'array', items: { type: 'string' }, description: 'List of keywords to cluster' },
386
- similarity_threshold: { type: 'number', description: 'Clustering sensitivity 0.1 - 1.0 (default 0.6)' }
387
- },
388
- required: ['keywords']
389
- }
390
- },
391
- {
392
- name: 'seo_search_intent_classify',
393
- description: 'Classifies keywords into Informational, Navigational, Commercial Investigation, or Transactional intent.',
394
- inputSchema: {
395
- type: 'object',
396
- properties: {
397
- keywords: { type: 'array', items: { type: 'string' }, description: 'Keywords to classify' }
398
- },
399
- required: ['keywords']
400
- }
401
- },
402
- // ==========================================
403
- // Layer 7. Schema & Entity Graph
404
- // ==========================================
405
- {
406
- name: 'seo_entity_salience_map',
407
- description: 'Extracts core entities, computes salience scores, and extracts Subject-Predicate-Object (SPO) relationship triples.',
408
- inputSchema: {
409
- type: 'object',
410
- properties: {
411
- text_or_url: { type: 'string', description: 'Page URL, raw HTML, or text' }
412
- },
413
- required: ['text_or_url']
414
- }
415
- },
416
- {
417
- name: 'seo_schema_generate',
418
- description: 'Generates validated Schema.org JSON-LD scripts (Article, FAQPage, Product, LocalBusiness, BreadcrumbList, Organization).',
419
- inputSchema: {
420
- type: 'object',
421
- properties: {
422
- schema_type: {
423
- type: 'string',
424
- enum: ['Article', 'FAQPage', 'Product', 'HowTo', 'LocalBusiness', 'Organization', 'BreadcrumbList', 'SoftwareApplication'],
425
- description: 'Type of schema to generate'
426
- },
427
- data: { type: 'object', description: 'Schema properties payload' }
428
- },
429
- required: ['schema_type', 'data']
430
- }
431
- },
432
- {
433
- name: 'seo_schema_validate',
434
- description: 'Validates on-page or pasted JSON-LD structured data against Schema.org and Google Rich Result requirements.',
435
- inputSchema: {
436
- type: 'object',
437
- properties: {
438
- url_or_jsonld: { type: 'string', description: 'Page URL or raw JSON-LD string' }
439
- },
440
- required: ['url_or_jsonld']
441
- }
442
- },
443
- // ==========================================
444
- // Layer 8. Performance & Maintenance
445
- // ==========================================
446
- {
447
- name: 'seo_pagespeed_audit',
448
- description: 'Checks Core Web Vitals (LCP, FCP, CLS, TTFB) with performance optimization fixes.',
449
- inputSchema: {
450
- type: 'object',
451
- properties: {
452
- url: { type: 'string', description: 'Page URL to test' },
453
- strategy: { type: 'string', enum: ['mobile', 'desktop'], description: 'Device strategy (default "mobile")' }
454
- },
455
- required: ['url']
456
- }
457
- },
458
- {
459
- name: 'seo_indexnow_submit',
460
- description: 'Submits newly created or updated URLs directly to Bing & Yandex via the IndexNow API protocol.',
461
- inputSchema: {
462
- type: 'object',
463
- properties: {
464
- host: { type: 'string', description: 'Website domain host (e.g. "example.com")' },
465
- key: { type: 'string', description: 'IndexNow API key' },
466
- key_location: { type: 'string', description: 'URL location of the key file' },
467
- url_list: { type: 'array', items: { type: 'string' }, description: 'Array of URLs to submit' }
468
- },
469
- required: ['host', 'key', 'key_location', 'url_list']
470
- }
471
- },
472
- {
473
- name: 'seo_content_decay_audit',
474
- description: 'Scans content for freshness decay (stale year references e.g. "2020", outdated statistics, broken external links).',
475
- inputSchema: {
476
- type: 'object',
477
- properties: {
478
- url_or_text: { type: 'string', description: 'Page URL or draft text to audit' }
479
- },
480
- required: ['url_or_text']
481
- }
482
- }
483
- ];
484
- // Initialize Server
485
- const server = new Server({
2
+ import { startStdioServer } from './server/server.js';
3
+ export * from './server/types.js';
4
+ export * from './server/registry.js';
5
+ export * from './server/server.js';
6
+ // Start Stdio MCP Server
7
+ startStdioServer({
486
8
  name: 'seo-gravity-mcp',
487
- version: '1.0.2'
488
- }, {
489
- capabilities: {
490
- tools: {}
491
- }
492
- });
493
- // Register list_tools handler
494
- server.setRequestHandler(ListToolsRequestSchema, async () => {
495
- return { tools: TOOLS };
496
- });
497
- // Register call_tool handler
498
- server.setRequestHandler(CallToolRequestSchema, async (request) => {
499
- const { name, arguments: args } = request.params;
500
- const a = (args || {});
501
- try {
502
- let result;
503
- switch (name) {
504
- // 0. Agent Orchestration & Remediation
505
- case 'seo_project_audit':
506
- result = await auditProject(a.project_path, a.base_url, a.crawl_depth);
507
- break;
508
- case 'seo_diagnose':
509
- result = await diagnoseSeo(a.project_path, a.target_url_or_file, a.focus_issue_id);
510
- break;
511
- case 'seo_prioritize':
512
- result = await prioritizeFindings(a.project_path, a.max_count);
513
- break;
514
- case 'seo_fix_plan':
515
- result = await generateFixPlan(a.project_path, a.finding_ids);
516
- break;
517
- case 'seo_snapshot_create':
518
- result = await createSnapshotTool(a.project_path, a.base_url, a.output_path);
519
- break;
520
- case 'seo_snapshot_compare':
521
- result = await compareSnapshotsTool(a.baseline_snapshot, a.current_snapshot);
522
- break;
523
- case 'seo_regression_check':
524
- result = await checkRegression(a.project_path, a.baseline_snapshot, a.base_url);
525
- break;
526
- // 1. SERP & Competitors
527
- case 'seo_serp_analyze':
528
- result = await analyzeSerp(a.query, a.country, a.language, a.num_results);
529
- break;
530
- case 'seo_competitor_content_gap':
531
- result = await analyzeCompetitorContentGap(a.target_url_or_text, a.target_keyword, a.competitor_urls);
532
- break;
533
- case 'seo_competitor_profile':
534
- result = await profileCompetitor(a.url);
535
- break;
536
- case 'seo_competitor_diff':
537
- result = await diffCompetitor(a.my_url, a.competitor_url, a.focus_keyword);
538
- break;
539
- case 'seo_forum_discussions_pulse':
540
- result = await analyzeForumDiscussions(a.topic_or_keyword);
541
- break;
542
- // 2. GEO & AI Search
543
- case 'seo_geo_ai_readiness_audit':
544
- result = await auditGeoAiReadiness(a.url_or_text, a.target_query);
545
- break;
546
- case 'seo_llms_txt_generate':
547
- result = generateLlmsTxt(a.site_name, a.site_description, a.key_pages);
548
- break;
549
- case 'seo_ai_bots_robots_audit':
550
- result = await auditAiBotsRobots(a.domain_or_url);
551
- break;
552
- // 3. E-E-A-T & Info Gain
553
- case 'seo_information_gain_score':
554
- result = await scoreInformationGain(a.my_content_or_url, a.keyword);
555
- break;
556
- case 'seo_eeat_audit':
557
- result = await auditEeat(a.url_or_html);
558
- break;
559
- // 4. On-Page
560
- case 'seo_onpage_audit':
561
- result = await auditOnPage(a.url_or_html, a.focus_keyword);
562
- break;
563
- case 'seo_content_brief_generate':
564
- result = await generateContentBrief(a.primary_keyword, a.secondary_keywords, a.search_intent);
565
- break;
566
- case 'seo_readability_score':
567
- result = await scoreReadability(a.text_or_url);
568
- break;
569
- // 5. Technical
570
- case 'seo_technical_audit':
571
- result = await auditTechnical(a.url);
572
- break;
573
- case 'seo_js_rendering_diff':
574
- result = await diffJsRendering(a.url);
575
- break;
576
- case 'seo_robots_txt_validate':
577
- result = await validateRobotsTxt(a.domain_or_url, a.test_path, a.user_agent);
578
- break;
579
- case 'seo_sitemap_inspect':
580
- result = await inspectSitemap(a.sitemap_url);
581
- break;
582
- case 'seo_internal_links_analyze':
583
- result = await analyzeInternalLinks(a.url);
584
- break;
585
- // 6. Keywords
586
- case 'seo_keyword_suggestions':
587
- result = await getKeywordSuggestions(a.seed_keyword, a.include_alphabet_soup);
588
- break;
589
- case 'seo_questions_find':
590
- result = await findQuestions(a.topic);
591
- break;
592
- case 'seo_keyword_cluster':
593
- result = clusterKeywords(a.keywords, a.similarity_threshold);
594
- break;
595
- case 'seo_search_intent_classify':
596
- result = classifySearchIntent(a.keywords);
597
- break;
598
- // 7. Schema
599
- case 'seo_entity_salience_map':
600
- result = await mapEntitySalience(a.text_or_url);
601
- break;
602
- case 'seo_schema_generate':
603
- result = generateSchemaMarkup(a.schema_type, a.data);
604
- break;
605
- case 'seo_schema_validate':
606
- result = await validateSchema(a.url_or_jsonld);
607
- break;
608
- // 8. Performance & Maintenance
609
- case 'seo_pagespeed_audit':
610
- result = await auditPageSpeed(a.url, a.strategy);
611
- break;
612
- case 'seo_indexnow_submit':
613
- result = await submitIndexNow(a.host, a.key, a.key_location, a.url_list);
614
- break;
615
- case 'seo_content_decay_audit':
616
- result = await auditContentDecay(a.url_or_text);
617
- break;
618
- default:
619
- throw new Error(`Unknown SEO Gravity MCP tool: ${name}`);
620
- }
621
- return {
622
- content: [
623
- {
624
- type: 'text',
625
- text: typeof result === 'string' ? result : JSON.stringify(result, null, 2)
626
- }
627
- ]
628
- };
629
- }
630
- catch (error) {
631
- return {
632
- isError: true,
633
- content: [
634
- {
635
- type: 'text',
636
- text: `SEO Gravity Tool Execution Error (${name}): ${error.message}`
637
- }
638
- ]
639
- };
640
- }
641
- });
642
- // Start the Server using Stdio transport
643
- async function main() {
644
- const transport = new StdioServerTransport();
645
- await server.connect(transport);
646
- console.error('SEO Gravity MCP Server running on stdio');
647
- }
648
- main().catch((err) => {
9
+ version: '1.2.0'
10
+ }).catch((err) => {
649
11
  console.error('Fatal error starting SEO Gravity MCP Server:', err);
650
12
  process.exit(1);
651
13
  });
@@ -0,0 +1,12 @@
1
+ import { InvariantDefinition, InvariantEvaluationContext } from './types.js';
2
+ import { SEOInvariant, Provenance } from '../types/findings.js';
3
+ export declare const BUILTIN_INVARIANTS: InvariantDefinition[];
4
+ export declare class InvariantRegistry {
5
+ private invariants;
6
+ constructor(initial?: InvariantDefinition[]);
7
+ register(invariant: InvariantDefinition): void;
8
+ get(id: string): InvariantDefinition | undefined;
9
+ getAll(): InvariantDefinition[];
10
+ evaluateContext(invariantId: string, context: InvariantEvaluationContext, provenance: Provenance): SEOInvariant | null;
11
+ }
12
+ export declare const defaultInvariantRegistry: InvariantRegistry;