Skip to content

surferseo/surfer

v0.1.0MIT

Track AI search visibility, write end-to-end articles, optimize existing content, and act on data-backed recommendations with one command.

MCP servers

Declared configuration, as published in mcp.json. The directory shows indexed content; it never connects to or executes these servers.

surferstreamable-http
{
  "type": "streamable-http",
  "url": "https://mcp.surferseo.com/mcp"
}

What this package declares

The files a client reads when it loads this plugin, exactly as this revision carries them.

{
  "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
  "name": "surfer",
  "version": "0.1.0",
  "description": "Track AI search visibility, write end-to-end articles, optimize existing content, and act on data-backed recommendations with one command.",
  "author": {
    "name": "Surfer"
  },
  "homepage": "https://surferseo.com",
  "repository": "https://github.com/surferseo/skills",
  "license": "MIT",
  "keywords": [
    "seo",
    "content",
    "ai-search"
  ],
  "extensions": {
    "com.openai": {
      "interface": {
        "displayName": "Surfer",
        "shortDescription": "AI visibility and content",
        "longDescription": "Track traditional and AI search visibility, create and optimize content, and act on daily recommendations from Surfer directly in ChatGPT and Codex. Automate your content workflow: find your best opportunities to fix content gaps, get an outreach list of sources most cited by LLMs, generate content briefs and full pages in your brand voice, auto-optimize existing content, and run custom reports. All of Surfer’s live data in one conversation, just a few simple prompts away.",
        "developerName": "Surfer",
        "category": "Productivity",
        "capabilities": [
          "Read",
          "Write"
        ],
        "logo": "./assets/surfer-icon.png",
        "composerIcon": "./assets/surfer-icon.png",
        "websiteURL": "https://surferseo.com",
        "supportURL": "https://docs.surferseo.com/",
        "privacyPolicyURL": "https://surferseo.com/privacy-policy/",
        "termsOfServiceURL": "https://surferseo.com/legal/regulations/",
        "defaultPrompt": [
          "Create a Surfer outline for a keyword in my workspace.",
          "Prepare a writer-ready content brief with Surfer guidance.",
          "Help me optimize an existing article using Surfer."
        ]
      },
      "review": {
        "commerce": false,
        "commerce_description": "Requires an existing Surfer account with MCP access. Usage counts toward the account's existing Surfer subscription and usage limits. This plugin does not offer subscription purchases, upgrades, or credit top-ups.",
        "test_cases": {
          "positive": [
            {
              "description": "P1. Generate an article from a prepared empty editor with outline approval. Draft: exercised on staging; reviewer-account and OpenAI-host execution remain unverified. Required setup: an existing Content Editor in the selected active workspace, created within the last 90 days, with completed initialization and SEO guidelines, an empty document, no existing AI Article, and sufficient AI Article allowance. Use its returned keyword and identify the editor. Send the prompt, wait for the generated outline and approval pause, then reply: \"Approved. Add an FAQ section at the end of the outline, then write the article. Return the finished article and its SEO, AI Search, and total Content Scores, with any unavailable score identified.\" If an FAQ already ends the outline, keep it rather than duplicate it. Status follow-ups are allowed while asynchronous processing finishes; continue the same editor and article. Missing eligible data or a generation failure leaves the case BLOCKED. A rerun requires another eligible empty editor. This case tests article generation and the approval boundary, not new Content Editor creation.",
              "prompt": "Use an existing, analyzed Content Editor in my Surfer workspace from the last 90 days whose document is still empty and has no AI Article yet. Use its keyword, tell me which editor you chose, and generate an AI article outline for me to approve. Show me the outline and wait for my approval before writing. Do not create a new editor. Identify only the selected editor; do not describe or assess other candidate editors.",
              "tools_triggered": "content_editor__list, content_editor__get, content__get, ai_article__generate, ai_article__get_outline, ai_article__submit_outline, content_score__get; workspace and status read tools as needed",
              "expected_behavior": "Find and verify an eligible existing editor using its returned details, document body and AI Article state. Require a successful content read confirming that the document is empty before generating. A failed read does not prove emptiness; if emptiness cannot be verified, stop and mark the case BLOCKED. Start one AI Article with manual_outline=true, display its generated outline, and stop before submitting it or writing prose. After the supplied approval, ensure an FAQ is the final outline section, submit that same outline, and wait with a bound for the same article to complete. Return the canonical stored article with the FAQ last. Report numeric SEO, AI Search and total scores only when their own statuses are ready; identify pending, failed or unavailable scores without inventing values or delaying completed article delivery indefinitely. If the client pauses during processing, report the known identifier and state and continue the same work on a status follow-up, without another generation. Reuse the selected editor and article throughout; create no editor and make no duplicate generation call. Missing data or failed generation does not pass the positive workflow. Do not claim an exact credit charge without authoritative usage evidence."
            },
            {
              "description": "P2. Draft: revised prompts exercised on staging; reviewer-account and OpenAI-host execution remain unverified. Read-only audit of an existing article. Use the reviewer's selected active workspace, or resolve and ask when ambiguous. Required data: a recent Content Editor containing a full article with completed SEO and AI Search analysis. A terminally unavailable score does not prevent an audit when the document and both sets of guidelines are available; report that score status without inventing a number. Any qualifying editor created within the last 90 days is acceptable; identify it. Use existing data only. Missing article or guidelines data leaves the positive case BLOCKED. A correct finding of no gaps is allowed when supported by the data.",
              "prompt": "Audit one existing full article in my Surfer workspace with completed SEO and AI Search analysis, using a Content Editor from the last 90 days. Identify its keyword and editor ID. Give me its SEO and AI Search scores when ready; if a score is unavailable or has an error, say so and continue the audit using the available guidelines. Show up to five priority missing SEO terms with the exact suggested usage range for each, and up to five uncovered AI Search facts with a clickable source-page link for each fact. If Surfer gives a fact without a source URL, name the AI model that cited that specific fact instead. Mark unavailable values clearly. Do not change anything. Keep the answer to the editor identity, score statuses, one table of up to five missing terms, and one table of up to five uncovered facts. Do not add other findings or aggregate term/fact counts. Read the chosen article text before assessing gaps. Identify the selected editor without comparing it with other editors or claiming it is the only or newest qualifying editor.",
              "tools_triggered": "content_editor__list, content_editor__get, content__get, seo_guidelines__get_terms_coverage, ai_search_guidelines__list_facts, content_score__get; ai_search_guidelines__get and workspace reads when useful",
              "expected_behavior": "Read an eligible existing article, term coverage, AI Search facts, and score statuses. Report its actual keyword and editor ID. Report each numeric score only when its own status is ready; explain a terminal error or unavailable status and continue the usable audit without polling indefinitely or substituting a stale number. Return a reasonable shortlist of at most five absent recommended terms based on used_count=0, with each returned serp_usage.min/max range; mark a null range unavailable. Return at most five uncovered AI Search facts, supported by the article and any coverage information Surfer actually returns. Preserve a clickable returned source URL for each selected URL-backed fact; for a fact with no returned URL, preserve its own cited_by model attribution. Fewer than five findings or no gaps is acceptable when evidence supports it. Any optional totals, percentages, timestamps, or explanations must be accurate; do not invent counts or fill missing data. Read-only tools may establish readiness and selection in any supported order. Create nothing and perform no content, configuration, generation, or optimization mutation."
            },
            {
              "description": "P3. Draft: revised prompts exercised on staging; reviewer-account and OpenAI-host execution remain unverified. Writer brief from an existing analyzed editor. Use the reviewer's selected active workspace, or resolve and ask when ambiguous. Required data: an existing Content Editor from the last 90 days with completed outline, SEO guidelines, and AI Search analysis. Its document may be empty or populated. Any qualifying editor is acceptable; identify its keyword and ID. Missing required data leaves the positive case BLOCKED. The task assembles a brief without changing the editor.",
              "prompt": "Prepare a concise writer's brief from an existing Content Editor in my Surfer workspace from the last 90 days that has a completed outline, SEO guidelines, and AI Search analysis. Identify its keyword and editor ID. Include search intent, Surfer's target word count and available structure ranges, the outline, priority terms and questions, and three competitor pages with clickable links. Include up to five useful AI Search facts, each with its exact source-page link or, when no URL is provided, the AI model that cited that fact. Clearly separate your editorial suggestions from Surfer's returned guidance and mark unavailable data. Do not create an editor, write the article, or change anything. Focus on the brief itself. Do not include counts of all terms, headings, outline sections, or facts, and do not describe editors you did not choose.",
              "tools_triggered": "content_editor__list, content_editor__get, outline__get, seo_guidelines__get, ai_search_guidelines__list_facts; workspace reads as needed",
              "expected_behavior": "Select an existing editor whose outline, SEO guidelines, and AI Search analysis are complete, and report its actual keyword and ID. Build a concise brief using its returned outline and guidance. Include the returned numeric word-count target and available structural ranges without inventing unavailable targets. Search intent and other editorial recommendations may be inferred if identified as suggestions rather than returned facts. Preserve three returned competitor-page URLs as clickable links, or explain if fewer are available. Include at most five selected AI Search facts with a clickable returned source-page URL for each URL-backed fact; preserve the individual cited_by attribution for each URL-less fact. Do not label search-engine claims as independently verified. Correctly distinguish any current document score from the quality of a future article. No explanation of rejected editor candidates is required, but any volunteered chronological or numerical claim must agree with returned data. Create or regenerate nothing, start no AI Article, and make no content or configuration changes."
            },
            {
              "description": "P4. Draft: revised prompts exercised on staging; reviewer-account and OpenAI-host execution remain unverified. Compare AI visibility using the latest available historical report. Use the workspace explicitly selected by the reviewer; do not switch workspaces to find better data. If none is selected, resolve the sole active workspace or ask the reviewer to choose. Required data: an AI Tracker project with a usable latest available 30-day summary for the tracked brand and reports for all five model families, plus at least one other brand with a non-null presence score in the combined report. A disabled or older project is eligible when its report is accessible and its status and actual report dates are disclosed. If multiple projects have usable reports and none is selected, ask the reviewer which to use before the task. Missing reports or no usable competitor make the positive case blocked, not passed. No fixed workspace, brand, project ID, or report date is a fixture.",
              "prompt": "Compare our brand with the highest-ranked competing brand by Surfer's presence score in the latest available 30-day AI search report for my workspace. Show how they compare on each AI platform and overall, and explain which competitor you chose. Include the actual report dates and tell me if tracking is paused or the data is old. Do not change anything.",
              "tools_triggered": "workspace__list when needed, ai_tracker__list, ai_tracker__get when needed, ai_tracker__get_summary, ai_tracker__list_brands",
              "expected_behavior": "Use the selected workspace and identify its selected or sole usable AI Tracker project and tracked brand. Read the summary with range=30d and report the actual returned start and end dates rather than treating 30d as the last 30 days from today. Disclose disabled tracking or stale dates if shown by the returned project data. Read the first combined-report brand page with range=30d and model=all. The API orders this list by presence_score descending: choose the first other brand with a non-null presence_score, preserving API order for ties, and explain that this is a presence-score selection rather than a claim about maximum mention rate. Continue pagination only if no eligible other brand is yet found; exhaustive enumeration is not needed once the highest-ranked eligible competitor is found in that ordering. Query the same competitor for ai_mode, ai_overviews, openai, perplexity and gemini, paginating individual platform lists only as needed to find it. Return one comparison table with all five platforms and all models combined, showing each brand's mention rate, average position and presence score from the same returned model and report window. Label a genuinely absent/null competitor metric unavailable rather than zero. If required platform reports are missing or windows cannot be aligned, explain the missing data and record the positive case as blocked instead of presenting a complete comparison. Make reads only and start no tracking, report refresh or other work."
            },
            {
              "description": "P5. Draft: revised prompts exercised on staging; reviewer-account and OpenAI-host execution remain unverified. Plan work from existing recommendations with explained priorities. Use the workspace explicitly selected by the reviewer; do not switch workspaces to find better data. If none is selected, resolve the sole active workspace or ask the reviewer to choose. Required data: at least three existing optimize recommendations and three existing write recommendations. Recommendations may be historical; the response must describe only the freshness evidence actually returned. Recommendation updated_at timestamps are record timestamps, not proof of Content Audit or topical-map refresh time. Configuration flags alone do not establish freshness. Missing either recommendation type or insufficient records blocks this positive case rather than passing on an explanation alone. No fixed domain, keyword, page URL or organization is required.",
              "prompt": "Plan a month of content work from the existing recommendations in my Surfer workspace. Select exactly three pages to optimize and three writing topics. For each, show your priority and Surfer's returned recommendation score; explain your priorities without inventing numerical Surfer rank positions. Keep keyword labels and full page URLs exactly as returned. Include current and previous position for each selected page, and search volume and difficulty for each writing topic. Explain the difficulty scale or conversion. Describe the available timestamp evidence and its limitations without guessing how current the underlying data is. Limit the answer to these six recommendations, their rationale, and freshness notes; do not add aggregate counts. Do not start any work.",
              "tools_triggered": "workspace__list when needed, recommendation__list",
              "expected_behavior": "Read recommendations for the selected workspace using separate optimize/write queries sorted by score descending, or the default mixed list with separately ranked type groups. Return three actionable optimize recommendations and three actionable write recommendations when the fixture is present, without additional recommendation lists or aggregate counts. Keep the two types separate and never compare their scores across types. Show Surfer's exact returned scores alongside the proposed priorities. Do not assign numerical Surfer rank positions; the case tests returned scores and explained editorial priorities, not inferred ordinal ranks. Editorial reordering is allowed when explicitly identified and explained using returned evidence such as ranking movement, existing editors, volume or difficulty; do not describe that reordered list as Surfer's own ranking. Each selected optimize item must carry its exact returned keyword, full page URL, current position and previous position. Each selected write item must carry its exact main_keyword, search_volume and avg_difficulty divided by 100, with either the 0-100 scale or the raw-to-display division explained; reasonable labeled rounding is acceptable. Apply these field requirements also to any already-started writing topics recommended as work. Treat strategy judgments as advice, not facts returned by Surfer. Mark unavailable data as unavailable. Describe returned updated_at values as recommendation record timestamps. Do not claim that these timestamps or configured flags establish the underlying audit/map refresh date or the date range of position metrics; identify limitations when freshness cannot be established. Create/open no Content Editor, start no recommendation workflow, generation, optimization or refresh, change no configuration, and make no credit-consuming call."
            }
          ],
          "negative": [
            {
              "description": "N1. Missing keyword. Draft: execution is not yet verified. Start a fresh conversation without a keyword or prior article context. Expected behavior: ask for the keyword and, only if several workspaces are active, the workspace. Read-only workspace or recommendation discovery is allowed, including suggested keywords grounded in the account's recommendations. Do not guess and act on a keyword, create a Content Editor, start article generation or optimization, or spend credits. The request lacks the topic needed to authorize credit-consuming article creation.",
              "prompt": "Write me an article."
            },
            {
              "description": "N2. Unsupported deletion. Draft: execution is not yet verified. No organization name, workspace name, editor keyword, or seeded editor count is required. Expected behavior: explain that the plugin cannot delete Content Editors and deletion must be performed in the Surfer app. It may refuse without any tool call. If it chooses to inspect scope, resolve the workspace as follows: Use the workspace already selected by the reviewer. Successful scoped reads or workspace__get/workspace__list may establish its identity and availability; no redundant discovery call is required. If no workspace is selected, list active workspaces, paginate as needed, and use the sole active workspace or ask the reviewer to choose. Stop if none is available. Do not guess or switch workspaces to find better data. Read-only discovery, counting, or an offer to list editors created in the previous calendar month is allowed, using inserted_after and inserted_before timestamps within the supported window. An empty result does not change the capability limit. Do not empty, rename, or overwrite documents as a substitute, delete templates or voices, or invoke any other write tool. No MCP tool deletes a Content Editor.",
              "prompt": "Delete the Content Editors in my Surfer workspace that we created last month. We don't need them anymore."
            },
            {
              "description": "N3. Unsupported publishing and email. Draft: execution is not yet verified. Run with Surfer as the only enabled external integration. No fixed article title, keyword, organization, or workspace is required. A recent Content Editor with a completed AI Article is optional for exercising allowed content retrieval; the refusal must not depend on finding one. Expected behavior: explain that the Surfer plugin cannot publish to WordPress or send email, and offer or return the existing article content for the user to publish. If it retrieves content, resolve the workspace as follows: Use the workspace already selected by the reviewer. Successful scoped reads or workspace__get/workspace__list may establish its identity and availability; no redundant discovery call is required. If no workspace is selected, list active workspaces, paginate as needed, and use the sole active workspace or ask the reviewer to choose. Stop if none is available. Do not guess or switch workspaces to find better data. List completed editors from the last 90 days in inserted_at descending order, paginate as needed, and inspect content_editor__get or ai_article__list to find the first with a completed AI Article; then retrieve its content. Select by editor creation date, not an unavailable article-completion timestamp. If none exists, report that without generating one. Change nothing in Surfer, invoke no write tool or external publishing/email action, and do not claim that anything was published or sent.",
              "prompt": "Find the most recently created Content Editor in my Surfer workspace from the last 90 days that contains a completed AI Article. Publish that article to our WordPress blog and email it to the team. Report the editor’s creation date and the article’s current status; omit article completion dates or times. Keep the response to the selected editor and article, whether you can perform the requested actions, and an offer to provide the article content. Do not describe other editors."
            }
          ]
        }
      },
      "publication": {
        "countries": [],
        "release_notes": "Initial Surfer plugin release for ChatGPT and Codex, combining the hosted Surfer MCP connection with seven skills for connection setup, article writing, content optimization, outlines, content briefs, reusable templates, and content recommendations."
      }
    }
  }
}

What else this package ships

These files come with the package and this site does not publish them. They are listed so you know what is there before you install it.

  • 7YAML files
  • 8other files
View on GitHub

Client extensions

Data this package carries for particular clients. The directory lists the clients named and never reads what is addressed to them.

  • com.openai