{"name":"io.github.jmg698/font-lab","slug":"jmg698-font-lab","title":"Font Lab","description":"A decision surface for typography: curate font directions on your real site, ship next/font code.","url":"https://mcp.market/server/jmg698-font-lab","rating":null,"grade":"B","score":80,"certified":false,"status":"active","category":"other","tags":[],"presence":{"score":25,"stars":4,"forks":0,"downloads_week":38,"last_push_at":"2026-07-29T18:12:19.000Z","license":"MIT"},"uptime":null,"claimed":false,"transport":"npm","callable_via_gateway":false,"default_price_micros":0,"repository":"https://github.com/jmg698/Font-Lab","website":null,"version":"1.0.0","remotes":[],"packages":[{"registryType":"npm","identifier":"font-lab","version":"1.0.0","transport":{"type":"stdio"},"packageArguments":[{"value":"mcp","type":"positional"}]}],"tools":[{"name":"font_lab_analyze","description":"Audit ANY web project's CURRENT typography before changing it: framework (Next/Vite/Astro/Remix/SvelteKit/TanStack/…), router, Tailwind version, the current display/body/mono fonts, how they're wired, and coverage warnings (e.g. a font that's declared but not actually rendered). The result's `capabilities` + `shipNote` name the right path for THIS stack — live panel on Next App Router, portable pr","write_action":false,"price_micros":0,"input_schema":null},{"name":"font_lab_apply","description":"Ship the human's pick, idempotently and reversibly (backup-first). On Next.js App Router it writes next/font + Tailwind — Google faces via next/font/google, open-foundry faces via next/font/local with the woff2 self-hosted into the source tree (every family is verified buildable BEFORE any file is written; unverifiable families refuse with the reason). On ANY OTHER framework (TanStack/Vite/Astro/R","write_action":false,"price_micros":0,"input_schema":null},{"name":"font_lab_check_fonts","description":"Check whether specific fonts can ship with Font Lab's preview==ship guarantee — use this to REACH BEYOND the built-in catalog. Pass family names (any of ~1,500 Google fonts like 'Hedvig Letters Serif', or a curated open-foundry face like 'Cabinet Grotesk' / 'General Sans'). Each returns a verdict: 'guaranteed' (full WYSIWYG), 'best-effort' (shippable, but the preview may not be byte-for-byte — sho","write_action":false,"price_micros":0,"input_schema":null},{"name":"font_lab_compose_directions","description":"The PRIMARY way to build the menu: assemble tailored font directions for the user's brief (from font_lab_start's intake answers). Pass the user's stated direction as `brief` — if you omit it, the result is INFERRED rather than tailored, and you'll get a warning telling you to ask first. Reach PAST the overexposed defaults — give each direction a distinctive face and a one-line rationale tying it t","write_action":false,"price_micros":0,"input_schema":null},{"name":"font_lab_curate","description":"FALLBACK menu — ~5 font directions (display+body+mono pairings) that move off the project's current fonts, no LLM. Seeded to THIS project (its name + palette + copy), so the spread differs from project to project instead of being the same five everywhere — but it is still a generic starting point, NOT tailored to the user's brief. Use it only when you have NO brief. When you DO have a brief (from ","write_action":false,"price_micros":0,"input_schema":null},{"name":"font_lab_finish","description":"THE FINISHING MOVE — run this when the human is done choosing (they clicked *done ✓* in the panel, said so in chat, or a pendingCleanup note rode a tool result). One call: strips the dev-panel scaffolding (uninit — applied fonts and copy edits are untouched), clears the panel's done signal, and returns the git-verified `commitPlan`: the SHIP pile (the human's copy edits + font apply, cross-checked","write_action":false,"price_micros":0,"input_schema":null},{"name":"font_lab_healthcheck","description":"VERIFY THE SETUP BEFORE INVITING THE HUMAN — run this after font_lab_init (and again after any dev-server restart or CSP/config change), and act on it: a white page or a missing panel is an AGENT failure to catch here, not a human setup step. One read-only pass checks: VERSION ALIGNMENT (this process vs the project's installed font-lab vs the panel stamp vs the :7777 endpoint — the npx-cache skew ","write_action":false,"price_micros":0,"input_schema":null},{"name":"font_lab_init","description":"SET UP the live preview panel in the project, built from the directions YOU composed for the user's brief — self-hosts the bundles, installs the dev panel, mounts it (dev-only). NEXT.JS APP ROUTER ONLY (the panel mounts in layout.tsx): on any other framework (Vite/Astro/Remix/SvelteKit/TanStack/…) SKIP this and use font_lab_preview instead — the pick still ships via font_lab_apply. Pass the `direc","write_action":false,"price_micros":0,"input_schema":null},{"name":"font_lab_list_catalog","description":"Browse Font Lab's curated catalog of ship-ready variable Google fonts (each verified for capsize/CLS-safe parity). Filter by role ('display'|'body'|'mono') or vibe tag (e.g. 'editorial','geometric','serif','technical'). Use this to compose your OWN font directions when the default curation isn't what the user asked for.","write_action":false,"price_micros":0,"input_schema":null},{"name":"font_lab_live_instructions","description":"Get ready-to-run commands to launch the FULL live editor (flip / mix / compare directions in a real browser) — for when the headless screenshots aren't enough and the human wants to drive it themselves. Detects the project's dev command. In a LOCAL session these run in the agent's/human's terminal here; in a REMOTE/container session the result reframes them as commands for the human's OWN machine ","write_action":false,"price_micros":0,"input_schema":null},{"name":"font_lab_more_directions","description":"Add MORE options to the live panel — when the human wants to keep exploring beyond the current set. Compose additional tailored directions first (font_lab_compose_directions), then pass them here; they're admitted and APPENDED to the panel (existing options are kept), and the panel updates live. Use this whenever the user asks 'what else?' / 'show me more' — the menu is never capped. This ALSO ful","write_action":false,"price_micros":0,"input_schema":null},{"name":"font_lab_prepare_preview","description":"Rebuild the LIVE preview bundle for the directions YOU composed for the user's brief (self-hosted woff2 + exact next/font fallbacks), so the HUMAN can flip through them and pick. Pass the `directions` from compose_directions. REFUSES without directions (don't rebuild the generic default menu without asking the user) — only pass allowFallback:true if they explicitly want the default. Use font_lab_i","write_action":false,"price_micros":0,"input_schema":null},{"name":"font_lab_preview","description":"LAST-RESORT specimen sheet — a self-contained HTML file of GENERIC CARDS (one per direction, parity fonts embedded, opens offline), rendered on the project's palette and copy. These are NOT the human's pages, so this tool is LOCKED until the real-site path has actually been tried: it REFUSES unless a font_lab_screenshot_directions attempt failed on infrastructure (no Chromium could launch, the dev","write_action":false,"price_micros":0,"input_schema":null},{"name":"font_lab_preview_screenshots","description":"Headless captures of the LAST-RESORT specimen sheet (font_lab_preview) — one render-checked PNG per generic card. Same lock as font_lab_preview: REFUSES until a real font_lab_screenshot_directions attempt has failed on infrastructure (recorded automatically), or force:true because the human explicitly wants the offline sheet — on every framework the real-site captures are the choosing surface, and","write_action":false,"price_micros":0,"input_schema":null},{"name":"font_lab_read_pick","description":"One-shot read of the human's pick (.font-lab/selection.json); null until they've chosen. Prefer font_lab_wait_for_pick (it blocks and shows the human 'agent listening') — use read_pick for a quick non-blocking check.","write_action":false,"price_micros":0,"input_schema":null},{"name":"font_lab_rewire_dead_roles","description":"Fix a role that font_lab_analyze flags as DEAD — declared but not actually rendered (common with Tailwind v4 @theme inline + a hand-written `font-family: var(--font-display)`, which resolves to nothing). Points those raw usages at the published leaf variable so the font renders, making the swap visible. Reversible via font_lab_undo. Offer this when analyze reports dead roles and the user wants tha","write_action":false,"price_micros":0,"input_schema":null},{"name":"font_lab_screenshot_directions","description":"Screenshot the human's REAL RUNNING SITE in each curated direction — THE choosing moment on every framework (and the ONLY sanctioned preview surface off Next until it has actually failed: the generic font_lab_preview sheet stays locked behind a failed attempt here). On Next.js with the panel init'd it drives the panel; on every other stack (Vite / Astro / Remix / SvelteKit / TanStack / plain CSS) ","write_action":false,"price_micros":0,"input_schema":null},{"name":"font_lab_select","description":"Record the human's pick by direction id — the HEADLESS counterpart to clicking Pick in the panel. Use AFTER the human has chosen from the screenshots (you must still let the HUMAN make the call — never auto-select). The id resolves against the SAME set the human was shown: explicit `directions` if passed, else the composed set persisted by font_lab_compose_directions. Writes the same selection.jso","write_action":false,"price_micros":0,"input_schema":null},{"name":"font_lab_start","description":"START HERE when a user wants to choose, change, or improve fonts — on ANY framework (Next.js, Vite, Astro, Remix, SvelteKit, TanStack, …). Returns the project analysis (including `capabilities` + `shipNote` — the preview/ship path for THIS stack, so a non-Next project is a different route, never a dead end), an `environment` block (local vs remote/container session — with the workflow consequences","write_action":false,"price_micros":0,"input_schema":null},{"name":"font_lab_status","description":"One snapshot of the whole handoff: the current pick (if any), whether it's been shipped (applied), whether an agent is waiting, whether the pick endpoint is up, the environment (local vs remote/container — with the workflow consequences), and the latest backup. Call this when resuming a session, before apply, or whenever you need to know where the loop stands. Its `devServer` field health-checks t","write_action":false,"price_micros":0,"input_schema":null},{"name":"font_lab_undo","description":"Revert Font Lab's last apply or rewire, restoring the edited files byte-for-byte from the backup.","write_action":false,"price_micros":0,"input_schema":null},{"name":"font_lab_uninit","description":"Strip ONLY the dev-panel scaffolding (the layout.tsx mount, app/_fontlab/, public/fontlab/ preview fonts) — any applied font change and copy edits are left intact. PREFER font_lab_finish: it runs this AND returns the git-verified commit plan in one call, which is what the end of a session actually needs. Reach for bare uninit only when you want the scaffolding gone mid-session (e.g. the human want","write_action":false,"price_micros":0,"input_schema":null},{"name":"font_lab_verify","description":"THE SHIP RECEIPT — after font_lab_apply (and any rewires or hand edits), re-render the RUNNING site headlessly and MEASURE whether the pick actually reached the pixels: per route, the % of heading/body/label text whose computed font now matches the picked families. Files written is not the same as fonts changed — never declare a font ship done without a converged receipt. If no dev server is reach","write_action":false,"price_micros":0,"input_schema":null},{"name":"font_lab_wait","description":"BLOCK until the human picks a direction, asks for more options, OR clicks *done ✓* in the panel — whichever comes first. This is the unified event loop: one call covers every panel event, so you never miss one because you were waiting for the wrong kind. While blocked, the panel shows 'agent listening' and the human's clicks reach you instead of the copy-a-prompt off-ramp. Returns one of: { event:","write_action":false,"price_micros":0,"input_schema":null},{"name":"font_lab_wait_for_pick","description":"BLOCK until the human picks in the live panel (or timeoutSec elapses). Prefer font_lab_wait (unified) — it covers both picks AND 'more options' requests in one call. This single-event variant is still useful when you ONLY want picks (e.g. after the panel is fully stocked and no more rounds are expected). Returns { picked: true, selection } or { picked: false, timedOut: true } — on timeout, call it","write_action":false,"price_micros":0,"input_schema":null},{"name":"font_lab_wait_for_request","description":"BLOCK until the human clicks 'more options / none of these' in the live panel (or timeoutSec elapses). Prefer font_lab_wait (unified) — it covers both picks AND requests in one call. This single-event variant is still useful when you specifically want to wait ONLY for a request. Returns { requested: true, request } — where request.brief is the mini-brief (feeling / departure / brand / note) and re","write_action":false,"price_micros":0,"input_schema":null}],"scan":{"score":80,"grade":"B","scanned_at":"2026-09-24T21:41:19.011Z","report":{"scannerVersion":"0.1.9","scannedAt":"2026-09-24T21:41:18.929Z","components":{"code":{"score":20,"max":25,"notes":["72 source files scanned"]},"reliability":{"score":-1,"max":20,"notes":["no gateway calls yet and no remote to probe"]},"poisoning":{"score":-1,"max":15,"notes":["tools not inspected (local package is not executed); not counted"]},"auth":{"score":12,"max":15,"notes":["local package, no credentials required"]},"maintenance":{"score":12,"max":15,"notes":["last push 57 days ago"]},"identity":{"score":8,"max":10,"notes":["registry namespace matches repository owner","GitHub account older than a year"]}},"findings":[{"id":"exec.eval","severity":"medium","component":"code","title":"eval / new Function used","evidence":"m6-test.mjs: …t click = (sel) => page.evaluate((s) => eval(s.host).querySelector(s.sel).click(), { …"}],"inputs":{"packages":[{"registryType":"npm","identifier":"font-lab","version":"1.0.0","found":true,"license":"MIT","hasInstallScripts":false,"dependencyCount":4,"publishedAt":"2026-07-26T19:44:34.953Z","repositoryUrl":"git+https://github.com/jmg698/Font-Lab.git","weeklyDownloads":38}],"repo":{"found":true,"owner":"jmg698","repo":"Font-Lab","archived":false,"pushedAt":"2026-07-29T18:12:19Z","stars":4,"forks":0,"openIssues":0,"ownerType":"User","ownerAvatarUrl":"https://avatars.githubusercontent.com/u/203669441?v=4","ownerCreatedAt":"2025-03-17T14:41:19Z","license":"MIT"},"icon":{"url":null,"source":"none"},"presence":{"stars":4,"forks":0,"downloadsWeek":38,"license":"MIT","lastPushAt":"2026-07-29T18:12:19.000Z","score":25}}}},"grade_history":[],"reviews":[]}