Automattic / Automattic/mcp-wordpress-remote
Requests send a bare "node" User-Agent, making this traffic impossible for firewalls/security plugins to identify
- Dominant language
- TypeScript
- Stars
- 180
- Forks
- 35
- PR merge metrics
- No merged PRs in 30d
Description
## Summary
The client never sets an explicit `User-Agent` header when calling the WordPress REST API. I ran the published package against a local test listener to see what actually goes out on the wire, and the request arrives with:
```
user-agent: node
```
That's Node's own built-in `fetch` (undici) default when nothing overrides it, not something specific to this package. It carries no identifying information at all, and `"node"` is common enough that it's effectively indistinguishable from a huge range of unrelated scripts and tools.
## Why this matters
I've run into WordPress security/firewall plugins blocking this traffic because their bot-protection systems classify requests partly by User-Agent, and a bare `node` string looks indistinguishable from bot/scraper traffic. Since MCP clients run on the end user's own machine with no fixed IP, User-Agent is really the only practical signal a security plugin has to work with here, and right now it doesn't carry one.
This would affect any WordPress security plugin that does UA-based classification, and any project built on this bridge, not just a single use case.
## Where this happens
`src/lib/wordpress-api.ts`, in the headers object construction (around lines 391-396):
```ts
const headers: Record = {
'Content-Type': 'application/json',
Accept: 'application/json, text/event-stream',
'MCP-Protocol-Version': '2025-06-18',
...customHeaders,
};
```
No `User-Agent` key is set here, which matches what actually goes out on the wire: Node's built-in fetch default.
## Suggested fix
Add an explicit, version-stamped User-Agent at the same spot, something like:
```ts
const headers: Record = {
'Content-Type': 'application/json',
Accept: 'application/json, text/event-stream',
'MCP-Protocol-Version': '2025-06-18',
'User-Agent': `mcp-wordpress-remote/${VERSION}`,
...customHeaders,
};
```
(keeping it before `...customHeaders` so a caller can still override it via `CUSTOM_HEADERS` if they need to)
This is a small change but it's the difference between security plugins being able to build a real allowlist rule for this traffic versus not being able to identify it at all. Happy to open a PR for this if that's useful, just wanted to raise it first in case there's a reason it's currently left unset that I'm not seeing.
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.