Skip to content
Conduit

mcp server

crawl

Crawl Engine - embeddable TypeScript web crawler with an MCP server for SEO, link, and schema analysis.

timothy-nishimura/crawlcommunitylistedunreviewed

Set up

Runs on your computer. Pick your agent and operating system.

This project does not publish an install method we can turn into a config. Follow the README instead.

README

synced Oct 21, 2026

Crawl Engine

License: MIT Node.js 20+ No Maintenance Intended

Released as an open-source snapshot for the community to use and build on. This codebase is not actively maintained — issues and pull requests are not monitored. Fork freely under the MIT license.

A modular, embeddable web crawler and MCP server toolkit for TypeScript/Node.js. Designed for crawl automation, SEO analysis, metadata extraction, and site auditing.


Project Layout

crawl-engine/
├── core/                   @crawl/engine — pure crawling kernel, frontier & security
├── modules/
│   ├── extractors/         @crawl/extractors — SEO, metadata, links, headings, schema, images
│   ├── tls-backend/        @crawl/tls-backend — TLS-fingerprinted fetch with socket SSRF defense
│   ├── playwright-backend/ @crawl/playwright-backend — Playwright headless browser transport
│   ├── chrome-pipe/        @crawl/chrome-pipe — Chrome-assisted extraction pipe
│   ├── mcp-server/         @crawl/mcp-server — production HTTP/SSE MCP server
│   └── mcp-test/           @crawl/mcp-test — smoke testing MCP server
├── scripts/                check-core-boundaries.mjs — automated boundary check
├── docker-compose.yml      Docker Compose configuration
├── .env.example            Environment configuration template
└── scratch/                Sandbox output directory (gitignored)

Architecture rule: @crawl/engine has zero internal dependencies and zero framework bloat. Domain packages (@crawl/extractors, @crawl/tls-backend, @crawl/playwright-backend) extend engine interfaces. User-facing applications (@crawl/mcp-server) assemble components into tools.


Quick Start

Requirements: Node.js 20+

Local Setup

# Install workspace dependencies
npm install

# Build all packages
npm run build --workspaces --if-present

# Verify core architectural boundaries
npm run check:core

# Run all test suites
npm run test --workspaces --if-present

Docker Deployment

# Copy example environment
cp .env.example .env

# Build and start container
docker compose up -d

# Check health endpoint
curl http://localhost:3001/health

Core Engine (core/)

Basic Crawl

import {
  CrawlConfig,
  CrawlEngine,
  HttpClientBackend,
  SsrfPolicy,
} from '@crawl/engine';

const backend = HttpClientBackend.create(SsrfPolicy.BLOCK_PRIVATE);

const config = CrawlConfig.builder('https://example.com')
  .maxDepth(3)
  .workers(8)
  .requestDelayMs(300)
  .build();

for await (const page of new CrawlEngine(config, backend, []).crawl()) {
  console.log(page.statusCode, page.url);
}

Custom Extractor

import type { Extractor, ParsedPage } from '@crawl/engine';

interface SchemaSignals {
  jsonLdBlocks: string[];
  hasProductSchema: boolean;
}

class SchemaExtractor implements Extractor<SchemaSignals> {
  readonly id = 'schema.jsonld';

  extract(page: ParsedPage): SchemaSignals | null {
    if (!page.document) return null;
    const blocks = page.document('script[type="application/ld+json"]')
      .map((_, el) => page.document?.(el).html() ?? '')
      .get();
    return {
      jsonLdBlocks: blocks,
      hasProductSchema: blocks.some(b => b.includes('"Product"')),
    };
  }
}

Configuration Reference

CrawlConfig.builder(seedUrl) options:

SettingDefaultDescription
maxDepth(n)InfinityMaximum link depth from seed URL (0 = seed only).
crawlSubdomains(bool)falseFollow links across subdomains.
includePattern(str)noneSubstring match required for discovered URLs.
excludePattern(str)noneSubstring filter skipping matching URLs.
workers(n)4Concurrency limit for fetch workers.
timeoutMs(ms)10000Per-request timeout in milliseconds.
maxBodyBytes(n)5242880Maximum response payload size (5 MB default).
maxRedirects(n)10Maximum redirect hops before failure.
requestDelayMs(ms)500Per-host throttling delay.
jitterPct(pct)20Random jitter percentage on request delays.
respectRobotsTxt(bool)trueFetch and adhere to domain robots.txt.
seedFromSitemap(bool)truePre-populate queue from discovered sitemap.xml.
detectDuplicates(bool)trueSHA-256 body deduplication.
stripSessionParams(bool)trueStrip session identifiers and tracking parameters.
ssrfPolicy(policy)BLOCK_PRIVATESSRF defense mode (BLOCK_PRIVATE or ALLOW_ALL).

MCP Server (modules/mcp-server/)

Exposes crawl and inspection tools over Model Context Protocol (MCP) Streamable HTTP transport.

Configuration

Environment VariableDefaultDescription
PORT3001Server listening port
MCP_API_KEY(none)Optional Bearer token for endpoint authorization
SCRATCH_DIR./scratchDirectory for temporary runtime outputs
MANIFESTS_DIR./manifestsDirectory for saved crawl manifests
DATA_DIR./dataDirectory for persistent storage

Available Tools

ToolDescription
crawlCrawls target domain and returns structured manifest snapshots.
fetch_pageFetches a single URL with SEO, heading, metadata, and link parsing.
fetch_apiPaginates through REST API endpoints and collects records.
parse_sitemapFetches and extracts URLs from sitemap.xml.
search_manifestFilters crawl manifests by query, pattern, or status code.
summarize_manifestAggregates page counts, status distributions, and word counts.
analyze_linksGenerates internal/external link graph and flags broken links.
analyze_metaAudits canonical tags, robots directives, and Open Graph tags.
analyze_headingsAudits H1–H6 hierarchy, missing tags, and ordering issues.
analyze_imagesAudits images for alt text, size, and missing attributes.
analyze_schemaParses structured JSON-LD and microdata blocks.
compare_manifestsComputes diffs between two manifest runs (added/removed/modified).
find_orphansIdentifies crawl pages with zero inbound links.

Security Model

  • SSRF Defense: Evaluates hostnames and IP addresses against blocked ranges prior to connection:
    • IPv4 Private: 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16
    • IPv4 Loopback & Link-Local: 127.0.0.0/8, 169.254.0.0/16
    • IPv4 Shared & Multicast: 100.64.0.0/10, 224.0.0.0/4
    • IPv6 Loopback & Link-Local: ::1/128, fe80::/10, fc00::/7
    • IPv6 Multicast, 6to4 & Teredo: ff00::/8, 2002::/16, 2001:0000::/32
    • Socket-Level DNS Resolution: Connection hooks prevent TOCTOU DNS rebinding.
  • Multi-Root Sandbox Containment: Path validation ensures disk writes remain bounded within configured directories (scratch/, manifests/, data/).
  • Session Protections: MCP session pool enforces a 100-session capacity cap and reaps idle sessions after 30 minutes.
  • Unprivileged Containers: Docker images run under non-root user (pwuser) with healthchecks.

License

MIT © Timothy Nishimura. See LICENSE.

↑↓ navigate openesc close