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

@lukaisailovic/remarkable-mcp

v0.2.1

Published

MCP server for a reMarkable tablet over SSH or rmfakecloud, with Cloudflare Code Mode.

Readme

remarkable-mcp

Give an AI assistant direct control of your reMarkable tablet — list notes, upload PDFs, export handwriting, write on pages — over SSH or rmfakecloud.

The assistant gets one MCP tool, remarkable_execute, and writes a short JavaScript snippet that calls rme.* (list, mkdir, write, export, …) in one shot.

| You have | This project is | | ------------------------------------------------- | ------------------------------------------------ | | A reMarkable with developer mode | An MCP server | | SSH (USB 10.11.99.1 / Wi‑Fi) or rmfakecloud | stdio or Streamable HTTP (Docker) | | Claude / Cursor / VS Code / any MCP client | Same rme.* on either storage backend |


How it works

MCP client                    this process                         storage
───────────                   ────────────                         ───────
remarkable_execute({          node:vm sandbox                      SSH → xochitl
  code: `async () => {   →    rme.list / rme.mkdir / …      →      or rmfakecloud sync v3
    await rme.mkdir(…)
    return await rme.list({})
  }`
})

Default is SSH into the tablet. rmfakecloud is opt-in (RMFAKECLOUD_URL + device token).

  1. Enable Settings → General → Developer mode on the tablet (SSH).
  2. SSH over USB ([email protected]) or Wi‑Fi — or pair with your rmfakecloud.
  3. Run this server. Point your MCP client at it.

Install

Node 22+. No clone required.

Claude Desktop, Cursor, VS Code, …

{
  "mcpServers": {
    "remarkable": {
      "command": "npx",
      "args": ["-y", "@lukaisailovic/remarkable-mcp"],
      "env": {
        "REMARKABLE_HOST": "10.11.99.1",
        "REMARKABLE_USER": "root",
        "REMARKABLE_PASSWORD": "your-tablet-password"
      }
    }
  }
}

Prefer a key? Set REMARKABLE_KEY to a private-key path (or the PEM). If unset, ~/.ssh/id_ed25519 then id_rsa are tried.

rmfakecloud

Same rme.*, sync-v3 instead of SFTP. Pair once, save the device token:

{
  "mcpServers": {
    "remarkable": {
      "command": "npx",
      "args": ["-y", "@lukaisailovic/remarkable-mcp"],
      "env": {
        "RMFAKECLOUD_URL": "https://cloud.example",
        "RMFAKECLOUD_TOKEN": "device-jwt-from-pair"
      }
    }
  }
}

First pair: npx -y @lukaisailovic/remarkable-mcp --cloud https://cloud.example --pair ABCDEFGH (code from the rmfakecloud UI). It prints a device token to stderr. Writes commit the hash tree; the tablet picks them up on next Check Sync. Not official reMarkable Cloud.

HTTP

Same server, Streamable HTTP on /mcp:

npx -y @lukaisailovic/remarkable-mcp --http
# → http://127.0.0.1:8080/mcp    health: /health

Or pull the image from GHCR:

docker run --rm -p 8080:8080 \
  -e REMARKABLE_HOST=10.11.99.1 \
  -e REMARKABLE_PASSWORD=your-tablet-password \
  ghcr.io/lukaisailovic/remarkable-mcp:latest

From a clone: docker compose up --build (bind 0.0.0.0:8080, pass REMARKABLE_*).

A local checkout’s .mcp.json watches src/ and restarts the stdio child on save (no client restart). pnpm dev:http does the same for Streamable HTTP. In Grok, /mcps disable+enable respawns the process; r only refreshes the list.


What the model can do

The client only lists remarkable_execute. Inside the snippet, methods live on rme.

async () => {
  const folder = await rme.mkdir({ name: "Projects" });
  await rme.createNotebook({ name: "Ideas", parent: folder.id });
  await rme.writeText({
    notebook: "Ideas",
    newPage: true,
    blocks: [
      { text: "Ship it", style: "title" },
      { text: "Talk to design", style: "checkbox" },
    ],
  });
  await rme.writeText({ notebook: "Ideas", text: "Write the RFC", style: "checkbox" });
  return await rme.read({ notebook: "Ideas", page: 2 });
};

