Spark Feed MCP
OAuth-protected remote MCP server for Cloudflare Workers that exposes get_videos and get_articles tools to read configured RSS/Atom feeds filtered by date, returning entries and article previews.
README
Spark Feed MCP
Spark Feed MCP is an OAuth-protected remote MCP server for Cloudflare Workers. It exposes two server-controlled tools:
get_videosreads the feeds hardcoded inVIDEO_OPML.get_articlesreads the feeds hardcoded inARTICLE_OPML.
Both tools require a date argument in MM/DD/YYYY format and return entries
published during that UTC calendar day. Article results additionally include
the first 30 Unicode characters of the cleaned article body.
Project files
| File | Purpose |
|---|---|
index.js |
Cloudflare Worker, MCP JSON-RPC endpoint, OAuth consent flow, OPML configuration, feed fetching, XML parsing, normalization, and date filtering. |
package.json |
Dependency versions and Wrangler commands. |
package-lock.json |
Reproducible npm dependency tree. |
wrangler.jsonc |
Cloudflare Worker entry point and required OAuth KV binding. |
.gitignore |
Prevents dependencies, local secrets, and generated output from being committed. |
What index.js does
Hardcoded feeds
VIDEO_OPML and ARTICLE_OPML are XML string constants near the beginning of
index.js. MCP callers cannot provide a feed URL, which keeps outbound requests
limited to the feeds you configure on the server.
Each OPML list can contain one or more nested outline elements:
<outline
text="Example feed"
type="rss"
xmlUrl="https://example.com/feed.xml"
/>
If a feed URL contains query parameters, XML-escape ampersands:
xmlUrl="https://example.com/feed.xml?topic=one&format=rss"
MCP tools
Both tools take the same required input:
{
"date": "12/12/2001"
}
get_videos returns:
{
"items": [
{
"title": "Example video",
"link": "https://example.com/video",
"date": "2001-12-12T17:00:00.000Z"
}
]
}
get_articles returns:
{
"items": [
{
"title": "Example article",
"link": "https://example.com/article",
"date": "2001-12-12T18:00:00.000Z",
"body": "The first thirty characters..."
}
]
}
The date filter includes timestamps greater than or equal to midnight UTC and
strictly earlier than midnight UTC on the following day. For 12/12/2001, that
means:
2001-12-12T00:00:00.000Z <= timestamp < 2001-12-13T00:00:00.000Z
Entries with missing or unparseable publication dates are excluded.
Feed parsing
The Worker uses XMLParser from fast-xml-parser. It supports common:
- RSS 2.0
channel.itemfeeds. - Atom
feed.entryfeeds. - RDF/RSS 1.0 feeds.
It recognizes common title, link, date, description, summary, and content fields. Dates are normalized to ISO 8601, duplicate entries are removed, and results are sorted newest first. HTML is removed from article bodies before the 30-character preview is created.
If one configured feed fails, the Worker logs that failure and still returns results from the remaining feeds. The tool returns an error only when every configured feed fails.
OAuth
OAuthProvider protects /mcp and supplies OAuth discovery, client
registration, authorization-code exchange, token refresh, revocation, bearer
validation, and OAuth storage.
The Worker implements its own /authorize consent page. Authorization requires
the server-side OAUTH_ADMIN_PASSWORD secret. The secret is never placed in
source control or wrangler.jsonc.
The public endpoints are:
| Path | Purpose |
|---|---|
/ |
Basic service information. |
/mcp |
OAuth-protected MCP endpoint. |
/authorize |
Password-protected consent page. |
/token |
OAuth token endpoint. |
/register |
Dynamic client registration endpoint. |
Prerequisites
- A Cloudflare account with Workers and Workers KV available.
- Node.js 22 or newer.
- npm.
Check your versions:
node --version
npm --version
Setup
1. Install dependencies
From this project directory:
npm ci
npm ci uses the included lockfile and installs the exact tested versions.
2. Sign in to Cloudflare
npx wrangler login
Complete the authorization page Wrangler opens.
3. Create the OAuth KV namespace
npx wrangler kv namespace create OAUTH_KV
Copy the namespace ID printed by Wrangler. Open wrangler.jsonc and replace:
REPLACE_WITH_YOUR_OAUTH_KV_NAMESPACE_ID
with that ID. The binding name must remain exactly OAUTH_KV because the OAuth
provider uses it for clients, grants, codes, access tokens, and refresh tokens.
4. Configure the Worker URL
Near the beginning of index.js, set PUBLIC_ORIGIN to the exact public origin
that Cloudflare will assign to this Worker:
const PUBLIC_ORIGIN =
"https://spark-feed-mcp.YOUR-WORKERS-SUBDOMAIN.workers.dev";
Do not include a trailing slash. The value must match the deployed Worker URL because it is used in OAuth resource and authorization-server metadata.
5. Configure the feeds
Replace the example xmlUrl in VIDEO_OPML with your video feed URL or URLs.
Replace the example xmlUrl in ARTICLE_OPML with your article feed URL or
URLs.
Example with multiple feeds:
<body>
<outline text="Feed one" type="rss" xmlUrl="https://one.example/feed.xml" />
<outline text="Feed two" type="rss" xmlUrl="https://two.example/atom.xml" />
</body>
Do not leave the example.com placeholder feeds in production.
6. Create the production authorization password
npx wrangler secret put OAUTH_ADMIN_PASSWORD
Enter a long, unique password at the prompt. Do not add this password to
wrangler.jsonc, package.json, or Git.
7. Validate the build
npm run check
This performs a Wrangler dry-run bundle without deploying.
8. Deploy
npm run deploy
After deployment, confirm the printed URL exactly matches PUBLIC_ORIGIN. If
it differs, correct PUBLIC_ORIGIN and deploy again.
9. Confirm the service
Open the Worker root URL or run:
curl https://spark-feed-mcp.YOUR-WORKERS-SUBDOMAIN.workers.dev/
The JSON response should list get_videos, get_articles, and the OAuth
endpoints. An unauthenticated request to /mcp should receive an OAuth bearer
challenge rather than tool data.
10. Connect Gemini
In the Gemini agent configuration that accepts a remote MCP server:
- Use
https://spark-feed-mcp.YOUR-WORKERS-SUBDOMAIN.workers.dev/mcpas the MCP server URL. - Select OAuth authorization if the interface asks for an authentication method.
- Allow the client-registration and authorization flow to open.
- Enter
OAUTH_ADMIN_PASSWORDon the consent page and approve access. - Verify that Gemini discovers
get_videosandget_articles.
The exact Gemini controls can vary by product surface, but the MCP URL always
ends in /mcp; the root Worker URL is not the MCP endpoint.
Local development
Create a .dev.vars file for local-only secrets:
OAUTH_ADMIN_PASSWORD=replace-with-a-local-test-password
Then run:
npm run dev
.dev.vars is ignored by Git. Never commit real production credentials.
Local OAuth redirects still depend on PUBLIC_ORIGIN. For a complete local
OAuth test, temporarily use the local origin Wrangler prints, then restore the
production origin before deployment.
Tool behavior and limits
- Date input must be a real calendar date in zero-padded
MM/DD/YYYYform. - Filtering uses UTC, regardless of the offset originally present in the feed.
- Feed requests time out after 10 seconds.
- Each feed is limited to 2 MB.
- At most four feeds are requested concurrently.
- Feed URLs must use HTTP or HTTPS.
- Results contain no feed metadata beyond the requested item fields.
- Article body previews contain at most 30 Unicode characters and no ellipsis is appended.
Troubleshooting
None of the configured feeds could be read
- Confirm that the placeholder
example.comURLs were replaced. - Open each feed URL directly and verify it returns RSS, Atom, or RDF XML.
- Check Worker logs for the URL and HTTP status of the failed feed.
OAuth or authorization fails
- Confirm
OAUTH_KVexists inwrangler.jsoncand contains the correct namespace ID. - Confirm
OAUTH_ADMIN_PASSWORDwas created withwrangler secret put. - Confirm
PUBLIC_ORIGINexactly matches the deployed HTTPS origin. - Use the
/mcpURL in Gemini, not/or/authorize.
The tools return an empty items array
- Confirm the requested date is in UTC and in
MM/DD/YYYYformat. - Confirm the feed entries contain a parseable publication or update date.
- Remember that an entry displayed as December 12 in a negative UTC offset may fall on December 13 after conversion to UTC.
Article bodies are empty
The feed must provide article text in a common field such as
content:encoded, content, summary, or description. Some feeds expose
only titles and links.
Updating dependencies
The dependency versions are intentionally pinned. To update them later:
npm outdated
npm update
npm run check
Commit both package.json and package-lock.json after testing an update.
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。