AI-powered SEO and marketing intelligence — keyword research, SERP analysis, backlink checking, and content optimization for any website.
The server defines 6 SEO/marketing tools with reasonable descriptions and Zod-based input schemas. All tools are explicitly registered with verb_noun naming (keyword_research, analyze_serp, check_backlinks, optimize_content, site_audit, content_brief). Descriptions are present and moderately detailed (avg ~150 chars), meeting the 10 - 1024 char range. However, critical gaps exist: (1) Output schemas are not documented, responses return free-form text wrapped in [{ type: 'text', text: result }] with no structure. LLMs cannot reliably extract or chain results. (2) Parameter descriptions are generic and lack format/constraint details, e.g., 'num_results' has no stated max enforcement; 'focus' for site_audit has no enum. (3) No error handling guidance, failed API calls will return raw errors without recovery hints. (4) Tier-based gating (pro/business) is implemented but error messages are promotional text, not actionable recovery steps. (5) No pagination support despite tools analyzing potentially large result sets. (6) Tool names use underscores (keyword_research) which is good, but descriptions embed emoji and '[Pro]' markers that clutter LLM parsing.
Analyze search engine results for a query — top ranking pages, content patterns, SERP features, and ranking opportunity assessment.
Analyze a website's backlink profile — referring domains, anchor text patterns, link quality indicators, and link building opportunities.
🔒 [Pro] Generate a production-ready content brief — analyzes top-ranking pages, provides title options, full outline with word counts, keyword targets, and differentiation strategy.
Research keyword opportunities for a business — search volume indicators, difficulty estimates, related terms, and content suggestions.
Analyze and optimize content for SEO — keyword density, readability, structure, meta tags, and actionable improvement suggestions.
No documented output schemas. All tools return free-form text responses wrapped in [{ type: 'text', text: result }]. LLMs cannot extract structured fields, parse pagination tokens, or reliably chain tool calls. Expected: Define and document the structure of response data (e.g., 'Returns object with fields: keywords (array), difficulty_score (number), search_volume (number), related_terms (array)').
Parameter descriptions lack constraint details. 'num_results' states '(max 10)' in description but Zod schema does not enforce max. 'focus' for site_audit has no enum constraint or list of valid values. 'content_type' has default in description but not in schema. Expected: Add z.number().max(10) and z.enum(['page_speed', 'schema_markup', 'mobile', ...]) to Zod schemas; remove redundant descriptions.
Inferred effective spec: <=2025-11-25.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-22 | C | 65 | <=2025-11-25 | v2 |
| 2026-03-09 | F | 35 | - | v1 |
🔒 [Pro] Full technical SEO audit of a website — crawls multiple pages, checks SSL, speed, schema, headings, linking structure, and provides a prioritized fix plan.
No error handling or recovery guidance. Tier-gated tools return upgrade messages, but no guidance on how agents should handle API failures (e.g., timeout, rate limit, missing data). Expected: Return structured error responses with error code, user-fixable vs. retryable classification, and next-step guidance. E.g., { error: 'rate_limited', message: 'API quota exceeded', retry_after_seconds: 60, suggestion: 'Try again in 1 minute' }.
Descriptions contain emoji and marketing text ('[Pro]', '🔒') that interfere with LLM parsing and tool selection reasoning. Expected: Use plain, concise descriptions without emoji or UI markers. Reserve tier information for server-side gating; do not embed in tool descriptions.
No pagination support. Tools analyzing SERP results, backlinks, and site content may return large datasets. No limit, page, offset, or cursor parameters. Expected: Add limit (default 20, max 100), offset/page, and a next_cursor field to responses for continuation. Return total_count so agents know result cardinality.
Parameter naming inconsistency. 'competitor_urls' is a comma-separated string, not an array. This forces LLMs to join arrays manually or misunderstand the format. Expected: Use 'competitor_urls' as z.array(z.string()) and accept either format in implementation, or rename to 'competitor_url_csv' and document the exact format (e.g., 'comma-separated, no spaces').