lightcms について
LightCMS は Go で書かれたオープンソースのコンテンツ管理システムで、AI と連携して運用したいチーム向けです。MCP サーバーとして約 130 のツールを提供し、Claude Code などのクライアントからコンテンツの読み取り、作成、公開、インポートができます。
主な機能
- 01コンテンツ管理向けの約 130 の MCP ツール
- 02人によるレビューを経てマージするエージェントサンドボックス
- 03フィールド単位の差分を確認する承認ワークフロー
- 04自動生成される llms.txt と Markdown 版ページ
- 05IndexNow 連携と RSS/Atom フィード
- 06静的ページ生成とバージョン履歴
活用シーン
- 01コーディングエージェントによるコンテンツの一括作成とインポート
- 02MCP クライアントからのサイトコンテンツ管理と公開
- 03AI クローラーのサイトへのアクセス方針の管理
MCP 対応
LightCMS は stdio と HTTP ストリーミングで動作する MCP サーバーとして、コンテンツ管理のツールとリソースを MCP クライアントに公開します。また、訪問者のエージェントがサイトを検索・閲覧できる公開読み取り専用の MCP エンドポイントも備えています。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
このサーバーのパッケージやリモートエンドポイントはまだ取得できていません。プロジェクトの README の手順に従ってください。
ツール
ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。
詳細
LightCMS
LightCMSは、AI時代に向けて構築されたGo製のコンテンツ管理システムです。AIネイティブ(セマンティック検索、Claudeを活用したチャットウィジェットを標準搭載、エージェント制御用のMCPサーバー)、エージェントによる制御が可能(Claude CodeやあらゆるMCPクライアントが、130個のMCPツールを使ってコンテンツの読み取り、書き込み、公開、一括インポートを実行可能)、そしてエージェントによる更新が可能(コードベースはクリーンで、構成の整ったGoコードのため、コーディングエージェントが安全に拡張可能)です。AIを避けるのではなく、AIと連携するCMSを求めるチームに最適です。
v7.3の新機能 — SEOとAI
| 機能 | 概要 |
|---|---|
| AIトラフィック | サイトを閲覧したAIクローラー(学習用、AI検索用、ユーザー起点の取得)と、最もよく閲覧されたコンテンツを確認できます。また、ChatGPT、Perplexity、Claude、Gemini、Copilotからの訪問数も確認できます。 |
| AIクローラーポリシー | AI学習、AI検索、ユーザーによる取得を個別に許可またはブロックできます。クローラーごとの上書き設定や、任意のContent-Signal行にも対応し、robots.txtに出力します。 |
| Markdownコピー | すべてのページを/<page>.mdからクリーンなMarkdown形式でも利用できます。ページおよびllms.txtからリンクされているため、エージェントはHTMLを使わずに読み取れます。 |
| 強化された構造化データ | 作成者、ロゴ付きの発行者、パンくずリスト、FAQマークアップ、ページのコンテンツが実際に変更された場合にのみ更新される更新日を含みます。 |
| RSSおよびAtomフィード | /feed.xml、/atom.xmlと、コンテンツ全文を含むコレクションごとのフィードを利用できます。 |
| 検索とAIから非表示 | ページごとのnoindex設定により、そのページはサイトマップ、llms.txt、フィード、IndexNowからも削除されます。 |
v7.2の新機能
| 機能 | 概要 |
|---|---|
| IndexNow | 公開、編集、移動、削除されたページが、Bing、YandexなどのIndexNow対応検索エンジンにすぐに通知されます。設定不要です。各インストールで専用のキーを生成し、送信前にBASE_URLの所有権を確認します。また、初回有効化時にはサイト全体を一度送信します。状態と履歴は「Tools → IndexNow」で確認できます。 |
| CMSエージェント | サイトの健全性、トラフィック、レビューキュー、エージェントのアクティビティ、リンク切れを対象に、AIによるコメントを任意で追加できる、設定可能なメールダイジェスト(Resend経由)を提供します。 |
v7.1の新機能
| 機能 | 概要 |
|---|---|
| アンビエントコパイロット | すべての管理ページにスライドイン式ドロワーとしてコパイロットを表示します。画面に浮かぶ🤖ボタン、全画面表示切り替え、ChatGPT風の検索可能なチャット履歴、リアルタイムの入力インジケーター、テーブル表示を備えています。平易な言葉での指示により、編集、作成、公開、分析やメンテナンスレポートの読み取りを実行します。 |
| 分析期間 | すべての分析ビューで、60日・90日のプリセットと任意の日付範囲を利用できます。 |
| AIクローラー向け高速エンドポイント | llms.txtは大規模サイトでも約1秒で応答します(クエリを予測)。また、ホームページにはSearchActionを含むschema.org WebSite JSON-LDを出力します。 |
| バージョン表示 | 管理画面のサイドバーに実行中のバージョンを表示します。 |
v7.0 の新機能
| 機能 | 概要 |
|---|---|
| エージェントサンドボックス(「コンテンツの PR」) | エージェントはコピーオンライトによる隔離されたフォーク内で作業し、人間がフィールドごとの差分をレビューしてマージします。マージするまでライブコンテンツには一切触れられません。 |
| エージェントガバナンス | スコープ付き API キー、サンドボックス専用キー(サーバー側で強制)、1 回の呼び出しでロールバックできるセッション単位の変更台帳、バージョンごとの来歴(人間かエージェントか、どのセッションか)。 |
| 管理 Copilot | /cm/copilot — 平易な言葉でコンテンツを編集、作成、公開できます。RBAC と完全な監査ログを備えています。 |
| llms.txt + JSON-LD | AI クローラー向けに /llms.txt と /llms-full.txt を自動生成し、すべてのページに schema.org 構造化データを付与します。 |
| 読者向け MCP | /mcp-public で公開読み取り専用 MCP エンドポイントを提供 — 訪問者のエージェントがサイトをネイティブに検索・閲覧できます。 |
| ローカル埋め込み | LIGHTCMS_EMBEDDINGS_PROVIDER=ollama により、完全にセルフホスト可能なセマンティック検索を実現 — API クレジットは不要です。 |
| 自己メンテナンスするサイト | 毎日のメンテナンススキャンが、古いページ、欠落したメタ情報、壊れたリンクをエージェントがすぐに処理できる作業キューとして浮かび上がらせます。 |
v6.0 の新機能
| 機能 | 概要 |
|---|---|
| コンテンツ承認 | 投稿者が承認のためにコンテンツを提出し、編集者/管理者が /cm/approvals から承認または却下します。却下コメントはディスカッションスレッドに自動投稿されます。 |
| 投稿者ロール | 閲覧者と編集者の間に位置する新しい RBAC ロール。コンテンツの作成 + アセットのアップロード(保留中)、コメントの投稿、承認の申請が可能ですが、直接公開したりシステム設定を管理したりすることはできません。 |
| 承認ワークフロー | 設定可能なトリガーベースのワークフロー(投稿者、フォルダパス、テンプレート ID、またはタグ)。設定可能な承認者リストによる順次または並行モード。 |
| コンテンツディスカッション | すべての編集ページの下部にあるインラインコメントスレッド。@メンションのオートコンプリート、ライブバッジカウント、管理者による削除。 |
| タブ付き下部パネル | コンテンツ編集ページで、ディスカッション、バージョン履歴、フォークをタブに整理。 |
| 承認ダッシュボード | /cm/approvals にマイキュー + その他の保留中 + ワークフロー設定。サイドバーのバッジに保留中の件数を表示。 |
| ダッシュボードセクション | 該当する場合、承認が必要な項目と最近のコメントが管理ダッシュボードに表示されます。 |
| 新しい Webhook イベント | comment.created、content.pending_approval、asset.pending_review。 |
| 14 個の新しい MCP ツール | コメントと承認のライフサイクルを完全にカバー — コメントの一覧表示/作成/削除、ワークフローの完全な CRUD、承認リクエストの一覧表示/取得/申請/承認/却下/キャンセル。 |
v5.0 の新機能
| 機能 | 概要 |
|---|---|
| インポートパイプライン | 3 つの新しいインポートタイプ — RSS/Atom フィード、Markdown/ZIP アップロード、CSV 一括インポート — と、/cm/imports の統合ジョブダッシュボード。 |
| RSS/Atom インポート | 毎時/毎日/毎週のスケジュール、テンプレートマッピング、フォルダのターゲティング、自動公開を備えた定期的なフィードソースを設定できます。 |
| Markdown インポート | YAML フロントマター付きの .md ファイルまたは .zip アーカイブをアップロードします。Notion のエクスポート、Obsidian の Vault、Hugo/Jekyll からの移行、AI 生成コンテンツをサポートします。 |
| CSV インポート | CSV ファイルをアップロードし、列をコンテンツフィールドにマッピングします。タイトル列を指定すると、他のすべての列が自動的にフィールドになります。 |
| リアルタイムなジョブステータス | /cm/imports/{jobID} で SSE によるライブログストリームを提供。インポートの進行を 1 行ずつ確認したり、後から完全な履歴を確認したりできます。 |
| 10 個の新しい MCP インポートツール | list_import_sources、create_import_source、update_import_source、delete_import_source、trigger_import_source、import_markdown、import_csv、list_import_jobs、get_import_job、cancel_import_job。 |
| エージェントによる一括コンテンツ作成 | import_markdown は、AI エージェントが大量のコンテンツバッチを 1 回の呼び出しで生成してインポートできるように設計されています。MCP.md を参照してください。 |
| 重複排除 | インポートは full_path で照合されます — 同じスラッグを再インポートすると、重複ではなく更新されます。 |
v4.5 の新機能
| 機能 | 概要 |
|---|---|
| Webhook | publish、unpublish、delete、create、update に対する HMAC-SHA256 署名付きイベント。管理 UI は /cm/webhooks にあり、配信履歴とドキュメントページを備えています。 |
| スケジュール公開 | 任意のコンテンツ項目に将来の publish_at タイムスタンプを設定できます。バックグラウンドスケジューラーが適切なタイミングで自動公開します。 |
| コンテンツロック | 編集時の勧告ロック(30 分で失効)。別のユーザーがすでに編集している場合は警告バナーを表示します。管理者は強制ロック解除できます。 |
| Incremental Static Regeneration (ISR) | テンプレートレイアウトの変更時、影響を受けるページを 20 ページずつのバッチで再生成し、大規模サイトでのサーバー過負荷を防ぎます。 |
| エッジキャッシュヘッダー | すべての公開ページに ETag、Cache-Control、Last-Modified、Vary ヘッダーを付与。304 Not Modified をサポートします。 |
| Cloudflare 連携 | Zone ID + API Token を設定すると、公開/非公開時に Cloudflare キャッシュを自動パージします。 |
| 構造化 JSON ログ | すべてのサーバーログが timestamp、level、message、およびコンテキストフィールドを含む構造化 JSON を出力します。 |
| レート制限ダッシュボード | 監査ログページの新しいタブで、ロックされた IP、試行回数、ワンクリッククリアボタンを表示します。 |
| MCP プロンプトリソース | 3 つの新しい MCP リソース: lightcms://site/structure、lightcms://content/recent、lightcms://theme/config。 |
なぜ LightCMS なのか?
軽量: クリーンで焦点を絞ったコードベースで、理解、変更、拡張が容易です。肥大化したフレームワークや複雑な抽象化はありません。
AI ネイティブ: AI 時代のためにゼロから構築されています:
- MCP 統合: ウェブサイト管理のための 130 のツールと 3 つのプロンプトリソースを備えた完全な Model Context Protocol サーバー。ローカルの stdio と HTTP ストリーミングの両方のトランスポートをサポートし、Claude Code、Claude Desktop、または任意の MCP 互換クライアントから接続できます。
- リモートエージェント向け OAuth 2.1: Claude の Cowork のようなサンドボックス化されたデスクトップアプリは、PKCE を使用した OAuth 2.1 により HTTP 経由で安全に接続できます。パスワードの埋め込みは不要で、一度認可するだけでエージェントがサイトを管理します。
- フォークしやすい: Claude Code によるフォークとカスタマイズを想定して設計されています。新しいコンテンツタイプの追加、テンプレートの変更、カスタム機能の構築を Claude に依頼できます — コードベースは AI 支援開発向けに構造化されています。
- 自然言語によるウェブサイト管理: 管理 UI を完全にスキップできます。会話を通じてページの作成、アセットの管理、テーマのカスタマイズ、コンテンツの公開を行えます。
機能
コンテンツ管理
- テンプレートシステム: カスタムフィールド(テキスト、リッチテキスト、画像、日付、選択、markdown)を使用して再利用可能なコンテンツ構造を定義できます
- 静的ページ生成: 事前レンダリングされた HTML によりページ読み込みが高速 — ランタイムでのテンプレート処理オーバーヘッドがありません
- コンテンツバージョニング: 差分比較とワンクリック復元を備えた完全なバージョン履歴
- ソフト削除: 削除したコンテンツを復元機能で復旧できます
- コンテンツタグ付け: 任意のコンテンツ項目に 1 つ以上の自由形式ラベルを付け、サイト全体でタグによるクエリが可能
- スニペット: 動的クエリ内で再利用可能なレンダリング単位として使用される、名前付き HTML テンプレートフラグメント
lc:queryディレクティブ: テンプレートレイアウトにライブコンテンツクエリを直接埋め込みます — 公開時に、一致するページのレンダリング済みリストへと展開されます- コンテンツコレクション: カテゴリでフィルタリングされた、自動生成されるページネーション付き一覧ページ
- フォルダーと URL 構成: 階層的なコンテンツ構成とクリーンな URL パス
- リッチテキストエディター: ビジュアルなコンテンツ編集のための Quill 2(
static/admin/quill/にベンダリングされ、サイト自体から配信されます) - 正規表現検索と置換: サイト全体またはスコープ限定の検索と置換。RE2 正規表現、キャプチャグループをサポートし、プレビュー手順が必須です
- 一括操作: 1 回の API 呼び出しで最大 100 ページにわたるフィールド操作の更新または適用が可能。エクスポート/変換/再インポートのパイプライン
- スケジュール公開(v4.5+): 将来の
publish_atタイムスタンプを設定すると、バックグラウンドスケジューラーが適切なタイミングで自動公開します - コンテンツロック(v4.5+): 編集中の勧告的ロック(30 分で失効)。別のユーザーがロックを保持している場合は警告バナーを表示。管理者は強制解除できます
- インクリメンタル静的再生成(v4.5+): テンプレートレイアウトの変更時、大規模サイトでのサーバー過負荷を防ぐために 20 ページずつのバッチでページを再生成します
インポートパイプライン(v5.0+)
- RSS/Atom フィードソース: 設定可能なスケジュール(毎時/毎日/毎週)、テンプレートマッピング、フォルダー指定、自動公開を備えた定期的なインポートソースを構成できます。ソースと実行履歴は
/cm/importsから管理します。フィード URL は公開アクセス可能である必要があります(プライベートおよびループバックアドレスは拒否されます、v7.4.3)。 - Markdown + ZIP インポート:
.mdファイルまたは Markdown の.zipアーカイブをアップロードします。各ファイルの YAML frontmatter がタイトル、スラッグ、フォルダー、テンプレート、タグ、スケジュール公開時刻を制御します。Notion のエクスポート、Obsidian Vault、Hugo/Jekyll サイトの移行、AI 生成コンテンツをサポートします。 - CSV 一括インポート: CSV をアップロードし、どの列がタイトルかを指定します。その他のすべての列は自動的にコンテンツフィールドとして保存されます。
- リアルタイム SSE ジョブステータス:
/cm/imports/{jobID}でのライブログストリーム — インポートの進行を行単位で監視したり、後から完全な履歴を確認できます。 - MCP ファースト設計:
import_markdownは、AI エージェントが大量のコンテンツバッチを 1 回の呼び出しで生成・インポートできるように特別に設計されており、数十回のcreate_content呼び出しを 1 回のimport_markdownと 1 回のget_import_jobに置き換えます。ワークフローの例については MCP.md を参照してください。
コンテンツフォーク (v4.0+)
- フォークワークスペース: ページ編集のセットを公開前に作成、プレビュー、レビューできる名前付きステージングワークスペースを作成します
- スパースモデル: 編集されたページのみがフォーク内に存在し、未変更のページは自動的にライブコンテンツにフォールスルーします
- フォークプレビューモード: ライブサイトに注入されるフローティングバーから有効化します。Cookie によってすべてのページリクエストがフォーク経由でルーティングされるため、マージ後にサイトがどのように表示されるかを正確に確認できます
- 競合検出付きマージ: 管理者はフォークをライブコンテンツにマージします。フォーク作成後にライブページが変更されていた場合、競合が記録されます (フォークが優先)。フォーク内で作成された新しいページはマージ時にライブへ挿入され、フォーク内で持っていた公開状態 (通常は下書き) を維持します。ただしマージが
publish_new付きで実行された場合を除きます - マージ後のクリーンアップ (v7.4+): マージはフォークのページコピーを削除し、作成数/更新数を含むフォークレコードを履歴として保持します。v7.4 より前にマージされたフォークは
purge_fork_copiesでクリーンアップできます - フォークコピーは邪魔にならない (v7.4+): フォークコピーは
include_forksが設定されていない限りコンテンツ一覧や検索から除外され、直接または一括で公開することはできません — マージのみが可能です - ホールドフラグ (v7.4+): 任意の下書きを
holdとしてマークすると、フラグが解除されるまで、あらゆる公開方法 (公開、一括公開、スケジュール公開、承認、フォークマージ) がブロックされます - 完全な MCP ツールセット: 9 個の専用フォークツール —
list_forks、create_fork、get_fork、fork_page、remove_fork_page、merge_fork、archive_fork、delete_fork、purge_fork_copies
バッチ & 並列操作
逐次的な単一項目呼び出しよりも、並列化された高スループットのワークフローを好むエージェント向けに設計されています:
bulk_update_content: 1 回の API 呼び出しで最大 100 ページを更新します。各項目はマージセマンティクスを使用し、指定したフィールドのみが変更されます。コミット前のdry_run検証、および同じ呼び出し内で以前に公開されたすべてのページを再公開するauto_republishをサポートし、別途の公開ステップを不要にしますbulk_field_operation: 一致するすべてのページにわたって 1 つのフィールドに単一の操作 (set、clear、prepend、append、wrap) を 1 回の呼び出しで適用します。テンプレート、フォルダ、カテゴリ、または明示的な ID リストでスコープを指定できます。免責事項の追加、メタデータの更新、コンテンツタイプ全体の古いフィールドのクリアに最適ですpublish_multiple: ID のリストを公開します — またはpublish_all_drafts: trueですべての下書きを一度に公開します —publish_contentをループする代わりに 1 回のリクエストで実行できますexport_content: スコープ指定されたページセットの完全なフィールドデータを構造化 JSON 配列としてダンプします。エクスポート → 変換 → 再インポートのパイプライン向けに設計されており、大規模なコンテンツ移行にはbulk_update_contentと組み合わせて使用します- スコープ付き検索 & 置換:
scoped_search_replace_previewとscoped_search_replace_executeはどちらもスコープフィルター (フォルダ、テンプレート、カテゴリ、ID) を受け付けるため、エージェントはサイト全体の操作を実行するのではなく、正確なサブセットを対象にできます - 並列安全な読み取り API:
include_data: trueを指定したlist_contentは 1 回のフェッチで完全なフィールド値を返します。エージェントは複数のlist_content/get_content呼び出しにわたって読み取りを並行してファンアウトし、その後bulk_update_contentでバッチ書き込みできます
大規模更新のための推奨エージェントパターン: list_content → 並列で変換 → bulk_update_content (1 回の呼び出しにつき最大 50) → publish_multiple。
AI チャットウィジェット (v4.2+)
- 埋め込み可能なウィジェット: 単一の
<script>タグで任意のページにフローティング AI チャットバブルを追加できます — 自己完結型で、ビルドステップは不要です - 2 段階パイプライン: 各訪問者のクエリはハイブリッドなセマンティック検索+全文検索を実行して関連するコンテンツ抜粋を取得し、その後それらの抜粋を Claude Haiku にストリーミングして会話形式の合成回答を生成します
- SSE ストリーミング: Haiku のトークンごとの出力は Server-Sent Events を介してブラウザにライブ転送されます。SSE 非対応のクライアントにはプレーンな JSON にフォールバックします
- AI はオプション: Anthropic API キーがなくても、ウィジェットはランク付けされた抜粋を返すチャット内検索体験として動作します — API コストはかかりません
- 完全に設定可能: 管理画面の「Chat Widget」ページでタイトル、ウェルカムメッセージ、プレースホルダーテキスト、プライマリカラー、位置 (左下/右下)、最大結果数、編集可能なシステム/ユーザープロンプトテンプレートを制御できます
- 専用のレート制限: 検索および API のリミッターとは独立した、IP ごと (5/分) およびグローバル (30/分) の個別リミッター
- ソースの帰属表示: すべての応答には、抜粋が使用されたコンテンツページがタイトルとパスとともに含まれます
マルチユーザーアクセス制御と承認 (v2.0+, v6.0+)
- ロールベースアクセス制御 (RBAC): 4 つのロール — 管理者、編集者、投稿者、閲覧者 — すべての管理 UI ページと REST API エンドポイントで詳細な権限が適用されます
- 投稿者ロール (v6.0+): コンテンツの作成、アセットのアップロード、コメントの投稿、編集承認の申請が可能 — 公開権限はありません
- 承認ワークフロー (v6.0+): 設定可能なトリガーベースのワークフロー (ロール、フォルダ、テンプレート、またはタグ別)。順次モードまたは同時モード。デフォルト (ワークフローなし): 任意の編集者または管理者が承認できます
- コンテンツ承認ダッシュボード (v6.0+):
/cm/approvalsにマイキュー、その他の保留中、ワークフロー設定。サイドバーバッジに保留中の件数を表示 - コンテンツディスカッション (v6.0+): すべてのコンテンツ編集ページにインラインのスレッド形式コメント。@メンションのオートコンプリート、管理者による削除、ライブカウントバッジ
- ユーザー管理: ユーザーの作成、ロールの割り当て、アカウントの無効化、パスワードのリセットを行う管理パネル
- 監査ログ: すべての変更 (誰が何をいつ行ったか) の永続的で検索可能なログ。365 日間保持
- レート制限ダッシュボード (v4.5+): 監査ログページの新しいタブで、ロックされた IP、試行回数、クリアボタンを表示
- ユーザー単位の API キー: API キーは所有ユーザーの権限を継承します
- パスワード変更の強制: 一時パスワードは初回ログイン時に必須の変更をトリガーします
スマートなエンドユーザー検索
- ハイブリッド検索: 全文の完全一致検索とセマンティックベクトル検索 (Voyage AI 埋め込み) を組み合わせ、相互ランク融合でマージします
- 設定可能なランキング: すべてのランキング重みは管理パネルで編集可能 — ナビブースト、タイトルブースト、ブースト対象テンプレート、降格対象パスプレフィックス、ペナルティスコア
- インテリジェントなデフォルト: ナビにリンクされたページが最初に表示され、コンセプトテンプレートのページは汎用コンテンツより上位にランク付けされ、動画のトランスクリプトは優先度が下げられます
- タイトルブースト: クエリがタイトルに含まれるページは、本文のみの一致よりも常に上位にランク付けされます
- タイプアヘッド候補: 高速なプレフィックス一致候補 — 直接ナビゲーション用のページ、完全検索用のキーワード — 同じ構造的ランキングを使用
- 埋め込みなしでも動作: Voyage API キーが設定されていない場合は全文検索にフォールバックします
- レート制限: DDoS 対策のための IP ごとおよびグローバルのレート制限
開発者向け・統合
- REST API: API キーと OAuth トークン認証を備えた完全な
/api/v1/JSON API、RBAC 適用 - MCP サーバー: エージェントによるウェブサイト管理のための 130 のツール + 3 つのプロンプトリソース(stdio + HTTP ストリーミング対応)
- OAuth 2.1: リモート MCP クライアント向けの PKCE を用いた認可コードフロー — パスワードの埋め込みは不要
- CLI ツール: すべてのコンテンツ管理操作のためのコマンドラインインターフェース
- URL リダイレクト: 管理パネルから管理できる 301/302 リダイレクトルール
- Webhook(v4.5+): 6 種類のイベント(
content.create、content.update、content.publish、content.unpublish、content.deleteなど)に対する HMAC-SHA256 署名付きイベント配信。Webhook ごとのシークレット。再試行の可視性を備えた配信履歴。管理 UI は/cm/webhooks。Webhook URL は公開されて到達可能でなければなりません。ループバック、プライベート、またはリンクローカルアドレスに解決される URL は拒否され、「blocked」として記録されます(v7.4.3) - Cloudflare 統合(v4.5+): Zone ID + API トークンによる公開/非公開時の Cloudflare キャッシュの自動パージ
- エッジキャッシュヘッダー(v4.5+): すべての公開ページに ETag、Cache-Control、Last-Modified、Vary、および 304 Not Modified を付与
- 構造化 JSON ログ(v4.5+): すべてのサーバーログは、タイムスタンプ、レベル、メッセージ、コンテキストフィールドを含む構造化 JSON を出力
サイトのカスタマイズ
- テーマのカスタマイズ: 色、フォント、角丸、カスタム CSS — すべてバージョン履歴付きで管理パネルから編集可能
- ヘッダー/フッター HTML: すべてのページの周囲に挿入されるサイトクロームを完全に HTML で制御
- アセット管理: 画像、ドキュメント、その他のファイルをアップロードして管理し、パスベースで配信
前提条件
- Go 1.24 以降
- MongoDB Atlas アカウント(無料枠で十分に動作します)
クイックスタート
- リポジトリをクローンします
config.dev.json.exampleをconfig.dev.jsonにコピーしますconfig.dev.jsonを MongoDB 接続文字列で編集しますgo run cmd/server/main.goを実行します- http://localhost:8082/cm にアクセスし、メールアドレスとパスワードでログインします
- 初回実行時に管理者アカウントが作成されます — ご自身のメールアドレスを使用するには
LIGHTCMS_ADMIN_EMAILを設定してください。設定しない場合はadmin@localhostがデフォルトになります
MongoDB Atlas のセットアップ
ステップ 1: Atlas アカウントの作成
- MongoDB Atlas にアクセスします
- 無料アカウントにサインアップします(クレジットカードは不要)
ステップ 2: クラスターの作成
- **「Build a Database」**をクリックします
- 「M0 FREE」(Shared)ティアを選択します
- お好みのクラウドプロバイダーとリージョン(最も近い場所)を選択します
- **「Create Deployment」**をクリックします
ステップ 3: データベースアクセスの設定
-
データベースユーザーを作成します:
- ユーザー名:
lightcms(任意の名前で可) - パスワード: 安全なパスワードを生成します(必ず保存してください!)
- **「Create User」**をクリックします
- ユーザー名:
-
IP アドレスを追加します:
- **「Add My Current IP Address」**をクリックします
- または、どこからでもアクセスを許可するために
0.0.0.0/0を追加します(安全性は低くなりますが、開発には便利です) - **「Finish and Close」**をクリックします
ステップ 4: 接続文字列の取得
- クラスターの**「Connect」**をクリックします
- **「Drivers」**を選択します
- 接続文字列をコピーします。次のようになります:
mongodb+srv://lightcms:<password>@cluster0.xxxxx.mongodb.net/?retryWrites=true&w=majority <password>を実際のパスワードに置き換えます
ステップ 5: 設定ファイルの作成
開発用には、サンプルをコピーして値を入力します:
cp config.dev.json.example config.dev.json
config.dev.json を編集します:
{
"port": "8082",
"mongo_uri": "mongodb+srv://lightcms:[email protected]/lightcms",
"env": "development",
"session_secret": "any-random-string-for-dev"
}
本番用には、config.prod.json を使用します:
cp config.prod.json.example config.prod.json
本番用の値で編集します(session_secret には openssl rand -hex 32 を使用します)。
インストール
# Clone or navigate to the project
cd lightcms
# Install dependencies
go mod tidy
# Run the server
go run cmd/server/main.go
または実行スクリプトを使用します:
./run.sh
設定
LightCMS は JSON 設定ファイルを使用します。次のいずれかを作成してください:
config.dev.json- 開発用config.prod.json- 本番用(両方存在する場合はこちらが優先されます)
| フィールド | 説明 |
|---|---|
port | サーバーポート(例:開発用は "8082"、本番用は "80") |
mongo_uri | MongoDB Atlas 接続文字列 |
database_name | MongoDB データベース名。任意、デフォルトは lightcms |
env | 環境:"development" または "production" |
session_secret | セッション暗号化用のランダム文字列 |
base_url | サイトの公開 URL |
secure_cookies | 本番環境(HTTPS)では true。平文 HTTP でのローカル開発では false |
MONGO_URI が設定されている場合、設定は代わりに環境変数から取得されます(MONGO_URI、SESSION_SECRET、BASE_URL、PORT、ENV、SECURE_COOKIES)。
データベース。 サーバーと cmd/ ツールは、特に指定がない限り lightcms データベースを使用します。DATABASE_NAME 環境変数を設定すると(設定ファイルの database_name より優先されます)、同一クラスタ上の別のデータベース、たとえばステージングやコピーをインスタンスの接続先に指定できます。サーバーは起動時に接続したデータベースをログに出力します。
開発環境での平文 HTTP。 secure_cookies: false の場合、管理画面は http://localhost で動作します。Cookie に Secure が付与されず、CSRF オリジンチェックは http:// と比較されます。secure_cookies: true(本番環境のデフォルト)の場合、管理画面には HTTPS 経由でアクセスする必要があり、CSRF チェックは平文 HTTP のオリジンを拒否します。
注意: 設定ファイルにはシークレットが含まれるため、.gitignore によって git から除外されます。
使用方法
サイトへのアクセス
- 公開サイト:http://localhost:8082
- 管理画面:http://localhost:8082/cm
初回ログイン
/cm/login でメールアドレスとパスワードを入力してログインします。データベースが空の状態で初回起動すると、LightCMS は LIGHTCMS_ADMIN_EMAIL 環境変数から管理者アカウントを作成します(デフォルトは admin@localhost、パスワードは admin123)。ログイン後はすぐにパスワードを変更してください。
コマンドからパスワードをリセットするには:
go run cmd/resetpw/main.go [email protected]
コンテンツの作成
/cmの管理画面にログインします- Content → New Content に移動します
- テンプレート(Blog Post、Press Release、Explanatory Page など)を選択します
- フィールドを入力します
- 「Published」にチェックを入れて保存します
ユーザーの管理(管理者のみ)
- 左サイドバーの Users に移動します(管理者のみに表示されます)
- メールアドレス、表示名、ロール(admin / editor / viewer)を指定してユーザーを作成します
- ユーザーは一時パスワードを受け取り、初回ログイン時に変更を求められます
- 編集ページからアカウントの無効化やパスワードのリセットができます
- Audit Log で全ユーザー操作の完全な監査証跡を確認できます
カスタムテンプレートの作成
- Templates → New Template に移動します
- フィールド(text、textarea、richtext、date、image、select)を定義します
{{.field_name}}プレースホルダーを使用して HTML レイアウトを作成します- テンプレートを保存します
使用可能なプレースホルダー:
{{.title}}- コンテンツのタイトル{{.slug}}- URL スラッグ{{.published_at}}- 公開日{{.your_field_name}}- 定義した任意のカスタムフィールド
動的インデックスページ:タグ、スニペット、lc:query
LightCMS には、コンテンツを公開するたびに自動更新される動的インデックスページを構築するためのシステムが含まれています。タグは個々のページにラベルを付け、スニペットは各結果のレンダリング方法を定義し、lc:query ディレクティブはテンプレートレイアウト内に直接ライブクエリを埋め込みます。この 3 つの機能が連携して動作します。
タグ
タグは、任意のコンテンツアイテムに付加できる自由形式の文字列ラベルです。1 つのページにタグを付けないことも、複数のタグを付けることもできます。タグは、コンテンツをグループ化してクエリするための主要な手段です。
管理 UI でタグを設定する:
- エディターで任意のコンテンツアイテムを開きます
- タグフィールドを見つけます (主要なフィールドの下にあります)
- タグ名を入力して Enter キーを押します — 複数のタグを付ける場合は繰り返します
- コンテンツアイテムを保存します
API でタグを設定する:
curl -X PUT http://localhost:8082/api/v1/content/{id} \
-H "Authorization: Bearer lc_your_key" \
-H "Content-Type: application/json" \
-d '{"tags": ["AI & Machine Intelligence", "Featured"]}'
タグは完全一致の文字列です。大文字と小文字およびスペースは保持されます — "AI & Machine Intelligence" と "ai & machine intelligence" は別のタグとして扱われます。
スニペット
スニペットは、CMS に保存された名前付きの HTML テンプレート断片です。lc:query が実行されると、一致する各コンテンツアイテムをスニペットを通してレンダリングし、その結果を連結します。
スニペットを作成する:
- 管理パネルで 設定 → スニペット に移動します
- 新規スニペットをクリックし、名前を付けます (例:
glossary-pill) - Go テンプレート変数を使用して HTML を記述します:
<a href="{{.FullPath}}">{{.Title}}</a>
スニペット内で使用できる変数:
| 変数 | 説明 |
|---|---|
{{.Title}} | コンテンツアイテムのタイトル |
{{.FullPath}} | 公開 URL パス (例: /my-page) |
{{.Slug}} | URL スラッグのみ (例: my-page) |
{{.MetaDescription}} | メタディスクリプションフィールド |
{{.PublishedAt}} | 公開タイムスタンプ |
スニペットの例:
ピルスタイルのリンク (用語集 / タグクラウドのレイアウト向け):
<a href="{{.FullPath}}" class="pill">{{.Title}}</a>
説明付きのカード:
<div class="card">
<h3><a href="{{.FullPath}}">{{.Title}}</a></h3>
<p>{{.MetaDescription}}</p>
</div>
シンプルなリスト項目:
<li><a href="{{.FullPath}}">{{.Title}}</a></li>
lc:query ディレクティブ
lc:query ディレクティブは、テンプレートレイアウトに埋め込む HTML コメントです。ページ生成時 — ページがレンダリングされる前に — CMS は一致するすべてのコンテンツアイテムを検索し、それぞれを指定されたスニペットを通してレンダリングし、そのコメントを結合された HTML で置き換えます。
構文:
属性:
| 属性 | 必須 | 説明 |
|---|---|---|
filter | はい | フィルター式。現在は tag:TAGNAME をサポートしており、TAGNAME が付けられたコンテンツに一致します。 |
sort | いいえ | 並べ替えフィールドと方向: title:asc、title:desc、created_at:asc、created_at:desc。デフォルトは title:asc です。 |
snippet | はい | 各結果をレンダリングするスニペットの名前。 |
テンプレートレイアウトでの例:
<h2>AI & Machine Intelligence</h2>
<div class="links">
</div>
ページが公開されると、ディレクティブは、AI & Machine Intelligence タグが付けられたすべての公開ページをそれぞれ glossary-pill スニペットを通してレンダリングした出力で置き換えられます:
<h2>AI & Machine Intelligence</h2>
<div class="links">
<a href="/artificial-intelligence" class="pill">Artificial Intelligence</a>
<a href="/machine-learning" class="pill">Machine Learning</a>
<a href="/neural-networks" class="pill">Neural Networks</a>
</div>
重要: lc:query ディレクティブは、コンテンツデータフィールドの内部ではなく、テンプレートの HTML レイアウトフィールドに配置する必要があります。CMS は、Go のテンプレートエンジンが実行される前のページ生成時にそれらを処理します (そうでなければ、Go のテンプレートエンジンが HTML コメントを削除してしまいます)。
自動再生成
lc:query を使用するインデックスページは、次のいずれかの場合に自動的に再生成されます:
- タグ付けされたコンテンツアイテムが公開または更新されたとき
- テンプレートレイアウトが変更されたとき
- スニペットが更新されたとき
- 管理パネルからすべて再生成が手動で実行されたとき
つまり、インデックスページを手動で再ビルドする必要は決してありません — "Games & Interactive Experiences" タグが付けられた新しいコンセプトページを公開すると、そのタグをクエリするすべてのインデックスに数秒以内に表示されます。
完全ウォークスルー: タグ付けを活用したインデックスの構築
自動的に最新の状態に保たれる概念用語集を構築する方法を紹介します。
ステップ 1: 概念ページにタグを付ける
各概念ページについて、コンテンツエディターで適切なタグを追加します。タグはいくつでも使用でき、同じコンテンツアイテムを複数のインデックスセクションに表示できます。
ステップ 2: スニペットを作成する
設定 → スニペットで、glossary-pill という名前のスニペットを作成します:
<a href="{{.FullPath}}">{{.Title}}</a>
ステップ 3: lc:query セクションを含むテンプレートを作成する
新しいテンプレート(例: 「Concepts Index」)を、次の HTML レイアウトで作成します:
<article class="index-page">
<h1>{{.title}}</h1>
<div class="page-content">
<h2>AI & Machine Intelligence</h2>
<div class="concept-links">
</div>
<h2>Games & Interactive Experiences</h2>
<div class="concept-links">
</div>
<h2>3D Graphics & Rendering</h2>
<div class="concept-links">
</div>
</div>
</article>
{{.title}} はコンテンツアイテムのタイトル用の Go テンプレート変数であることに注意してください。テンプレート変数は Go の {{.field}} 構文を使用し、lc:query ディレクティブが展開された後に解決されます。
ステップ 4: インデックスページを作成して公開する
「Concepts Index」テンプレートを使用して、新しいコンテンツアイテムを作成します。タイトルとスラッグ(例: /glossary)を付けます。公開すると、現在タグ付けされているすべてのコンテンツが反映された状態で静的ページが生成されます。
ステップ 5: 公開を続ける
以降、一致するタグを付けた新しい概念ページを作成して公開するたびに、そのタグをクエリするすべてのインデックスページが自動的に再生成されて更新されます。
テンプレート変数
コンテンツデータフィールドに加えて、テンプレートではいくつかの組み込み変数にアクセスできます:
| 変数 | 説明 |
|---|---|
{{.title}} | コンテンツアイテムのタイトル |
{{.slug}} | URL スラッグ |
{{.published_at}} | 公開タイムスタンプ |
{{.your_field}} | テンプレートで定義された任意のカスタムフィールド(リッチテキストフィールドは HTML としてレンダリングされます) |
テンプレートで定義したカスタムフィールドは、キーで直接利用できます。キー intro でフィールドを定義すると、レイアウト内で {{.intro}} として利用できます。リッチテキストフィールドは自動的に安全済みとしてマークされ、その HTML はエスケープされずにそのままレンダリングされます。
コンテンツオーサリング: 前処理とマークアップ機能
LightCMS は、コンテンツフィールドの値をテンプレートにレンダリングする前に処理します。執筆者は、任意のテキストまたはリッチテキストデータフィールドで次のマークアップ機能を使用できます。
Wikilink
二重角括弧構文を使用してページ間をリンクします。Wikilink は公開時に解決され、ページのタイトルやパスが変更されると自動的に最新の状態に保たれます。
| 構文 | 結果 |
|---|---|
[[Page Title]] | タイトルで一致したページへのリンク(大文字と小文字を区別しません) |
[[Page Title|display text]] | 同じですが、カスタムリンクテキスト付き |
[[/full/path]] | 正確な URL パスでページにリンク |
[[/full/path|display text]] | カスタムリンクテキスト付きのパスリンク |
壊れたリンク(一致するページが見つからない場合)は <span class="broken-link">Page Title</span> としてレンダリングされるため、簡単に特定して修正できます。
スニペットのインクルード
任意のコンテンツフィールド内に、名前付きスニペットをインラインで埋め込みます:
[[include:snippet-name]]
snippet-name は、設定 → スニペットにあるスニペットの Name フィールドと完全に一致する必要があります。スニペットのインクルードは、多くのページに表示されるコールアウト、免責事項、コールトゥアクションなど、再利用可能なコンテンツブロックに便利です。
目次
テンプレートの HTML レイアウト内の任意の場所に {{.lc_toc}} を配置すると、その位置に自動生成された目次が挿入されます:
<nav class="sidebar">
{{.lc_toc}}
</nav>
<article>
{{.body}}
</article>
ページ生成時に、LightCMS は最終的にレンダリングされた HTML 内のすべての見出しをスキャンし、それぞれへのアンカーリンクを含む <nav class="lc-toc"> ブロックを出力します。見出しには、そのテキスト内容から生成された id= 属性が自動的に付与されるため(後述の 見出し ID を参照)、TOC リンクは追加設定なしで機能します。
見出し ID
レンダリングされたページ出力内のすべての見出し(<h1> から <h6>)には、そのテキストから生成された id= 属性が自動的に付与されます。これにより、特定のセクションへのディープリンクが可能になります。
例:
<h2>Getting Started</h2>
<h2 id="getting-started">Getting Started</h2>
id は、テキストを小文字に変換し、スペースと句読点をハイフンに置き換えることで生成されます。2 つの見出しが同じ id を生成した場合は、数値のサフィックスが追加されます(getting-started-2 など)。
Markdown フィールドタイプ
テンプレートのフィールドには、text や richtext の代わりに markdown というタイプを指定できます。Markdown フィールドは、テーブル、打ち消し線、タスクリスト、自動リンクを含む GitHub Flavored Markdown (GFM) をサポートします。フィールドの値はページ生成時に HTML へ変換されます。
Markdown フィールドは、WYSIWYG エディターを必要とせず、シンプルなマークアップが役立つ構造化コンテンツに適しています。たとえば、ドキュメントページ、変更履歴、FAQ、その他同様のコンテンツです。
Markdown フィールドを作成するには、テンプレートを定義する際にフィールドタイプを markdown に設定します。
{ "name": "body", "label": "Body", "type": "markdown", "required": true }
インラインタグの検出
コンテンツフィールド内の任意の場所に #tagname と記述すると、そのページに自動的にそのラベルが付与されます。タグはページのタグリストに追加され、手動で適用したタグと同様に lc:query インデックスページで扱われます。
タグのルール:
- 先頭は英字でなければなりません
- 英字、数字、アンダースコア、ハイフンを含めることができます
- 例:
This article covers #machine-learning and #aiは両方のタグを追加します
これは、Tags フィールドを別途編集する代わりの便利な方法です。Markdown フィールドやリッチテキストでコンテンツを書きながら、インラインでタグ付けしたい場合に役立ちます。
コレクションの作成
コレクションは、グループ化されたコンテンツ (ブログの一覧ページなど) を表示します。
- Collections → New Collection に移動します
- コンテンツのカテゴリに一致するようにカテゴリフィルターを設定します
- アイテムテンプレートとページテンプレートを定義します
- コレクションは
/collection-slugで利用可能になります
テーマのカスタマイズ
- 管理パネルの Theme に移動します
- 色、フォント、角丸を調整します
- 必要に応じてカスタム CSS を追加します
- 保存するとサイト全体に変更が適用されます
エンドユーザー検索
LightCMS は、サイトのフロントエンドから呼び出せる公開検索 API を /api/search で提供します。
検索 API
GET /api/search?q=QUERY&mode=hybrid&limit=10
| パラメーター | 説明 |
|---|---|
q | 検索クエリ (必須) |
mode | hybrid (デフォルト)、fulltext、または semantic |
limit | 最大結果数 1~50 (デフォルト 10) |
{
"query": "game design",
"mode": "hybrid",
"total": 3,
"results": [
{ "id": "...", "title": "Game Design", "full_path": "/concepts/game-design",
"snippet": "...matching context...", "score": 0.97, "match_type": "both" }
]
}
match_type は exact、semantic、または both です。
Typeahead Suggest API
GET /api/search/suggest?q=PREFIX&limit=8
ライブのタイプアヘッドドロップダウンを構築するための 2 つのリストを返します:
{
"keywords": ["game design", "game mechanics"],
"pages": [{"title": "About Jon Radoff", "path": "/about"}]
}
- keywords — 公開済みコンテンツから抽出されます。クリックすると完全な検索が実行されます
- pages — 直接ナビゲーションの結果で、次の順位でランク付けされます: ナビリンクあり → ブーストされたテンプレート → タイトルが前方一致 → タイトルが部分一致 → 降格されたパス
JavaScript の例
<input type="text" id="q" placeholder="Search..." autocomplete="off">
<ul id="suggest"></ul>
<div id="results"></div>
<script>
const input = document.getElementById('q');
const suggest = document.getElementById('suggest');
const results = document.getElementById('results');
let timer;
// Typeahead while typing
input.addEventListener('input', () => {
clearTimeout(timer);
const q = input.value.trim();
if (q.length < 2) { suggest.innerHTML = ''; return; }
timer = setTimeout(async () => {
const r = await fetch('/api/search/suggest?q=' + encodeURIComponent(q) + '&limit=8');
const d = await r.json();
suggest.innerHTML = [
...(d.pages || []).map(p => `<li><a href="${p.path}">📄 ${p.title}</a></li>`),
...(d.keywords || []).map(k => `<li><a onclick="doSearch('${k}')">🔍 ${k}</a></li>`),
].join('');
}, 200);
});
// Full search on Enter
input.addEventListener('keydown', e => { if (e.key === 'Enter') doSearch(input.value); });
async function doSearch(q) {
suggest.innerHTML = '';
const r = await fetch('/api/search?q=' + encodeURIComponent(q) + '&mode=hybrid&limit=10');
const d = await r.json();
results.innerHTML = (d.results || [])
.map(r => `<div><a href="${r.full_path}"><strong>${r.title}</strong></a><p>${r.snippet}</p></div>`)
.join('') || '<p>No results.</p>';
}
</script>
ランキング設定
ランキングの重みは、管理パネルの Tools → End User Search → Search Ranking で設定できます。デフォルト: タイトル一致ブースト 0.20、ナビページブースト 0.15、コンセプトテンプレートブースト 0.05、動画パスペナルティ −0.05。セマンティック検索を有効にするには、Configuration で Voyage AI キーを設定してください。
プロジェクト構造
lightcms/
├── cmd/
│ ├── server/main.go # HTTP server entry point
│ ├── mcp/main.go # MCP server entry point
│ ├── cli/main.go # CLI tool entry point
│ └── resetpw/main.go # Password reset utility
├── config/
│ └── config.go # Configuration loading
├── internal/
│ ├── apiclient/ # Reusable HTTP client for REST API
│ ├── auth/ # Authentication, RBAC permissions, session management
│ ├── cli/ # CLI subcommands and output formatting
│ ├── database/ # MongoDB connection & operations
│ ├── handlers/ # HTTP handlers (admin UI + REST API)
│ ├── mcp/ # MCP server and tool definitions
│ ├── middleware/ # API auth middleware (API keys + OAuth)
│ ├── models/ # Data models & default templates
│ ├── oauth/ # OAuth 2.1 authorization server
│ └── services/ # Business logic (content, search, users, audit, etc.)
├── static/ # CSS, JS, and uploaded files
├── content/ # Custom pages and generated HTML
└── .goreleaser.yaml # Release configuration
デフォルトテンプレート
ブログ投稿
フィールド: title, excerpt, featured_image, content, author, tags
プレスリリース
フィールド: headline, subheadline, dateline, release_date, body, boilerplate, contact_info
解説ページ
フィールド: title, subtitle, hero_image, intro, main_content, sidebar, cta_text, cta_link
コンセプトページ
フィールド: title, definition, topic_links — wiki 形式のナレッジベースのエントリに最適です
標準ページ、空白ページ、ホームページ
柔軟なコンテンツ向けの汎用レイアウトです。
マルチユーザーアクセス制御
LightCMS v2.0+ は、ロールベースの権限を持つ複数ユーザーをサポートします。
ロール
| ロール | 権限 |
|---|---|
| admin | フルアクセス: ユーザー、テンプレート、テーマ、設定、監査ログ、すべての API キーの管理 |
| editor | コンテンツの作成/編集/削除/公開、アセットのアップロードと削除、自身の API キーの管理 |
| viewer | コンテンツ、テンプレート、アセット、設定への読み取り専用アクセス |
監査ログ
すべての変更 (コンテンツの作成/更新/削除/公開、ユーザー管理、設定変更、ログイン) は、操作したユーザーのメールアドレス、タイムスタンプ、および関連する詳細とともに記録されます。ログは 365 日間保持され、/cm/audit でアクセスできます。
API キーの権限
ユーザーが作成した API キーは、そのユーザーのロールを継承します。編集者が作成したキーは、そのトークンが共有されたとしても、管理者専用の操作を実行することはできません。管理者はすべてのキーを管理できますが、非管理者は自分のキーのみを管理できます。
初回マイグレーション
users コレクションが空の状態で初めて起動すると、LightCMS はデータベース内の既存のパスワードハッシュから管理者ユーザーを自動的に作成します。使用するメールアドレスを指定するには、LIGHTCMS_ADMIN_EMAIL 環境変数を設定してください(デフォルトは admin@localhost)。
API キー
API キーは、REST API、MCP サーバー、および CLI ツールで必要です。管理パネルから作成してください。
/cmにログインします- Settings → API Keys に移動します
- Create New Key をクリックし、名前と説明を入力します
- キーをすぐにコピーしてください — 表示されるのは一度だけです
キーは lc_ に続けて 32 桁の 16 進数文字列という形式を使用します。SHA-256 ハッシュとして保存され、作成したユーザーの権限を継承します。
OAuth 2.1 認可
LightCMS は OAuth 2.1 を実装しているため、リモート MCP クライアント(Claude の Cowork など)は、パスワードや API キーを埋め込むことなく安全に接続できます。これは PKCE を使用した標準的な認可コードフローに準拠しています。
エンドポイント
| エンドポイント | 目的 |
|---|---|
POST /oauth/register | 動的クライアント登録(RFC 7591) |
GET /oauth/authorize | 認可ページ(管理者ログイン+同意) |
POST /oauth/token | トークンの交換と更新 |
POST /oauth/revoke | トークンの失効(RFC 7009) |
GET /oauth/jwks | JWKS エンドポイント(不透明トークン、空を返します) |
セキュリティ
- すべての認可リクエストに PKCE(S256) が必須です
- トークンローテーション: リフレッシュトークンは 1 回限りで、毎回新しいペアが発行されます
- 短命なアクセストークン: TTL は 1 時間です
- リフレッシュトークン: TTL は 30 日間で、失効可能です
- レート制限: ログインの失敗が続くと段階的なロックアウトが発生します(1 分 → 5 分 → 15 分)
- すべてのトークンはデータベースに SHA-256 ハッシュとして保存されます
クライアントの接続方法
- クライアントは
/.well-known/oauth-authorization-serverを取得してエンドポイントを検出します - クライアントは名前とリダイレクト URI を指定して
POST /oauth/registerを呼び出します - クライアントは PKCE チャレンジを付けて管理者を
/oauth/authorizeにリダイレクトします - 管理者はパスワードを入力し、アクセスを承認します
- クライアントは認可コードをアクセストークン+リフレッシュトークンと交換します
- クライアントはアクセストークンを Bearer トークンとして
/mcpまたは/api/v1/エンドポイントで使用します
これはすべて MCP 互換クライアントによって自動的に処理されます — LightCMS の URL を指定して接続を承認するだけです。
REST API
LightCMS は /api/v1/ に完全な REST API を提供しており、API キーまたは OAuth トークンで認証します。すべてのエンドポイントで RBAC が適用され、認証されたユーザー(またはキーの所有者)の権限によって許可される操作が決まります。
認証
Authorization ヘッダーに API キーまたは OAuth アクセストークンを含めます:
# With API key
curl -H "Authorization: Bearer lc_your_key_here" http://localhost:8082/api/v1/content
# With OAuth token
curl -H "Authorization: Bearer <oauth_access_token>" http://localhost:8082/api/v1/content
エンドポイント
| リソース | エンドポイント |
|---|---|
| Content | GET/POST /content、GET/PUT/DELETE /content/{id}、POST .../publish、.../unpublish、.../restore、GET .../versions、POST .../versions/{v}/revert、GET /content/by-path?path=... |
| Templates | GET/POST /templates、GET/PUT/DELETE /templates/{id} |
| Snippets | GET/POST /snippets、GET/PUT/DELETE /snippets/{id} |
| Assets | GET/POST /assets、GET/DELETE /assets/{id}、GET /assets/folders、GET /assets/by-path?path=... |
| Theme | GET/PUT /theme、GET /theme/versions、POST /theme/versions/{v}/revert |
| Config | GET/PUT /config |
| Redirects | GET/POST /redirects、GET/PUT/DELETE /redirects/{id} |
| Folders | GET/POST /folders、GET/DELETE /folders/{id} |
| Collections | GET/POST /collections、GET/PUT/DELETE /collections/{id} |
| Search | GET /search?q=...、POST /search-replace/preview、POST /search-replace/execute |
| API Keys | GET/POST /api-keys、DELETE /api-keys/{id} |
| Utility | POST /regenerate |
すべてのエンドポイントは JSON を返します。PUT エンドポイントは部分更新をサポートしています(変更したいフィールドのみを含めてください)。
CLI ツール
lightcms CLI は、すべてのコンテンツ管理操作へのコマンドラインアクセスを提供します。
インストール
# Build from source
go build -o bin/lightcms ./cmd/cli
# Or download a release binary from GitHub
設定
export LIGHTCMS_URL=http://localhost:8082
export LIGHTCMS_API_KEY=lc_your_key_here
またはフラグを使用します: --url と --api-key。
コマンド
lightcms content list # List all content
lightcms content get <id> # Get content by ID
lightcms content create --template <id> --title "My Post" --slug my-post --data '{"body":"Hello"}'
lightcms content publish <id> # Publish content
lightcms content versions <id> # Show version history
lightcms template list # List templates
lightcms asset upload --file logo.png --path /images/logo.png
lightcms theme update --primary-color "#1a1a2e"
lightcms search "search terms" # Search content
lightcms api-key create --name "CI/CD" # Create API key
lightcms --json content list # JSON output
完全な使用方法については lightcms --help を実行してください。
MCP サーバー(AI によるコンテンツ管理)
LightCMS には、AI エージェントを通じてウェブサイト全体を管理するための 130 個のツールと 3 個のプロンプトリソースを備えた完全な MCP(Model Context Protocol)サーバーが含まれています。2 つのトランスポートモードをサポートしています:
- Stdio — Claude Code などのローカルツール向け
- HTTP Streamable — Claude の Cowork、Claude Desktop、その他の MCP 互換アプリなどのリモート/サンドボックス化されたクライアント向け
オプション A: ローカルセットアップ(Stdio 経由の Claude Code)
同じマシン上で Claude Code を直接使用する開発者に最適です。
- 管理パネルの
/cm→ Settings → API Keys で API キーを作成します - セットアップスクリプトを実行します:
export LIGHTCMS_API_KEY=lc_your_key_here
./setup-mcp.sh
または手動で登録します:
go build -o bin/lightcms-mcp ./cmd/mcp
claude mcp add --transport stdio lightcms-mcp \
-e LIGHTCMS_URL="http://localhost:8082" \
-e LIGHTCMS_API_KEY="lc_your_key_here" \
-- /path/to/lightcms/bin/lightcms-mcp
Claude Code を再起動し、/mcp を実行して確認します。
オプション B: リモートセットアップ(HTTP + OAuth 経由の Cowork / Claude Desktop)
ローカルバイナリを実行できないサンドボックス化されたデスクトップアプリに最適です。/mcp の HTTP MCP エンドポイントは OAuth 2.1 認可をサポートしています — API キーやパスワードをクライアントに埋め込む必要はありません。
仕組み:
- クライアントは well-known エンドポイントを通じてあなたの LightCMS インスタンスを検出します
- OAuth クライアントとして登録します(初回のみ、自動)
- ブラウザで管理者パスワードを入力してクライアントを認可します
- クライアントは短命のアクセストークンを受け取り、自動的に更新します
リモート MCP クライアントから接続するには、あなたの LightCMS の URL(例: https://yoursite.example.com)を指定するだけです。残りはクライアントが標準の OAuth 2.1 ディスカバリを使用して処理します。
ディスカバリエンドポイント:
| エンドポイント | 目的 |
|---|---|
/.well-known/oauth-authorization-server | OAuth サーバーメタデータ(RFC 8414) |
/.well-known/oauth-protected-resource | 保護リソースメタデータ(RFC 9728) |
/.well-known/mcp/server-card.json | ツールスキーマを含む MCP サーバーカード |
認証
MCP HTTP エンドポイントは両方の認証方法を受け付けます:
- API キー(
lc_プレフィックス)— 長期間有効で、管理パネルで作成します - OAuth 2.1 トークン — 短命で、認可フローを通じて取得します
どちらの方法も、認証されたユーザーのロールに基づいて RBAC を適用します。
利用可能なツール (合計 130) + 3 つのプロンプトリソース
- コンテンツ (19): 一覧取得、読み取り、作成、更新、パスによる更新、削除、復元、公開、非公開、複数公開、プレビュー、バージョン (一覧 + 取得)、巻き戻し、一括作成、一括更新、一括フィールド操作、エクスポート、被リンク
- テンプレート (5): 作成、読み取り、更新、削除、一覧取得
- スニペット (5): 作成、読み取り、更新、削除、一覧取得
- アセット (6): アップロード、URL からのアップロード、読み取り、削除、ファイルとフォルダの一覧取得
- 検索 (7): 全文検索、エンドユーザー検索、検索と置換 (グローバル + スコープ限定、プレビュー + 実行)、埋め込みの再インデックス
- 設定 (23): テーマの CRUD + バージョニング + ピン留め、サイト設定、リダイレクト、フォルダ、コレクション、全コンテンツの再生成
- フォーク (9): 一覧取得、作成、取得、ページのフォーク、ページの削除、マージ、アーカイブ、削除、コピーのパージ
- インポート (10、v5.0 以降): インポートソースの一覧取得/作成/更新/削除/実行、Markdown のインポート、CSV のインポート、インポートジョブの一覧取得/取得/キャンセル
- Webhook (6、v4.5 以降): Webhook の一覧取得、作成、更新、削除、シークレットの再生成、配信の一覧取得
- コンテンツロック (4、v4.5 以降): ロックの取得、ロックの取得 (獲得)、ロックの解放、強制ロック解除
- スケジュール公開 (3、v4.5 以降): 公開のスケジュール、スケジュール済みの一覧取得、スケジュールのキャンセル
- 監査とリンクチェック (3、v4.5 以降): 監査ログの一覧取得、リンクチェックの開始、リンクチェック結果の取得
- コメント (3、v6.0 以降): コメントの一覧取得、コメントの投稿、コメントの削除
- 承認 (11、v6.0 以降): 承認ワークフローの一覧取得/取得/作成/更新/削除、承認リクエストの一覧取得/取得/提出/承認/却下/キャンセル
- エージェントサンドボックスとガバナンス (10、v7.0 以降): エージェントサンドボックスの開始/取得/終了、フォーク差分、エージェントセッションの変更、セッションのロールバック、メンテナンスレポート、メンテナンススキャンの実行、公開日のバックフィル、フォーク破損の修復
- IndexNow (3、v7.2.3 以降): ステータスの取得、有効化/無効化、送信
- SEO と AI (3、v7.3 以降): SEO 設定の取得/更新、AI トラフィック
- プロンプトリソース (3、v4.5 以降):
lightcms://site/structure、lightcms://content/recent、lightcms://theme/config
詳細な API ドキュメントについては、MCP.md を参照してください。
環境変数 (Stdio モード)
LIGHTCMS_URL— サーバー URL (デフォルト:http://localhost:8082)LIGHTCMS_API_KEY— API キー (Stdio モードでは必須)
MCP の例
これらの例は、MCP ツールが連携して自然言語を通じてウェブサイトを管理する仕組みを示しています。各例では、ユーザーのプロンプトと、バックグラウンドで実行される正確な MCP ツール呼び出しを挙げています。
例 1: ブログ記事を作成して公開する
プロンプト: 「AI エージェントに関するブログ記事を作成して公開して」
ツール呼び出し:
list_templates— ブログ記事テンプレートとその ID を検索しますcreate_content— テンプレート ID、タイトル、スラッグ、フィールドデータを指定して記事を作成します:{ "template_id": "6971098ad0761968133b8e43", "title": "The Rise of AI Agents", "slug": "rise-of-ai-agents", "data": { "excerpt": "How autonomous AI agents are reshaping software development.", "content": "<p>AI agents represent a fundamental shift...</p>", "author": "Editorial Team" } }publish_content— 公開状態にします。静的 HTML ページが/rise-of-ai-agentsに生成されます
例 2: サイトテーマを更新する
プロンプト: 「サイトの配色を、青をアクセントにしたダークテーマに変更して」
ツール呼び出し:
get_theme— 現在のテーマ設定 (色、フォント、ヘッダー/フッターの HTML) を読み取りますupdate_theme— 新しいパレットを適用します:
公開済みのすべてのページが新しいテーマで自動的に再生成されます。{ "primary_color": "#1a1a2e", "secondary_color": "#16213e", "accent_color": "#0f3460", "background_color": "#0a0a0a", "text_color": "#e0e0e0" }
例 3: サイト全体で検索と置換を行う
プロンプト: 「サイト内の『Acme Corp』をすべて『Acme Industries』に置換して」
ツール呼び出し:
search_replace_preview— 変更を加えずに影響を受けるページを表示します:
コンテンツ項目、一致したフィールド、一致件数の一覧を返します。{ "search": "Acme Corp", "replace": "Acme Industries" }search_replace_execute— ユーザーの確認後に置換を実行します。影響を受ける各コンテンツ項目には、ロールバックできるよう新しいバージョンが付与されます。
例 4: カスタムテンプレートを作成する
プロンプト: 「名前、役割、経歴、写真を持つチームメンバープロフィール用のテンプレートを作成して」
ツール呼び出し:
create_template— 構造と HTML レイアウトを定義します:
テンプレートはすぐにコンテンツ作成に利用できるようになります。{ "name": "Team Member", "slug": "team-member", "fields": [ { "name": "role", "label": "Role", "type": "text", "required": true }, { "name": "photo", "label": "Photo", "type": "image", "required": false }, { "name": "bio", "label": "Biography", "type": "richtext", "required": true } ], "html_layout": "<div class=\"team-member\"><img src=\"{{.photo}}\" alt=\"{{.title}}\"><h2>{{.title}}</h2><h3>{{.role}}</h3><div>{{.bio}}</div></div>" }
例 5: 画像をアップロードしてコンテンツで使用する
プロンプト: 「このロゴをアップロードして、about ページに追加して」
ツール呼び出し:
upload_asset— ファイルを base64 として、配信パスとともにアップロードします:
画像は{ "filename": "logo.png", "serve_path": "/images/logo.png", "data_base64": "iVBORw0KGgoAAAANSUhEUg..." }/images/logo.pngでアクセスできるようになりました。get_content— パスで about ページを取得し、現在のデータを取得しますupdate_content— ページの content フィールドに画像参照を追加します
例 6: URL リダイレクトを設定する
プロンプト: 「古いブログが /news から /blog に移動した — 古い URL のリダイレクトを設定して」
ツール呼び出し:
create_redirect— 永続リダイレクトを作成します:{ "from_path": "/news", "to_path": "/blog", "status_code": 301, "description": "Blog section moved from /news to /blog" }/newsへの訪問者は自動的に/blogへリダイレクトされます。異なるパスに対して複数のリダイレクトを連続して作成できます。
例 7: コンテンツのバージョン管理とロールバック
プロンプト: 「ホームページのバージョン履歴を表示して、それからバージョン 2 に戻して」
ツール呼び出し:
get_content— パス (/) でホームページを取得し、その ID を取得しますget_content_versions— タイムスタンプとコメントを含む完全なバージョン履歴を返します:Version 5 — "Updated hero section" — 2026-02-25 Version 4 — "Added testimonials" — 2026-02-20 Version 3 — "Redesigned layout" — 2026-02-15 Version 2 — "Initial content" — 2026-02-10 Version 1 — "Created page" — 2026-02-08revert_to_version— バージョン 2 にロールバックし、古いデータを持つ新しいバージョン 6 を作成します。公開済みページは即座に再生成されます。
例 8: フォルダーでコンテンツを整理する
プロンプト: 「/docs セクションを作成して、API リファレンスページをそこに移動して」
ツール呼び出し:
create_folder— URL パスセグメントを作成します:{ "name": "Documentation", "slug": "docs" }get_content— API リファレンスページを取得し、その ID を取得しますupdate_content— 新しいフォルダーに移動します:
ページは{ "id": "...", "folder_path": "/docs" }/api-referenceではなく/docs/api-referenceでアクセスできるようになりました。
例 9: コンテンツコレクション (ブログインデックス) を構築する
プロンプト: 「すべてのブログ記事を新しい順に並べて表示するブログ一覧ページを作成して」
ツール呼び出し:
create_collection— カテゴリフィルター、並べ替え、表示テンプレートを指定してコレクションを定義します:
ページ分割されたブログ一覧が{ "name": "Blog", "slug": "blog", "category": "blog", "sort_field": "created_at", "sort_order": "desc", "items_per_page": 10, "item_template": "<article><h2><a href=\"{{.Path}}\">{{.Title}}</a></h2><p>{{.excerpt}}</p><time>{{.PublishedAt}}</time></article>", "page_template": "<div class=\"blog-index\"><h1>Blog</h1>{{.Items}}{{.Pagination}}</div>" }/blogで公開され、カテゴリが "blog" のコンテンツが自動的に含まれるようになりました。
例 10: 動的なタグ付きインデックスページを構築する
プロンプト: 「すべてのコンセプトページをカテゴリ別にグループ化して自動的に一覧表示する用語集インデックスを作成し、新しいページを追加するたびに更新されるようにして」
ツール呼び出し:
-
create_snippet— 各結果のための再利用可能なレンダリングテンプレートを作成します:{ "name": "glossary-pill", "html": "<a href=\"{{.FullPath}}\">{{.Title}}</a>" } -
create_template—lc:queryディレクティブを埋め込んだインデックスページテンプレートを作成します:{ "name": "Concepts Index", "slug": "concepts-index", "fields": [ { "name": "intro", "label": "Introduction", "type": "textarea" } ], "html_layout": "<article class=\"index-page\">\n<h1>{{.title}}</h1>\n{{if .intro}}<p>{{.intro}}</p>{{end}}\n\n<h2>AI & Machine Intelligence</h2>\n<div class=\"links\">\n\n</div>\n\n<h2>Games & Interactive Experiences</h2>\n<div class=\"links\">\n\n</div>\n</article>" } -
create_content— 新しいテンプレートを使用してインデックスページを作成します:{ "template_id": "<concepts-index-template-id>", "title": "Concepts Glossary", "slug": "glossary", "data": { "intro": "An index of all concepts, grouped by category." } } -
update_content— 既存のいくつかのコンセプトページにタグを付けます (呼び出しごとに):{ "tags": ["AI & Machine Intelligence"] } -
publish_content— インデックスページを公開します;lc:queryディレクティブはこの時点で解決され、現在タグ付けされているすべてのコンテンツがすでに反映された状態でページが生成されます。
これ以降、一致するタグを持つ新しいコンセプトページが公開されるたびに、/glossary のインデックスページが自動的に再生成されます — 追加の操作は不要です。
例 11: 全文検索とコンテンツ監査
プロンプト: 「'pricing' に言及しているすべてのページを検索して、まだ下書きのものを教えて」
ツール呼び出し:
search_content— すべてのコンテンツフィールドを対象に全文検索を実行します:
一致するコンテンツ項目を、公開ステータス、パス、および一致したフィールドとともに返します:{ "query": "pricing", "search_type": "fulltext" }
その後、2 つの下書き項目を確認し、必要に応じて編集して公開できます。Found 4 results for 'pricing': - "Pricing Plans" at /pricing — published — matched in: content - "Enterprise FAQ" at /enterprise-faq — published — matched in: content, sidebar - "New Pricing Draft" at /new-pricing — draft — matched in: title, content - "Q1 Press Release" at /press/q1-update — draft — matched in: body
例 12: バルクコンテンツマイグレーション
プロンプト: 「/docs セクションのすべてのページに 'last_reviewed' フィールドを追加し、それらをすべて公開してください」
ツール呼び出し:
-
list_content— 1 回の呼び出しで/docs配下のすべてのコンテンツを完全なフィールドデータとともに取得します:{ "folder_path": "/docs", "include_data": true }ID、タイトル、現在のフィールド値、公開ステータスを 34 ページすべてについて返します。
-
(並列) エージェントは 50 件ずつのバッチに分かれ、
bulk_update_contentを同時に呼び出します:{ "updates": [ { "id": "abc123", "data": { "last_reviewed": "2026-03-24" } }, { "id": "def456", "data": { "last_reviewed": "2026-03-24" } } ], "version_comment": "Added last_reviewed field — Q1 2026 audit", "auto_republish": true }auto_republish: trueは、以前に公開されていたすべてのページを即座に再公開します — 別途公開ステップは不要です。
34 ページすべてが、34 回の逐次呼び出しではなく 2 回の並列呼び出しで更新され公開されます。
例 13: フォークベースの段階的リデザイン
プロンプト: 「公開前にプレビューできるように、ステージングエリアでホームページと /about ページをリデザインしてください」
ツール呼び出し:
-
create_fork— 名前付きのステージングワークスペースを作成します:{ "name": "Q2 Redesign", "description": "Homepage and About refresh" }フォーク ID を返します。ライブサイトはまったく影響を受けません。
-
fork_page— ホームページをフォークにコピーし、編集を適用します:{ "fork_id": "fork_abc123", "content_id": "homepage_id", "data": { "hero_headline": "Build the web with AI", "hero_subtext": "..." } } -
fork_page—/aboutに対しても同様の処理を行います:{ "fork_id": "fork_abc123", "content_id": "about_id", "data": { "body": "<p>Updated company story...</p>" } }ライブサイトにフローティングプレビューバーが挿入されます — フォーク Cookie を有効にしてアクセスすると、マージ後の両ページの表示を正確に確認できます。
-
merge_fork— 承認後、両方のフォークページをライブコンテンツにマージし、それらの静的 HTML を再生成します:{ "fork_id": "fork_abc123" }マージされたページの概要 (件数に加えて
created_idsとupdated_ids) と、検出された競合を返します。フォークが追加したページは、"publish_new": trueを渡さない限り下書きとして作成されます。保留中のページは常に下書きのままです。マージが成功すると、フォークのページコピーは削除されます。
例 14: 自動再公開を伴うサイト全体のお知らせ
プロンプト: 「/v1 ドキュメントセクションのすべてのページの先頭に非推奨のお知らせを追加し、それらを再公開してください」
ツール呼び出し:
bulk_field_operation— フォルダ全体にわたって特定のフィールドにお知らせを 1 回の呼び出しで追加します:
更新および再公開されたページの件数を返します。ライブサイトには即座に変更が反映されます。{ "operation": "prepend", "field": "body", "value": "<div class=\"deprecation-notice\"><strong>⚠️ This page covers v1 (deprecated).</strong> See <a href=\"/docs\">current docs</a>.</div>\n\n", "folder_path": "/v1", "auto_republish": true, "version_comment": "Added v1 deprecation notice" }
お知らせを削除する必要が生じた場合は、正確なお知らせの HTML を指定した 1 回の scoped_search_replace_execute で、すべてのページを 1 回の呼び出しで元に戻せます。
スニペットの操作
# List all snippets
list_snippets
# Create a callout snippet
create_snippet {
"name": "callout-warning",
"description": "Warning callout box",
"html": "<div class=\"callout callout-warning\"><strong>⚠️ {{.Title}}</strong><p>{{.Body}}</p></div>"
}
# Use a snippet inline in content
update_content {
"id": "...",
"data": {
"body": "Here is important information:\n\n[[include:callout-warning]]\n\nContinued text..."
}
}
コンテンツのタグ付けとインデックスページ
# Tag a page at creation time
create_content {
"template_id": "...",
"title": "Introduction to AI",
"slug": "intro-to-ai",
"tags": ["AI & Machine Intelligence", "Getting Started"],
"data": { "body": "..." }
}
# Inline tagging via content body
update_content {
"id": "...",
"data": {
"body": "This page covers #machine-learning and #neural-networks."
}
}
# Query directive in a template layout (for index pages)
バルク操作
# Step 1: Export all Concept Pages with specific fields
export_content {
"template_name": "Concept Page",
"fields": ["definition", "layer_badge"]
}
# Step 2: Transform the data externally, then bulk update
bulk_update_content {
"updates": [
{ "id": "abc123", "data": { "layer_badge": "<new html>" } },
{ "id": "def456", "data": { "layer_badge": "<new html>" } }
],
"version_comment": "Updated layer badges"
}
# Clear a field across all pages of a template
bulk_field_operation {
"operation": "clear",
"field": "old_badge",
"template_name": "Concept Page",
"version_comment": "Cleared deprecated field"
}
# Prepend a disclaimer to all blog posts
bulk_field_operation {
"operation": "prepend",
"field": "body",
"value": "<div class=\"disclaimer\">Views are my own.</div>",
"template_name": "Blog Post",
"version_comment": "Added disclaimer to all posts"
}
正規表現の検索と置換
# Preview: find all pages with old badge HTML pattern
scoped_search_replace_preview {
"search": "<div class=\"badge-v1\".*?</div>",
"replace": "",
"regex": true,
"template_name": "Concept Page"
}
# Execute after confirming preview
scoped_search_replace_execute {
"search": "<div class=\"badge-v1\".*?</div>",
"replace": "",
"regex": true,
"template_name": "Concept Page",
"version_comment": "Removed old v1 badge HTML"
}
ウィキリンク
# Link to another page by title
update_content {
"id": "...",
"data": {
"body": "See also: [[Machine Learning]] and [[AI Ethics|ethics considerations]]."
}
}
# Find what pages link to a given path
get_backlinks { "path": "/concepts/machine-learning" }
コンテンツのバージョニング
# See version history for a page
get_content_versions { "content_id": "abc123" }
# Restore a previous version
revert_to_version {
"content_id": "abc123",
"version": 3,
"version_comment": "Reverted to pre-redesign version"
}
開発
# Run with hot reload (using air)
go install github.com/cosmtrek/air@latest
air
# Build all binaries
go build -o bin/lightcms-server ./cmd/server
go build -o bin/lightcms-mcp ./cmd/mcp
go build -o bin/lightcms ./cmd/cli
# Run the server
./bin/lightcms-server
セキュリティに関する注意事項
本番環境では:
- 強力な
session_secretを使用してください — 最低 32 文字 (openssl rand -hex 32で生成します)。本番環境でこの要件が満たされていない場合、サーバーは起動時にハードフェイルします。 LIGHTCMS_ADMIN_EMAILを設定して、初期管理者アカウントが実際のメールアドレスを使用するようにしてください- 初回ログイン後、すぐにデフォルトの管理者パスワードを変更してください
- HTTPS を使用してください (nginx や caddy などのリバースプロキシの背後に配置します)
- MongoDB Atlas の IP ホワイトリストをサーバーの IP に制限してください
- API キーは所有ユーザーの権限を継承します — 管理者キーは安全に保管してください
/cm/auditで監査ログを定期的に確認してください- MongoDB データベースを定期的にバックアップしてください
- ユースケースに合わせて、サイト設定で
max_upload_bytesを構成し、ファイルアップロードサイズの上限を設定してください
組み込みのセキュリティ機能:
- すべての
/cmルートに対する CSRF 保護 - 管理画面の Content-Security-Policy: スクリプトとスタイルシートはサイト自体からのみ読み込みます (エディターの Quill ファイルはベンダリングされており、CDN から取得されません)
- すべての管理ハンドラーおよび REST API エンドポイントに対する RBAC 権限チェック
- セッション Cookie: SameSite=Strict、24 時間の有効期限、本番環境では Secure
- ファイルアップロード: 拡張子ホワイトリスト + MIME 検証 + 構成可能なサイズ上限
- API リクエストボディの上限: すべての
/api/v1/エンドポイントで 10 MiB を適用 - ログインのレート制限: 段階的なロックアウト (1 分 → 5 分 → 15 分)
- エンドポイントごとのレートリミッター: 再生成 (2/分)、検索置換の実行 (10/分)、一括更新 (5/分)、エクスポート (5/分)、再インデックス (1/分)
- パスワード: bcrypt (cost=12)
- すべての変更に対する監査ログ (365 日間保持)
- Fly.io デプロイメント: 実際のクライアント IP に
Fly-Client-IPヘッダーを使用 (X-Forwarded-Forと異なり、なりすまし不可) - チャットウィジェットのプロンプトインジェクション対策: ユーザー入力を XML デリミタでラップし、
</シーケンスをエスケープ
プライバシーポリシー
LightCMS はセルフホスト可能なソフトウェアです — データベース、ホスティング、データはすべてお客様が管理します。MCP サーバーと CLI ツールは REST API を介してお客様の LightCMS インスタンスに接続します — データが Metavert LLC や第三者に送信されることはありません。
プライバシーポリシーの全文はこちらをご覧ください: https://www.metavert.io/lightcms-privacy-policy
ライセンス
MIT
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。