npm.io
1.0.9 • Published yesterdayCLI

lockin-mcp

Licence
MIT
Version
1.0.9
Deps
6
Size
563 kB
Vulns
0
Weekly
505

LockIn MCP

A Model Context Protocol (MCP) server that blocks distracting websites at the system level by managing entries in /etc/hosts. Use it with Poke, Claude Desktop, or ChatGPT custom MCP connectors to stay focused.

Features

Tool Description
get_agent_guidelines Coaching instructions for AI agents (when to enforce focus, how to handle unblock requests)
block_domains Block a list of domains (e.g. youtube.com, x.com, tiktok.com)
unblock_domains Permanently unblock specific domains
temporarily_unblock_domains Allow access for a limited time, then auto re-block
enter_focus_mode Block common distraction sites in one action (YouTube, X, TikTok, Instagram, Reddit, Facebook, Netflix, Twitch)
get_block_status Show what is blocked, temporarily allowed, and system readiness

Blocking redirects domains to 127.0.0.1 and ::1, including www. variants.

Pro license required: block_domains, unblock_domains, temporarily_unblock_domains, and enter_focus_mode require an active Pro license. get_agent_guidelines and get_block_status are read-only and work without Pro. For local development only, set MDB_SKIP_LICENSE_CHECK=1.

Requirements

  • macOS / Linux / Windows (hosts-based blocking; macOS uses dscacheutil for DNS flush)
  • Node.js 18+
  • Administrator privileges to modify /etc/hosts (see below)

Web App & Pro Licensing

The web/ directory contains the landing page, user accounts, Stripe checkout, and license API.

Quick start (local)
# Terminal 1 — web app
cd web
cp ../.env.example .env.local   # edit with your Stripe keys
npm install
npm run dev                     # http://localhost:3001

