npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

punchlist-mcp

v0.8.0

Published

MCP companion server for Punchlist — discover a Punchlist iOS device on your LAN and pull voice-narrated screen sessions (screenshots + synchronized transcripts) straight into Claude or any MCP client.

Readme

punchlist-mcp

Talk through your app. Ship the fixes.

punchlist-mcp is the companion Model Context Protocol server for Punchlist — the iOS app that records your screen while you narrate, then hands your AI a clean, synchronized list of screenshots + transcripts to fix.

This server runs on your computer, discovers your Punchlist phone on the local network over Bonjour/mDNS, and exposes MCP tools so Claude (Desktop or Code) — or any MCP client — can say "grab the latest punchlist from my phone" and iterate.

Nothing touches a DoMore Tech server — there is no account and no backend. By default everything stays on your LAN; optionally, connect_icloud adds your own private CloudKit database as a second source so sessions synced from the phone can be pulled even when it's off-LAN (on cellular).


Requirements

  • Node.js 20+
  • A phone running Punchlist with the in-app LAN server enabled, on the same Wi-Fi network as this computer.

Install / run

You don't need to install anything globally — MCP clients launch it via npx:

npx -y punchlist-mcp

That command starts the server on stdio. You normally never run it by hand; you point your MCP client at it (see Client configuration).


Pairing walkthrough

Pairing happens once per device. The token is stored on both ends.

  1. In Punchlist on your phone, open the Connect tab and flip on Turn on sharing (step 2 of the guided flow); the card shows a 6-digit pairing code.

  2. In your MCP client, discover the phone:

    "List my Punchlist devices."

    This calls list_devices and returns something like:

    {
      "count": 1,
      "devices": [
        { "name": "Johns-iPhone", "host": "Johns-iPhone.local", "port": 7443,
          "addresses": ["192.168.1.42"],
          "txt": { "device": "Johns-iPhone", "version": "1", "tls": "1", "fp": "…" },
          "paired": false }
      ]
    }
  3. Pair using the code from step 1:

    "Pair with Johns-iPhone, the code is 482137."

    This calls pair_device with { device_name: "Johns-iPhone", code: "482137" }. On success the token is written to ~/.punchlist-mcp/config.json (along with the device's TLS certificate fingerprint, pinned trust-on-first-use) and the device becomes the default for the other tools.

Now you can:

"What punchlists are waiting on my phone? Fetch the newest one and walk each item."


Tool reference

| Tool | Input | What it does | |---|---|---| | list_devices | timeout_ms? | mDNS scan of _punchlist._tcp; returns devices + whether each is paired. | | pair_device | code, device_name?, host?, port? | Exchanges the app's 6-digit code for a token (and pins the device's TLS fingerprint). Give device_name (resolved via mDNS) or an explicit host. | | set_preferred_device | device | Sets the default device used when device is omitted. | | connect_icloud | environment?, api_token?, container?, disable? | Opens the Apple ID sign-in in your browser and adds your private CloudKit database as a second source (works off-LAN). | | export_icloud_credentials | environment?, api_token?, container? | Same sign-in flow, but mints a separate token to set as env vars in a remote environment (see below). | | list_pending_punchlists | device?, app? | Unprocessed sessions (GET /mcp/pending), optionally scoped to one app. | | list_apps | device? | Apps registered on the device, with session/pending counts and standing instructions. | | add_app | app_name, icon_path?, instructions?, instruction_files?, device? | Registers an app on the device's Apps tab (optionally with icon + instructions in one call). | | set_app_instructions | app_name, instructions? or instruction_files?, append?, keep_synced?, device? | Standing processing instructions for an app; can sync from local .md files. | | upload_app_icon | app_name, icon_path, keep_synced?, device? | Pushes the app's icon PNG so the device's picker shows the real icon. | | list_punchlists | device? | All sessions (GET /punchlists). | | get_punchlist_manifest | punchlist_id, device? | Just the manifest.json, no media download. | | fetch_punchlist | punchlist_id, device?, include_video? | Downloads + unzips into the cache, returns the manifest plus absolute local paths for every screenshot (and the video if include_video: true). | | mark_punchlist_processed | punchlist_id, device?, resolution_note?, user_confirmed | Marks a session consumed (POST /punchlists/{id}/processed) — requires the user's explicit yes. For tester feedback sessions, resolution_note is a short line shown in the tester's app next to the Reviewed status. | | diagnose_processed_sync | punchlist_id? | Debugging aid: traces why a processed mark isn't reaching the phone/cloud. |

