使用说明
afpnews-mcp
MCP (Model Context Protocol) server that exposes AFP news content as tools for AI assistants. Works with any MCP-compatible client.
The package can also be used as a library without MCP server glue via afpnews-mcp-server/definitions.
Prerequisites
- Bun 1.3+
- An AFP API account (API key + username/password)
Setup
git clone https://github.com/julesbonnard/afpnews-mcp-server.git
cd afpnews-mcp-server
bun install
Create a .env file:
APICORE_API_KEY=your-api-key
APICORE_USERNAME=your-username
APICORE_PASSWORD=your-password
Usage
Stdio transport (default)
For local MCP clients like Claude Code or Claude Desktop:
{
"mcpServers": {
"afpnews": {
"command": "bun",
"args": ["src/index.ts"],
"cwd": "/absolute/path/to/afpnews-mcp-server",
"env": {
"APICORE_API_KEY": "your-api-key",
"APICORE_USERNAME": "your-username",
"APICORE_PASSWORD": "your-password"
}
}
}
}
HTTP transport
For remote or multi-user deployments. Stateless: each request is served by a fresh MCP server instance built from that request's own bearer token, so any number of instances can sit behind a plain round-robin load balancer with no sticky sessions or shared store. Users authenticate via OAuth2 PKCE using their AFP credentials.
Required environment variables for HTTP mode:
APICORE_API_KEY=your-api-key
APICORE_BASE_URL=https://api.afp.com
MCP_SERVER_URL=https://news-mcp.example.com
JWT_SECRET=a-random-string-of-at-least-32-characters
MCP_TRANSPORT=http
PORT=3000
Optional:
-
MCP_ALLOWED_REDIRECT_URIS— comma-separated list of allowed OAuth redirect URIs.localhost/127.0.0.1(any port) is always allowed regardless of this list — it covers any client that runs a local OAuth callback server (Claude Code, MCP Inspector, most IDEs). This var is the single place to allowlist clients with a fixed, non-localhost callback URL. Known ones:- Claude:
https://claude.ai/api/mcp/auth_callback,https://claude.com/api/mcp/auth_callback - ChatGPT:
https://chatgpt.com/connector_platform_oauth_redirect,https://chatgpt.com/oauth/callback,https://chat.openai.com/oauth/callback - Mistral (Le Chat):
https://callback.mistral.ai/v1/integrations_auth/oauth2_callback
Add others as you connect new clients — the exact
redirect_urishows up in the failed/oauth/authorizerequest when a client isn't allowlisted yet. - Claude:
bun src/index.ts
If you expose the server remotely, use HTTPS.
Docker
docker build -t afpnews-mcp .
docker run \
-e APICORE_API_KEY=your-api-key \
-e APICORE_BASE_URL=https://api.afp.com \
-e MCP_SERVER_URL=https://news-mcp.example.com \
-e JWT_SECRET=your-secret-32-chars-minimum \
-e MCP_TRANSPORT=http \
-p 3000:3000 \
afpnews-mcp
Cloudflare Workers
The HTTP transport is built as a plain Hono app with no server-side state
(the OAuth authorization code and the bearer tokens are all self-contained), so it also runs as a
Cloudflare Worker via src/http/worker.ts — no KV, Durable Objects, or other bindings needed.
bunx wrangler login
bunx wrangler secret put APICORE_API_KEY
bunx wrangler secret put JWT_SECRET
Edit wrangler.toml's [vars] (APICORE_BASE_URL, MCP_SERVER_URL — the latter must match your
actual *.workers.dev subdomain or custom domain), then:
bun run dev:worker # local dev server via workerd (bunx wrangler dev)
bun run deploy:worker # bunx wrangler deploy
Rate limiting isn't implemented in-process (it would be per-isolate and largely pointless on the edge) — use Cloudflare's own Rate Limiting in front of the Worker instead.
As a library (without MCP server dependency)
You can import pure definitions (tools, prompts, resources) and wire them into your own runtime:
import { AFP_DEFINITIONS } from 'afpnews-mcp-server/definitions';
const { tools, prompts, resources } = AFP_DEFINITIONS;
Or import each collection directly:
import {
TOOL_DEFINITIONS,
PROMPT_DEFINITIONS,
RESOURCE_DEFINITIONS,
} from 'afpnews-mcp-server/definitions';
Each definition is framework-agnostic:
tools:name,title,description,inputSchema,handler(apicore, args)prompts:name,title,description,argsSchema,handler(args)resources:name,uri,description,mimeType,handler()
Tools
| Tool | Description |
|---|---|
afp_search_articles |
Search AFP articles with filters, presets, and full-text mode |
afp_get_article |
Get a full article by its UNO identifier |
afp_find_similar |
Find similar articles (More Like This) from a UNO |
afp_list_facets |
List facet values (topics, genres, countries) with frequency counts |
afp_search_media |
Search AFP media documents (photos, videos, graphics) |
afp_get_media |
Get a full media document by UNO, with optional base64 image embed |
Search presets
The afp_search_articles tool supports presets that apply predefined filters:
a-la-une— Top story (French, last 24h)agenda— Upcoming eventsprevisions— Editorial planning / forecastsmajor-stories— Major articles
List preset
trending-topics— Trending topics from the last 24h
Full text
By default, afp_search_articles returns excerpts (first 2 paragraphs). Set fullText: true to get the complete article body. Presets default to full text.
Pagination
Use offset to paginate through results (e.g. offset: 10 to skip the first 10). For large chronological scans, prefer narrowing dateFrom/dateTo ranges in facets over high offsets. Keep size small (10–20) for best performance.
Prompts
| Prompt | Description |
|---|---|
daily-briefing |
Generate a daily news briefing |
comprehensive-analysis |
In-depth analysis on a topic |
factcheck |
Verify facts using AFP factchecks |
country-news |
News summary for a specific country |
Resources
| Resource | Description |
|---|---|
afp://topics |
AFP Stories topic catalog by language |
Development
bun install
bun test
Internal Architecture
src/tools/*.ts,src/prompts/*.ts,src/resources/*.tscontain pure definitions.src/tools/index.ts,src/prompts/index.ts,src/resources/index.tscontain MCP registration glue.src/definitions.tsexports aggregated, server-agnostic definitions:AFP_DEFINITIONSTOOL_DEFINITIONSPROMPT_DEFINITIONSRESOURCE_DEFINITIONS
License
ISC