# Terminal 2 — CLI installer (points at local API by default)
export MDB_APP_URL=http://localhost:3001
export MDB_LICENSE_API_URL=http://localhost:3001/api/v1
npm run build
npm run install:local
# or from GitHub (no clone):
# npx -y lockin-mcp install
Architecture
Component Purpose
Landing page (/) Features, how-it-works, pricing
Device auth (/device) Browser login for CLI OAuth device flow
Dashboard (/dashboard) License keys, Pro status, install instructions
Report (/report) Bug reports and feature requests (rate-limited; not indexed)
MCP OAuth consent (/oauth/consent) Browser approval for ChatGPT / Claude web MCP connectors
Checkout (/checkout) Stripe checkout (requires verified email)
API (/api/v1/*) License verify, OAuth device flow, token status
Stripe webhook Pro upgrade + license key generation
CLI auth handshake
  1. Installer calls POST /api/v1/oauth/device → receives user_code + device_code
  2. Browser opens /device?code=ABCD-1234
  3. User signs in and approves (requires Pro)
  4. Installer polls POST /api/v1/oauth/token → receives access_token
  5. Daemon verifies token via POST /api/v1/license/status on startup and hourly
MCP OAuth (ChatGPT, Claude web)
  1. MCP client registers via DCR at POST /api/v1/oauth/register (proxied from relay at POST /register)
  2. Client discovers metadata from /.well-known/oauth-authorization-server (web app and relay)
  3. User authorizes at /api/v1/oauth/authorize → browser consent at /oauth/consent
  4. Client exchanges code at POST /api/v1/oauth/token
  5. MCP requests to relay use OAuth access tokens or the device mdb_* API key
Environment variables

See .env.example for all configuration options.

Production deployment

Use this checklist before pointing lockinmcp.com at live traffic.

1. Generate secrets (once)
openssl rand -base64 32   # MDB_JWT_SECRET
openssl rand -base64 32   # MDB_SERVER_SECRET
openssl rand -base64 32   # REGISTRATION_SECRET (relay)

Set Vercel and Convex production env vars separately in each dashboard — do not copy MDB_SERVER_SECRET from your laptop with a sync script (local dev secrets are different from production).

Secret Vercel Convex prod
MDB_SERVER_SECRET Yes — same value on both Yes — npx convex env set MDB_SERVER_SECRET '…' --prod once
MDB_JWT_SECRET No Yes — Convex only
STRIPE_* Yes No
2. Convex production
cd web
npx convex deploy          # production only — not convex dev

Set env vars in the Convex dashboardProduction → Settings → Environment Variables. Do not run ./scripts/sync-convex-env.sh for production — it only targets your dev deployment and .env.local often has localhost URLs.

Convex prod variable Value
MDB_APP_URL https://www.lockinmcp.com
MDB_SERVER_SECRET Same string as Vercel
MDB_JWT_SECRET Production JWT secret (Convex only)
GOOGLE_* / GITHUB_* Production OAuth app credentials
RESEND_API_KEY / RESEND_FROM_EMAIL Production Resend
MDB_RELAY_URL / MDB_RELAY_PUBLIC_URL https://relay.lockinmcp.com
REGISTRATION_SECRET Same as relay Worker

One-off CLI (paste production values, not from .env.local):

cd web && npx convex env set MDB_APP_URL 'https://www.lockinmcp.com' --prod
3. Stripe live mode

In Stripe Dashboard (toggle Live):

Variable Where to get it
STRIPE_SECRET_KEY Developers → API keys → sk_live_...
STRIPE_PRICE_ID Products → one-time $9.99 price → price_...
STRIPE_WEBHOOK_SECRET Developers → Webhooks → endpoint https://www.lockinmcp.com/api/stripe/webhookwhsec_...
STRIPE_PROMOTION_CODE_ID Optional — locks one promo at checkout; leave unset so customers can enter any code (e.g. LOCKIN50)

Webhook events: checkout.session.completed, checkout.session.created, checkout.session.expired (follow-up scheduling backup)

Abandoned checkout follow-up (24h email)

When a signed-in user starts Stripe Checkout but does not pay, a follow-up email is scheduled via Convex (ctx.scheduler.runAfter). After deploy:

cd web && npx convex deploy
./scripts/backfill-oauth-email-verified.sh --prod   # one-time OAuth emailVerified backfill

Verify production:

  1. Convex MDB_APP_URL is https://www.lockinmcp.com (not localhost).
  2. Vercel MDB_SERVER_SECRET === Convex MDB_SERVER_SECRET.
  3. Stripe webhook enables checkout.session.created and checkout.session.expired.
  4. Preview email: ./scripts/send-abandoned-checkout-preview.sh you@example.com
  5. Dev smoke test (60s delay): npx convex env set CHECKOUT_FOLLOW_UP_DELAY_MS 60000 then ./scripts/test-abandoned-checkout-schedule.sh <userId>
  6. Inspect jobs: ./scripts/list-checkout-follow-ups.sh scheduled

Optional Convex env: CHECKOUT_FOLLOW_UP_DELAY_MS (default 86400000 = 24h).

4. OAuth (production callbacks)
Provider Redirect URI
Google https://www.lockinmcp.com/api/auth/oauth/google/callback
GitHub https://www.lockinmcp.com/api/auth/oauth/github/callback

Add GOOGLE_* / GITHUB_* to Vercel and Convex production dashboards (not dev keys from .env.local).

5. App URLs (hosting + Convex)
MDB_APP_URL=https://www.lockinmcp.com
NEXT_PUBLIC_APP_URL=https://www.lockinmcp.com
MDB_LICENSE_API_URL=https://www.lockinmcp.com/api/v1
MDB_RELAY_PUBLIC_URL=https://relay.lockinmcp.com
MDB_RELAY_URL=https://relay.lockinmcp.com

The apex domain (lockinmcp.com) redirects to www in production.

6. Deploy web app

Deploy the web/ Next.js app to your host (Vercel, etc.) with all env vars from .env.example.

7. Smoke test
  1. Sign up → verify email → checkout with a real card (or Stripe test in test mode first)
  2. Confirm /dashboard shows Pro + license key
  3. Run installer: curl -fsSL https://www.lockinmcp.com/install | bash
  4. Approve device at /device → confirm MCP tunnel provisions

One-Line Installer

The fastest way to set up blocking, tunneling, and Poke integration:

macOS / Linux (curl)
curl -fsSL https://raw.githubusercontent.com/Kiog-Aser/LockIn/main/install.sh | bash

Or use the hosted installer (recommended):

curl -fsSL https://www.lockinmcp.com/install | bash
Windows (PowerShell)
iwr -useb https://raw.githubusercontent.com/Kiog-Aser/LockIn/main/install.ps1 | iex
npm
npx -y lockin-mcp@1.0.7 install
# or from a local clone:
npm run install:local

The npm package lockin-mcp (v1.0.7) replaces the legacy mac-distraction-blocker-mcp name. Legacy bin aliases (mac-distraction-blocker-mcp, mdb-install) still work.

What the installer does
  1. Detects your platform (macOS, Linux, or Windows)
  2. Verifies your $9.99 Pro license via browser login or license key
  3. Prompts for distraction sites — popular presets pre-selected (YouTube, X, TikTok, Instagram, Reddit) plus custom domains
  4. Applies initial blocks to /etc/hosts
  5. Starts the MCP HTTP server locally with an outbound relay connection (background LaunchAgent on macOS)
  6. Provisions a stable relay URL (https://relay.lockinmcp.com/device/{id}/mcp) so Poke, Claude, and ChatGPT can reach your Mac
  7. Connects your AI agent — Poke, Claude (web), and ChatGPT use OAuth via lockinmcp.com; Claude Desktop uses your API key via mcp-remote
Installer flags (non-interactive)
curl -fsSL .../install.sh | bash -s -- --yes --browser-login --poke-recipe
npx -y lockin-mcp install --license-key lockin_pro_xxx --sites all --poke-recipe
Flag Description
--yes Non-interactive with defaults
--license-key <key> Pro license key
--browser-login Verify license via browser device flow (default)
--skip-tunnel Local MCP only (no relay URL)
--skip-block Skip initial domain blocking
--skip-poke Skip Poke URL generation
--port <number> Local MCP HTTP port (default 3000)
--sites all Block all presets
--custom-domains a.com,b.com Extra domains
--poke-recipe Generate distraction-coach recipe URL
--mcp-auth-token <token> Custom bearer token for tunneled MCP

Setup details are saved to ~/.lockin/setup-manifest.json.

Pro licensing ($9.99 lifetime — 50% off $19.99)
  • Purchase: Create an account at /login (email or Google/GitHub; /signup redirects here), verify email, pay via Stripe
  • License key: Available on dashboard after purchase; pass --license-key to installer
  • Browser login: Default installer flow — OAuth device authorization in your browser
  • Auth: Google and GitHub OAuth supported; email/password requires verification before checkout
  • Support: Bug reports and feature requests at /report (also linked in the site footer)

Quick Start (manual)

git clone https://github.com/Kiog-Aser/LockIn
cd LockIn
npm install
npm run build
Run locally (stdio — advanced)

For MCP clients that spawn a local subprocess:

node dist/index.js --stdio

MCP Client Configuration (after installer)

Your MCP URL and API key are in ~/.lockin/setup-manifest.json:

  • MCP URL: from manifest — e.g. https://relay.lockinmcp.com/device/abc123/mcp (Poke, Claude, ChatGPT)
  • API key: mdb_…
Poke

The installer copies your relay MCP URL and opens poke.com/integrations/new. In Poke:

  1. Paste the MCP URL (ends with /mcp)
  2. Choose OAuth authentication (do not paste your API key in the integration form)
  3. Sign in on lockinmcp.com when prompted
  4. Install the LockIn recipe

Legacy CLI (optional): npx poke@latest mcp add 'https://YOUR_RELAY_HOST/device/YOUR_ID/mcp' -n 'LockIn MCP' with OAuth in the Poke UI.

Claude (claude.ai)

The installer opens a link that pre-fills the connector name and MCP URL (connectorName + connectorUrl). Claude web uses OAuth — do not paste your API key in Advanced settings. See the connector setup guide.

  1. Choose Claude (claude.ai) in the installer (or build the link with connectorName=LockIn MCP and your encoded MCP URL)
  2. Confirm the pre-filled MCP server URL (e.g. https://relay.lockinmcp.com/device/abc123/mcp)
  3. Leave Advanced OAuth settings empty. Click Add, then sign in on lockinmcp.com when Claude prompts (Pro license required)
  4. Start a new chat with LockIn enabled

For Bearer/API-key auth, use Claude Desktop instead — the installer can write claude_desktop_config.json automatically.

Claude Desktop

Claude Desktop only supports stdio MCP servers in claude_desktop_config.json — not direct url entries. The installer merges a config that uses mcp-remote to bridge your relay URL (requires Node.js 18+).

Config paths:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json
  • Linux: ~/.config/Claude/claude_desktop_config.json

Manual example:

{
  "mcpServers": {
    "lockin-mcp": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote@latest",
        "https://relay.lockinmcp.com/device/YOUR_ID/mcp",
        "--header",
        "Authorization:${LOCKIN_MCP_AUTH_HEADER}"
      ],
      "env": {
        "LOCKIN_MCP_AUTH_HEADER": "Bearer mdb_..."
      }
    }
  }
}

On Windows, use "command": "npx.cmd" instead of "npx". Quit Claude Desktop completely before editing, then reopen.

ChatGPT

Custom MCP connectors require Developer mode under Advanced settings. ChatGPT cannot accept credentials from an external link — copy from the installer or setup guide.

  1. Open ChatGPT → Settings → Connectors → Advanced
  2. Enable Developer mode
  3. Add connector → paste MCP server URL from your manifest
  4. Set Authentication to OAuth and leave DCR enabled — sign in on lockinmcp.com when prompted (do not paste your API key in OAuth fields)
  5. Start a new chat and enable the LockIn connector
Relay deployment (operators)

The relay/ package is a Cloudflare Worker + Durable Object that bridges remote MCP HTTP requests to each Mac daemon over an outbound WebSocket.

cd relay
npm install
npx wrangler secret put REGISTRATION_SECRET
npx wrangler secret put MDB_JWT_SECRET   # optional, same as web app
npm run deploy

Set relay vars on Convex production in the dashboard. For local dev only: web/.env.local + ./scripts/sync-convex-env.sh (dev deployment).

Privileges & /etc/hosts

The server writes marked entries between:

# lockin-mcp BEGIN
...
# lockin-mcp END

Legacy installs may still show # mac-distraction-blocker-mcp markers; those are stripped on the next hosts sync.

Only those lines are touched; the rest of /etc/hosts is preserved.

Option A: Run the server with sudo (simplest)
sudo node dist/index.js --http --port 3000

For stdio MCP clients, configure the client to launch with sudo (see client config examples below).

The installer creates ~/.lockin/update-hosts.sh and a sudoers entry at /etc/sudoers.d/lockin-mcp-hosts that allows your user to run that script without a password. Temp files use the prefix lockin-mcp-hosts-{pid}.

If you installed manually, re-run the installer or configure sudoers to allow (replace YOUR_USER with your macOS username):

sudo visudo -f /etc/sudoers.d/lockin-mcp-hosts

Add:

YOUR_USER ALL=(ALL) NOPASSWD: /Users/YOUR_USER/.lockin/update-hosts.sh

(Adjust paths for Linux/Windows as needed.)

Verify permissions

Call get_block_statushostsFileWritable: true means the server can update blocking without extra setup.

Legacy: local stdio (Claude Desktop)

~/Library/Application Support/Claude/claude_desktop_config.json:

{
  "mcpServers": {
    "lockin-mcp": {
      "command": "node",
      "args": ["/absolute/path/to/LockIn/dist/index.js", "--stdio"]
    }
  }
}

Security

  • MCP bearer auth: HTTP MCP requires MDB_MCP_AUTH_TOKEN or --mcp-auth-token (mdb_* tokens). Relay-backed HTTP refuses to start without a token.
  • API rate limiting: Login, signup, OAuth (account + MCP), license verify, checkout, consent, and user-report routes are rate-limited.
  • User reports: POST /api/report accepts bug/feature submissions (5 per IP per hour). Requires RESEND_API_KEY in production; falls back to Convex logs in dev.
  • Relay tokens: Device tokens are hashed at rest on the Cloudflare worker (SHA-256).
  • Setup manifest: Written with 0o600 permissions; contains your relay URL and API key — do not commit or share.

Hooking up to poke.com/kitchen

The installer tunnels your local MCP over HTTPS so Poke can connect remotely — no extra terminal tab. When you choose Poke during install, it copies your relay URL and opens the integrations page for OAuth setup.

Install the official LockIn recipe for the best Poke experience:

https://poke.com/r/KQ7myvC_Xpo

The recipe connects your MCP tools and coaches you through focus sessions. You can also build custom recipes in poke.com/kitchen using get_agent_guidelines, block_domains, get_block_status, etc.

Tool Examples

Get agent guidelines

No arguments. Returns focus-coaching instructions for AI agents — call at the start of focus or blocking conversations.

Block sites
{
  "domains": ["youtube.com", "x.com", "tiktok.com", "reddit.com"]
}
Unblock one site
{
  "domains": ["youtube.com"]
}
15-minute break
{
  "domains": ["youtube.com"],
  "duration_seconds": 900
}
Check status

No arguments. Returns blocked list, temporary allowances with expiry timestamps, and whether hosts is writable.

How it works

flowchart LR
  A[MCP Client / Poke] --> R[Relay Worker]
  R --> B[MCP Server on Mac]
  B --> C[State JSON\n~/.lockin/]
  B --> D[/etc/hosts]
  B --> E[DNS cache flush]
  C --> B
  1. State — Block list and temporary unblocks live in ~/.lockin/state.json
  2. Hosts sync — Active blocks are written to /etc/hosts with a managed marker
  3. Expiry watcher — A background timer re-applies blocks when temporary unblocks expire (server process must be running)
  4. DNS flush — Best-effort dscacheutil / mDNSResponder refresh after changes

Development

npm install
npm run dev          # watch TypeScript
npm run build
npm run lint
npm test             # Vitest (root MCP tests)
cd web && npm test   # web rate-limit tests
cd relay && npm test # relay token hashing tests

CI (.github/workflows/ci.yml) runs lint, test, build, and npm audit --audit-level=high for the MCP server, web app, and relay worker.

Reset local install state (development only):

npx lockin-mcp dev-reset              # reset hosts, manifest, relay config
npx lockin-mcp dev-reset --full       # also remove LaunchAgent / background service
npx lockin-mcp dev-reset --wipe-license  # clear saved license

See relay/README.md for Cloudflare WebSocket hibernation details on the device relay worker.

Troubleshooting

Issue Fix
EACCES on block/unblock Run with sudo or configure passwordless sudo (see above)
Site still loads Hard-refresh browser; DNS cache may take a moment. Try private window.
Temp unblock didn't re-block Keep the MCP server process running (expiry watcher runs in-process)
Poke can't connect Re-run install and confirm OAuth completed in Poke. Check manifest relay URL + /health returns lockin-mcp with relay.connected: true. If offline, re-run npx lockin-mcp install once — the daemon self-heals reconnects automatically.
Wrong platform macOS, Linux, and Windows are supported; DNS flush behavior differs by OS

License

MIT