Contentgate

io.github.adsandcodePublished by GitHub account adsandcodev0.2.0Updated Oct 29, 2026

Pre-deploy checks for content sites: keywords, translations, links, claims, page SEO/GEO audit.

VerifiedSTDIODesktop onlyDeveloper ToolsData & Analytics

Overview

AI-generated overview

Local MCP server that runs pre-deploy checks on content pages: keywords, translations, internal links, claims, SEO/GEO audit and page comparison.

What you can do
  • Check keyword coverage and whether a translation still matches its source structurally
  • Verify internal links to commercial pages and flag affirmative performance claims
  • Audit a rendered page for visible text without JavaScript, JSON-LD, outbound link rel, image alt/width and favicon
  • Hash page content and decide honest sitemap lastmod dates
  • Compare two pages for sentences shared word for word
When to use it
Useful when writing or shipping content pages and you want problems caught before publication rather than after going live, for example keyword coverage, translation drift, missing internal links, risky claims or SEO/GEO markup issues.
Requirements
Runs as a local stdio process, typically started with npx from the npm package mcp-server-contentgate, so Node.js is needed. No authentication, environment variables or headers are declared. Tools are pure: no filesystem or network access.
Before you install
Tools only take content in and return verdicts; they do not write, send or delete anything. Defaults need tuning: pass exclude_classes so site-wide boilerplate does not satisfy keyword and internal-link checks, and set forbid_source_script to false when source and target share a script. The default stock-phrase list reflects one editor's Traditional Chinese taste and should be replaced.

Installation

In SourceWeft

  1. Open Contentgate in the dashboard and add it to a workspace.
  2. Enable the server for the chats that should use its tools.

Desktop only via STDIO. STDIO servers start a local process, so they need the SourceWeft desktop host.

Other MCP clients

Follow the launch instructions in the repository.

README

mcp-server-contentgate

MCP server for pre-deploy content checks. Catch the problem while the page is being written, not after it is live.

Documentation and background: adsandcode.com/en/open-source/contentgate

json
{  "mcpServers": {    "contentgate": { "command": "npx", "args": ["-y", "mcp-server-contentgate"] }  }}

Tools

ToolWhat it answers
check_keywordsDo the terms this page is meant to rank for actually appear in it?
check_translationIs this translation still structurally the same document as its source?
check_internal_linksDoes this page link to anything on its own site that makes money, outside the boilerplate? Absolute links count only for hosts in site_hosts.
check_claimsDoes this copy state outcomes as facts in a way regulated advertising rejects? A disclaimer counts only when its negation governs the claim itself.
sitemap_lastmodHas this page genuinely changed, or is the build about to lie about it?
content_hashStable hash of a page with volatile blocks removed.
audit_pageIs this page readable without JavaScript, marked up with JSON-LD that parses, honest about its outbound links, and complete in its images and favicon?
compare_pagesHow many sentences do these two pages share word for word?

Every tool is pure: content in, verdict out. No filesystem access, no network access, nothing written.

The guards are also importable as plain functions, and importing starts nothing: import { checkClaims, auditPage } from "mcp-server-contentgate".

Page audit

audit_page runs six checks on one rendered page and returns a verdict for each; pass checks to run fewer.

  • visible_text: characters readable with JavaScript off, leaving out <template> and elements with the hidden attribute. Google renders JavaScript; many AI crawlers read only the HTML the server sent, so an article injected by a script is invisible to them. 1200 is a house default, not a search-engine number.
  • structured_data: every JSON-LD block parses, the @type values you require are present (default Article, BreadcrumbList, Organization), and there is a dateModified. A required type is satisfied by its schema.org subtypes (BlogPosting and NewsArticle are Articles; Corporation, NewsMediaOrganization or a LocalBusiness is an Organization). A ProfilePage is not required to be an Article.
  • outbound_links: external links without rel nofollow, sponsored or ugc. Google does not require any rel on ordinary editorial links (only sponsored on paid or affiliate links and ugc on user-generated ones), so do not add nofollow to a citation to make this pass: list the sites you cite in cite_ok. Hosts are resolved the way a browser resolves them, so backslashes and extra slashes do not disguise where a link goes; registries anyone can register under (co.uk, github.io, pages.dev) are refused in cite_ok.
  • images: <img> without alt or width. alt="" is accepted.
  • favicon: home page only; an icon <link> in the head, in a format Google Search lists (BMP, GIF, ICO, PNG, JPEG, PPM, TIFF), read from the URL path or, for a data: URI, its MIME type.
  • stock_phrases: an editorial style list, not a detector of machine-written text. The default list is one editor's Traditional Chinese taste and is meant to be replaced: connectives such as 因此, and 然而, flag ordinary sentences. Pass your own, and always for any other language.

compare_pages splits both pages into sentences (on 。!? and on . ! ? before whitespace), ignores sentences under ten characters, and measures the shared share in characters in both directions.

Sources for each rule are in the repository README.

The one design rule

A guard that has never been shown to fail is decoration.