device? accepts a paired device name. When omitted, the preferred device is used (or the only paired device). Every session has a stable five-character code (also shown in the app's session list; derived from the id, never stored) — the punchlist_id params accept either the code or the full id. fetch_punchlist defaults to the lightweight screenshots-only bundle; pass include_video: true to also pull recording.mp4. When iCloud is connected, the punchlist tools fall back to the cloud source automatically if the phone isn't reachable on the LAN.

Typical flow

list_devices  ──►  pair_device (once)  ──►  list_pending_punchlists
                                              │
                                              ▼
                             fetch_punchlist ──► (read screenshots + manifest)
                                              │
                                              ▼
                                   mark_punchlist_processed

Client configuration

Claude Code — .mcp.json

Add to .mcp.json in your project root (or ~/.claude.json):

{
  "mcpServers": {
    "punchlist": {
      "command": "npx",
      "args": ["-y", "punchlist-mcp"]
    }
  }
}

Claude Desktop — claude_desktop_config.json

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json
{
  "mcpServers": {
    "punchlist": {
      "command": "npx",
      "args": ["-y", "punchlist-mcp"]
    }
  }
}

Restart the client after editing. On first launch npx downloads the package; subsequent starts are instant.

Remote sessions (cloud sandboxes)

The repo root carries a .mcp.json with the config above, so any cloud sandbox or remote session (e.g. a Claude remote session / CI) that clones this repo gets the MCP installed automatically. Remote environments have no LAN, so only the iCloud source works there — the LAN tools (list_devices, pair_device, …) are unavailable remotely by nature.

To give a remote environment iCloud access, run the export_icloud_credentials tool on your local machine (it opens the Apple ID sign-in in your browser and mints a token independent of your local one), then set the returned values as environment variables in the remote environment:

  • PUNCHLIST_ICLOUD_TOKEN — the web-auth token (account-scoped; treat it like a password).
  • PUNCHLIST_ICLOUD_ENV — set to development for phones running an Xcode-installed build; the default is production (TestFlight / App Store). Needed until the TestFlight/App Store build ships.
  • PUNCHLIST_ICLOUD_API_TOKEN / PUNCHLIST_ICLOUD_CONTAINER — only needed for non-default tokens/containers.

The MCP seeds its config from these variables on first use and keeps the token fresh (CloudKit rotates it) for the life of the sandbox.


Config file format

State lives in ~/.punchlist-mcp/:

~/.punchlist-mcp/
├── config.json        # paired devices + tokens (chmod 0600)
└── cache/             # unzipped punchlists, per device/session
    ├── Johns-iPhone/
    │   └── 2026-07-08_1315/
    │       ├── manifest.json
    │       ├── 001_screen-a.png
    │       └── ...
    └── cloud/         # sessions fetched from the iCloud source
        └── 2026-07-08_1315/…

config.json:

{
  "devices": {
    "Johns-iPhone": {
      "name": "Johns-iPhone",
      "host": "Johns-iPhone.local",
      "port": 7443,
      "token": "…pairing token…",
      "scheme": "https",
      "certFingerprint": "…pinned sha-256 of the device's TLS cert…",
      "addresses": ["192.168.1.42"],
      "pairedAt": "2026-07-08T13:20:00.000Z"
    }
  },
  "preferredDevice": "Johns-iPhone"
}

Running connect_icloud adds a cloud section (container, environment, and the rotating web-auth token); offline mark_punchlist_processed calls queue under pendingMarks and flush on the next contact with the phone.

The file is written 0600 because it contains pairing tokens. You can safely hand-edit it (e.g. to remove a device) or delete it to reset all pairings.


Troubleshooting

No devices found (list_devices returns nothing).

  • Confirm Punchlist is open and the LAN server is enabled in the app.
  • Confirm the phone and this computer are on the same Wi-Fi (not a guest network, and not one with "client isolation" / "AP isolation" enabled).
  • Windows firewall frequently blocks mDNS (UDP 5353). Allow Node.js through the firewall for private networks, or add an inbound rule for UDP 5353. Some corporate networks block multicast entirely — in that case pair by explicit host: pair_device with host: "<phone-ip>" (the app shows its IP).
  • VPNs and virtual adapters can hijack the multicast interface; disconnect the VPN while pairing.

iOS local-network permission.

  • Punchlist must be granted Local Network access on the phone (iOS prompts on first use). If you denied it, enable it under Settings → Punchlist → Local Network, then reopen the app.

Found the device but requests fail / time out.

  • The phone may have slept or dropped the server. Reopen Punchlist.
  • .local mDNS name resolution can be flaky on some Windows setups; pair using the phone's IP address as host instead.

Pairing code rejected (HTTP 403).

  • Check the code against the one currently shown on the Connect tab — it changes when the user taps Rotate (which also invalidates old tokens). Repeated wrong codes rate-limit /pair (HTTP 429) for up to 15 minutes.

Wrong device selected.

  • With multiple paired devices, pass device: "<name>" explicitly, or edit preferredDevice in config.json.

License

MIT © DoMore Tech LLC