New:Microsoft Teams Notifications Are Now Available in Socket.Learn more →
Get Started

@page-scanner/mcp

Package Overview
Dependencies
Maintainers
1
Versions
7
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@page-scanner/mcp

Let a local AI agent capture a web page with the Page Scanner Chrome extension.

latest
Source
npmnpm
Version
0.4.2
Version published
Weekly downloads
629
113.95%
Maintainers
1
Weekly downloads
 
Created
Source

@page-scanner/mcp

An MCP server that lets an AI agent on your machine capture a web page with the Page Scanner Chrome extension, and get the file on disk.

The agent talks to this over stdio. The capture happens in a Chrome you are already signed in to, which means a page behind a login is a page you are logged into. The page and the file never leave the machine.

This package is seven tools over @page-scanner/cli, which is where the bridge, the pairing and the daemon actually live. If you want the same thing at a shell prompt, install that instead; the two share one pairing and one daemon, so they can be used at the same time.

Setup

1. Point the agent at the server. For Claude Code, as a plugin that also installs the agent skill, which teaches it when and how to use these tools:

claude plugin marketplace add sbd530/page-scanner-skills
claude plugin install page-scanner@page-scanner-skills

Or the server alone:

claude mcp add page-scanner -- npx -y @page-scanner/mcp

Or as an mcpServers block, which Claude Desktop reads from claude_desktop_config.json and Codex and others read from .mcp.json:

{
  "mcpServers": {
    "page-scanner": {
      "command": "npx",
      "args": ["-y", "@page-scanner/mcp", "serve"]
    }
  }
}

In Cursor, Add to Cursor writes that block for you. In VS Code:

code --add-mcp '{"name":"page-scanner","command":"npx","args":["-y","@page-scanner/mcp","serve"]}'

The server is in the MCP Registry as io.github.sbd530/page-scanner, for a client that installs from there.

For Codex, Cursor and the other agents that read the Agent Skills format, npx skills add sbd530/page-scanner-skills adds the skill beside that block.

2. Set up Page Scanner on this computer. Ask the agent to run the install tool, or do it yourself:

npx @page-scanner/mcp install

It sets up Page Scanner's helper for every Chromium browser on the machine: the program Chrome starts, through Native Messaging, to connect the extension to this server. Nothing secret comes back, so the agent can run it without a token reaching the conversation.