The server runs its negative tests at startup and refuses to start if they fail. A checker that cannot prove it still catches a known-bad input should not be answering questions about your content.

The same test file is run by the Python implementation in the same repository, and both are required to produce identical verdicts on every case.

Three behaviours worth knowing before you call it

Keyword matching never normalises whitespace. web hosting and webhosting are different strings with different search volumes. If you pass one, the other does not satisfy it.

Pass exclude_classes. A call-to-action block that appears on every page will otherwise satisfy check_keywords and check_internal_links everywhere, and both tools become decoration.

Set forbid_source_script: false when the target language shares the source script, such as Simplified Chinese from a Traditional Chinese source. Otherwise every document in that locale is reported as untranslated.

Python CLI

The same checks run as a deploy gate, reading your site from disk, in the contentgate package in the same repository.

Licence

MIT.

Maintainer

Built and maintained by Ads & Code.

Source: mcp/README.md at commit 7a892be

Tools

8

check_keywords

Verify that target keywords actually appear in a rendered page. Every term tied at the highest search volume must appear at least `primary_min_hits` times; every other term at least once. Matching is literal and case-insensitive: whitespace is never normalised, because 'web hosting' and 'webhosting' are different terms with different search volumes.

Parametershtmlrequiredscopekeywordsrequiredexclude_classesprimary_min_hits

check_translation

Compare a translation against its source document for structural drift: heading sequence, HTML tag sequence, table row count, internal link paths, price tokens, locale prefix on internal links, leftover source-script characters, introduced em dashes and emoji. This checks structure, not meaning: it cannot tell you a translation is good, only that it is no longer the same document.

Parameterslocalerequiredsourcerequiredtranslationrequiredcheck_locale_prefixforbid_source_scriptrequire_front_matter

check_claims

Scan copy for affirmative performance claims of the kind that get finance, health and other regulated advertising rejected: guaranteed profit, stated win rates, promised returns. A disclaimer is not flagged when its negation governs the claim itself, shortly before it in the same clause (不保證獲利, 'we do not guarantee profit', 'no guaranteed returns'), or when the phrase is named as forbidden ('guaranteed profit claims are banned'). A negation elsewhere in the sentence does not count: 保證獲利,絕不會虧損 is still a claim.

Parameterstextrequired

sitemap_lastmod

Decide a sitemap lastmod date honestly. Hash the meaningful content of a page, compare it against the stored hash, and move the date only when the content genuinely changed. Stamping today's date on every URL every build teaches crawlers that the field carries no information.

Parametersbodyrequiredtodayrequiredprevious_hashstrip_classesstrip_patternsprevious_lastmod

content_hash

Hash the meaningful content of a page, with volatile blocks and scripts removed. Use it to tell a real edit from a rebuild.

Parametersbodyrequiredstrip_classesstrip_patterns

audit_page

Page-level SEO/GEO audit of one rendered HTML page, before it ships. Checks: visible_text (characters readable with JavaScript off, excluding <template> and elements with the hidden attribute; Google renders JavaScript, but many AI crawlers read only the HTML the server sent, so an article injected by a script is invisible to them); structured_data (every JSON-LD block parses, required @type values are present, dateModified exists; a required type is satisfied by its schema.org subtypes, e.g. BlogPosting or NewsArticle for Article; a ProfilePage is not required to be an Article); outbound_links (external links without rel nofollow, sponsored or ugc, with hosts resolved the way a browser resolves them, so backslash and extra-slash tricks are caught. Google does not require any rel on ordinary editorial links, only sponsored on paid or affiliate links and ugc on user-generated ones: do not add nofollow to citations to make this pass; list the sites you cite in cite_ok instead); images (<img> without alt or width); favicon (home page only: an icon <link> in <head>, in a format Google Search lists); stock_phrases (an editorial style list of filler phrases, meant to be replaced with your own; not a detector of machine-written text). Returns a verdict per check. Pure: nothing is fetched or written.

Parametersurlrequiredhtmlrequiredcheckscite_okmin_charsrequire_typesstock_phrasesrequire_date_modified

compare_pages

Measure how many sentences two pages share word for word, using the text a crawler sees with JavaScript off (navigation and footers excluded). Sentences split on 。!? and on . ! ? followed by whitespace; sentences under ten characters are ignored. The share is measured in characters, in both directions, and the larger figure decides, because a short page copied into a long one is a small share of the long page and all of the short one.

Parametershtml_arequiredhtml_brequiredmax_share

Version history

1
  1. v0.2.0LatestOct 22, 2026

Score

90% of the applicable checks met

How complete this listing is, computed from the registry entry, the endpoint and public sources. Not a rating of the server and not a statement that it is safe or working today: reachability is a dated check, and no installs or reviews go into the score.

  • Reached in the last 30 days25 pts
  • Auth declared10 pts

    Declare the credential headers in the registry entry, or keep the endpoint answering the probe so its auth can be classified.

  • Tools listedRequired15 pts
  • DescriptionRequired15 pts
  • Logo10 pts
  • Documentation15 pts
  • License10 pts