Lens について
Lensは、画像処理、スクリーンショット、ページ読取、フォントなどを提供するTypeScript製のWebサービスツールキットです。HTTP APIをMCPツールとしても公開し、クライアントから利用できます。
主な機能
- 01画像のリサイズ、変換、最適化
- 02ウェブサイトのスクリーンショット撮影
- 03ページ内容をMarkdownまたはHTMLで抽出
- 04フォント配信とOpen Graph画像の生成
- 05ファビコン取得とGravatarアバターのプロキシ
- 06RedisキャッシュとURLの安全性チェック
活用シーン
- 01指定形式のウェブ画像を生成
- 02デスクトップやモバイル表示のページを撮影
- 03後続処理向けに記事内容を抽出
- 04ページ用のOpen Graph画像を生成
MCP 対応
Lensは`/mcp`のHTTP接続で各サービスをMCPツールとして公開します。reader、screenshot、favicon、OG画像、Gravatar、画像変換を利用できます。
設定
リモートサーバーはインストール不要です。クライアントを選んで設定をコピーするか、ワンクリックで導入できます。
https://api.bysages.com/mcpclaude mcp add --transport http lens https://api.bysages.com/mcp{"mcpServers":{"lens":{"type":"http","url":"https://api.bysages.com/mcp"}}}Cursor で開く{"servers":{"lens":{"type":"http","url":"https://api.bysages.com/mcp"}}}VS Code で開く{"mcpServers":{"lens":{"type":"http","url":"https://api.bysages.com/mcp"}}}{"mcpServers":{"lens":{"serverUrl":"https://api.bysages.com/mcp"}}}コマンドはターミナルで実行し、JSON は各クライアントの MCP 設定に貼り付けて再起動します。認可が必要なサーバーは初回接続時にログインを求めます。
ツール
6| パラメーター | 型 | 必須 | 説明 |
|---|---|---|---|
| url | string | はい | 内容を抽出するウェブサイトの URL |
| format | enum | いいえ | 出力形式(デフォルト:markdown)html | markdown |
詳細
Lens
最新の TypeScript で構築された、高性能な画像プロキシおよびウェブサービスツールキットです。Lens は、画像処理、スクリーンショットの撮影、フォント配信など、包括的なウェブユーティリティ一式を提供します。
🚀 機能
コアサービス
- 🖼️ 画像プロキシ:UnImage を活用した画像処理。リサイズ、形式変換、最適化に対応
- 📸 スクリーンショット撮影:リソースを最適化した高速なウェブサイトスクリーンショットサービス
- 📄 リーダー:Readability による記事コンテンツの抽出(Markdown/HTML)
- 🅰️ フォントサービス:複数のプロバイダーに対応した Google Fonts 互換 API
- 🎨 Open Graph 画像:OG 画像の動的生成
- 🎯 ファビコン抽出:ウェブサイトからファビコンをスマートに抽出
- 👤 Gravatar プロキシ:メールアドレスまたはハッシュを入力して利用できる、キャッシュ対応の Gravatar アバタープロキシ
- 🤖 MCP サーバー:すべてのサービスを JSON-RPC 2.0 経由でツールとして公開する Model Context Protocol サーバー
パフォーマンスとスケーラビリティ
- ⚡ Redis キャッシュ:24 時間のインテリジェントなキャッシュに対応した Redis ベースのキャッシュ
- 🧭 オンデマンドブラウザー:CDP 経由で操作する Moli ヘッドレスブラウザー(Rust)。Chromium の約 1/10 のメモリー使用量
- 🛡️ レート制限:負荷の高い操作に対するレート制限
- 🔒 SSRF 保護:DNS 解決チェックを含む URL 検証と、ブラウザーレベルでのプライベートネットワークへのアクセス遮断
- 🔄 グレースフルデグラデーション:サービスが利用できない場合の自動フォールバック
📦 クイックスタート
前提条件
- Node.js 24+
- pnpm 10+(推奨)または npm
- Moli ヘッドレスブラウザー(スクリーンショット/リーダーは CDP 経由で接続します)
インストール
# Clone the repository
git clone https://github.com/bysages/lens.git
cd lens
# Install dependencies
pnpm install
# Copy environment configuration
cp .env.example .env
開発
# Start the Moli browser server (default CDP endpoint: http://127.0.0.1:9222)
moli serve --layout --resource
# In another terminal, start development server
pnpm dev
# Build for production
pnpm build
# Preview production build
pnpm preview
サーバーはデフォルトで http://localhost:3000 で起動します。
🛠️ 設定
設定
すべての設定は省略可能で、省略した場合も適切に機能が低下するように処理されます。
# Image proxy security
ALLOWED_DOMAINS=example.com,cdn.example.com
# Set only when requests arrive through a trusted reverse proxy
TRUST_PROXY=1
# Requests per IP within RATE_WINDOW seconds; Redis makes these cluster-wide
BROWSER_RATE_LIMIT=20
FAVICON_RATE_LIMIT=30
IMAGE_RATE_LIMIT=120
GRAVATAR_RATE_LIMIT=120
RATE_WINDOW=60
# Caching (significantly improves performance)
REDIS_URL=redis://localhost:6379
# Browser: Moli CDP endpoint (defaults to http://127.0.0.1:9222)
BROWSER_CDP_ENDPOINT=http://127.0.0.1:9222
# Browser: optional user-agent overrides (default: the engine's own UA)
#BROWSER_USER_AGENT=...
#BROWSER_USER_AGENT_MOBILE=...
# Browser: cluster-wide maximum with Redis (process-local fallback otherwise)
BROWSER_MAX_CONCURRENCY=4
# Maximum wait for a global browser slot (ms)
BROWSER_QUEUE_TIMEOUT=15000
# Reject full-page captures above this CSS pixel count
SCREENSHOT_MAX_PIXELS=24000000
# Cluster: worker count (Docker defaults to 2; raw Nitro defaults to CPU count)
NITRO_CLUSTER_WORKERS=2
利用可能なすべてのオプションについては .env.example を参照してください。
📡 API リファレンス
キャッシュ対応のルートは X-Cache と強力な ETag を返します。一致する If-None-Match リクエストには 304 が返されます。
画像
画像プロキシ
UnImage を使用し、IPX 互換 URL で画像を変換および最適化します。
GET /img/{modifiers}/{image_url}
例:
# Resize to 300px width, negotiate the best supported format
https://api.bysages.com/img/w_300,f_auto/https://example.com/image.jpg
# Explicit WebP output
https://api.bysages.com/img/w_300,f_webp/https://example.com/image.jpg
# Create a 200x200 cover thumbnail
https://api.bysages.com/img/s_200x200,q_80/https://example.com/image.png
# Rotate and desaturate
https://api.bysages.com/img/rotate_90,grayscale/https://example.com/photo.jpg
よく使うモディファイア:
w_XXX/h_XXX- 幅/高さs_XXXxYYY- サイズの略記fit_contain|cover|fill|outside- フィットモードf_FORMAT- 出力形式(webp、jpg、png、avif、svg、gifなど。f_autoはAcceptに応じて形式を選択します)q_XXX- 品質rotate_90、grayscale、blur_2、sharpen_1、animated- よく使う変換_/path- モディファイアなしでそのまま通過
サーバースタックでは、SVG に SVGO、対応する操作に Canvas を使用し、ラスター画像のフォールバックとして Sharp を使用します。リモート画像は、許可ドメインリスト、DNS/プライベートアドレスのチェック、リダイレクトの検証によって保護されます。ローカルパスは public 内に制限されます。レスポンスは Redis ベースのキャッシュ、強力な ETag、304、およびネゴシエーションされた形式向けの Vary: Accept を使用します。
スクリーンショットのキャプチャ
ブラウザー風のオプションを指定して、ウェブサイトのスクリーンショットを撮影します。
GET /screenshot?url={website_url}&options
例:
# Basic screenshot
https://api.bysages.com/screenshot?url=https://example.com
# JPEG with custom quality
https://api.bysages.com/screenshot?url=https://example.com&type=jpeg&quality=80
# Mobile screenshot with custom viewport
https://api.bysages.com/screenshot?url=https://example.com&width=375&height=667&mobile=true
# Full page capture
https://api.bysages.com/screenshot?url=https://example.com&fullPage=true
# Clip region (x,y,width,height)
https://api.bysages.com/screenshot?url=https://example.com&clip=0,0,400,300
# Disable animations for clean capture
https://api.bysages.com/screenshot?url=https://example.com&animations=disabled
# Custom CSS scale
https://api.bysages.com/screenshot?url=https://example.com&scale=css
# Inject custom stylesheet
https://api.bysages.com/screenshot?url=https://example.com&style=body{background:red}
パラメーター:
| パラメーター | 説明 | デフォルト |
|---|---|---|
url | ウェブサイトの URL(必須) | - |
width | ビューポートの幅(100-2560) | 1280 |
height | ビューポートの高さ(100-1440) | 720 |
type | 出力形式(png、jpeg) | png |
quality | 画像品質、1-100(jpeg のみ) | - |
fullPage | スクロール可能なページ全体をキャプチャ(true/false) | false |
clip | x,y,width,height 形式でクリップ領域を指定 | - |
scale | スクリーンショットの倍率(CSS ピクセルは css、デバイスピクセルは device) | device |
animations | アニメーションの処理(disabled または allow) | disabled |
caret | テキスト入力カーソル(hide または initial) | hide |
style | 適用するカスタム CSS スタイルシート | - |
timeout | ナビゲーションのタイムアウト(ミリ秒、1000-30000) | 10000 |
mobile | モバイルユーザーエージェントとタッチ入力(true/false) | false |
darkMode | ダークモード(true/false) | false |
waitUntil | ナビゲーションの待機条件(load、domcontentloaded、networkidle) | load |
delay | ページ読み込み後の追加待機時間(ミリ秒、0-10000) | - |
パフォーマンスに関する注意事項:
- スクリーンショットはレート制限付きで1日間キャッシュされます
- 同一のリクエストにはキャッシュされた結果が返され、応答時間は1秒未満です
- スクリーンショットの撮影時にはフォントと画像の読み込みを短時間待機し、デフォルトでアニメーションを停止します
- Moli はページ全体のキャプチャを1枚のビットマップとしてレンダリングします。
SCREENSHOT_MAX_PIXELSはサイズが大きすぎるキャプチャを拒否します BROWSER_MAX_CONCURRENCYは Redis を使用してクラスター全体に適用され、上限付きキューを含みます
Open Graph 画像
動的な OG 画像を生成します。
GET /og?title={title}&description={description}
例:
# Basic OG image
https://api.bysages.com/og?title=Welcome&description=Get%20started%20with%20Lens
# Custom styling
https://api.bysages.com/og?title=Hello%20World&theme=dark&fontSize=72&width=1200&height=630
キャッシュ:
- 生成された OG 画像は24時間キャッシュされます
- 同じパラメーターを使用した同一のリクエストには、キャッシュされた結果が即座に返されます
ウェブサービス
Reader(コンテンツ抽出)
任意の URL から、レンダリング済みの Markdown または HTML コンテンツを抽出します。
GET /reader?url={website_url}&options
例:
# Extract rendered Markdown (default)
https://api.bysages.com/reader?url=https://github.com/bysages/lens
# Get HTML instead
https://api.bysages.com/reader?url=https://github.com/bysages/lens&format=html
# Wait for full page load
https://api.bysages.com/reader?url=https://github.com/bysages/lens&waitUntil=load
パラメーター:
| パラメーター | 説明 | デフォルト |
|---|---|---|
url | ウェブサイトの URL(必須) | - |
format | 出力形式(html、markdown) | markdown |
waitUntil | ナビゲーションの待機条件(load、domcontentloaded、networkidle) | domcontentloaded |
delay | ページ読み込み後の追加待機時間(ミリ秒、0-10000) | - |
timeout | ナビゲーションのタイムアウト(ミリ秒、1000-30000) | 10000 |
ファビコンの抽出
高品質なファビコンを抽出します。
GET /favicon?url={website_url}&size={size}
例:
# Extract favicon
https://api.bysages.com/favicon?url=github.com
# Custom size
https://api.bysages.com/favicon?url=github.com&size=64
機能:
- 複数のソース(PWA マニフェスト、Apple touch icon、HTML タグ)からファビコンをスマートに抽出します
- ETag/304 に対応し、サーバー側で30日間キャッシュします
- ファビコンが見つからない場合は、生成したファビコンに自動的にフォールバックします
Gravatar プロキシ
メールアドレス、MD5 ハッシュ、またはパスから Gravatar アバターを取得します。email/hash 以外のすべてのクエリパラメーターは、Gravatar に直接転送されます。URL のプレフィックスを置き換えるだけで、Gravatar から切り替えられます。
GET /gravatar/{md5}?{gravatar_params}
GET /gravatar?email={email}
GET /gravatar?hash={md5}&{gravatar_params}
使用例:
# By path (drop-in replacement for Gravatar URLs)
https://api.bysages.com/gravatar/{md5}?size=200
# By email
https://api.bysages.com/[email protected]
# By MD5 hash
https://api.bysages.com/gravatar?hash={md5}
# With Gravatar parameters
https://api.bysages.com/[email protected]&size=200&default=identicon&rating=pg
パラメーター:
{md5}- URL パス内の MD5 ハッシュ(そのまま置き換えるモード)email- メールアドレス(自動的に MD5 ハッシュ化されます)hash- 事前に計算された MD5 ハッシュ(emailの代替)- その他のすべてのパラメーターは Gravatar API に転送されます
MCP サーバー
HTTP 経由の JSON-RPC 2.0 を使用して、すべての Lens サービスをツールとして公開する Model Context Protocol サーバーです。
POST /mcp
Claude Desktop の設定(claude_desktop_config.json):
{
"mcpServers": {
"lens": {
"url": "https://api.bysages.com/mcp"
}
}
}
利用可能なツール:
| ツール | 説明 | 戻り値 |
|---|---|---|
reader | URL から記事のコンテンツを抽出します(Markdown/HTML) | text |
screenshot | ウェブサイトのスクリーンショットを撮影します | image |
favicon | ウェブサイトのファビコンを抽出します | image |
og | 動的な Open Graph 画像を生成します | image |
gravatar | メールアドレスまたはハッシュから Gravatar アバターを取得します | image |
img | 画像を変換、最適化します(サイズ変更、切り抜き、形式変換) | image |
フォント
フォントサービス
v1 および v2 の両エンドポイントに対応した Google Fonts 互換 API です。
GET /css?family={font_family}&display=swap
GET /css2?family={font_family}&display=swap
API の違い:
| 機能 | /css(v1) | /css2(v2) |
|---|---|---|
| 複数のフォント | family=A|B(パイプ区切り) | family=A&family=B(パラメーターを繰り返し指定) |
| スタイル構文 | FontName:400,700(旧形式) | FontName:wght@400;700(新形式、厳密) |
| 可変フォント | ❌ 非対応 | ✅ 範囲指定([email protected])に完全対応 |
| ベース URL | fonts.googleapis.com/css | fonts.googleapis.com/css2 |
パラメーター:
family- フォントファミリー名(必須)display- フォントの表示方法(デフォルト:swap)subset- フォントのサブセット(デフォルト:latin)provider- フォントプロバイダー(google、bunny、fontshare、fontsource、デフォルト:google)proxy- フォントファイルにプロキシを使用するかどうか(true/false、デフォルト:false)
使用例:
# Basic font (v1 API - pipe separator)
https://api.bysages.com/css?family=Roboto:wght@400;700|Open+Sans:wght@300;400;600&display=swap
# Multiple fonts (v2 API - repeated family parameter)
https://api.bysages.com/css2?family=Inter:wght@400;700&family=Roboto:wght@300;400&display=swap
# Variable fonts with weight range (v2 only)
https://api.bysages.com/css2?family=Inter:[email protected]&display=swap
# Font metadata
https://api.bysages.com/webfonts?sort=popularity&category=sans-serif
推奨事項:
- 古い Google Fonts 構文とのレガシー互換性には
/cssを使用します - 可変フォントとより優れた最適化が必要な最新のアプリケーションには
/css2を使用します - どちらのエンドポイントも、すべてのフォントプロバイダー(Google、Bunny、Fontshare、Fontsource)に対応しています
🏗️ アーキテクチャ
Lens は最新のウェブ標準に基づいて構築され、クリーンアーキテクチャの原則に従っています。
コア技術
- ランタイム:Nitro を使用する Node.js 24+
- 言語:厳密な型安全性を備えた TypeScript
- 画像プロキシ:SVGO、Canvas、Sharp を使用する UnImage
- ブラウザー自動化:Moli:Playwright によって CDP 経由で操作されるヘッドレスブラウザー
- キャッシュ:unstorage を使用する Redis
設計原則
- KISS(シンプルに保つ):複雑な抽象化よりも、シンプルで目的を絞ったソリューションを優先します
- DRY(同じことを繰り返さない):共通のユーティリティと設定を使用します
- 段階的な機能縮退:依存関係が利用できない場合に備えてフォールバックを用意します
- 型安全性:TypeScript を包括的に適用します
- パフォーマンス優先:速度と効率を最適化します
🚀 デプロイ
前提条件
- Node.js 24+ ランタイム
- pnpm 10+ パッケージマネージャー
- Redis(Docker Compose に同梱。他のセットアップでは任意)
本番環境へのデプロイ
# Build the application
pnpm run build
# Start production server
pnpm run preview
Docker によるデプロイ(推奨)
オプション 1:Docker Compose を使用する
# Copy environment variables
cp .env.example .env
# Edit .env file to configure your settings
# nano .env
# Start the application
docker-compose up -d
# View logs
docker-compose logs -f app
# Stop the application
docker-compose down
アプリケーションは http://localhost:3000 で利用できます。
GET /healthz は、ブラウザー(CDP)が利用可能かどうかを含む稼働状況を報告します。Compose のヘルスチェックとオーケストレーターのプローブは、このエンドポイントを参照するようにしてください。
スタックには以下が含まれます。
- Lens アプリケーション(ポート 3000)。コンテナー内で Moli ブラウザーが実行されます
- 分散キャッシュ用の Redis(LRU 削除で上限 512 MB)
オプション 2:Docker Run を使用する
# Pull the official image
docker pull bysages/lens:latest
# Run container with host network (recommended for accurate IP logging);
# --init is needed because the image runs Moli alongside Node
docker run -d \
--name lens \
--network host \
--init \
--env-file .env \
--restart unless-stopped \
bysages/lens:latest
# View logs
docker logs -f lens
# Stop the container
docker stop lens
docker rm lens
オプション 3:ソースからビルドする
# Build Docker image
docker build -t lens .
# Run container
docker run -d \
--name lens \
--network host \
--init \
--env-file .env \
--restart unless-stopped \
lens
環境変数
すべての設定は任意です。
# Image Proxy Security
ALLOWED_DOMAINS=example.com,cdn.example.com
# Set only when requests arrive through a trusted reverse proxy
TRUST_PROXY=1
# Caching (significantly improves performance)
REDIS_URL=redis://localhost:6379
# Browser: Moli CDP endpoint (defaults to http://127.0.0.1:9222)
BROWSER_CDP_ENDPOINT=http://127.0.0.1:9222
# Browser: cluster-wide maximum with Redis (process-local fallback otherwise)
BROWSER_MAX_CONCURRENCY=4
# Maximum wait for a global browser slot (ms)
BROWSER_QUEUE_TIMEOUT=15000
# Reject full-page captures above this CSS pixel count
SCREENSHOT_MAX_PIXELS=24000000
# Cluster: worker count (Docker defaults to 2; raw Nitro defaults to CPU count)
NITRO_CLUSTER_WORKERS=2
# Moli server flags used by the Docker entrypoint
# (--block-private-networks is always enforced by the entrypoint)
MOLI_FLAGS=--layout --resource --http-cache-dir=/tmp/lens-cache/moli-http --http-max-concurrent=32 --http-max-total-connections=64
利用可能なすべてのオプションについては、.env.example を参照してください。
📄 ライセンス
MIT License — 詳細については LICENSE ファイルを参照してください。
By Sages が ❤️ を込めて開発しました
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。