A notebook is the file (name, path /Work/Notes, or UUID). A page is 1-based inside that notebook. writeText always writes native Type Folio text and appends — call it again to stack more paragraphs. Ink points are [x, y] in 0–1 from the top-left. remove moves to trash. Writes apply once after the tool returns: SSH restarts xochitl; rmfakecloud commits the sync tree.

| rme.* | What it does | | -------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | | list({ includeTrash?, folder? }) | Library listing (trash hidden by default) | | browse({ path? }) | One folder, or a single notebook | | search({ query, tag? }) | Name / path search, optional tag | | info({ notebook }) | Id, path, type, tags, page count, pages[].title | | read({ notebook, page? }) | Native paragraphs (and checkbox state), or all pages if page is omitted. PDF/EPUB text. | | download({ notebook }) | Raw PDF/EPUB as base64 | | exportPage({ notebook, page?, format? }) | Ink on a page → png or svg (typed text is not drawn) | | upload({ name, dataBase64, parent?, fileType? }) | Put a PDF or EPUB on the tablet | | mkdir / move / rename / remove | Folders and trash | | createNotebook / addPage / removePage | Notebooks and pages | | writeInk({ notebook, strokes, page? }) | Pen / highlighter strokes | | writeMermaid({ notebook, mermaid, page? }) | Mermaid → ink (flowchart, sequence, state, class, ER, xychart) | | writeText({ notebook, text?, style?, checked?, blocks?, page?, newPage?, replace? }) | Native Type Folio: title heading body bullet checkbox. Stacks unless replace. | | tag({ notebook, tag, remove?, page? }) / tags() | Notebook or page tags | | refresh() | Apply now (SSH: restart xochitl; cloud: pull if remote moved, then commit) |


Configuration

Flags and env vars are interchangeable (--hostREMARKABLE_HOST).

| Tablet | Default | | | ------------------------------------ | ---------------------------------- | ---------------------- | | REMARKABLE_HOST / --host | 10.11.99.1 | SSH host (USB default) | | REMARKABLE_USER / --user | root | SSH user | | REMARKABLE_PORT / --port | 22 | SSH port | | REMARKABLE_PASSWORD / --password | | Password | | REMARKABLE_KEY / --key | ~/.ssh/id_ed25519, then id_rsa | Key path or PEM |

| rmfakecloud | Default | | | ------------------------------- | ------- | -------------------------------- | | RMFAKECLOUD_URL / --cloud | | Base URL of your rmfakecloud | | RMFAKECLOUD_TOKEN / --token | | Device JWT from a prior --pair | | RMFAKECLOUD_PAIR / --pair | | One-shot 8-letter pairing code |

| Server | Default | | | ---------------------------------------- | ----------- | ----------------------------------------- | | --http / MCP_HTTP=1 | off | Streamable HTTP instead of stdio | | MCP_HTTP_HOST / --http-host | 127.0.0.1 | Bind address (0.0.0.0 in Docker) | | MCP_HTTP_PORT / PORT / --http-port | 8080 | HTTP port | | --fake / REMARKABLE_FAKE=1 | off | In-memory tablet (tests, no device) | | --fake-dir / REMARKABLE_FAKE_DIR | | Local directory treated as a xochitl tree |


Agent skill

Installable with skills.sh:

npx skills add lukaisailovic/remarkable-mcp

The skill lives at skills/remarkable-mcp/SKILL.md.


Develop

pnpm test
pnpm test:e2e
pnpm lint
pnpm fmt
pnpm build
pnpm exec tsx src/index.ts --fake
pnpm exec tsx src/index.ts --fake --http --http-port 8080

pnpm test uses an in-memory tablet and a mock sync-v3 server. A live device is never required.

pnpm test:e2e starts rmfakecloud via docker-compose-test.yml, seeds it with test/fixtures/mcp-test (a tablet-verified dump of /mcp-test), pairs, reads that tree, then writes a notebook and reads it back from a second client. Needs Docker. Override the URL with RMFAKECLOUD_E2E_URL to point at an already-running server (skips seed).

Inspired by sammorrowdrums/remarkable-mcp and itsfabioroma/remarkable-cli.

MIT. See LICENSE.