Server data from the Official MCP Registry
Local PDF, image, archive and video tools for AI assistants. Files never leave your computer.
About
Local PDF, image, archive and video tools for AI assistants. Files never leave your computer.
Security Report
Valid MCP server (2 strong, 2 medium validity signals). No known CVEs in dependencies. ⚠️ Package registry links to a different repository than scanned source. Imported from the Official MCP Registry. 1 finding(s) downgraded by scanner intelligence.
12 files analyzed · 1 issue found
Security scores are indicators to help you make informed decisions, not guarantees. Always review permissions before connecting any MCP server.
Permissions Required
This plugin requests these system permissions. Most are normal for its category.
What You'll Need
Set these up before or after installing:
Environment variable: ROUNDERTOOLS_ALLOW
Environment variable: ROUNDERTOOLS_FFMPEG
How to Install
Add this to your MCP configuration file:
{
"mcpServers": {
"io-github-adam-sari-roundertools": {
"env": {
"ROUNDERTOOLS_ALLOW": "your-roundertools-allow-here",
"ROUNDERTOOLS_FFMPEG": "your-roundertools-ffmpeg-here"
},
"args": [
"-y",
"@roundertools/mcp"
],
"command": "npx"
}
}
}Documentation
View on GitHubFrom the project's GitHub README.
Rounder
Free browser tools with no junk: roundertools.com. Every tool runs on the visitor's device, so files are never uploaded and hosting is a static site.
Stack
- Astro 7 (static output) with Svelte 5 islands and Tailwind 4
- One page per tool, generated from the registry in
src/tools/ - Engines that run in Web Workers:
src/engines/image: jSquash codecs (MozJPEG, OxiPNG, WebP, AVIF), HEIC via heic-tosrc/engines/pdf: pdf-lib, PDF.js and qpdf (wasm)src/tools/lib/office: Office conversions. PDF → Word/Excel/PowerPoint rebuilds pages from PDF.js text and layout (docx, ExcelJS, PptxGenJS). Word/Excel/PowerPoint → PDF lays the file out in the browser (docx-preview, ExcelJS, pptx-renderer) and paints that layout into a PDF with real text, in metric-compatible fontssrc/engines/media: Mediabunny (WebCodecs), with an ffmpeg.wasm fallback for unusual formatssrc/engines/ai: transformers.js and onnxruntime-web, on WebGPU with a WASM fallback
- Hosted on Cloudflare as a Worker with static assets (the ratings API is its only server code)
Adding a tool
- Write the island in
src/tools/islands/<Name>.svelte, and put pure logic insrc/tools/lib/<tool>/. - Add
src/tools/defs/<slug>.ts. It default-exports aTool(or a list of them, for variant pages); seesrc/tools/types.ts. The registry picks it up automatically, and the page, search entry, sitemap entry and share image are all generated. - Add unit tests for the pure logic in
tests/unit/<slug>.test.ts.
Two optional hooks, both off unless a tool uses them:
notes(in the def): first-hand content, rendered between "How it works" and the questions, never between the tool and its download button.settings(what each control does),results(real, measured runs, never estimates; they needmeasured: { date: 'YYYY-MM-DD', device: 'Chrome 141 on a 2021 MacBook Air' }, shown as the table's caption),formatsandlimits(a platform's file caps, with an httpssourcelink to its own docs).notesProblems()in the registry checks them, andtests/unit/tool-notes.test.tsruns it over every tool.- Success signal: once a run gives the visitor a usable result (a download is ready, a result was copied), the island
calls
toolSucceeded()fromsrc/tools/lib/success.ts, once per run and never for errors. Saving the result withdownloadResult()(src/tools/lib/files.ts) instead ofdownloadBlob()does both; listeners ignore repeats. It dispatchesCustomEvent('rounder:tool-success', { detail: { slug } })from ToolHost's wrapper (which carries the page's slug, so variant pages report their own) up towindow; page-level islands subscribe withonToolSuccess(). The rating prompt (src/components/tool/RatePrompt.svelte, rendered under the tool card throughRateSlot.svelte) listens for it. It must never gate a download or offer anything in exchange for a rating. Leave it unwired on the ad-free privacy tools.
Heavy tools (video, ffmpeg fallback, AI, big PDFs, collages, slideshows) check the device before a run with
checkDevice(job, { bytes, seconds, width, height, count }) from src/tools/lib/device-guard.ts: ok, warn (show it
with DeviceNote.svelte and let the run start) or block (disable the start button; only for hard limits, or when
navigator.deviceMemory says the job needs far more than the device has). In the catch, deviceMessage(job, err) turns
any out-of-memory shape (RangeError, wasm Aborted(OOM), Safari's canvas limit, an engine's out-of-memory code) into
"too big for this device: try …" advice. tests/e2e/device-guard.spec.ts covers it with emulated low-memory phones.
Ratings
"Rate this tool" is the site's only server code: worker/index.ts on the same Worker as the static assets, run first for
/api/* only (run_worker_first in wrangler.jsonc), with a D1 database (rounder-ratings, schema in migrations/).
POST /api/rate stores { slug, stars, comment? }, one per visitor and tool a day; rate limiting keys on a hash of the
IP with a salt that is deleted after each UTC day, and no IP is stored. GET /api/rating/:slug and GET /api/ratings
return { avg, count }. Before each build scripts/seo/ratings.mjs snapshots the aggregates into src/seo/ratings.json
(keeping the last snapshot when offline). A tool page shows its rating, and adds aggregateRating to its WebApplication
JSON-LD, only from 20 ratings on (src/seo/ratings.ts). Never seed, edit or hard-code ratings.
To try the API locally: npm run build, then npx wrangler@4 d1 migrations apply rounder-ratings --local and
npx wrangler@4 dev.
Search
The ⌘K palette and the home page's search box share one engine in src/search/, all of it on the visitor's device:
core/: a deterministic intent parser (formats and aliases, sizes and ranges, dimensions, durations, platforms with their sourced limits, devices, verbs, typos, romanised Hindi) that routes to a tool, a preset and, for several steps, a chain; BM25 with typo tolerance over the lean index; and the fusion that ranks them. Parser routes are strong boosts, never pins. The conversion graph is read off the registry's slugs and variant props, so most new tools need no search code.semantic/: Model2Vec potion-base-2M (MIT), pruned to its Latin vocabulary and quantised to int8 byscripts/vendor-search.mjsfrom a pinned revision with SHA-256 checks, and committed inpublic/models/search/. It loads after the first query (never on Save-Data or slow connections) and only re-ranks.ai/: Chrome's built-in Prompt API plans long requests, only when the visitor turns it on in the palette and the model is already on the device.src/pages/search/[file].tsserves the content-hashed index and tool vectors./search-index.jsonstays as it is for the ratings Worker.
Results deep-link with presets in the hash (/compress-pdf#target=150kb, /image-resizer#range=20-50kb), which
src/tools/presets.ts validates per island and ToolHost merges into the props. Queries are never logged, stored or put in a URL.
tests/unit/search/eval.test.ts gates quality on the dev, held-out, independent "fresh" and adversarial-review sets in tests/fixtures/search/
(dev is the only one to tune on); run it with --silent=false to see every miss.
npm packages (SDK, CLI, MCP)
packages/ holds three MIT packages that run the site's tools in Node, on the user's machine: @roundertools/sdk
(typed functions), roundertools (the CLI, npx roundertools compress-pdf report.pdf) and @roundertools/mcp (an MCP
server for AI assistants). packages/build (private) holds the bundler plugins. Docs for users are on /developers.
- They import the site's own
src/enginesandsrc/tools/libcode, bundled with rolldown. Browser-only leaves are swapped for Node twins inpackages/sdk/src/platform/node(qpdf in process, PDF.js's environment, the image codecs, the compress-pdf runner, the PDF fonts), and a guard fails the build if?url/?raw,import.meta.env, a Web Worker or a.sveltefile reaches a package. So a shared module that gains a browser-only import breaksnpm run sdk:build, not users. - One spec per tool (
packages/sdk/src/ops/) drives the SDK's types, the CLI's flags and help, the MCP schemas and the site's "Use this in code" block (src/components/tool/UseInCode.astro, viasrc/developers.ts). - Media runs on the user's own ffmpeg; nothing of ffmpeg, libheif or mediabunny ships. The packages make no network
requests, and the CLI and MCP bins load
@roundertools/sdk/no-networkfirst. - The site files they bundle are listed in
REUSE.tomlas "AGPL-3.0-only OR MIT". The SDK build fails when its bundle and that list differ;node packages/sdk/build.mjs --reuse-writeupdates the list (see CONTRIBUTING.md).
npm run sdk:build # builds the SDK, CLI and MCP server into packages/*/dist
npm run sdk:test # plugin and licence checks, SDK ops, CLI end-to-end, MCP protocol tests
npm run sdk:check # type checks the packages, tests included (npm run check skips packages/)
Commands
| Command | What it does |
|---|---|
npm run dev | Dev server on http://localhost:4321 |
npm run build | Production build into dist/ |
npm run check | Type checks (astro check plus svelte-check --incremental; the plain mode skips files here) |
npm run check:dist | Checks a build in dist/: every sitemap page is linked and no link is broken, no ad code on ad-free pages, no two pages share more than 80% of their text |
npm test | Unit tests (Vitest) |
npm run e2e | Browser tests (Playwright): builds into ../.rounder-e2edist, serves it on :4600 (E2E_PORT to change it) and runs every page plus real file flows in Chromium, Firefox, WebKit and two phone profiles. Install the browsers once with npx playwright install chromium firefox webkit; E2E_SKIP_BUILD=1 reuses the last build, E2E_DIST=<dir> picks the build folder. |
npm run sdk:build / npm run sdk:test / npm run sdk:check | Builds, tests and type checks the npm packages in packages/ (Node 22.13+; the media tests use a system ffmpeg when there is one) |
npm run vendor | Copies runtime files (ffmpeg, onnxruntime, Tesseract, PDF.js, libarchive, the Office to PDF fonts) into public/vendor. It runs automatically before dev and build. |
Engine test pages live under /dev/ (for example /dev/media-lab, /dev/ai-lab). They are dropped from production builds.
Deploying (Cloudflare)
Production runs as a Cloudflare Worker with static assets (wrangler.jsonc). Asset requests are free and unmetered and
never run server code; only /api/* (ratings) does. The custom domain's DNS record is created on deploy.
npm run build # also runs the vendor step
npm run deploy # wrangler: ratings DB migrations, the site on roundertools.com, plus workers/www-redirect (www → apex, 301)
.env.production holds the public build settings (AdSense publisher id, analytics token). Self-hosters can delete
it to build without ads or analytics. There is no *.workers.dev copy of the site, so only roundertools.com is
indexed. public/_headers sets security and cache headers.
Large wasm files are split into parts under 25 MB that are joined again in the browser and checked against a SHA-256,
so the site also fits Cloudflare Pages if you prefer it (build output dist, NODE_VERSION=22).
Network use
Everything runs locally, with these exceptions:
- AI model weights are downloaded once from Hugging Face, pinned to exact revisions. The video background remover's selfie-segmenter model comes from Google's model storage (storage.googleapis.com).
- Tesseract language data comes from jsDelivr.
- The currency converter fetches European Central Bank rates from the Frankfurter API.
- The password checker's breach lookup (Have I Been Pwned) runs only when the user clicks it.
- Images a document links to (Markdown editor, Markdown to PDF, HTML to PDF), and the email signature generator's photo or logo address, load from wherever they're hosted.
- In Chrome, the translator, summarizer, paraphraser and grammar checker can use the browser's built-in AI. Chrome may download that model from Google itself.
- Ratings:
POST /api/rateon roundertools.com, only when a visitor sends one (tool slug, stars, optional comment). - Cloudflare Web Analytics (cookieless), only when
PUBLIC_CF_BEACON_TOKENis set. - Google AdSense and its consent message, only when
PUBLIC_ADSENSE_CLIENTis set (ad slots also needPUBLIC_ADS_LIVE=true). Never on the privacy, legal and trust pages, 404, offline, or the ad-free tools (noAdsin their defs, mirrored inSITE.adFreeforscripts/seo/check-ads.mjs).
The full list for users is on /security (keep the two in step), and /privacy explains what each service sees. Licenses for libraries, fonts and models are listed on /credits.
Open source
Rounder is open source so anyone can check that the tools do what the site says: files stay on the device, and every
network request is the one listed on /security. Bug reports, tool ideas and pull requests are welcome; see
CONTRIBUTING.md, SECURITY.md for vulnerabilities, and the
code of conduct.
Self-hosting
The build is a folder of static files, so any static host works.
- Set
siteinastro.config.mjsto your own address (it drives canonical URLs, the sitemap and share cards). npm ci, thennpm run build(Node 22). The output isdist/.- Serve
dist/over HTTPS (browsers allow WebGPU, camera access, Web Crypto and the service worker only on secure origins). - Copy the headers from
public/_headersinto your host's config. That file uses the Cloudflare Pages format. Don't add COOP/COEP headers; the tools are built without them. - Leave
PUBLIC_ADSENSE_CLIENT,PUBLIC_ADS_LIVEandPUBLIC_CF_BEACON_TOKENunset, and your copy carries no ads and no analytics. Please give your copy its own name and logo, and replacepublic/.well-known/security.txtand the contact details insrc/site.tswith your own. - Ratings need the Worker and D1 database in
worker/. Without them, deletesrc/components/tool/RatePrompt.svelte(no rating box) and build withRATINGS_OFFLINE=1and an emptysrc/seo/ratings.json, so your copy never shows roundertools.com's ratings.
AI tools download model weights from Hugging Face at runtime, and OCR downloads language data from jsDelivr. To run
fully offline, mirror those files, set baseUrl on the models in src/engines/ai/models.ts and point
LANGUAGE_BASE in src/tools/lib/ocr/languages.ts at your copies.
License
Rounder is licensed under the GNU Affero General Public License v3.0 (AGPL-3.0). You may use, change and share it under that license. If you run a modified version as a network service, you must offer its users the corresponding source code (section 13).
The npm packages in packages/ are MIT, and the site files they bundle (listed in REUSE.toml) are offered
under "AGPL-3.0-only OR MIT". UI code, page copy and everything else stay AGPL-3.0 only.
Third-party licenses
Libraries, vendored runtime files (public/vendor, copied from npm by npm run vendor), self-hosted models
(public/models), fonts and downloaded AI models keep their own licenses. They are listed with links on
/credits (source: src/pages/credits.astro), and each npm package's license is in its
folder under node_modules.
Reviews
No reviews yet
Be the first to review this server!
More Developer Tools MCP Servers
Rea
Freeby Morluto · Developer Tools
Reverse engineer anything from your terminal or agent with one CLI and MCP server.
Paperclip
Freeby Paperclipai · Developer Tools
Trending hip-hop artist momentum scores across four cultural dimensions.
Toleno
Freeby Toleno · Developer Tools
Toleno Network MCP Server — Manage your Toleno mining account with Claude AI using natural language.
MCP Marketplace
Freeby mcp-marketplace · Developer Tools
Search and install MCP servers from inside your AI client.
mcp-creator-python
Freeby mcp-marketplace · Developer Tools
Create, build, and publish Python MCP servers to PyPI — conversationally.
by Lharries · Communication
Read, search, and send WhatsApp messages through your AI assistant
