Metadata-Version: 2.4
Name: kranked-mcp
Version: 0.1.0
Summary: MCP server exposing App Store keyword intelligence — difficulty, popularity, and live rank — to any MCP client. The GUI-free companion to the Kranked ASO app.
Project-URL: Homepage, https://github.com/akoskomuves/kranked-mcp
Project-URL: Repository, https://github.com/akoskomuves/kranked-mcp
Author-email: Akos Komuves <akos@tallpoppy.xyz>
License: MIT
License-File: LICENSE
Keywords: app-store,app-store-optimization,aso,ios,keywords,mcp
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Requires-Python: >=3.10
Requires-Dist: httpx>=0.25.0
Requires-Dist: mcp[cli]>=1.2.0
Requires-Dist: uvicorn[standard]>=0.30
Description-Content-Type: text/markdown

# Kranked MCP

An [MCP](https://modelcontextprotocol.io) server that exposes **App Store keyword
intelligence** — keyword difficulty, popularity, and live rank — as tools any MCP
client (Claude, etc.) can call. It's the headless companion to the
[Kranked](https://github.com/akoskomuves) ASO app: same scoring, no GUI.

Stateless and zero-config: every tool is a live call to Apple's public endpoints (the
iTunes Search API and search-hints). **No database, no API keys.** Runs locally via `uvx`
or as a hosted server.

## Tools (free / open core)

| Tool | What it answers |
|---|---|
| `search_apps` | Find apps (and their `app_id`) matching a term |
| `check_keyword` | **One-shot report:** difficulty + popularity + KEI + competitors, and your app's rank |
| `keyword_difficulty` | How hard a keyword is to rank for (0–100), with the top-10 competitors |
| `keyword_popularity` | How searched a keyword is (suggest-based 20/50/80) |
| `keyword_suggestions` | Apple's autocomplete hints for a seed term |

All tools take a two-letter `country` (default `us`).

> **Premium (hosted):** `popular_keywords` — top most-searched keywords by category with
> *real* Apple Search Ads popularity (0–100) — is available on the hosted service, not in
> this open-source package.

### How the scores work

- **Difficulty (0–100)** — analyzes the top-10 ranking apps' review volume and rating
  quality. More established competitors = harder. Labeled Very Easy → Very Hard.
- **Popularity (20/50/80)** — whether Apple auto-suggests the term (exact / related /
  neither). For real ASA popularity numbers, use `popular_keywords`.
- **KEI** — Keyword Efficiency Index = popularity / difficulty. Higher is a better bet.

## Install

Once published to PyPI, no clone needed — `uvx` runs it on demand. Add to your MCP
client config:

```json
{
  "mcpServers": {
    "kranked": {
      "command": "uvx",
      "args": ["kranked-mcp"]
    }
  }
}
```

For Claude Code: `claude mcp add kranked -- uvx kranked-mcp`

### Local / development

```bash
git clone https://github.com/akoskomuves/kranked-mcp
cd kranked-mcp
uv sync
```

Point your client at the local checkout:

```json
{
  "mcpServers": {
    "kranked": {
      "command": "uv",
      "args": ["--directory", "/absolute/path/to/kranked-mcp", "run", "kranked-mcp"]
    }
  }
}
```

Run the tests (they hit live APIs, so they can be flaky under rate limiting):

```bash
uv run pytest
```

## Self-hosting (remote MCP)

Kranked runs in two modes from the same code:

| Mode | Transport | Use | Command |
|---|---|---|---|
| **Local** | stdio | one user, on your machine | `kranked-mcp` |
| **Hosted** | streamable-HTTP at `/mcp` | shared server, many users | `kranked-mcp-serve` |

The hosted server is stateless (`stateless_http`), so it scales horizontally. Deploy the
included `Dockerfile` to any container host (Railway, Fly, Render, …); it reads `PORT` from
the environment and exposes `GET /health` for liveness checks.

### Deploy to Railway

The repo ships a `railway.toml` (Dockerfile build, `/health` healthcheck). To deploy:

```bash
# one-time
npm i -g @railway/cli && railway login

# from the repo root
railway init            # create/select a project
railway up              # build the Dockerfile and deploy
railway domain          # get a public https URL
```

Or connect the GitHub repo in the Railway dashboard — it picks up `railway.toml` automatically.
Set `KRANKED_CACHE_TTL` in the service's Variables if you want a longer/shorter cache.

Then point a client at the URL:

```bash
claude mcp add --transport http kranked https://your-app.up.railway.app/mcp
```

### Config

| Env var | Default | Purpose |
|---|---|---|
| `PORT` / `HOST` | `8000` / `0.0.0.0` | bind address |
| `KRANKED_CACHE_TTL` | `3600` | seconds to cache upstream responses (`0` disables) |
| `KRANKED_CACHE_MAX` | `2000` | max cached entries |

**Caching is not optional for a hosted deployment.** All users' requests leave from one IP,
so without it you hit Apple's/Astro's per-IP throttle immediately. Difficulty/popularity change
slowly, so cached results stay useful for hours. For multiple instances, move the cache to Redis.

> **Roadmap (paid tier):** the hosted server is free and open at launch. API-key auth + usage
> metering are the intended gate for a paid tier. The popularity data source is isolated in
> `popularity.py` so it can be swapped to a first-party Apple Search Ads feed before monetizing.

## Rate limiting

The iTunes API throttles unauthenticated callers per IP with a 403/429 and a non-JSON
body. The server serializes requests through a global throttle and retries throttles
with exponential backoff + jitter, so it degrades gracefully instead of surfacing bogus
decoding errors.

## License

MIT © Akos Komuves
