Automattic / Automattic/mcp-wordpress-remote

Requests send a bare "node" User-Agent, making this traffic impossible for firewalls/security plugins to identify

Open
#111 4 comments 0 reactions 1 assignee Claimed by @galatanovidiu View on GitHub
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.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.