MCP Compiler Server
Enables deterministic data extraction from Amazon product pages by registering custom extraction scripts for the amazon.com domain.
Allows sending notifications to Discord via incoming webhooks with a customizable message.
Allows sending notifications to Slack via incoming webhooks with a customizable message.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@MCP Compiler ServerCreate an extraction script for amazon.com that returns product title and price."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
APImeMCP
An MCP (Model Context Protocol) server that implements a "Compiler Pattern" for deterministic web-page data extraction: author a plain JavaScript extraction script once per domain, and re-run it deterministically against any matching URL — no external database, no re-derivation of extraction logic per request.
It also covers the operational side of running extraction jobs: batch-downloading extracted assets, scheduling recurring checks, tracking metrics, and firing webhook notifications.
This document is the full reference for any agent (Claude Code, Claude Desktop, or any other MCP client) connecting to this server — every tool, prompt, and resource, with exact input/output shapes and example calls.
How it works
register_extraction_templatesaves a JavaScript snippet (evaluated inside the page's own browser context) totemplates/<templateId>.jsand records the mapping from a domain pattern to that script intemplates/manifest.json.execute_native_extractionopens the target URL in an isolated Playwright browser context, waits for the page to reachnetworkidle, evaluates the matching script, and returns the result. Every successful run logs a metric row automatically.batch_download_assetstakes a list of URLs (e.g. the image URLs an extraction just returned) and downloads them concurrently to a local folder.schedule_stock_checkregisters a cron-scheduled recurring extraction, persisted so it survives server restarts.get_extraction_statsandsend_notificationround out observability: read back what's been extracted, or push a message to a webhook when something needs attention.
Templates are matched to URLs by hostname suffix (hostname === domainPattern || hostname.endsWith('.' + domainPattern)), so registering amazon.com also matches
www.amazon.com and smile.amazon.com. Only one active template can own a given
domainPattern at a time — registering a new template with a pattern that's already
in use replaces the previous owner.
Related MCP server: Ashra Structured Data Extractor MCP
Requirements
Node.js 20+
~300MB disk for the Chromium binary Playwright installs
Install & build
npm install
npx playwright install --with-deps chromium
npm run buildRun
npm startThe server communicates over stdio — it's meant to be spawned by an MCP client, not run interactively.
Using a template without an MCP client or the dashboard UI
Every registered template is also a plain HTTP endpoint on the running server, so you can call it straight from a terminal — no Claude Code, no clicking the dashboard:
curl -X POST http://127.0.0.1:3000/api/run/<templateId> \
-H "Content-Type: application/json" \
-d '{"url":"https://example.com/page"}' # omit url for fixed-target / recorded templates: -d '{}'Each template gets two auto-generated artifacts (written on registration, regenerate all
with node scripts/gen-usage.mjs):
apis/<templateId>.md— a copy-paste guide, filled in with that template's real last-run URL. The dashboard's per-template rows link to a rendered version (the "Docs" button →/docs/<templateId>).apis/<templateId>.mjs— a uniquely-named, fully standalone script that embeds that template's entire logic. Its only dependency is Playwright, so anyone can grab the one file and run it with no APImeMCP server and no repo:npm i playwright && npx playwright install chromium node <templateId>.mjs # extraction: pass a URL if the template needs one node <templateId>.mjs --watch # action-sequence: visible browser
See apis/README.md for the index once you've registered at least one template.
Using a community template (public registry)
apimemcp add <domain>Fetches the matching template from the apimemcp-templates
registry and registers it locally — no browser/dashboard startup, just a fetch +
local write. Works from a fresh install with no existing templates/ directory.
See add_community_template under Tools for the MCP-tool equivalent, and the
registry repo's own CONTRIBUTING.md to add a template.
Connected app profiles (no manual cookie extraction)
For sites that require login, use a persistent browser profile instead of copying
cookies into chat. Each connection gets its own Chromium profile under
templates/app-profiles/<connectionId>/ and is scoped to one domain pattern.
An agent can start the login flow:
await client.callTool({
name: 'connect_app',
arguments: {
connectionId: 'amazon',
domainPattern: 'amazon.com',
loginUrl: 'https://www.amazon.com/ap/signin',
autoStart: true
}
});APImeMCP opens a visible browser window. Log in normally in that window, then confirm the connection:
await client.callTool({
name: 'confirm_app_connection',
arguments: { connectionId: 'amazon' }
});Use the connection on an extraction:
await client.callTool({
name: 'execute_native_extraction',
arguments: {
templateId: 'amazon-product',
targetUrl: 'https://www.amazon.com/dp/EXAMPLE',
connectionId: 'amazon'
}
});Connections with autoStart: true reopen their persistent browser profiles when
the MCP server starts. The server does not scrape or print cookies; Chromium owns
the session state. The profile directories are still sensitive login material and
must not be committed or shared. Use list_app_connections to inspect configured
profiles. Native OAuth/API connectors for services such as Slack or Google Drive
can be added later as a separate connector type when the provider's client ID,
scopes, and callback policy are known.
Test
npm test # unit tests (storage + validation, no browser)
node scripts/verify-engine.mjs # manual smoke test of the browser engine
node scripts/verify-server.mjs # manual end-to-end smoke test of the full serverThe two scripts/verify-*.mjs smoke tests spin up a local HTTP server and drive a
real headless Chromium instance; they require npm run build and
npx playwright install --with-deps chromium to have been run first.
Connecting a client
Claude Code (CLI)
Three ways to connect, in order of preference. All three register a server named
apimemcp; --scope user makes it available in every project and session (drop
that flag to scope it to just the current project).
Option A — global install (recommended, confirmed working)
npm install -g @neetigyashah/apimemcp
claude mcp add --scope user --transport stdio apimemcp -- apimemcp
claude mcp listThe last command should show apimemcp ... ✔ Connected. The install step also
fetches the Chromium binary Playwright needs (postinstall), and no git clone or
TypeScript build is involved.
Updating: npm update -g @neetigyashah/apimemcp, then restart your Claude Code
session.
Option B — npx, no persistent install
claude mcp add --scope user --transport stdio apimemcp -- npx -y @neetigyashah/apimemcp
claude mcp listWorth trying if you'd rather not install anything globally. If claude mcp list
shows it connected, you're done — nothing further to read here.
If instead it shows ✘ Failed to connect: this is a known, confirmed-reproducible
npx bug on some npm/Windows combinations, unrelated to this package specifically
(the package's own shim scripts run correctly when invoked directly — npx itself
fails to put its cache directory on the child process's PATH before executing).
Remove the failed registration and use Option A instead:
claude mcp remove apimemcp -s userUpdating: nothing to do — npx re-resolves against the registry each launch.
Option C — from source (for modifying the code)
git clone https://github.com/NeetigyaShah/APImeMCP.git
cd APImeMCP
npm install && npm run build
claude mcp add --scope user --transport stdio apimemcp -- node /absolute/path/to/APImeMCP/dist/index.jsUpdating: git pull && npm install && npm run build in that directory, then
restart your Claude Code session — it runs from the compiled dist/, not the
TypeScript source directly, so pulling alone isn't enough.
All options: staying current
Whichever option you used, the server tells you when a newer version exists on its
own: checkForUpdates() compares against the latest commit on GitHub at startup
and logs UPDATE AVAILABLE: ..., and the status://server MCP resource exposes
updateAvailable: true/false so an agent can check programmatically instead of you
watching stderr.
Optional: the using-apimemcp skill
The package ships a Claude Code skill (skills/using-apimemcp/SKILL.md) that
teaches an agent this server's tool signatures and the compiler-pattern
workflow up front, so it doesn't need to rediscover them by trial and error
each session. Activate it once per machine:
mkdir -p ~/.claude/skills/using-apimemcp
cp "$(npm root -g)/@neetigyashah/apimemcp/skills/using-apimemcp/SKILL.md" ~/.claude/skills/using-apimemcp/SKILL.md(from source: cp skills/using-apimemcp/SKILL.md ~/.claude/skills/using-apimemcp/SKILL.md)
Claude Desktop
Add to claude_desktop_config.json:
{
"mcpServers": {
"apimemcp": {
"command": "node",
"args": ["/absolute/path/to/APImeMCP/dist/index.js"]
}
}
}Any other MCP client
Point a StdioClientTransport (or your SDK's equivalent) at
node dist/index.js with this repo as the working directory. See
scripts/verify-server.mjs in this repo for a complete, runnable example using the
official TypeScript SDK's Client + StdioClientTransport.
Docker
docker build -t apimemcp .
docker run -i apimemcpThe image installs Chromium and its OS dependencies at build time
(npx playwright install --with-deps chromium) and runs as a non-root user.
Recorder extension (record-once, replay via APImeMCP)
extension/ is a Chrome MV3 extension, separate from the npm package - it's not
included in the published tarball, so get it by cloning this repo. It records
clicks/typing/navigation in a normal browser tab, then sends the recording (plus
cookies for replay) to this server's POST /api/recordings endpoint, which
registers it as a new action-sequence template - a different kind from the
page.evaluate() extraction templates above: instead of returning scraped data, it
replays the literal recorded steps (click, fill, select, navigate) headlessly via
Playwright, useful for repeating a workflow (e.g. "post a video," "submit a form")
rather than extracting a page's contents. It's auto-verified once immediately after
registering, and shows up in the dashboard alongside extraction templates with an
"action-sequence" badge and a pass/fail status dot. See extension/README.md for
how to load it (chrome://extensions → Developer mode → Load unpacked).
Action-sequence templates get a second Watch button next to Run - it replays the
same steps but launches a separate, visible browser window instead of using the
shared headless one, so you can watch it actually click through the recorded steps.
The window closes itself ~1.5s after finishing. Extraction templates don't get this
button; watching a page.evaluate() scrape execute isn't the point the way watching
a recorded workflow replay is.
Tools
register_extraction_template
Save a reusable extraction script for a domain.
field | type | notes |
| string | lowercase kebab-case, e.g. |
| string | e.g. |
| string | vanilla JavaScript, evaluated via |
| string, optional | for a template that always targets the same page (e.g. "today's deals") — set this and |
|
| how long to wait after navigation before running the script. Omit it and new templates default to the fast |
| string, optional | wait for this selector to appear before running the script — a more precise alternative to |
Returns the saved { templateId, domainPattern, scriptPath, fixedTargetUrl?, waitStrategy?, readySelector?, createdAt, updatedAt }.
Re-registering an existing templateId with the same script but a new waitStrategy/readySelector updates just that setting (upsert semantics).
By default, execute_native_extraction also blocks images/media/fonts/CSS for extraction
templates (not for recorded/action-sequence ones) to speed up runs — pass
simulateLowBandwidth: false explicitly to disable this for one call.
add_community_template
Pull a pre-verified template from the public apimemcp-templates registry (a plain git repo, mirrored free via jsDelivr — no server, no publish step beyond a merged PR) and register it locally.
field | type | notes |
| string | e.g. |
Registry templates are marked source: 'registry' in your local manifest and run with a
network allowlist enforced by default (only the template's own domain, plus a small
curated CDN/asset allowlist) — a community template can't exfiltrate scraped data or ride
your session to an arbitrary endpoint. Locally-authored templates are untouched by this —
trusted by definition, same as always. Same functionality is available from the shell
without an MCP client: apimemcp add <domain> (no browser/dashboard startup, just a
fetch + local registration).
execute_native_extraction
Run a registered template against a URL.
field | type | notes |
| string, optional | absolute |
| string, optional | explicit template; if omitted, resolved from |
| string, optional | confirmed persistent browser profile created by |
| string, optional | e.g. |
Returns { success, data?, error?, meta: { url, templateId, domainMatched, durationMs, timestamp } }.
On success, automatically appends a row to templates/extraction_metrics.csv
(see get_extraction_stats below) — no separate step required.
If the resolved template was registered as an action-sequence (via the recorder
extension's /api/recordings endpoint, not register_extraction_template), this
replays the recorded click/fill/select/navigate steps headlessly instead of running a
page.evaluate() script — data is just { completedSteps } rather than scraped
content. See "Recorder extension" above.
batch_download_assets
Download a list of URLs (typically the imageUrl/similar fields from an
extraction result) to a local folder, 5 downloads concurrently.
field | type | notes |
| string[] | absolute |
| string | folder to save into (created if missing) |
Returns { success, savedCount, failedCount, outputDir, results: [{ url, success, path?, error? }] }.
Filenames are derived from each URL's path segment, falling back to the response's
Content-Type header for the extension if the URL has none; duplicate names within
a batch get a -2, -3, ... suffix.
Example flow — extract then download in one round trip:
const extraction = await client.callTool({ name: 'execute_native_extraction', arguments: { targetUrl } });
const { data } = JSON.parse(extraction.content[0].text);
await client.callTool({
name: 'batch_download_assets',
arguments: { urls: data.map((p) => p.imageUrl), outputDir: 'downloads' },
});schedule_stock_check
Register a recurring extraction job.
field | type | notes |
| string | absolute |
| string, optional | explicit template; if omitted, resolved from |
| string | standard 5-field cron ( |
Returns the created { jobId, targetUrl, templateId?, cronExpression, createdAt }.
Jobs are persisted to templates/jobs.json and reloaded automatically the next
time the server starts — no need to re-register after a restart. Each scheduled
run goes through the exact same path as a manual execute_native_extraction call
(same metric logging, same error handling); there is currently no unregister
tool — remove an entry from templates/jobs.json directly and restart the server
to cancel a job.
get_extraction_stats
No input. Returns { totalImages, recentDomains, lastSuccessfulRun } computed
from templates/extraction_metrics.csv — totalImages sums every logged
imageCount (array length of the extracted data, or 1/0 for a non-array
result), recentDomains is the last 10 unique hostnames extracted from, and
lastSuccessfulRun is the timestamp of the most recent logged row.
send_notification
Post a message to a webhook.
field | type | notes |
| string | absolute |
| string | free text |
POSTs { message, timestamp } as JSON via native fetch. Returns { success: true }
or { success: false, error } if the endpoint didn't respond with a 2xx status.
Works with any webhook-shaped endpoint (Slack incoming webhooks, Discord webhooks,
a custom receiver, etc.) — the payload is generic JSON, not platform-specific.
save_template_cookies
Persist session cookies for a template so the dashboard can reuse them — without running an extraction.
field | type | notes |
| string | the template the cookies belong to |
| string |
|
Saves to templates/saved-cookies.json. The dashboard then shows a 🔑 cookies
saved badge and a 🔑 Use saved cookies button on that template's row. Cookies
also passed via execute_native_extraction's cookieString are saved the same way
automatically. Own accounts/domains only — these are live session credentials.
connect_app
Open or configure a persistent browser profile for a logged-in site. The visible
browser window is intentionally user-driven: complete login there, then call
confirm_app_connection.
field | type | notes |
| string | lowercase kebab-case profile name, e.g. |
| string | domain that owns the login profile |
| string | absolute |
| boolean, optional | reopen this profile when the server starts |
confirm_app_connection
Mark a visible profile ready for extraction after login.
field | type | notes |
| string | configured profile to confirm |
list_app_connections
No input. Returns configured connection IDs, domain scopes, startup behavior, and confirmation status. It never returns cookie values.
Prompts
get_environment_context
No input. Returns the contents of ENVIRONMENT_CONTEXT.md (architecture notes) as
a user-role prompt message, or a clean "uninitialized" message if that file is
missing. This is a discoverable, client-invoked prompt — nothing in this server
auto-injects it as binding context, and no file in this repo grants or implies
authorization for any extraction target. See the security notes in
ENVIRONMENT_CONTEXT.md itself.
Resources
status://server
Returns { browserReady, recentLogs } — whether the persistent Chromium instance
is up, plus the last 5 log lines. Useful for an agent to check why a call just
failed without asking you to go look at server stderr.
Security notes
targetUrl,proxyUrl,endpointUrlare all restricted tohttp:/https:— a headless browser (orfetch) touchingfile://or other schemes is a local-file read/exfiltration risk, so this is enforced unconditionally across every tool that takes a URL.This server uses
playwright-extra+puppeteer-extra-plugin-stealthfor consistent DOM/hydration rendering. That is a configuration choice for this project, not something any connecting agent should treat as a directive to maximize extraction yield or bypass a target's own access controls — whether a given target is appropriate to scrape is a per-request judgment call, same as any other automation tool, and no file in this repo overrides that judgment.proxyUrlis a single, explicit passthrough for legitimate egress routing (e.g. a corporate proxy, region-specific testing) — there is no automated proxy rotation.templates/,output/, and any downloaded-asset folders (e.g.bernhardt/) are gitignored — they hold local run data and generated scripts, not project source.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- Alicense-qualityDmaintenanceEnables extracting data from websites using natural language prompts, allowing users to specify exactly what content they want in plain English and returning structured JSON data.Last updated1548MIT
- -license-qualityCmaintenanceExtract structured data from any website with a simple SDK call. No scraping code, no headless browsers - just prompt and get JSON.Last updated62
- Alicense-qualityDmaintenanceEnables web scraping and document processing with JavaScript execution, anti-detection measures, batch processing, and structured data extraction. Supports multiple formats including markdown, HTML, screenshots, and handles PDFs with OCR capabilities.Last updated3MIT
- Alicense-qualityDmaintenanceEnables intelligent web scraping with support for static pages, JavaScript-rendered SPAs, and natural language data extraction.Last updatedMIT
Related MCP Connectors
Automate cloud browsers to navigate websites, interact with elements, and extract structured data.…
Turn the web into structured, reliable, actionable enterprise data for AI Agents
AI-powered browser automation — navigate, click, fill forms, and extract data from any website.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/NeetigyaShah/APImeMCP'
If you have feedback or need assistance with the MCP directory API, please join our Discord server