Koskamo

App Pain API MCP

An MCP server that mines iOS and Android app store reviews to identify ranked, evidence-backed user pain points, trends, and version history for competitive research and product intelligence.

Endpoint and access

No sign-in to connect and list tools. Individual tools may still need a vendor account, credentials, or permissions; check the documented prerequisites.

App Pain API MCP logo, by HawkmillCommunity listingStreamable HTTPNo sign-inEndpoint checked 2026-11-01Published by Hawkmill
MCP endpoint (Streamable HTTP)
https://hawkmill.com/mcp
Vendor documentation

What you can do with it

  • Rank user complaints by severity and share percentage
  • Track pain point trends over time to see what got worse
  • Find competitor apps across iOS and Android stores
  • Analyze raw reviews and developer replies for specific apps

Source and maintenance

Community listingRegistry 0.3.1
Maintenance checked

Protocol and capabilities

Server
app-pain-api 0.3.0
MCP protocol
2025-06-18
Tools
7 advertised
Resources
Not advertised
Resource templates
Not advertised
Prompts
2 advertised
Server-advertised capabilities
{
  "tools": {
    "listChanged": false
  },
  "prompts": {
    "listChanged": false
  }
}

Server-provided instructions

Untrusted server output shown for inspection. It is not Koskamo guidance and is excluded from knowledge search.

App Pain API — review intelligence for ANY iOS / Android app (not just your own). Typical flow: search_apps → mine_app_pain_points (the core tool: ranked complaint clusters with verbatim evidence) → drill down with get_pain_trend (what got worse / fixed over time), get_version_history (rating per release) or get_app_reviews (raw text). For ongoing tracking, watch_competitors pushes new 1-2★ reviews and rising pain points to Slack/Discord/webhooks (paid plans). appId accepts an App Store / Google Play URL, an iOS numeric id or an Android package; store is inferred when omitted. Cached analyses return instantly (popular apps are pre-warmed); a cold analysis takes 30-120s. Without an API key the server works anonymously with a small daily allowance of server-side analyses; beyond it, mine_app_pain_points returns prepared negative reviews with "instructions" ("mode":"agent") for you to cluster with your own model — do that and present the result.

Tools

7 advertised

search_apps — Search apps
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

Search the iOS App Store and Google Play (both merged by default) to find apps and their ids. Use this FIRST when you only know an app name or a category.

search_apps input schema
{
  "type": "object",
  "required": [
    "q"
  ],
  "properties": {
    "q": {
      "type": "string",
      "description": "search query, e.g. \"habit tracker\" or \"notion\""
    },
    "limit": {
      "type": "integer",
      "maximum": 30,
      "minimum": 1,
      "description": "max results per store, default 10"
    },
    "store": {
      "enum": [
        "ios",
        "android"
      ],
      "type": "string",
      "description": "limit to one store (default: both merged)"
    },
    "country": {
      "type": "string",
      "description": "ISO country code, default \"us\""
    }
  }
}
search_apps annotations
{
  "title": "Search apps",
  "readOnlyHint": true,
  "openWorldHint": true,
  "idempotentHint": true,
  "destructiveHint": false
}
mine_app_pain_points — Mine app pain points
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

THE core tool: fetch recent reviews of any iOS/Android app, keep the negative ones, and cluster them into ranked pain points (title, sharePercent, severity 1-5, verbatim evidence quotes). Ideal for competitive research and product discovery. Cached 7 days (instant on repeat); a COLD server-side analysis takes 30-120s. If the result has "mode":"agent", it contains prepared negative reviews and "instructions" — do the clustering yourself and present it to the user.

mine_app_pain_points input schema
{
  "type": "object",
  "required": [
    "appId"
  ],
  "properties": {
    "appId": {
      "type": "string",
      "description": "App Store or Google Play URL, iOS numeric id (e.g. 324684580) or Android package (e.g. com.spotify.music) — get ids from search_apps"
    },
    "model": {
      "enum": [
        "glm-5.3-flash"
      ],
      "type": "string",
      "description": "premium refinement model (paid keys only). Omit for the free default."
    },
    "store": {
      "enum": [
        "ios",
        "android"
      ],
      "type": "string",
      "description": "optional — inferred from appId (numeric id / App Store URL → ios, package / Play URL → android)"
    },
    "analyze": {
      "enum": [
        "auto",
        "server",
        "agent"
      ],
      "type": "string",
      "description": "who clusters on a cold run: \"server\" = our model; \"agent\" = you get the prepared negative reviews + instructions and cluster them with your own model; \"auto\" (default) = server, switching to agent when the server-side allowance is used up"
    },
    "country": {
      "type": "string",
      "description": "ISO country code, default \"us\""
    },
    "reviews": {
      "enum": [
        100,
        300,
        500
      ],
      "type": "integer",
      "description": "reviews to analyze, default 300 (other values round up to these tiers; iOS depth is ~50 due to Apple edge limits)"
    },
    "maxRating": {
      "type": "integer",
      "maximum": 5,
      "minimum": 1,
      "description": "ratings <= this count as negative, default 3"
    }
  }
}
mine_app_pain_points annotations
{
  "title": "Mine app pain points",
  "readOnlyHint": true,
  "openWorldHint": true,
  "idempotentHint": true,
  "destructiveHint": false
}
get_pain_trend — Pain-point trend
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

