Docs
NewsMCP is an MCP server that lets Claude, Claude Code, Cursor, or any MCP-capable client search global news from inside a chat. You ask in plain language; it returns story events — clusters of articles covering the same story, each with a few representative citations. Keyless to start, full commercial licence.
00 — Quickstart
Nothing to install and no signup. The fastest way to see real output is the REST surface — same data, no JSON-RPC envelope:
curl -s -X POST https://api.newsmcp.com/v0/search_news \
-H 'Content-Type: application/json' \
-d '{"q":"\"OpenAI\"","event_size":3}'
Or over MCP, which is what your assistant uses:
claude mcp add --transport http newsmcp https://mcp.newsmcp.com/mcp
Then just ask: “What are the top stories about Apple today?”
If you are an AI agent reading this, the compressed machine-readable contract is at /agent-onboarding/SKILL.md — endpoint, query syntax, schema and limits in one fetch.
01 — The model
This is the one concept worth understanding before anything else. A search does not return a flat list of articles. It returns events — and every outlet covering the same story collapses into one of them.
So a busy story arrives as a single object with article_count: 125 rather
than 125 near-identical rows. Your agent reads one result instead of thirty duplicates,
and article_count doubles as a salience signal: how many newsrooms thought
this was worth covering.
Each event carries up to 3 representative citations — headline, summary, link, date, theme, sentiment. Article body text is never returned. Follow the link to read the full piece at the publisher.
02 — Connect
The server URL is https://mcp.newsmcp.com/mcp — streamable HTTP, stateless,
no session handshake.
Claude Code:
claude mcp add --transport http newsmcp https://mcp.newsmcp.com/mcp
Claude Desktop / Cursor — add to your MCP config, then restart:
{
"mcpServers": {
"newsmcp": {
"url": "https://mcp.newsmcp.com/mcp"
}
}
}
Same behaviour, plain HTTP. Useful for scripts and backends.
POST https://api.newsmcp.com/v0/search_news
GET https://api.newsmcp.com/health
Full machine-readable spec: openapi.json.
None required — keyless works. To use a token, send it as a header:
x-api-token: <your-token>
Authorization: Bearer and x-api-key are
silently ignored. They return 200 with keyless results, so a
misconfigured header looks like it is working while quietly giving you the free tier.
Use x-api-token.
03 — Writing queries
Bare space-separated words get an implicit AND. Mixing that with an
explicit OR at the same level is rejected — this is the single most common
failure:
AI OR artificial intelligence → rejected
AI OR "artificial intelligence" → correct
Only q is required. It is matched against whichever fields
search_in selects.
| Syntax | Meaning | Example |
|---|---|---|
| space | both words must appear (implicit AND) | interest rates |
"…" | exact phrase | "artificial intelligence" |
AND OR NOT | boolean logic (also &&, ||, !) | bitcoin NOT futures |
( ) | grouping | (bitcoin OR ethereum) AND regulation |
* | wildcard — cannot start a term | technolog* |
+ / - | require / exclude a term | tesla -musk |
NEAR(a, b, n) | terms within n words | NEAR("central bank", inflation, 10) |
MULTIPLE(t, n) | term appears at least n times | MULTIPLE(recession, 3) |
* alone | match everything — for filter-only searches | * |
[ ] / \ : ^Apple iPhone beats apple.* as the query when you only care about filters: “everything in the
Weather theme from GB in the last day” needs no keywords at all.| Goal | q |
|---|---|
| One company, precisely | "Apple" AND ("iPhone" OR "App Store") |
| A phrase or its acronym | AI OR "artificial intelligence" |
| Broad topic, one exclusion | (electric vehicles OR EV) NOT China |
| Adverse media screen | fraud OR bribery OR "money laundering" |
04 — Parameters
Your assistant sets most of these from your wording — you rarely name them yourself. List-type parameters accept several values at once: multiple values inside one parameter mean OR, while different parameters combine with AND.
| Parameter | Purpose | Values | Default |
|---|---|---|---|
q | Search terms | free text + boolean operators | required |
search_in | Which part of the article to match | title, title_content | title_content |
response_formatMCP only | Output shape. Not accepted over REST, which always returns JSON | markdown, text, json | markdown |
sources | Restrict to named publishers | list of domains | none |
source_groups | Restrict to a ranked publisher list | one Top N … expression | none |
lang | Article language | ISO 639-1 codes | all allowed |
countries | Publication country | ISO 3166-1 alpha-2 | all |
from_ | Start of time range | ISO 8601 or plain English | 7 days ago |
to_ | End of time range | ISO 8601 or plain English | now |
sort_by | Which articles get gathered first | relevancy, date, -date | relevancy |
theme | Topic category | 16 fixed labels, below | all |
sentiment | Tone | Positive, Neutral, Negative | all |
grouping | Clustering tightness | low, medium, high | low |
event_size | How many story events | 1–100 | 1 |
search_intitle_content matches headline and body — broader recall.
title matches headlines only, which gives you stories that are
about a subject rather than merely mentioning it in passing.
sort_byControls the order articles are collected in, before clustering — so it decides which articles make it into your results.
relevancy — best text match firstdate — newest first-date — oldest firstThe leading minus on -date means ascending, the opposite of the
usual convention. date is the one that gives you the latest news.
event_sizeCaps events, not the articles inside them. The default of 1
gives one focused story — ask for more when you want breadth. There is
no pagination: to go wider, raise event_size or split the
time range across several searches.
groupingThe cosine-similarity threshold for treating two articles as the same story:
low = 0.7 (loosest, broader events), medium = 0.8,
high = 0.9 (strictest, more single-article events). If results feel lumped
together, raise it; if one story keeps appearing as several events, lower it.
source_groupsSearch a ranked set of publishers without maintaining a domain list:
Top <N> [languages] [topics] [countries].
Top 20 the 20 highest-ranked publishers globally
Top 10 Finance GB top 10 UK finance publishers
Top 15 English Financial Crime US "Financial Crime" reads as one topic
FR means France, French means the language.Top 10 English Politics US
does not filter results to English, Politics, or the US — ask for those explicitly.themeA fixed list of 16; anything else is rejected. Business,
Finance and Economics overlap in practice — pass all three for
full business coverage. General is the catch-all, so filtering to it
narrows rather than widens.
Automotive | Business | Crime | Economics |
Entertainment | Finance | Financial Crime | General |
Health | Lifestyle | Politics | Science |
Sports | Tech | Travel | Weather |
Three filters apply to every search and cannot be switched off: a
minimum length so stubs don't crowd out reporting,
no paywalled content, and news publishers only.
That last one has a deliberate exception — when you name publishers yourself via
sources or source_groups, your list replaces the default.
05 — What comes back
response_format | You get |
|---|---|
| markdown | Readable digest — the default, and the cheapest for a model to reason over |
| text | Plain title / link / date / summary lines |
| json | The structured payload — use this when you are parsing |
Ask for it in words (“give me that as JSON”) or pass
response_format: "json" directly. If you intend to parse the result,
request JSON rather than pattern-matching the markdown.
response_format exists on the MCP surface only. The REST endpoint has
no output-shape option — it always returns the JSON below — and rejects unknown
fields, so sending response_format to /v0/search_news fails
with 499 unexpected_field.
{
"status": "ok",
"events_count": 41,
"events": [
{
"event_id": "1847a4931a6c8002",
"article_count": 125,
"event_score": 5.85,
"articles": [
{
"title": "White House summons AI giants after models go rogue",
"summary": "Meta, Anthropic, OpenAI and Google have been invited…",
"link": "https://www.independent.co.uk/tech/…",
"published_date": "2026-08-04T08:21:26",
"theme": ["Tech", "Politics"],
"sentiment": "Negative"
}
]
}
]
}
| Field | What it is |
|---|---|
events_count | How many clusters were found before the event_size cap |
event_id | Identifier for this cluster within this response. Derived from cluster membership, so the same story gets a different value on a later search — don't store it |
article_count | How many articles were grouped into this story. Usually larger than the number of citations shown |
event_score | Mean match strength. Comparable between events in the same response only — never across searches |
articles | Up to 3 representative citations |
summary | A short generated summary. Can be null |
keyless_notices | Present when your request was narrowed for lack of a token — read it rather than guessing |
06 — Access and limits
| Keyless | With an API token | |
|---|---|---|
| How far back | ~last 24 hours | ~last 30 days |
| Languages | English only | any supported language |
| Events per search | up to 8 | up to 100 |
| Searches per hour | limited per network address | governed by your plan |
| Commercial use | yes | yes |
Ask for a wider window than keyless allows and the search still runs — narrowed —
with a keyless_notices entry explaining what was adjusted, for example
“from_ was reset to the last 24 hours.” You will not get a hard
failure just for asking.
Every plan, keyless included, comes with a full commercial licence — ship what you build from day one. For a token, a longer window or the Enterprise tools, go through sign in.
07 — Troubleshooting
| Symptom | What it means | What to do |
|---|---|---|
| “invalid query” | Malformed syntax — most often an unquoted multi-word phrase next to an OR, or unbalanced parentheses |
Quote phrases: AI OR "artificial intelligence". Balance brackets. Remove [ ] / \ : ^ |
| Validation error naming a parameter | A value is outside the allowed set — unknown language, country or theme, event_size over 100, or from_ later than to_ |
Correct it against §04 |
| Rate-limit error | Too many keyless searches from your network in the window | Wait for the window to reset, or get a token |
| Results narrowed with a notice | You asked for more than the keyless allowance | Nothing is broken — the search ran, narrowed. A token lifts the limits |
| Empty results | The filters genuinely match nothing — often a misspelled domain, too tight a sources list, or too narrow a window |
Loosen one filter at a time: widen from_, drop sources, lower grouping |
| Connection refused | Datacenter and cloud IPs are blocked when keyless — CI, serverless and VPS calls hit this | Call from a normal network, or use a token. Retrying will not help |
check_health confirms the service is reachable — no token, no parameters,
no news returned. Use it when a search fails and you want to know whether the problem is
the service or the request. Ask: “Check NewsMCP health.”
08 — Example asks
These are all valid things to say to your assistant:
| What you say | What gets used |
|---|---|
| “What are the top stories about Apple today?” | q, from_, event_size |
| “Find English news about AI regulation” | q, lang |
| “Search reuters.com and bbc.com for interest rates” | q, sources |
| “Show positive tech news about AI this week” | q, theme, sentiment, from_ |
| “Only headlines mentioning the ECB — nothing in passing” | search_in: title |
| “Check the top 10 English finance publishers in the US for rate-cut coverage” | source_groups |
| “Latest first, and split each development separately” | sort_by: date, grouping: high |
| “How did this story start? Oldest coverage first” | sort_by: -date |
| “Everything in the Health theme in the last 24 hours, no keyword” | q: *, theme, from_ |
| “Give me that as JSON” | response_format: json (MCP only) |
| “Is NewsMCP up?” | check_health |
Apple iPhone beats
apple; "Tim Cook" in quotes beats it unquoted.