3. Connect Chrome. Open the Page Scanner settings (the gear in the editor toolbar, or chrome://extensions then Details then Extension options). Under Local agents:

  • give the browser a name, so an agent can tell your profiles apart ("work", "personal"),
  • press Connect, and allow Chrome's prompt, which asks whether the extension may "communicate with cooperating native applications".

Chrome runs a separate copy of the extension in every profile, so repeat that for each profile you want reachable. They identify themselves by name.

page-scanner-mcp status says whether a pairing exists and whether anything is connected.

Pairing with a port and a token

The older way, for a machine where the helper cannot be installed. Run npx @page-scanner/mcp pair in a terminal: it prints a port and a token and saves them to ~/.page-scanner/config.json, which is owner-readable only on macOS and Linux and not on Windows, where NTFS does not implement the mode it is written with (the CLI's README says how to restrict it). In the settings, set Connect through to A port and a token, paste both, and press Connect. pair --rotate issues a new token, which also invalidates the old one everywhere.

The pair tool does the same from the agent, and returns the token to it, which means it lands in the conversation, and a transcript is a place secrets should not be. Prefer install, or run pair in a terminal yourself; the agent never needs to see the token.

Updating

Both setups run npx -y @page-scanner/mcp, which asks npm for the newest version each time the client starts the server. Restart the client, or start a new Claude Code session, to pick one up. The daemon restarts itself on the new version and the pairing carries over.

If you also installed the command line globally, update it at the same time with npm install -g @page-scanner/cli@latest. A daemon of one version is replaced by a client of any other, so the two would keep replacing each other's daemon.

Tools

install Sets up Page Scanner's helper for every Chromium browser on the machine and says which, and what the user does next: press Connect in the extension's settings and allow Chrome's prompt. Returns no secret. An unpacked build loaded in developer mode is found and allowed by itself; the optional extensionIds adds ids by hand.

pair The older setup: writes the pairing and returns the port and token to paste into Chrome. See the note above.

list_browsers The Chrome profiles paired and connected right now, with the name you gave each one. Start here when more than one is connected.

list_tabs The windows and open tabs of one browser. Tabs carry the windowId they belong to, and windows say which is focused, so an agent can pick a window as well as a tab. Takes an optional browserId, which is only required when more than one browser is connected, and an optional waitSeconds.

scan_page Captures a page, or a list of them, and writes each to disk. Returns the absolute path.

ArgumentMeaning
browserIdWhich browser. Optional when only one is connected.
tabIdA tab from list_tabs. Give one of tabId, url or urls.
urlOpens a background tab there, captures it, closes it again.
urlsUp to 50 addresses, captured one at a time into outputPath, which is then a directory. A page that fails is reported and the rest are captured.
windowIdWhich window to open url in. Ignored with tabId.
formatpdf (default), png, jpeg.
pageSizePDF only. a4 (default) and letter slice onto printable sheets with a half-inch margin; auto is one page the size of the capture.
qualityJPEG only, 0.1 to 1.
videoHandlingframe keeps a video's paused frame, blank leaves its area empty.
colorSchemeWhich of a page's two themes to capture: auto (default, whatever the browser shows), light, dark.
captureWidthLay the page out at a sheet's width first, so the PDF prints at 1:1: window (default), a4, letter.
openEditorAlso leave the capture open in a Page Scanner editor tab.
outputPathA file, or a directory to keep the suggested name. A leading ~ is home. Defaults to the cwd, or ~/Downloads when that is / or read-only, as under Claude Desktop.
hideClutter to hide before the capture and put back after: any of ads, consent, chat, overlays; [] hides nothing. Left out, the extension's own settings decide, and they hide all four unless the user changed them. The result counts what was hidden as hidden.
markdownThe page as Markdown, read from the page rather than the PDF: inline returns it in the result, beside writes a .md next to the file, only writes the .md and no file. Adds page: title, address, capture time, language, headings. Pictures are left out.
fileNameThe file name inside outputPath, as a template: {n} (place in urls), {host}, {name} (the suggested name), {date}, {time}, {ext} (added when left out). A / makes a subdirectory.
waitSecondsHow long to wait for a browser to connect. 0 fails immediately.

A PDF from a vector capture keeps real, selectable text. The result says selectableText: true when that is what you got, and carries a truncated object when the page was larger than Page Scanner will capture and the file is missing part of it. Given urls, it returns results, one per page in order, each either that page's result with ok: true and its url, or ok: false with an error carrying a code and a message, plus written and failed counts.

With markdown, the result also has page: title, url, capturedAt (ISO 8601), language (the page's own lang, or null) and headings (level and text, in order), plus markdownPath where the .md was written, or markdown with the text itself for inline. For only, path is the .md. An extension older than this feature sends no text, and the call fails with a sentence saying to update it. With urls, the call is an error as a whole only when nothing could be scanned at all (no pairing, no browser).

diff_captures Says what changed between two captures of a page that scan_page wrote: two Markdown files a passage at a time, or two PNGs pixel by pixel, outlining the changed regions on the newer one. For PDFs, scan with markdown: "beside" and pass the PDFs or their .md files.

ArgumentMeaning
oldPathThe older capture: a .md from markdown beside or only, a PNG, or a PDF with its .md beside it.
newPathThe newer capture of the same page, of the same kind.
outputPathFor two PNGs, where to write the newer one with the changed regions outlined. Defaults to <name>.diff.png.

Returns kind (text or visual) and changed. For text: added and removed line counts, hunks, the same as a unified diff, each side's source and captured from its front matter, and sameAddress. For pictures: regions (x, y, width, height in pixels of the newer capture), changedFraction, both sides' sizes, and path, the outlined picture, or null when nothing changed. No browser is needed: both captures are already on disk.

extract_design Reads a page's design as the browser draws it, in its light and its dark scheme, from one page, several, or the pages a crawl finds, and writes six files into a directory (nine with components): tokens.json (W3C Design Tokens format), tokens.css, tailwind.preset.js, audit.md (values nearly equal, probably meant as one), contrast.md (WCAG 2 contrast for every text color over its background; text over a gradient or a picture is listed apart, not failed) and extract.json (the measurements).

ArgumentMeaning
browserIdWhich browser. Optional when only one is connected.
tabIdA tab from list_tabs, read as it stands. Give one of tabId, url, urls or crawl.
urlOpens a background tab there, reloads it under each color scheme, reads it and closes it again.
urlsUp to 20 pages of one site, read one after another and written as one design; audit.md lists what only one page uses.
crawlA start address: its same-origin links are followed, one page per kind, honoring robots.txt and nofollow, never a log-out or delete address; a page that lands on another site or a page already read is left out.
maxPagesWith crawl, the most pages to read. Default 10, at most 50.
depthWith crawl, how many links from the start. Default 2, at most 5.
outputPathThe directory. Defaults to design-<host> in the working directory, or in ~/Downloads as for scan_page.
minUsesHow many elements must use a value before it becomes an inferred token. Default 2.
componentstrue to find the components as well: repeated structures and controls, their variants and hover and focus states, written to components.json and components.md, and catalog.pdf with each variant cut from the page as vector artwork. Each page is scanned too, so it takes longer.
waitSecondsHow long to wait for a browser to connect. 0 fails immediately.

Returns the directory, each file's path, the tokens counted by group, how many the page declared, the contrast pairs (pairs, failing below AA, overImage left to the eye), nearlyEqual and darkDiffers, unusedDeclared, the declared colors nothing was drawn in, left out of the tokens, and onePage, the values only one page uses. pages lists every page with ok and, when it was not read, message; in a crawl, landed and left say where a page went and why it was left out, and crawl says whether robots.txt was read and which links were passed over, by reason. With components, components counts the components and their variants. Declared custom properties keep their names; inferred tokens are numbered by use, so naming them is left to the agent. An extension too old to read a design is refused with a sentence saying to update it.

What an agent can do with this, and what it cannot

It can list the addresses of every tab you have open, capture any of them, and open an address of its own choosing to capture that. It captures whatever the browser renders, which on a logged-in tab means whatever you are logged in as.

It cannot reach a browser until you press Connect in that browser's Page Scanner settings and allow Chrome's prompt, and Disconnect closes the connection immediately. The token is in the pairing install saved in ~/.page-scanner/, where the helper reads it; no web page can. A page an agent opens sits in a green Page Scanner tab group while it is scanned, unless Group an agent's tabs is off.

Three checks run on every connection: the Origin has to be a chrome-extension:// one, which stops a web page in any browser talking to the server; the first frame has to carry the token, which stops any other program on the machine doing so; and the protocol number has to match, so an extension and a server that disagree say so instead of misbehaving.

Limits

  • A scan attaches chrome.debugger, so Chrome shows its "Page Scanner started debugging this browser" bar for as long as the scan takes. That is Chrome's notice and cannot be suppressed. Unattended, it will appear without you having asked for it.
  • A tab with DevTools open cannot be captured at all: only one debugger can attach at a time.
  • There is no raster fallback for an agent scan. The fallback needs activeTab, which requires a click, so an agent scan of a page the vector capture cannot handle fails loudly instead.
  • chrome:// pages, the Web Store and other extensions' pages are off limits to any extension.
  • The crop is always the whole page. An agent has no preview to crop against.
  • The helper needs Node 22 or later where install ran. On Windows it has not been run on a real machine yet.

License

Apache-2.0. See LICENSE.

Keywords

mcp

FAQs

Package last updated on 24 Sep 2026

Related posts