How an app's pain points changed over time: compares two archived analyses and labels each theme new / resolved / rising / falling / stable with share deltas (percentage points). Instant (archive read, no LLM). Default: latest vs ~30 days earlier. Returns a note when the app has fewer than two snapshots yet.

get_pain_trend input schema
{
  "type": "object",
  "required": [
    "appId"
  ],
  "properties": {
    "to": {
      "type": "string",
      "description": "comparison date YYYY-MM-DD (optional, default newest)"
    },
    "from": {
      "type": "string",
      "description": "baseline date YYYY-MM-DD (optional)"
    },
    "appId": {
      "type": "string",
      "description": "App Store or Google Play URL, iOS numeric id (e.g. 324684580) or Android package (e.g. com.spotify.music) — get ids from search_apps"
    },
    "store": {
      "enum": [
        "ios",
        "android"
      ],
      "type": "string",
      "description": "optional — inferred from appId (numeric id / App Store URL → ios, package / Play URL → android)"
    }
  }
}
get_pain_trend annotations
{
  "title": "Pain-point trend",
  "readOnlyHint": true,
  "openWorldHint": true,
  "idempotentHint": true,
  "destructiveHint": false
}
get_app_details — App details
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

App metadata: name, developer, category, price, average rating, rating count and 1-5★ histogram (when available).

get_app_details input schema
{
  "type": "object",
  "required": [
    "appId"
  ],
  "properties": {
    "appId": {
      "type": "string",
      "description": "App Store or Google Play URL, iOS numeric id (e.g. 324684580) or Android package (e.g. com.spotify.music) — get ids from search_apps"
    },
    "store": {
      "enum": [
        "ios",
        "android"
      ],
      "type": "string",
      "description": "optional — inferred from appId (numeric id / App Store URL → ios, package / Play URL → android)"
    },
    "country": {
      "type": "string",
      "description": "ISO country code, default \"us\""
    }
  }
}
get_app_details annotations
{
  "title": "App details",
  "readOnlyHint": true,
  "openWorldHint": true,
  "idempotentHint": true,
  "destructiveHint": false
}
get_version_history — Version history
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

Per-version review stats (review count, average rating, first/last seen) — spot a rating crash right after a bad release. Android: aggregated from recent reviews. iOS: current version + release notes.

get_version_history input schema
{
  "type": "object",
  "required": [
    "appId"
  ],
  "properties": {
    "appId": {
      "type": "string",
      "description": "App Store or Google Play URL, iOS numeric id (e.g. 324684580) or Android package (e.g. com.spotify.music) — get ids from search_apps"
    },
    "store": {
      "enum": [
        "ios",
        "android"
      ],
      "type": "string",
      "description": "optional — inferred from appId (numeric id / App Store URL → ios, package / Play URL → android)"
    },
    "country": {
      "type": "string",
      "description": "ISO country code, default \"us\""
    }
  }
}
get_version_history annotations
{
  "title": "Version history",
  "readOnlyHint": true,
  "openWorldHint": true,
  "idempotentHint": true,
  "destructiveHint": false
}
watch_competitors — Watch competitors (alerts)
Advertised by the server during the last successful anonymous check.
Open-world

Continuous competitor monitoring (paid plans: Starter 2 apps weekly, Pro 15 apps daily). Manage the watchlist and the alert destination; digests of NEW 1-2★ reviews and NEW/RISING pain points are pushed to a Slack / Discord / any https webhook. action: list | add | remove | set_webhook | test.

watch_competitors input schema
{
  "type": "object",
  "required": [
    "action"
  ],
  "properties": {
    "appId": {
      "type": "string",
      "description": "for add/remove: store URL, iOS id or Android package"
    },
    "store": {
      "enum": [
        "ios",
        "android"
      ],
      "type": "string",
      "description": "optional — inferred from appId (numeric id / App Store URL → ios, package / Play URL → android)"
    },
    "action": {
      "enum": [
        "list",
        "add",
        "remove",
        "set_webhook",
        "test"
      ],
      "type": "string"
    },
    "webhookUrl": {
      "type": "string",
      "description": "for set_webhook (or add): https URL, e.g. a Slack incoming webhook or Discord channel webhook"
    }
  }
}
watch_competitors annotations
{
  "title": "Watch competitors",
  "readOnlyHint": false,
  "openWorldHint": true,
  "idempotentHint": true,
  "destructiveHint": false
}
get_app_reviews — Raw reviews
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

Fetch raw app reviews (unified schema across stores: rating/title/body/version/date/devReply/thumbsUp), 50 per page. Use for drill-down after mine_app_pain_points.

get_app_reviews input schema
{
  "type": "object",
  "required": [
    "appId"
  ],
  "properties": {
    "page": {
      "type": "integer",
      "maximum": 10,
      "minimum": 1,
      "description": "page number, default 1 (50/page)"
    },
    "sort": {
      "enum": [
        "recent",
        "helpful"
      ],
      "type": "string",
      "description": "default recent (Android only; iOS uses the store default order)"
    },
    "appId": {
      "type": "string",
      "description": "App Store or Google Play URL, iOS numeric id (e.g. 324684580) or Android package (e.g. com.spotify.music) — get ids from search_apps"
    },
    "store": {
      "enum": [
        "ios",
        "android"
      ],
      "type": "string",
      "description": "optional — inferred from appId (numeric id / App Store URL → ios, package / Play URL → android)"
    },
    "country": {
      "type": "string",
      "description": "ISO country code, default \"us\""
    }
  }
}
get_app_reviews annotations
{
  "title": "Raw reviews",
  "readOnlyHint": true,
  "openWorldHint": true,
  "idempotentHint": true,
  "destructiveHint": false
}

Prompts

2 advertised

competitor_pain_report — Competitor pain-point report

Advertised by the server during the last successful anonymous check.

Find the top apps in a category and compare what their users complain about — shared pains, unique weaknesses, opportunities.

category
app category or niche, e.g. "habit tracker" (required)
apps
how many competitors to analyze (default 4)
app_pain_deep_dive — Single-app pain deep dive

Advertised by the server during the last successful anonymous check.

Everything users hate about one app: ranked pain points, how they trend, which releases hurt, with quotes.

app
app name, store URL or id (required)

Resources

Not advertised

No resource definitions available.

30-day availability

Aggregated from read-only remote checks; this is not a tool-execution or security guarantee.

Successful checks
1 of 1 (100%)
Average latency
523 ms
95th percentile latency
523 ms

Maintenance history

Public check and source-refresh events. Editorial and ownership records remain private.

  • · probe · passed · 523 ms · metadata changed · 7 tool(s), 2 prompt(s)

Connect from your client

Each snippet registers the same endpoint; pick the client you use.

This server is operated by the named third party. Listing and endpoint checks are not an endorsement or a security audit. Review the operator's permissions, terms, and data handling before connecting. How listings are checked and corrected.

Claude Code

Run this once in a terminal. It registers the remote server. Use --scope project to write .mcp.json for the repo.
Claude Code configuration
claude mcp add --transport http app-pain-api-mcp https://hawkmill.com/mcp

Codex

Run this once. Codex stores MCP servers in ~/.codex/config.toml (or .codex/config.toml in a trusted project).
Codex configuration
codex mcp add app-pain-api-mcp --url https://hawkmill.com/mcp

Cursor

Merge this server into .cursor/mcp.json in your project, then enable app-pain-api-mcp in your MCP settings.
Cursor configuration
{
  "mcpServers": {
    "app-pain-api-mcp": {
      "url": "https://hawkmill.com/mcp"
    }
  }
}

Cline

Merge this into cline_mcp_settings.json (Cline → MCP Servers → Configure).
Cline configuration
{
  "mcpServers": {
    "app-pain-api-mcp": {
      "type": "streamableHttp",
      "url": "https://hawkmill.com/mcp",
      "disabled": false
    }
  }
}

VS Code

Merge this server into .vscode/mcp.json. Use MCP: List Servers to start app-pain-api-mcp and inspect its tools.
VS Code configuration
{
  "servers": {
    "app-pain-api-mcp": {
      "type": "http",
      "url": "https://hawkmill.com/mcp"
    }
  }
}

Gemini CLI

Run this once. It writes .gemini/settings.json in the current project; pass --scope user for ~/.gemini/settings.json.
Gemini CLI configuration
gemini mcp add --transport http app-pain-api-mcp https://hawkmill.com/mcp

Claude Desktop

Merge this into claude_desktop_config.json (macOS: ~/Library/Application Support/Claude/, Windows: %APPDATA%\Claude\), then restart Claude Desktop.
Claude Desktop configuration
{
  "mcpServers": {
    "app-pain-api-mcp": {
      "url": "https://hawkmill.com/mcp"
    }
  }
}

Windsurf

Merge this into ~/.codeium/windsurf/mcp_config.json, then refresh MCP in Cascade. Windsurf remote servers use serverUrl, not url.
Windsurf configuration
{
  "mcpServers": {
    "app-pain-api-mcp": {
      "serverUrl": "https://hawkmill.com/mcp"
    }
  }
}

Let your agent find its tools

Find servers like App Pain API MCP from your agent. Add Koskamo once to search the index for endpoints, access requirements, and client setup. Public discovery needs no key.