# NewsBlog Composer (pypi · newsblog-composer-mcp)

Verifies news stories, mines SEO keywords, builds schema and reviews your draft. You write it.

- Trust score: 56/100 (low)
- Change this week: −12
- Registry status: active
- Liveness: live
- Owner verified: no
- Last scored: 2026-09-23

## Components

- pypi · `newsblog-composer-mcp`: 56/100 (this document), [markdown](https://verifymcp.io/servers/mohammed-jameal-j-newsblog-composer/newsblog-composer-mcp.md), [page](https://verifymcp.io/servers/mohammed-jameal-j-newsblog-composer/newsblog-composer-mcp)

## Channel facts

- Registry: `pypi`
- Package: `newsblog-composer-mcp`
- Version: `0.5.2`
- Transport: `stdio`

## Trust breakdown

How this component scores in each security and reliability category. Every signal is checked automatically from public evidence about the published package, including repeated runs of it in an isolated sandbox, and we only credit what we can confirm. Scores are 0–100 per category. Scoring method: https://verifymcp.io/docs/scoring (what has changed: https://verifymcp.io/docs/scoring/changelog)

Scored 2026-09-23.

- **Supply Chain Security**: 50/100
  - Malware scan not yet available for this package.
  - No known CVEs affecting this package version or its production dependencies.
  - Runs hatchling.build at install time, a recognised native-build step with no shell scripting around it.
  - 3 of 54 dependencies flagged as unhealthy.
- **Provenance & Transparency**: 32/100
  - Source repository is publicly reachable at the declared URL.
  - Provenance check failed: no build-provenance attestation is published.
  - License check failed: no license is declared.
  - Actively maintained (last published 4 days ago).
  - Disclosure check failed: no security disclosure policy was found in the source repository.
- **Schema Quality & AI Usability**: 78/100
  - 100% of prompts and resources have a non-trivial description (not blank, and not just the item's name).
  - AI-judged instruction clarity (excellent).
  - Context-footprint check failed: tool/resource definitions use about 4462 tokens (~212/item across 21 items; 19 tools + 2 resources), over budget; trim descriptions and params.
  - Usage-examples check failed: none of the tools include examples.
- **Stability & Change Management**: 37/100
  - Stability observed for 11 of 30 days with no destabilising changes; credit accrues until the full window elapses.
- **Tool Coverage**: 67/100
  - 100% of tools have a non-trivial description (not blank, and not just the tool's name).
  - 0% of tool parameters carry a description.
- **Tool Safety**: 100/100
  - No prompt-injection markers were found in the server instructions, tool names or descriptions we captured.
  - We read all 19 captured tool definition(s), and no name or description among them implies an irreversible operation.
  - An AI judge read all 21 captured unit(s) of tool text and found none that tries to manipulate the model reading it.
- **Capabilities**: 100/100
  - Implements a current MCP spec version (2026-07-28).

## Install

### How do I install the NewsBlog Composer MCP server?

NewsBlog Composer runs locally as a PyPI package, launched with uvx newsblog-composer-mcp. Ready-made configuration for Claude, Cursor, VS Code, Codex and 5 more is on this page, copied from each client's own documentation.

### Claude

```bash
claude mcp add mohammed-jameal-j-newsblog-composer -- uvx newsblog-composer-mcp
```

### Cursor

```json
{
  "mcpServers": {
    "mohammed-jameal-j-newsblog-composer": {
      "command": "uvx",
      "args": [
        "newsblog-composer-mcp"
      ]
    }
  }
}
```

### VS Code

```json
{
  "servers": {
    "mohammed-jameal-j-newsblog-composer": {
      "command": "uvx",
      "args": [
        "newsblog-composer-mcp"
      ]
    }
  }
}
```

### Codex

```bash
codex mcp add mohammed-jameal-j-newsblog-composer -- uvx newsblog-composer-mcp
```

### opencode

```json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "mohammed-jameal-j-newsblog-composer": {
      "type": "local",
      "command": [
        "uvx",
        "newsblog-composer-mcp"
      ],
      "enabled": true
    }
  }
}
```

### OpenClaw

```bash
openclaw mcp add mohammed-jameal-j-newsblog-composer --command uvx --arg newsblog-composer-mcp
```

### Hermes

```yaml
mcp_servers:
  mohammed-jameal-j-newsblog-composer:
    command: "uvx"
    args: ["newsblog-composer-mcp"]
```

### Netclaw

```json
{
  "McpServers": {
    "mohammed-jameal-j-newsblog-composer": {
      "Transport": "stdio",
      "Command": "uvx",
      "Arguments": [
        "newsblog-composer-mcp"
      ]
    }
  }
}
```

### Vellum

```bash
assistant mcp add mohammed-jameal-j-newsblog-composer -t stdio -c uvx -a newsblog-composer-mcp
```

### Other

```json
{
  "mcpServers": {
    "mohammed-jameal-j-newsblog-composer": {
      "command": "uvx",
      "args": [
        "newsblog-composer-mcp"
      ]
    }
  }
}
```

## Changelog

Every change recorded for this component, newest first. Days that predate change tracking, or that we cannot explain, say so: "we were watching and nothing happened" and "we were not watching" are different claims.

### 2026-09-23 (score 56, +1)

No change was recorded against any check on this day. Stability & Change Management went from 33 to 37. That category is still filling its 30-day observation window: 10 days of observed history at the previous scan, 11 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-09-20 (score 55, −14)

- [security regression] Malware scan: pass → unverified

### 2026-09-19 (score 69, +15)

- [security improvement] Malware scan: unverified → pass

### 2026-09-18 (score 54, +1)

- [security improvement] Malware scan: unverified → pass
- [functional] Package version: 0.5.1 → 0.5.2

### 2026-09-17 (score 53, −15)

- [security regression] Malware scan: pass → unverified

### 2026-09-16 (score 68, +17)

- [security regression] Tool safety: pass → unverified
- [security improvement] Malware scan: unverified → pass
- [security] Stability: Stability not yet verified: we do not have a sandbox capture of the MCP schema this version of the package serves yet.
- [functional regression] Schema quality: 182 → 212
- [functional regression] Capabilities: pass → unverified
- [functional regression] Tool coverage: 100 → unverified
- [functional regression] Schema quality: 100 → unverified
- [functional improvement] Stability: unverified → 0.13
- [functional] Package version: 0.3.3 → 0.5.1

### 2026-09-14 (score 51, −15)

- [security regression] Malware scan: pass → unverified

### 2026-09-12 (score 66)

First indexed and scored.

## MCP tools (19)

### `get_profile` (~107 tokens)

Check whether this server has been set up, and with what.

CALL THIS FIRST, before anything else. If `configured` is false, ask the user
the returned questions in the chat, wait for their answers, then call
set_profile. Every content tool refuses to run until then.

The answers decide the byline, the voice, the schema publisher, where the
call to action links, and the canonical URL for every post. Nothing here is
inferred from the environment.

### `set_profile` (~309 tokens)

Record who is publishing, where, and in what voice. Run once, after asking.

author_name: the person's real name. Prints as "By <name>" and goes into the
  NewsArticle author field.
tone: neutral | witty | upbeat | heartfelt | sombre. Shapes how posts are
  written; it never changes a fact, a figure, a quote or a link.
company_name: the publisher. Becomes the schema publisher and the linked text
  in the closing call to action.
site_url: the domain where posts are published. Canonical URLs, image paths
  and the call-to-action link are all built from it. A main domain or a
  subdomain both work.
company_url: only when the blog is on a subdomain and the call to action
  should point at a different company site. Defaults to site_url.
logo_url: defaults to <company_url>/logo.png.

Only pass values the user actually typed. Ask the name, company and domain
as free-text questions - do not offer guessed options, do not take a name
from the account or folder path, do not pick a tone for them, and do not
carry over a company or domain from an earlier post or example.

Input parameters:

- `author_name` (string, required)
- `company_name` (string)
- `company_url` (string)
- `logo_url` (string)
- `site_url` (string)
- `tone` (string, required)

### `reset_profile` (~23 tokens)

Forget the byline and voice, so the setup questions are asked again.

### `capabilities` (~69 tokens)

Report which providers are configured and which keyless fallbacks are in use.

Call this first when something behaves unexpectedly - it shows whether
verify_news has a real search key, whether humanize_text can rewrite
server-side, and whether score_ai_text is using a real detector or the local
heuristic.

### `write_blog_post` (~201 tokens)

Write a complete, publication-ready blog post about a news story.

USE THIS TOOL whenever the user asks for a blog post, an article, a news
write-up, or "content" about a headline or a current topic - including when
the request is as plain as "write me a blog post about X", and including when
they do not mention this server by name.

Do not search the web and draft the article yourself. That produces an
unverified post with no schema, no SEO pass and no publishing pack, which is
the exact outcome this server exists to prevent. Call this first instead.

It does not write the article on its own - it checks the input, confirms
setup, and returns the ordered plan with the next call to make. Follow the
plan. The article gets written at the draft_brief step, by you, to the
structure that tool returns.

Input parameters:

- `topic_or_headline` (string, required)

### `find_stories` (~226 tokens)

START HERE when the user gives a topic rather than a specific headline.

"write about AI today", "something on electric vehicles", "this week in fintech"
are topics. Find what actually happened before writing anything.

"AI today", "electric vehicles", "Indian fintech" are topics: there is no
claim to verify yet, you first have to find out what actually happened.
This searches recent coverage, groups articles reporting the same event into
stories, and ranks them by independent publisher count and freshness.

Use `ready_to_write` - those stories already clear the two-publisher bar and
have fetchable URLs. Check `age_hours` to pick something current. Then pass
the chosen story's `headline` to verify_news and its `fetchable_urls` to
fetch_article_facts.

\`days` is the recency window and defaults to 2. Widen it if nothing comes
back; narrow it to 1 for same-day news only.

Input parameters:

- `days` (integer)
- `limit` (integer)
- `topic` (string, required)

### `verify_news` (~271 tokens)

START HERE when the user gives a specific headline and wants a post about it.

Confirms the headline describes a real, corroborated story before anything is
written. Call this even if the user just says "write a blog post about <headline>" -
verifying first is the point of this server.

Searches every configured news provider, keeps only results that actually
match the headline, and counts how many INDEPENDENT publishers are carrying
it. Returns is_legit=false unless at least two independent publishers match,
or a single primary/official source does.

This verifies a headline; it does not find one. If the user gave you a topic
("today's AI news") rather than a headline, call find_stories first. Note
that an old headline will correctly return old sources - `days` limits how
far back to look.

Do not draft anything if is_legit is false. Feed `fetchable_urls` to
fetch_article_facts, and use `reference_candidates` as the reference list -
those are real publisher URLs. Some providers return aggregator redirects
that still name the outlet; they count toward corroboration but are not
usable as links, and build_schema rejects them.

Input parameters:

- `days`
- `limit` (integer)
- `title` (string, required)

### `fetch_article_facts` (~124 tokens)

Step 3. Download the verified sources and extract usable material.

Returns facts, short attributed quotes (<=15 words) and figures, each tagged
with the source_url it came from. URLs that fail to fetch or extract are
reported in per_url with the reason - they are never filled in with guesses.

Everything you write in the article must trace back to an entry returned
here. If a claim is not in this output, it does not go in the post.

Input parameters:

- `max_facts_per_url` (integer)
- `urls` (array, required)

### `draft_brief` (~221 tokens)

Step 5. Get the writing order, then write the article.

Takes the verified facts and the keywords and returns the plan: a 1000-1300
word target, exactly two sections, the facts grouped by source with numbers
and quotes separated out, keyword placement, FAQ questions, and the angles
only this author can supply.

ACT ON IT IMMEDIATELY. You are the writer: compose the full body in the
configured voice and pass it to build_schema as `article`. Do not print the
brief for the user and ask them to write from it - they asked for a post.

Every reported claim must trace to a fact in the output. Where the sourcing
is thin, reach the length with explanatory background and mark it as
background; never attribute an invented detail to a source. Then run
find_ai_words until clean and review_draft before build_schema.

Input parameters:

- `facts`
- `faq_candidates`
- `headline` (string, required)
- `keywords`
- `references`

### `review_draft` (~148 tokens)

Step 6. Read the writer's draft and say where it is weak. Never rewrite it.

Pass the human-written draft and the facts from fetch_article_facts. Returns
must_fix / worth_fixing / consider, each note naming the sentence and what to
do about it, plus what the draft already does well.

Checks claims against the researched facts and flags figures or quotes
nothing supports, quotes over 15 words or missing attribution, stock AI
phrasing, weak openings, hedging stacks, passive density, and flat sentence
rhythm.

Returning a rewritten draft defeats the purpose. Give the writer the notes.

Input parameters:

- `draft` (string, required)
- `facts`

### `humanize_text` (~201 tokens)

Optional. Rewrite a draft to strip AI writing tells, keeping facts intact.

Prefer review_draft. This rewrites the text for the writer, which produces
machine-written prose again; a detector will read it as such, because
detectors measure how predictable the wording is rather than how many stock
phrases it contains. Use this only to edit text the writer already wrote, and
tell them it was used.


With an LLM key configured, the rewrite happens server-side and comes back in
rewritten_text. Without one, mode='delegated_to_caller' and you must apply the
returned `instructions` to `text_to_rewrite` yourself, preserving every fact,
figure, name, date, quote and URL exactly.

Optionally pass voice_sample to match a specific writer's rhythm. The sample
governs style only and never contributes facts.

Input parameters:

- `text` (string, required)
- `voice_sample` (string)

### `score_ai_text` (~110 tokens)

Step 7. Score how human the text reads, 0-100 (higher = more human).

Uses a real detector API if one is configured, otherwise a local heuristic
that measures structural tells (sentence-length burstiness, stock phrases,
em dash density, lexical variety). Check is_real_detector before presenting
the number, and always surface the caveat: no detector score proves
authorship. Run it before and after humanize_text to show the improvement.

Input parameters:

- `text` (string, required)

### `find_ai_words` (~122 tokens)

Check a draft for stock AI phrasing and report exactly where it appears.

Returns `clean` (boolean), a count, and every occurrence with the sentence it
sits in. Run it after humanize_text and rewrite each flagged sentence,
keeping every fact, figure, name and link. Repeat until `clean` is true - the
house standard is zero, not "fewer".

Cheaper and more precise than score_ai_text for this one job; score_ai_text
also measures rhythm and gives you the number.

Input parameters:

- `text` (string, required)

### `build_publishing_pack` (~348 tokens)

Final step. Everything needed to publish, in one block.

Returns the title, the Blogger labels line, the custom permalink slug, the
search description, the image alt text, and `gemini_image_prompt` - a
paste-ready prompt for Gemini with brand names already stripped, so the
banner cannot reproduce a real trademark.

\`image_style` MUST be the style the USER picked. Leave it empty and this
tool asks them directly, through the client, and waits for the answer - do
not fill it in yourself. The eight styles are product_hero,
explainer_diagram, scene_with_display, hardware_macro, whiteboard_sketch,
newspaper_front, editorial_illustration and newsletter_header. With no style
chosen there is no image prompt in the result and save_and_present refuses
the pack, because a banner the user was never asked about is the wrong
banner.

\`image_concepts`: describe what the banner should show in plain words (the
objects and ideas, not the company names), drawn from the article you just
wrote. `banner_text` shortens the headline for the image; `banner_kicker`
adds a smaller second line.

Pass the result to save_and_present as `pack` and it is written to
publish-pack.md alongside the post.

Input parameters:

- `banner_kicker` (string)
- `banner_text` (string)
- `canonical_url` (string)
- `description` (string)
- `entities`
- `headline` (string, required)
- `image_concepts` (string)
- `image_style` (string)
- `keywords`
- `slug` (string)

### `generate_image` (~126 tokens)

Step 8. Generate a banner image for the article and save it locally.

Build the prompt from the article's visual concepts, not its brand names. A
trademark filter runs anyway and rewrites brand terms into generic
descriptors before the prompt leaves this machine; check terms_removed to see
what it changed.

The returned path is local. Upload the file and pass a public https URL to
build_schema, or NewsArticle.image will point somewhere no crawler can reach.

Input parameters:

- `prompt` (string, required)
- `slug` (string)
- `style` (string)

### `seo_keywords` (~171 tokens)

Step 4. Mine the keywords this post should target, before drafting.

Pass the headline plus the `text` of the facts returned by
fetch_article_facts. Keywords come out of the source material you actually
fetched, so they reflect the reporting rather than a guess.

Returns primary_keyword, secondary_keywords, entities, and - from real Google
autocomplete data - long_tail_queries and faq_query_candidates. Draft the FAQ
from faq_query_candidates wherever your facts can answer them: those are
questions people actually type. Also returns a suggested slug, meta title and
meta description to feed into build_schema and seo_audit.

No search-volume or competition data; that needs a paid keyword API.

Input parameters:

- `include_suggestions` (boolean)
- `texts`
- `title` (string, required)

### `seo_audit` (~194 tokens)

Step 10. Score the finished body against on-page SEO rules before publishing.

Checks H1 uniqueness and keyword placement, keyword density, H2 structure,
word count, meta title and description lengths, slug shape, image alt text,
and external source links. Returns a score plus must_fix / should_fix /
nice_to_have lists.

Pass `headline` when the body has no H1 because the blog platform renders the
title itself - the H1 checks then run against that headline instead of
failing a correctly-built post.

Fix everything in must_fix and call again. On-page structure only - it says
nothing about search volume, competition or backlinks.

Input parameters:

- `headline` (string)
- `html_body` (string, required)
- `meta_description` (string)
- `meta_title` (string)
- `primary_keyword` (string, required)
- `secondary_keywords`
- `slug` (string)

### `build_schema` (~465 tokens)

Step 9. Render the HTML body and both JSON-LD blocks, then check them.

article: {headline, description (110-160 chars, used as the meta
  description), intro:[str,str] (exactly two), sections:[{heading,
  paragraphs:[str], bullets?:[str]}] - TWO or THREE sections, each with TWO
  to FOUR paragraphs, and the whole body must come to 1000-1300 words,
  cta (one closing sentence that
  must contain CTA_LINK_TEXT verbatim so it renders as a link),
  date_published?, author?, slug?, url?, meta_title?, section?, language?,
  include_h1?}
faq: [{question, answer}] - 4 to 8 entries
image: {url, alt, title?, caption?} - url must be the public https URL
references: [{title, url, publisher?}] - real fetched URLs only
keywords: the primary and secondary keywords from seo_keywords; they go into
  NewsArticle.keywords and come back in `meta` for save_and_present

Pure templating, no model call. Renders the house body format: 720px
container, inline styles, banner, byline, hr-separated H2 sections, FAQ as
H3/P pairs, references as an ordered list. By default the body carries NO H1
because Blogger renders the post title itself - set BODY_INCLUDES_H1=true if
your platform does not.

Returns `paste_block`, which is both JSON-LD scripts followed by the body,
ready to paste into the post editor, and `meta` - pass that straight to
save_and_present so the head, the schema and the body cannot drift apart. Returns validation.issues listing every
mismatch found: FAQ questions that differ between the HTML and the FAQPage
schema, an image URL that differs between the <img> tag and NewsArticle.image,
references missing from the body. Fix the issues and call again rather than
publishing output with a non-empty issues list.

Input parameters:

- `article` (object, required)
- `faq` (array, required)
- `image` (object, required)
- `keywords`
- `references` (array, required)

### `save_and_present` (~459 tokens)

Step 11. Write the finished package to disk and hand the post over.

\`pack` from build_publishing_pack is REQUIRED - this refuses without it.
That tool holds the permalink, tags, banner URL and image prompt, and it is
where the user gets asked what the banner should look like. Skipping it
produces a package that looks finished and is missing all five.

Returns `SHOW_THIS_TO_THE_USER` (print it verbatim) and `preview_html` (put
it in an HTML artifact so the user can see the post laid out).

Produces a timestamped folder containing paste-into-blogger.html (both
JSON-LD blocks plus the styled body - the file to paste into the post
editor), index.html (a standalone preview page with meta, canonical, Open
Graph and Twitter tags in the head), body.html, newsarticle.jsonld,
faqpage.jsonld, a copy of the image, meta.json, report.md, and - when `pack`
from build_publishing_pack is supplied - publish-pack.md with the title,
labels, permalink and Gemini image prompt.

report.md is the human-readable summary: verification verdict and
publishers, human score before and after humanising, SEO score with any
must-fix items, and the reference list. Populate `meta` with keys
\`verification`, `human_score` ({before, after, detector_used,
is_real_detector}), `seo` and `references` and they all appear in it.

Pass the `meta` dict that build_schema returned - canonical_url, image_url and
the rest are read from it when not given explicitly. Put the verification
result, both human scores, the SEO audit and the reference list in meta so the
post stays auditable later.

Input parameters:

- `canonical_url` (string)
- `description` (string)
- `html_body` (string, required)
- `image_path` (string)
- `image_url` (string)
- `json_ld_article` (string)
- `json_ld_faq` (string)
- `language` (string)
- `meta`
- `pack`
- `slug` (string, required)
- `title` (string)

## Diagnostics

Captured diagnostic sections: Provenance, Install scripts, Dependencies. The full working is on the page: https://verifymcp.io/servers/mohammed-jameal-j-newsblog-composer/newsblog-composer-mcp#diagnostics

## Score history

- 2026-09-23: 56
- 2026-09-22: 55
- 2026-09-21: 55
- 2026-09-20: 55
- 2026-09-19: 69
- 2026-09-18: 54
- 2026-09-17: 53
- 2026-09-16: 68
- 2026-09-15: 51
- 2026-09-14: 51
- 2026-09-13: 66
- 2026-09-12: 66

## Common questions

### What is the NewsBlog Composer MCP server?

NewsBlog Composer is an MCP server listed in the public MCP registry as io.github.Mohammed-Jameal-J/newsblog-composer. Verifies news stories, mines SEO keywords, builds schema and reviews your draft. You write it. This page covers its PyPI package (newsblog-composer-mcp).

### Is the NewsBlog Composer MCP server safe to use?

NewsBlog Composer scores 56 out of 100 on VerifyMCP. We found no known CVEs affecting it as of 23 September 2026. That is a record of what we were able to check automatically, not an endorsement. The category breakdown on this page shows every signal behind the number, including the ones we could not confirm.

### What tools does the NewsBlog Composer MCP server expose?

NewsBlog Composer exposes 19 tools: get_profile, set_profile, reset_profile, capabilities, write_blog_post, and 14 more. Their descriptions and schemas cost roughly 3,895 tokens of context every time the server is loaded.

### Is the NewsBlog Composer MCP server still maintained?

NewsBlog Composer is still listed as active in the MCP registry. We last reached this channel on 23 September 2026. Those dates come from our own scans of the registry and the channel itself, not from anything the publisher announced.

## Links

- PyPI project: https://pypi.org/project/newsblog-composer-mcp/
- Socket report: https://socket.dev/pypi/package/newsblog-composer-mcp
- Repository: https://github.com/Mohammed-Jameal-J/newsblog-composer-mcp
- Changelog RSS feed: https://verifymcp.io/servers/mohammed-jameal-j-newsblog-composer/newsblog-composer-mcp.xml
- Changelog JSON feed: https://verifymcp.io/servers/mohammed-jameal-j-newsblog-composer/newsblog-composer-mcp.json
- HTML version of this page: https://verifymcp.io/servers/mohammed-jameal-j-newsblog-composer/newsblog-composer-mcp
