{"id":"7e07ffbb-880f-4cf9-a9c0-abfe3c167503","slug":"flowscope","kind":"mcp","name":"flowscope","summary":"","owner":"DavidNgugi","repoUrl":"https://github.com/DavidNgugi/flowscope","license":"MIT","licenseTier":"permissive","trust":"community","stars":2,"match":null,"fewStars":true,"format":"mcp","createdAt":"2026-07-31T11:00:34.000Z","addedAt":"2026-10-14T05:11:02.948Z","logoUrl":"https://avatars.githubusercontent.com/u/5968269?u=7b7602126efacc128ed0491042fb3f296e76c0c3&v=4","linkOnly":false,"collection":null,"skillPath":null,"categories":["utilities"],"tags":[],"runtime":"python","local":true,"cloudCapable":false,"cloudCapability":"unknown","cloudReadyOnPlatform":false,"needsApiKey":false,"reviewed":false,"syncedAt":"2026-10-14T13:19:09.447Z","sample":false,"url":"https://conduits.dev/tools/flowscope","language":"Python","transports":["stdio"],"install":{"pypi":"flowscope-mcp"},"requirements":{"env":[{"name":"FLOWSCOPE_API_URL","secret":false,"required":false,"description":"Base URL of the running FlowScope backend. '/api' is appended if absent."},{"name":"FLOWSCOPE_API_TOKEN","secret":true,"required":false,"description":"Bearer token, only needed when the backend sits behind an authenticating proxy."},{"name":"FLOWSCOPE_MAX_WAIT","secret":false,"required":false,"description":"Default seconds that flowscope_analyze_video waits for a job before returning a job id."}],"upstreamMayCharge":false},"tools":null,"readme":"# FlowScope\n\n[![CI](https://img.shields.io/github/actions/workflow/status/DavidNgugi/flowscope/mcp.yml?branch=main&logo=github&label=CI)](https://github.com/DavidNgugi/flowscope/actions/workflows/mcp.yml) [![release](https://img.shields.io/github/actions/workflow/status/DavidNgugi/flowscope/release.yml?logo=github&label=release)](https://github.com/DavidNgugi/flowscope/actions/workflows/release.yml) [![PyPI](https://img.shields.io/pypi/v/flowscope-mcp?logo=pypi&logoColor=white&label=flowscope-mcp)](https://pypi.org/project/flowscope-mcp/) [![Python](https://img.shields.io/pypi/pyversions/flowscope-mcp?logo=python&logoColor=white)](https://pypi.org/project/flowscope-mcp/) [![License: MIT](https://img.shields.io/github/license/DavidNgugi/flowscope)](LICENSE) [![tag](https://img.shields.io/github/v/tag/DavidNgugi/flowscope?logo=git&logoColor=white&label=tag)](https://github.com/DavidNgugi/flowscope/releases) [![MCP Registry](https://img.shields.io/badge/MCP_Registry-io.github.DavidNgugi%2Fflowscope-1f6feb)](https://registry.modelcontextprotocol.io/v0.1/servers?search=flowscope)\n\nGiven one or more YouTube product-demo URLs, FlowScope downloads the video, transcribes it (captions or local Whisper), extracts and deduplicates representative screenshots of distinct screens, aligns them to the narration, and uses an LLM to produce a structured breakdown of the product's flow, screens, and UX patterns — plus cross-video comparison.\n\nFor personal competitive UX research use. Downloaded videos and derived analysis stay local.\n\n## Use it from an LLM (MCP)\n\n`mcp/` is an [MCP](https://modelcontextprotocol.io) server that exposes this\npipeline as tools, plus two installable skills, so any MCP-capable client can\nrun the analyses for you:\n\n> Compare the onboarding flows in these two videos: `<url>` and `<url>`\n\nStart the backend, then install into your client:\n\n```bash\ncd backend && uvicorn app.main:app --port 8000     # terminal 1\n\n# Claude Code: one step, brings the skills and the server registration\n/plugin marketplace add DavidNgugi/flowscope\n/plugin install flowscope@flowscope\n```\n\nFor any other harness, generate the client config — the shapes genuinely differ\n(VS Code's own file uses `servers` where everyone else uses `mcpServers`, and\nCodex is TOML):\n\n```bash\nuvx --from flowscope-mcp flowscope-mcp-install --help   # every client and its path\nuvx --from flowscope-mcp flowscope-mcp-install cursor   # or vscode, codex, gemini\n```\n\n(`flowscope-mcp-install` is a console script inside the `flowscope-mcp`\ndistribution, hence `--from`. If you installed the package locally, the bare\n`flowscope-mcp-install` works too.)\n\nThe two bundled skills install separately, into any Agent Skills-compatible\nclient. `.agents/skills/` is the cross-client convention, so one copy serves most\nharnesses:\n\n```bash\nmkdir -p .agents/skills && cp -r mcp/skills/* .agents/skills/\nnpx skills add DavidNgugi/flowscope        # or via the skills CLI\n```\n\nAsk the agent to run `flowscope_health_check` — it reports whether the backend,\nffmpeg, yt-dlp, and an LLM provider key are all in place, so a missing\nprerequisite is a clear message rather than a failed ten-minute job.\n\nThen just describe what you want:\n\n> Tear down the onboarding UX in this demo: `<youtube-url>`\n\n> Compare the onboarding flows in these two demos. Where do they diverge, and what's the trade-off each one makes?\n> - `<youtube-url-1>`\n> - `<youtube-url-2>`\n\n> In this demo, how many steps does signup take, and what does each one ask for? `<youtube-url>`\n\nAnalysing a video takes **2–10 minutes** and makes one vision call per distinct\nscreen, so it costs real money. Results are cached by YouTube video id — asking\n\"what has FlowScope already analysed?\" is free, and re-reading a report costs\nnothing. The bundled skills teach the agent to check the cache before spending.\n\nThe server is a stateless client of the backend's REST API and imports none of\nthe application code, so it installs without ffmpeg bindings or Whisper.\n\nSee [mcp/README.md](mcp/README.md) for the tool list,\n[mcp/docs/install.md](mcp/docs/install.md) for the per-harness install reference,\n[mcp/docs/usage.md](mcp/docs/usage.md) for the full set of example prompts and\ntroubleshooting, [mcp/docs/skills.md](mcp/docs/skills.md) for the skills matrix,\nand [mcp/docs/publishing.md](mcp/docs/publishing.md) and\n[mcp/docs/security.md](mcp/docs/security.md) for the details.\n\nThe MCP package releases on its own cadence, from version tags. Bumping is a\nsingle command because six declarations in five files must agree:\n\n```bash\ncd mcp && ./.venv/bin/python scripts/version.py bump 0.2.0\n```\n\nThen commit, tag `v0.2.0`, and push the tag — CI verifies everything, publishes\nto PyPI, publishes to the MCP Registry, and attaches the wheel to the GitHub\nrelease.\n\n## Setup\n\n```bash\nbrew install ffmpeg\n\ncd backend\npython3 -m venv .venv && source .venv/bin/activate\npip install -r requirements.txt\ncp .env.example .env   # fill in a provider key (see Models below)\nuvicorn app.main:app --reload --port 8000\n```\n\n```bash\ncd frontend\nnpm install\nnpm run dev\n```\n\nOpen http://localhost:5173.\n\n## Models\n\nThe LLM layer is provider-neutral: adding a vendor is configuration, not code.\nFour providers are built in — `anthropic`, `openai`, `deepseek`, and\n`openai_compatible` (any vendor or local server that speaks the OpenAI\nchat-completions format, e.g. xAI, Mistral, Groq, Together, OpenRouter, vLLM,\nOllama).\n\nSelection is by **purpose**, so frames and text can run on different models:\n\n```bash\nLLM_PROVIDER=openai            # default provider\nLLM_MODEL=gpt-5-mini           # default model\n# Optional per-purpose overrides (each falls back to the default):\n# LLM_VISION_PROVIDER / LLM_VISION_MODEL          frame analysis (needs vision)\n# LLM_SYNTHESIS_PROVIDER / LLM_SYNTHESIS_MODEL    one video's flow\n# LLM_COMPARISON_PROVIDER / LLM_COMPARISON_MODEL  cross-video comparison\n```\n\nPer-provider credentials: `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`,\n`DEEPSEEK_API_KEY`, or `OPENAI_COMPATIBLE_API_KEY` + `OPENAI_COMPATIBLE_BASE_URL`.\nA provider with no key is simply unavailable; selecting it produces a clear\nconfiguration error naming the variable to set.\n\nNotes that save time:\n\n- **Vision is required for the frame stage.** `deepseek-flash` accepts images;\n  `deepseek-v4-pro` does not, and a text-only model produces an explicit error\n  rather than silently analysing nothing.\n- **Reasoning models** (`gpt-5.x`, `o-series`) spend part of the completion\n  budget on hidden reasoning, so the adapter applies a floor and\n  `LLM_REASONING_EFFORT` (default `low`). A budget sized for the visible answer\n  alone fails with `finish_reason=length` and no tool call.\n- **Claude Sonnet 5.5 rejected forced tool use**, so those models are routed to\n  automatic tool choice; other Claude models keep forced tool use.\n- **Cost is recorded per call** with the rate snapshotted onto the row. Models\n  without a published rate in `app/llm/catalog.py` record tokens with a null\n  cost rather than a guess.\n\n### Analysing frames that already exist\n\nDownloading and frame extraction are separate from the paid stages, so a run that\nstopped at the LLM step — or a re-run against a different model — costs nothing\nto repeat:\n\n```bash\npython scripts/evaluate_existing_frames.py --data-dir ./data          # resumable\npython scripts/export_analysis.py --data-dir ./data --out ./export    # plain files\n```\n\n## Docker\n\n```bash\ndocker compose build          # rebuild after any change under backend/app\ndocker compose up -d          # backend :8000, frontend :5180\nopen http://localhost:5180\n```\n\n`backend/data` is **bind-mounted** to `/app/data`, so the database, media and frame\nfiles live on the host: they survive rebuilds, can be inspected directly, and are\nshared with a local `uvicorn` run. (The older `backend_data` named volume is still\ndeclared but unused, so its contents are not lost.)\n\nBecause the app copy is baked into the image at build time, **a code change needs\n`docker compose build`** — `up -d` alone reuses the old image.\n\nData portability: frame paths are stored absolute, but the API resolves them by\ntheir path below the last `media/` segment, so the same database works from the\nhost and from inside the container.\n\n## YouTube authentication\n\nYouTube may challenge yt-dlp with `Sign in to confirm you're not a bot`, even\nfor public videos. FlowScope can reuse an authenticated YouTube session in one\nof two ways (configure only one):\n\n- Local development: set `YTDLP_COOKIES_FROM_BROWSER=chrome` in\n  `backend/.env` (also supported: `firefox`, `safari`, and other browsers\n  recognized by yt-dlp), then restart the backend.\n- Docker/server: export a Netscape-format `youtube-cookies.txt`, mount it into\n  the backend container, and set `YTDLP_COOKIE_FILE` to its container path.\n\nFor Docker, add a read-only mount under the backend service, for example:\n\n```yaml\nvolumes:\n  - backend_data:/app/data\n  - ./secrets/youtube-cookies.txt:/app/secrets/youtube-cookies.txt\n```\n\nThen set `YTDLP_COOKIE_FILE=/app/secrets/youtube-cookies.txt` in\n`backend/.env`. Cookie files contain account credentials; keep them out of\nsource control and refresh the export if YouTube invalidates the session.\n"}