Rivalize MCP Server
by Downshift
README.md
# Rivalize MCP Server
[](https://www.npmjs.com/package/@rivalize/mcp)
[](./LICENSE)
```bash
npx -y @rivalize/mcp
```
> **Moved:** this package was published as `@kasyml/rivalize-mcp` up to 0.2.0.
> It is now `@rivalize/mcp`. Replace the old name in your client config; the
> tools, environment variables and behaviour are the same.
**Tear down any competitor's full strategy — right inside Claude, Claude Code,
Cursor, or Codex.** One prompt → their positioning, pricing, ads, social,
reviews, hiring, momentum, and where they're weak. Source-backed
and dated, not guessed — questions a general model literally can't answer
because it has no live data.
> Ad-teardown tools stop at the ads. Rivalize tears down the whole playbook —
> positioning, pricing, ads, social, reviews, hiring, momentum — and tells you
> who's even *in* the space.
Competitive intelligence as agent-callable tools. Your Claude, Cursor, or any
MCP client pulls structured, cited, dated facts about any company in the
Rivalize universe, plus your own projects and reports. Read-only by default;
set `RIVALIZE_MCP_ALLOW_WRITES=1` to also let your assistant add competitors.
**Included with every paid Rivalize plan** (Starter and up). A free account can
still create an API key for rate-limited reads (100 requests/hour), so you can
try it before you upgrade; plan-gated tools return an explicit upgrade message.
Higher plans raise the limits and unlock cited battlecards, deeper timeline and
landscape history, webhooks, API report triggers and deeper watches. Plans:
[rivalize.ai/pricing](https://rivalize.ai/pricing).
## Tools
| Tool | Type | What it does |
|------|------|--------------|
| `list_universe_companies` | read | Search the cross-customer universe by keyword, category slug, or populated intelligence layer. Compact rows; `limit`/`offset`, continue with `pagination.next_offset` |
| `get_universe_company` | read | Profile for one domain — identity, pricing, features, ads, social, reviews, funding/hiring, rankings, signals, momentum. `layers` returns only the named layers; long arrays are capped with counts |
| `teardown_competitor` | read | **One-call strategy teardown** — positioning, pricing, ads (the creatives), social, reviews, hiring, momentum + weaknesses to attack, as ready-to-read Markdown |
| `list_projects` | read | What products/projects you have — the ids the project-scoped tools take |
| `list_reports` | read | Your reports, newest first (reading is free; never generates one) |
| `get_report` | read | One report as Markdown — TL;DR, biggest threat, blind spots, per-competitor sections, cited battlecards. `section` returns one named section (see below); `competitor` returns one competitor's sections; `page` reads a long report page by page |
| `list_competitors` | read | Which competitors you are tracking (tenant-isolated). `limit`/`offset`, continue with `pagination.next_offset` |
| `get_competitor_intelligence` | read | Latest stored intelligence for one tracked competitor; each field is present only when measured |
| `get_battlecard` | read | Cited sales battlecard for one tracked competitor (Pro); may come from the competitor's latest report (`source: "report"`, `report_id`) |
| `get_strategic_timeline` | read | Five-lane temporal arc with move clusters, tracking-since dates, and evidence URLs; `lanes` to keep only pricing, product, people, funding or content-social; `page` for long timelines |
| `get_competitive_landscape` | read | Current or stored weekly activity × importance positions with an honest history start; `page` for long views |
| `get_freshness` | read | How current a project's data is: its latest report, and per tracked competitor the date it was last actually observed and how (`report_run`, `site_crawl`, `monitoring_page_capture`). A competitor never observed says so, with no date |
| `get_evidence` | read | The sources behind the facts for your product (no `competitor_id`) or one competitor: each source's URL, what it supports, and when the report run read it. Withheld claims stay withheld; corrected figures show the correction |
| `add_competitor` | write, **opt-in** | Add competitor URLs to a project — consumes credits and triggers analysis (a competitor Rivalize has never seen also queues a free Scout crawl). Registered only with `RIVALIZE_MCP_ALLOW_WRITES=1` |
`get_report` shows any claim the report's fabrication check flagged as
`[removed — unverified]`, exactly as the report itself does.
### Report sections
A whole report is several thousand to over a hundred thousand characters; one
section is a fraction of that. Ask `get_report` for the section a question needs:
| Section | Holds |
|---------|-------|
| `tldr`, `biggest-threat`, `blind-spots`, `actions` | the report's headline sections (`actions`: what your product should do) |
| `battlecards` | the cited sales battlecards |
| `competitors` | every competitor's section, in full |
| `pricing`, `momentum`, `app-store`, `strengths`, `weaknesses`, `key-findings`, `creators`, `ads`, `tech-stack` | one topic gathered from every competitor's section, under each competitor's name |
A report has only the sections it has data for. A name that is not one of the
report's sections is an error listing the ones it has. `section` combines with
`competitor` ("pricing" + "Notion" is Notion's pricing). Without `section`,
`get_report` returns the whole report exactly as before.
### Long responses
Every tool response stays under 25,000 characters, and nothing is cut silently:
- **Markdown** (`get_report`, `get_strategic_timeline`, `get_competitive_landscape`):
a document over the limit is split into pages at section boundaries. Each page
starts with `Page N of M`, how many characters remain, the exact call for the
next page (`{"page": N+1}`), and the sections on later pages. A document that
fits is returned unchanged.
- **Lists** (`list_universe_companies`, `list_competitors`, `list_reports`):
`pagination` carries `returned` and `next_offset`; if a page does not fit, fewer
rows come back, `pagination.limit` says how many, and `next_offset` resumes at
the first row not shown.
- **Objects** (`get_universe_company`, JSON timeline/landscape): long arrays are
capped and listed in `_capped` (kept/total); a field that still does not fit is
left out and listed in `_omitted` with the call that fetches it. The JSON is
always valid.
## Setup
Requires **Node.js 22 or newer** (`node --version`).
1. Sign up free at [rivalize.ai](https://rivalize.ai)
2. Create an API key: Dashboard → Settings → API Keys (`rk_live_...`)
3. Add the server to your client:
### Claude Desktop
`~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or
`%APPDATA%\Claude\claude_desktop_config.json` (Windows):
```json
{
"mcpServers": {
"rivalize": {
"command": "npx",
"args": ["-y", "@rivalize/mcp"],
"env": { "RIVALIZE_API_KEY": "rk_live_..." }
}
}
}
```
### Claude Code
```bash
claude mcp add rivalize -e RIVALIZE_API_KEY=rk_live_... -- npx -y @rivalize/mcp
```
### Cursor
`.cursor/mcp.json` in your project (or `~/.cursor/mcp.json` globally):
```json
{
"mcpServers": {
"rivalize": {
"command": "npx",
"args": ["-y", "@rivalize/mcp"],
"env": { "RIVALIZE_API_KEY": "rk_live_..." }
}
}
}
```
### Windows: if the client cannot start `npx`
Some clients on Windows cannot launch `npx` directly (it is `npx.cmd` there).
Run it through `cmd` instead:
```json
{
"mcpServers": {
"rivalize": {
"command": "cmd",
"args": ["/c", "npx", "-y", "@rivalize/mcp"],
"env": { "RIVALIZE_API_KEY": "rk_live_..." }
}
}
}
```
### Codex
`~/.codex/config.toml`:
```toml
[mcp_servers.rivalize]
command = "npx"
args = ["-y", "@rivalize/mcp"]
env = { RIVALIZE_API_KEY = "rk_live_..." }
```
### Docker
The repository includes a `Dockerfile` that runs the same stdio server as a
non-root user on Node 22:
```bash
docker build -t rivalize-mcp .
```
```json
{
"mcpServers": {
"rivalize": {
"command": "docker",
"args": ["run", "-i", "--rm", "-e", "RIVALIZE_API_KEY", "rivalize-mcp"],
"env": { "RIVALIZE_API_KEY": "rk_live_..." }
}
}
}
```
`-e RIVALIZE_API_KEY` with no value passes the key through from the client's
environment, so it never appears in the `docker run` command line.
## Troubleshooting
### "Connection closed"
When the server cannot start, or exits at once, many clients show only
"Connection closed" (Claude Code) or a failed status, not the reason. The
server prints the reason as the first line of its stderr, prefixed
`rivalize-mcp:`; most clients keep stderr in their MCP log. The causes, in
the order they are most common:
1. **`RIVALIZE_API_KEY` is missing or invalid.** The log reads
`rivalize-mcp: RIVALIZE_API_KEY is required`, or that the key does not
look like a Rivalize API key (`rk_live_` prefix). Put the key in the
server's `env` block (or the environment the client starts from) and
restart the client. A key that starts but is rejected is a 401 on the
first tool call instead; see `RIVALIZE_API_URL` below.
2. **Node.js is older than 22.** Run `node --version`; install Node.js 22 or
newer. The client runs whichever `node` and `npx` are first on its `PATH`,
which can differ from your terminal's.
3. **No network.** `npx` downloads the package on first run, and every tool
call goes to `https://rivalize.ai` (or `RIVALIZE_API_URL`). Behind a
corporate proxy, set `HTTPS_PROXY`. A network error on a tool call names
the server and the cause code (`ECONNREFUSED`, `ENOTFOUND`).
To see the message directly, run the server in a terminal with the same
command and key:
```bash
RIVALIZE_API_KEY=rk_live_... npx -y @rivalize/mcp
```
A server that started prints `rivalize-mcp-server connected via stdio` to
stderr and waits for input (Ctrl+C to stop); anything else is the reason the
client could not connect.
## Configuration
| Env var | Required | Default | Purpose |
|---------|----------|---------|---------|
| `RIVALIZE_API_KEY` | yes | — | Your `rk_live_*` key (any plan, incl. free) |
| `RIVALIZE_API_URL` | no | `https://rivalize.ai` | API base origin. **A key only works on the server that issued it**: a key created on a staging or self-hosted Rivalize needs this set to that server's origin, or every call returns 401 |
| `RIVALIZE_MCP_ALLOW_WRITES` | no | off | `1` / `true` / `yes` registers `add_competitor`, which spends credits and queues analysis |
| `HTTPS_PROXY` / `HTTP_PROXY` (and `NO_PROXY`) | no | — | Behind a corporate proxy: requests are routed through it (via undici's `EnvHttpProxyAgent`). Network errors name the server, the proxy host and the cause code (e.g. `ECONNREFUSED`, `ENOTFOUND`) |
## Limits
| Plan | Requests/hour | add_competitor/day | Webhooks | API report triggers |
|------|---------------|--------------------|----------|---------------------|
| Free | 100 | 10 | — | — |
| Starter | 300 | uncapped | yes | yes |
| Growth | 1,000 | uncapped | yes | yes |
| Pro | 5,000 | uncapped | yes | yes |
| Agency | 10,000 | uncapped | yes | yes |
The Rivalize API enforces these limits; the table mirrors them. Cited
battlecards (`get_battlecard`) unlock on Pro and up.
Rate-limit headers (`X-RateLimit-Limit`, `X-RateLimit-Remaining`,
`X-RateLimit-Reset`) are returned on every response; 429 responses include
`Retry-After`. Requests without a valid key are limited too: 200 a minute per
client.
## Report access
Reports are private until their owner shares them. `get_report` reads your own
reports with your API key. A shared report is also readable without a key at
`GET https://rivalize.ai/api/shared-reports/{share-token}/ai` (JSON; add
`?format=md` for Markdown) until the owner revokes the link; the id-keyed
`/api/reports/{id}/ai` answers only the owner.
## Try it
> "Tear down cursor.com" → `teardown_competitor` (their positioning, pricing,
> ads, social, reviews, hiring and momentum, dated — one prompt)
>
> "Who are all the players in the AI dev-tools space?" → `list_universe_companies`
>
> "What does linear.app charge now?" → `get_universe_company`
>
> "What strategic moves have competitors made this quarter?" → `get_strategic_timeline`
>
> "Who is the biggest moving threat this month?" → `get_competitive_landscape`
>
> "Summarise my latest report" → `list_reports` → `get_report`
>
> "What did my report say about Watershed?" → `get_report` with `competitor: "Watershed"`
>
> "What do my competitors charge?" → `get_report` with `section: "pricing"`
>
> "How fresh is this?" → `get_freshness`
>
> "Where does that claim about Notion come from?" → `get_evidence` with its `competitor_id`
>
> "Who is my top competitor?" → `list_competitors` (highest `threat_level`, then `momentum_score`)
>
> "Add a competitor to my project" → `add_competitor`, with writes enabled (the
> watch starts — Rivalize enriches it across 8 intelligence layers)
## Privacy Policy
This server is a thin client for the Rivalize API. What it does with your data:
- **What it sends, and where.** Each tool call becomes an HTTPS request to the
Rivalize API at `https://rivalize.ai` (or the origin you set in
`RIVALIZE_API_URL`). A request carries your API key as a Bearer token, a
`User-Agent` of `rivalize-mcp/<version>`, and the tool's arguments (for
example a company domain, a search keyword, a project, report or competitor
id, and, with writes enabled, the competitor URLs you add). If you set
`HTTPS_PROXY` / `HTTP_PROXY`, requests go through that proxy. Nothing is sent
anywhere else.
- **What it does not send.** No telemetry, analytics or crash reports. It does
not read files on your machine, your conversation, or other tools' output;
it sees only the arguments your MCP client passes to its own tools.
- **What it stores locally.** Nothing. It writes no files, keeps no cache and
holds no state between runs. Your key lives in your MCP client's
configuration, not in this server. Diagnostic messages go to stderr, which
your MCP client may log; they never include your API key.
- **What Rivalize does with requests.** The API processes them under the
Rivalize Privacy Policy: [rivalize.ai/privacy](https://rivalize.ai/privacy).
Rivalize is operated by Downshift LLC, the data controller for that data;
privacy questions go to privacy@rivalize.ai.
## Security
Report a vulnerability privately to **support@rivalize.ai** with "security" in
the subject, rather than in a public issue. Include the version
(`npm view @rivalize/mcp version` or the `User-Agent` above), what you did and
what happened. We will acknowledge the report and keep you updated until it
is resolved.
Your API key is a credential: keep it in your client's `env` block or your
shell environment, never in a shared or committed file. Revoke a leaked key
from Dashboard → Settings → API Keys.
## Support
Bugs and feature requests:
[github.com/Downshift/rivalize-mcp/issues](https://github.com/Downshift/rivalize-mcp/issues).
Account and billing questions: support@rivalize.ai.
## Development
```bash
npm install
npm run typecheck
npm run build # emits dist/ for the rivalize-mcp bin
npm test # offline: every API call is mocked or served by a local fixture
```
`server.json` is the [MCP Registry](https://registry.modelcontextprotocol.io)
entry. The tests validate it against the official schema (vendored in
`schema/`) and check that its name, version and package match `package.json`.
## License
MIT, see [LICENSE](./LICENSE).
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues