Creatif Space について
Creatif Spaceは、AIクライアントからソーシャルコンテンツを管理するリモートMCPサーバーです。下書き、承認、公開、レポートに対応し、公開操作の前にプレビューと確認を行います。
主な機能
- 01チャンネル、投稿、ファイルの一覧
- 02ソーシャル投稿の作成と編集
- 03承認リンクの作成と追跡
- 04公開前のプレビューと確認
- 05インサイトとレポートの確認
活用シーン
- 01キャンペーン用の投稿準備
- 02クライアントへの下書き承認依頼
- 03投稿の予約または再試行
- 04パフォーマンスレポートの共有
MCP 対応
Creatif Spaceのアカウント、コンテンツ、承認、公開、インサイト機能をMCPツールとして提供します。呼び出し元のBearerトークンで既存のV1 APIにアクセスします。
設定
リモートサーバーはインストール不要です。クライアントを選んで設定をコピーするか、ワンクリックで導入できます。
https://mcp.creatif.space/mcpclaude mcp add --transport http creatifren-creatif-space https://mcp.creatif.space/mcp{"mcpServers":{"creatifren-creatif-space":{"type":"http","url":"https://mcp.creatif.space/mcp"}}}Cursor で開く{"servers":{"creatifren-creatif-space":{"type":"http","url":"https://mcp.creatif.space/mcp"}}}VS Code で開く{"mcpServers":{"creatifren-creatif-space":{"type":"http","url":"https://mcp.creatif.space/mcp"}}}{"mcpServers":{"creatifren-creatif-space":{"serverUrl":"https://mcp.creatif.space/mcp"}}}コマンドはターミナルで実行し、JSON は各クライアントの MCP 設定に貼り付けて再起動します。認可が必要なサーバーは初回接続時にログインを求めます。
ツール
詳細
creatif.space MCP サーバー
creatif.space 用のリモート MCP サーバーです。コネクター
URL:https://mcp.creatif.space/mcp(/ でも応答します)。Streamable HTTP、ステートレス、Node 22、
公式の @modelcontextprotocol/sdk を使用しています。
これは薄いレイヤーです。各ツールは呼び出し元自身のベアラートークンを使って既存の V1 API を呼び出すため、所有権、プラン、Credits、検証は引き続き Laravel が処理します。ビジネスロジックはここにはありません。
60 秒で試す(Claude)
- Claude で Settings → Connectors → Add custom connector を開き、名前を
creatif.spaceにして、コネクター URL を貼り付けます:https://mcp.creatif.space/mcp - Connect をクリックし、creatif.space にサインインしてアクセスを許可します。これで Claude は チャンネル、下書き、承認リンクを参照できます。あなたの OK なしに投稿されることはありません: 送信のたびに、まずプレビューが表示されます。
- 次のいずれかを尋ねます。それぞれ、すぐに使えるプロンプトを実行します(Claude の
プロンプトメニューにもあります):
- 「来週の計画を立てて:冬のローンチについて Instagram の投稿を 5 件。」 →
plan_weekがチャンネル用の投稿を下書きします。下書きのみで、投稿はされません。 - 「承認のために、下書きを [email protected] に送って。」 →
send_for_approvalが、クライアントが承認したり変更を依頼したりできる承認リンクを作成します。 - 「今週の結果はどうだった?クライアント用のリンクを作って。」 →
weekly_resultsが直近 7 日間の結果をまとめ、誰でも開けるリンクを作成します。 - 「クライアント用に先月のレポートを作って。」 →
monthly_reportが 1 か月分の結果をまとめ、同様のリンクを作成します。
- 「来週の計画を立てて:冬のローンチについて Instagram の投稿を 5 件。」 →
エンドポイント
| パス | 内容 |
|---|---|
POST /mcp(および POST /) | MCP JSON-RPC(ベアラー認証が必要) |
GET /health | 稼働状況。認証不要:{ok, name, version} — serverInfo と同じバージョン(package.json から取得。CHANGELOG.md を参照) |
GET /.well-known/glama.json | Glama コネクターの申告。認証不要(HEAD にも対応)。同じドキュメントを GET /mcp/.well-known/glama.json でも提供 |
GET /.well-known/oauth-protected-resource | RFC 9728 メタデータ:resource: "https://mcp.creatif.space/mcp"、authorization_servers: ["https://api.creatif.space"] |
GET /.well-known/oauth-protected-resource/mcp | RFC 9728 のパス形式による同じドキュメント |
POST /free | Creatif Space Free Tools — 独立した MCP サーバー。認証不要、IP ごとに 1 分あたり 30 回 |
/mcp、/、/free における CORS(MCP Inspector web や Web IDE などのブラウザークライアント向け):OPTIONS → 204。Access-Control-Allow-Origin: *(認証情報は使用しません — 認証には Bearer ヘッダーのみを使用)、Allow-Methods: GET, POST, DELETE, OPTIONS、Allow-Headers: authorization, content-type, mcp-protocol-version, mcp-session-id, last-event-id、Expose-Headers: mcp-session-id, www-authenticate、Max-Age: 600。401 や 429 を含め、これらのパスからのすべての応答に同じヘッダーが付与されます。Node アプリ(src/cors.ts)で処理します。nginx は OPTIONS をそのまま通し、独自の
Access-Control-* ヘッダーを追加してはいけません。
トークンがない、または無効な場合 → 401 と
WWW-Authenticate: Bearer resource_metadata="https://mcp.creatif.space/.well-known/oauth-protected-resource/mcp"(RFC 9728 のパス形式。オリジンから構築。ルートの well-known も同じドキュメントを提供します)。
認証
トークン(Passport OAuth 2.1 アクセストークンまたは cs_live_… API キー)は、
POST {V1_API_URL}/oauth/introspect、ヘッダー X-MCP-Secret、本文 {token} →
{active, user_ulid, scopes[], client_id, client_name, token_type, exp} で検証されます。
応答は 60 秒間キャッシュされます(exp を超えることはありません)。同じベアラーがその後、
V1 のルートに転送されます(OAuth PR に組み込まれた mcp ガードを使用します)。
スコープ(scopes_supported):read、draft、approve、publish、approvals:decide — API の
config/mcp.php と同じ名前です。すべての V1 呼び出しには、API の監査ログ用に
X-MCP-Tool と X-MCP-Client が含まれます(コンテンツは含まれません)。
レート制限:トークンあたり 1 分間に 60 リクエスト(429 + Retry-After)。
クライアントは、動的クライアント登録(POST /oauth/register)または OAuth の
クライアント ID メタデータドキュメントによって client_id を取得します。
client_id は、{client_id, client_name, redirect_uris, token_endpoint_auth_method: "none"} を配信する https URL です。API はこれを
取得し(公開アドレスのみ、リダイレクトなし、≤ 5 KB、Cache-Control に従って
5 分〜24 時間キャッシュ)、client_id_metadata_document_supported: true を通知します。
ツール
| ツール | スコープ | V1 エンドポイント |
|---|---|---|
list_channels — 再接続が必要なチャンネルには reconnect {reason, next_step} が含まれ、needs_reconnect に一覧表示されます | 読み取り | GET /social-accounts |
list_posts (status: draft, waiting, changes_requested, scheduled, published, failed, cancelled; from/to は日付または時刻; channel_id, limit) — waiting / changes_requested は status=scheduled を読み取り、承認待ちの投稿を保持します | 読み取り | GET /social-posts?status&from&to&account_id&limit |
list_failed_posts (limit, cursor) — 過去 30 日間、チャンネルごとの failure_code + reason。一部のチャンネルのみ公開に失敗した投稿では、失敗したチャンネルのみ一覧表示します | 読み取り | GET /social-posts?status=failed + ?status=published (from/to = 過去 30 日間) |
get_post | 読み取り | GET /social-posts/{id} |
list_files (search, type, folder_id, limit) | 読み取り | GET /files |
draft_post (caption, channel_ids, file_ids, media_urls, captions_by_channel, type) | 下書き | POST /social-posts with draft: true |
get_account_summary — 1 回の呼び出しでオンボーディングに必要な情報を取得します:プラン、使用済み/残りの上限、残りの Credits、接続済み/再接続が必要なチャンネル、使用済みストレージ、failed_posts (過去 30 日間)、approvals {waiting, changes_requested}、next_steps | 読み取り | GET /credits, GET /social-accounts, GET /files/usage, GET /social-posts?status=failed + ?status=published (list_failed_posts と同様), GET /social-posts?status=scheduled |
get_onboarding — 「Get started」チェックリスト (接続、下書き、送信、公開)。各項目は {done, at} を含み、next {step, tool, suggest} は次に提案するステップです | 読み取り | GET /me/onboarding |
get_credits — プラン、上限、Credits。spend (今月のアクション別:publish, reply, ai) および renewal (resets_at, days_until) | 読み取り | GET /credits (limits.spend) |
create_approval_link (post_ids — または Content Plan: date_from, date_to, timezone, channel_ids — approver_email (必須 — クライアントはこのメールアドレスでサインインして決定します), title, client_name, expires_in_hours) — あらゆるプランに対応。Free:クライアント 1 名 (approver_email で判定)、7 日間、キュー登録 10 件 | 承認 | POST /social-approval-links (下書きも受け付けます) |
create_content_plan (date_from, date_to, timezone, channel_ids, approver_email, title, client_name, expires_in_hours, confirm) — まずプレビューを表示します。confirm: true で Content Plan を作成し、承認者にメールを送信します | 承認 | GET /social-accounts, GET /social-posts?from&to (プレビュー); confirm: true → POST /social-approval-links with notify_approver: true |
check_approval_status (post_id | link_id) | 読み取り | GET /social-posts/{id} または GET /social-approval-links/{id} |
send_approval_reminder (link_id) | 承認 | POST /social-approval-links/{id}/remind (リンクごとに 12 時間に 1 回) |
update_post (caption, scheduled_at, labels, file_ids | add_file_ids) | 下書き (下書きおよび承認待ちの投稿のみ) | PATCH /social-posts/{id} |
schedule_posts (posts: [{post_id, scheduled_at}] 最大 10 件、confirm) — すべての投稿のプレビューと合計 Credits を一度に表示します。confirm: true ですべてを予約するか、何も予約しません | 公開 | 各投稿のプレビューは GET /social-posts/{id}/send-preview; confirm: true → POST /social-posts/send-batch (まずすべてを確認し、拒否された場合はすでに送信された投稿を取り消します) |
schedule_post (post_id, scheduled_at, confirm) | 公開 | プレビュー GET /social-posts/{id}/send-preview; confirm: true → POST /social-posts/{id}/send |
publish_post (post_id, confirm) | 公開 | 同様に、今すぐ送信します |
retry_post (post_id, confirm) — 投稿のうち失敗したチャンネルに再度送信します。プレビューには各 failure_code と理由が表示されます | 公開 | プレビュー GET /social-posts/{id}/retry-preview; confirm: true → POST /social-posts/{id}/retry |
get_insight_summary (period: {month} | {from, to} ≤ 92 days, channel_ids) — Pro / Max。Free → plan_required | 読み取り | GET /insight/summary?month | from&to&channel_ids |
list_top_posts (period: {month} | {from, to} ≤ 92 days, channel_ids, limit, cursor) — Pro / Max。Free → plan_required | 読み取り | GET /insight/top-posts?month | from&to&channel_ids |
get_best_times (days 7–92, channel_ids) — Pro / Max。Free → plan_required | 読み取り | GET /insight/best-times?days&channel_ids |
get_insight_csv_link (from, to ≤ 366 days, channel_ids) — Pro / Max。Free → plan_required | 読み取り | POST /insight/export-csv-link |
get_insight_report_link (from, to ≤ 92 days, format onepage|deck|details, channel_ids, locale) — Insight PDF (1 ページ、16:9 のデッキ、または詳細版) をダウンロードするための 15 分間有効な署名付きリンクです。Pro / Max | 読み取り | POST /insight/export-link |
create_insight_share_link (from, to ≤ 92 days, channel_ids, recipient_email) — Insight レポートへの読み取り専用ウェブリンクです。アカウントなしで 30 日間閲覧できます。recipient_email を指定すると、その宛先に一度メールが送信され、list_shared_with_me に表示されます | 承認 | POST /insight/share |
revoke_insight_share_link (share_id) — 共有 Insight リンクをすぐに無効にします | 承認 | DELETE /insight/share/{id} |
request_media_upload (filename, mime, size_bytes, folder_id) | 下書き | POST /files/presign → file_id + 署名付き PUT URL (15 分間有効) |
confirm_media_upload (file_id) | 下書き | POST /files/{id}/complete (409 → GET /files/{id}:すでに準備完了の場合はその状態を返します) |
list_conversations (type comment|dm, channel_id, unread_only, since, limit, cursor) — Engage のコメントと DM を 1 つのリストにまとめ、新しい順に表示します | 読み取り | GET /inbox/feed?type&account&unread&since&per_page&cursor |
reply_to_conversation (conversation_id, text, confirm) — DM のスレッドへの返信、またはコメントへの公開返信です | 公開 | プレビュー GET /inbox/feed/{id}; confirm: true → POST /inbox/feed/{id}/reply |
get_storage_usage — 使用量とクォータ (Free:合計 1 GB。有料プラン:Keep クォータ)、保持済みと自動削除の対象 (最も近い日付)、最新の 300 ファイルを表示します | 読み取り | GET /files/usage + GET /files?per_page=60&page=1..5 |
keep_file (file_id) — Pro/Max。Free → plan_required、クォータ超過 → storage_full、未準備 (409) → file_not_ready | 下書き | POST /files/{id}/keep |
unkeep_file (file_id) — 保持ルールに戻します。auto_delete_at を返します | 下書き | DELETE /files/{id}/keep |
suggest_caption (brief, platform) — ユーザーのスタイルに合わせたキャプションとハッシュタグを提案します。保存はしません。Pro/Max。AI_CAPTION_ENABLED がオフの場合は 404 → not_enabled ("キャプションを自分で書いてください")、Free → plan_required | 下書き | POST /ai/caption |
discard_draft (post_id, confirm) — 下書きのみを削除します。まずプレビューを表示し、confirm: true で削除します。scheduled / published / failed の場合は、次のステップとともに not_draft を返します | 下書き | GET /social-posts/{id}, then DELETE /social-posts/{id}/draft |
list_approval_links (status active|expired|revoked|all, limit) — ステータス、承認者のメールアドレス、投稿数、承認済み/承認待ち/修正依頼を表示します | 読み取り | GET /social-approval-links |
revoke_approval_link (link_id, confirm) — プレビューを表示してからリンクを完全に取り消します。未回答の投稿はユーザーに戻されます | 承認 | GET then DELETE /social-approval-links/{id} |
list_waiting_approvals — 他のユーザーがこのユーザーに承認を依頼した投稿 | approvals:decide | GET /me/approvals/waiting |
decide_approval (link, post_id, decision approve|revise, reason, confirm) — 承認者側の操作です。承認ページと同じルールに従い、mcp として監査記録されます | approvals:decide | プレビュー GET /me/approvals/{post}/preview; confirm: true → POST /me/approvals/{post}/decision |
list_spaces (status draft|published|archived, search, limit) — Pro/Max | 読み取り | GET /spaces?tab&search |
create_space_from_files (title, file_ids 1–100, view_mode) — 常に Draft+Private Space として作成され、公開されることはありません。Pro/Max | 下書き | POST /spaces with file_ids (作成前に検証されます) |
publish_space (space_id, confirm) — Pro/Max | 公開 | プレビュー GET /spaces/{id}/publish-preview; confirm: true → POST /spaces/{id}/publish |
get_approval_history (post_id) — 1 件の投稿に対するすべての決定を古い順に表示します:実行者 (メールアドレスはマスク)、日時、決定、コメント | 読み取り | GET /social-posts/{id}/approval-audit |
get_plan_calendar_link (link_id) — Content Plan の ICS フィード URL (予約済み投稿、キャプションの先頭 60 文字)。読み取り専用で、URL は固定です | 読み取り | GET /social-approval-links/{id}/calendar |
get_approval_audit (link_id) — ユーザーのリンクに関するすべての決定を表示します:実行者、投稿、日時、決定、コメント。行単位および CSV で取得できます | 読み取り | GET /social-approval-links/{id}/audit.csv |
send_feedback (kind bug|idea|other, message, page) — creatif.space チーム宛てです。公開されず、Credits も消費しません。ユーザーあたり 1 時間に 10 件まで | 下書き | POST /feedback |
get_notification_settings — ユーザーが受信するメールの種類:post_missed_or_failed (“Post missed / failed”;API が独自のキーを提供しない限り、publish_failed スイッチ)、approval_decided、weekly_digest | 読み取り | GET /me/notification-settings |
update_notification_settings (post_missed_or_failed — または旧名称の publish_failed —、approval_decided、weekly_digest: true/false;月曜 08:00 のダイジェストのタイムゾーン;少なくとも 1 つ指定) | 下書き | PATCH /me/notification-settings |
list_shared_with_me — 「自分と共有されたレポート」:他のユーザーがこのユーザーのメールアドレス宛てに共有した Content Plan と Insight レポート | approvals:decide | GET /me/reports/shared |
get_connect_link (network) — 手順を含むアプリの接続ページ (https://creatif.space/social/connect?network=…) です。レスポンスにトークンは含まれません。上限に達したプランで新しいネットワークを追加する場合は plan_required | 読み取り | GET /social-accounts + GET /credits (POST /social-accounts/auth-url は使用しません) |
メディアのアップロード。 request_media_upload → クライアントが URL に正確なバイト列を PUT します(Content-Type と Content-Length は署名されます)→ confirm_media_upload → ID は draft_post / update_post の file_ids に指定します。アプリと同じ署名付き URL の発行と完了処理を使うため、すべてのルールは Laravel で適用されます。Free は合計 1 GB、Pro は 25 GB、Max は 50 GB の容量上限、ファイルごとの上限、対応形式、マジックバイトのチェックが含まれます。拒否された場合は、storage_full(空き容量確保用の files_url とアップグレード用の billing_url リンク)、file_too_large、unsupported_format、upload_limit、upload_incomplete(PUT の前に確認)、file_not_ready(投稿内で未確認または別ユーザーの ID を使用)として返されます。別のワークスペースの ID は not_found になります。 |
confirm: true を指定せずに schedule_post / publish_post を呼び出すと、プレビューのみが返されます(チャンネル、Credit のコスト、本日残りの送信数、ブロック要因)。ベアラートークンによる送信は、ユーザーごとに UTC の 1 日あたり 20 件までに制限され、Laravel で適用されます(CapTokenSends、429 daily_send_cap)。アプリの Cookie セッションには上限がありません。
confirm_token。 送信プレビューでは、API が署名した confirm_token が返されます(アプリキーを使った HMAC。ユーザー、投稿、ターゲット ID、Credit の価格に紐付き、有効期間は 10 分です)。ベアラートークン(MCP ガードまたは API キー)による送信では、このトークンを再送する必要があります。トークンがない場合は 422 confirm_token_required、不一致、期限切れ、または偽造の場合は 409 preview_stale になります。承認待ちの下書きとアプリの Cookie セッションには不要です。このサーバーは、ユーザーと投稿ごとに最後のプレビューのトークンをメモリ上に保持し、confirm: true の際に送信します。モデルにトークンが見えることはありません。プレビューの記録がない場合(表示されていない、期限切れ、使用済み、サーバー再起動後)は、新しいプレビューを返すだけで送信は行われません。409 の場合は、新しいプレビューを details.preview に含むツールエラー preview_stale が返されます。
承認と編集には API のルールが適用されます。 クライアントの承認が必要な下書き(またはクライアントが変更を求めた下書き)は、アプリからでもトークンからでも送信・予約されません(409 approval_required)。クライアントに再度承認を求めることのみ可能です。トークンを使っても、編集者自身の承認手順を省略することはできません。トークンで編集できるのは、承認待ちの下書きと投稿のみです(409 not_editable)。
Spaces。 接続済みアプリでは Pro と Max のみ利用できます。トークンがアクセスできるすべての Spaces ルートは config('mcp.route_features') に定義されているため、Free の呼び出し元にはコントローラーの実行前に EnforceTokenScope から標準の 402 plan_required(feature: "spaces")が返されます。ただし、アプリでは Free ユーザーの既存の Spaces も引き続き表示されます。publish_space は publish_post と同様に動作します。プレビューでは confirm_token が返され(ユーザー、Space、タイトル、アドレス、公開範囲、パスワード、有効期限、ファイルの HMAC。10 分間有効)、このサーバーが保持して confirm: true の際に送信します。トークンによる公開でこれがない場合は 422 confirm_token_required、Space が変更された場合は 409 preview_stale になります。プレビューには、公開をブロックする要因(active_slots_full)と警告事項(no_handle:アドレス未設定、empty、expired)も表示されます。Space のリンクは {public_url}/{handle}/{slug} です(public_url は Space リソースに含まれ、ハンドルがない場合は null)。
プランの制限にも API のルールが適用されます(プラン定義は PlanSeeder に一元化され、PlanQuota で適用されます)。Free では最大 7 日先(UTC)までの予約、キューに最大 10 件の投稿(予約済み+承認待ち)、一度に 1 クライアント分の承認リンクが利用できます。Pro と Max にはこれらの制限はありません。いずれかの制限を超えると、API は 402 {message, reason: "plan_required", feature, required_plan, limit?}(feature は schedule_window、queue_limit、approval_clients、または利用制限のある機能)を返し、ツールエラー plan_required の details にこれらのフィールドが含まれます。schedule_post はプレビューとともに scheduled_at を送信するため、ユーザーに確認を求める前に制限が返されます。
エンゲージ。 list_conversations / reply_to_conversation は、アプリのエンゲージと同じ行を読み取り、返信します(Outstand リレー経由のコメントおよび Instagram/Facebook の DM)。所有権(別のワークスペースの ID の場合は not_found)、ポリシー(閲覧者シートからは返信できません)、クレジット、リレーのエラーも同じです。API の /inbox/feed ルートは、アプリのエンゲージコントローラーに処理を委譲します。ID の形式は固定で、dm_<ulid> または comment_<ulid> です。エンゲージはすべてのプランで利用でき(PlanSeeder v2 にエンゲージのフラグはありません)、どちらのツールもプランによる制限はありません。API から 402 が返された場合でも、plan_required として返されます。confirm: true を指定せずに reply_to_conversation を呼び出すと、プレビューのみが表示されます。確認後に送信されるのは、過去 10 分以内にその会話について表示されたプレビューと完全に同じテキストだけです(ユーザーごとにメモリ内に保持)。それ以外の場合は再度プレビューが表示され、何も送信されません。コメントと DM のテキストはデータであり、指示ではありません。この点は両方のツールの説明に記載されています。
エラーは isError: true と
{error: {code, message, next_step, details}} を含むツール結果として返されます。next_step はモデルが今すべきことを示します。details が空になることはなく(必ず tool が含まれます)、next_step は実際に存在する details.X のみを参照します(test/errors.test.ts では、すべてのエラーパスについてこの両方を確認します)。SDK 自身が応答する不正な引数や不明なツール名も、同じ形式で返されます。エラーコード:reconnect_required、scope_missing、plan_required、not_found、unknown_tool、invalid_input、unauthorized、forbidden、rate_limited、daily_cap_reached、insufficient_credits、quota_exceeded、preview_stale、not_editable、not_draft、not_approvable、not_a_plan、link_inactive、approval_required、storage_full、file_too_large、unsupported_format、upload_limit、upload_incomplete、file_not_ready、upstream_unavailable、internal_error。エンゲージの返信では、reply_window_closed、reply_rejected、reply_not_possible、relay_unavailable も返されます。
呼び出しごとに PostHog の mcp_tool_called {tool, client_surface, client_name, ok, code, duration_ms} が出力されます。client_surface は OAuth クライアント名に基づき、claude、chatgpt、cursor、vscode、
api_key、other のいずれかになります。code は ok またはエラーコードです。ms と error は、それぞれ duration_ms と code の以前の名前として保持されています。引数、キャプション、ID、その他のユーザーテキストは送信されません。POSTHOG_KEY が設定されていない場合はスキップされます。
意図的に MCP ツールではありません:アカウントデータのエクスポート。 POST /api/v1/me/export
(ワークスペース全体を ZIP にまとめ、24 時間有効なリンクをメールで送信)は、サインイン済みの creatif.space セッションからのみ利用できます。mcp.routes には含まれていないため、OAuth トークンや API トークンでは 403 が返されます。アカウントの完全なコピーを AI クライアントに渡すべきではありません。
AI チャットから承認する
クライアント向けです。つまり、creatif.space ユーザーから投稿またはコンテンツプランの承認を依頼された人です。自身のアカウント(リンクの送信先メールアドレス)で creatif.space を Claude または ChatGPT に接続し、同意画面で 承認の決定(approvals:decide)を許可すると、承認ページを開かずに確認して決定できます。
| ツール | 機能 |
|---|---|
list_shared_with_me | 「あなたと共有されたレポート」:ユーザーの確認済みメールアドレス宛てに共有されたコンテンツプランとインサイトレポートについて、タイトル、日付、送信者、リンク(プランの場合は、承認待ちの投稿数も表示します)。 |
list_waiting_approvals | ユーザーの決定を待っているすべての投稿と、決定に使用するリンク ID および投稿 ID を表示します。 |
decide_approval | 承認するか、理由を添えて修正を依頼します。必ず最初にプレビューを表示し、ユーザーが同意した後、confirm: true の場合にのみ決定します。 |
オーナー側には、さらに 2 つのツール(スコープ read)があります。get_approval_audit は、オーナー自身のリンクのうち 1 つについて、誰がいつ何を決定したかをコメントとともに行および CSV で表示します。get_approval_history は、承認者のメールアドレスをマスキングしたうえで、1 つの投稿が含まれていたすべてのリンクにわたる同じ履歴を表示します。
ツールが適用するルール(API が強制し、ツールは説明のみを行います):
- ユーザーの確認済みメールアドレス宛てのリンクのみが対象です。それ以外の人には、想定されるアドレスのヒントとともに
forbiddenが返されます。別のワークスペースの ID にはnot_foundが返されます。 - すべての決定は 2 段階です。プレビューの後に確定します。確定時には、ユーザーが確認した投稿そのものに対する署名付きトークン(有効期限 10 分)が送信されます。その間に投稿が編集された場合は、新しいプレビューとともに
preview_staleが返され、決定は行われません。トークンがモデルに渡されることはありません。 - 承認ページと同じルールが適用されます。投稿はプランの日付とチャネルの範囲内にあり、まだ承認待ちである必要があります。送信者が Free プランの場合、決定できるのは今後 7 日分のみです(
decidable_fromを含むinvalid_inputが返されます)。 - すべての決定は
source: mcpとして監査記録に残り、送信者にはページからの場合とまったく同じように通知されます。 - 最初の承認待ち投稿の公開日の 1 日前に、承認者にリマインダーメールが 1 通送信されます(プランごとに 1 回。メールからオフにするか、オーナーが
PATCH /social-approval-links/{id}{reminders: false}を指定してオフにできます)。
会話例
Rani: 今週、承認が必要なものはありますか?
Claude が
list_shared_with_meとlist_waiting_approvalsを呼び出します。Claude: Bro からコンテンツプラン December が 1 件共有されています (12 月 1 日〜31 日、Asia/Jakarta)。2 件の投稿が承認待ちです:
- 「発売日 — 全品 20% オフ…」— Instagram、12 月 2 日(水)09:00
- 「スタジオの舞台裏」— Instagram、12 月 4 日(金)18:00
Rani: 1 つ目を承認してください。2 つ目は、チームが写っている写真を使うよう伝えてください。
Claude は投稿 1 に対して
decision: "approve"、投稿 2 に対してdecision: "revise"とreason: "Please use the photo with the team in it"を指定してdecide_approvalを呼び出します。どちらもconfirmを指定しないため、両方ともプレビューが返されます。Claude: 次の内容で進めます:
- 承認:「発売日…」— 12 月 2 日(水)09:00 に Instagram で公開されます。
- 修正を依頼:「スタジオの舞台裏…」— Bro に「チームが写っている写真を使ってください」と伝えます。
進めてもよろしいですか?
Rani: はい。
Claude は投稿ごとに 1 回ずつ、同じ引数と
confirm: trueを指定してdecide_approvalを再度呼び出します。Claude: 完了しました。「発売日…」は承認され、水曜日の 09:00 に公開されます。Bro には「スタジオの舞台裏…」についてメモを送りました。ほかに承認待ちのものはありません。
オーナー側では、後日次のように確認できます:
Bro: 12 月の発売投稿を誰がいつ承認しましたか?
Claude がプランのリンク ID を指定して
get_approval_auditを呼び出します。Claude: Rani([email protected])は、12 月 1 日 03:10 UTC に「スタジオの舞台裏…」の修正を依頼しました(「チームが写っている写真を使ってください」)。また、03:10 UTC に「発売日…」を承認しました。どちらも AI チャットからの操作です。CSV も必要ですか?
ツールのアノテーション
すべてのツールには、人が読める title があり、4つの MCP ヒントを明示的な
ブール値として設定します。list_*、get_*、check_* は
readOnlyHint です。公開投稿、削除、取り消し、または取り消せない決定の記録を行うものは
destructiveHint です。対象は publish_post、schedule_post、schedule_posts、
reply_to_conversation、retry_post、publish_space、discard_draft、
unkeep_file、decide_approval、revoke_insight_share_link です。公開投稿
(ソーシャルネットワークまたは公開ウェブ)を行うツールのみが
openWorldHint です。対象は publish_post、schedule_post、schedule_posts、
reply_to_conversation、retry_post、publish_space です。ディレクトリの審査フォーム向けの
ツールごとの説明は、docs/tool-justifications.md にあります。
test/annotations.test.ts はこれらのルールと同ファイルを確認し、スナップショットで
すべてのツールのヒントを固定します。すべてのツールのスコープ、ヒント、説明、入力を網羅した
リファレンスは docs/mcp-tools.md です。提供される
ツール一覧から npm run docs:tools で生成されます。test/tools-doc.test.ts は、古くなっている場合に CI を失敗させます。
プランのエラーと ChatGPT
どのクライアントについても、ツールの説明に価格、プランの階層、アップグレードについての記述はありません
(test/no-upsell.test.ts)。OAuth クライアントが ChatGPT の場合、API の
イントロスペクションで client_surface: "chatgpt" と判定されるとき(DCR 名、または
chatgpt.com / openai.com のリダイレクトホスト)、あるいはクライアント名に
ChatGPT / OpenAI が含まれるときは、すべての 402 または plan_required が次のようになります。
{ "error": { "code": "not_available_on_plan", "message": "This isn’t available on this account’s plan.", "next_step": "…no plan change or purchase…", "details": { "tool": "…" } } }
アップグレードリンクや価格提示の手順はなく、その他のエラーからは課金/チャージの
リンクが取り除かれます。他のクライアントには、API のメッセージとリンクが変更されずに返されます
(test/chatgpt-surface.test.ts)。
レート制限(429)
すべてのツールは、API の 429 を同じエンベロープに変換します。
{code: 'rate_limited', message, next_step, details: {retryable: true, retry_after_seconds}}。
message: API 独自のテキストです。retry_after_seconds: 本文のretry_after、なければRetry-Afterヘッダー(EnforceTokenScopeのトークン制限ではヘッダーのみが送信されます)、それもなければ 60 が使われます。
2種類の 429 は、それぞれ独自のコードを維持します。upload_limit(本日のアップロードが一時停止中)と
daily_cap_reached(接続済みアプリからの送信が1日20回に達した場合)です。test/ratelimit.test.ts はすべてのツールに 429 を送信します。
冪等性(二重送信)
API は Idempotency-Key を含む POST を、ユーザーごと、キーごとに24時間に1回だけ
実行します。再度送信すると、最初の応答が返され(Idempotent-Replayed: true)、
処理は再実行されません。これは公開/予約送信(/send)、/retry、承認リンクの作成に適用されます。
サーバーは確認ごとに1つのキーを送信します。
publish_post、schedule_post、retry_postは、確認済みプレビューのトークンからキーを 生成します。確認を2回送信しても、送信と課金はそれぞれ1回だけです。create_approval_linkは、10分間のウィンドウ内で引数からキーを生成します。同じリンクを2回要求しても、作成されるのは1つです。
キーはハッシュです。トークンや引数が含まれることはありません。2xx の 応答のみが保持されるため、拒否された確認は、原因を解消すれば再送信できます。
ページネーション
すべての list_* ツールは同じ方法でページ分割します。limit と cursor を受け取り、
next_cursor(次のページがない場合は null)を返します。同じフィルターを指定して
next_cursor を cursor として渡すと、次のページを取得できます。
- 不透明なカーソル: ツール、位置、フィルターのフィンガープリントが含まれます。別のリストからのカーソルや、
異なるフィルターで再利用されたカーソルは、次の手順「カーソルなしで最初からやり直す」とともに
invalid_inputとして拒否されます。 list_posts:GET /social-postsのlimit+offsetでページ分割し、次のページがあるか確認するために行を1つ余分に取得します。list_files: API のページ番号に従います。カーソルには最初のページのページサイズが保持されます。list_conversations: インボックス独自のカーソルを使用します。- その他: API から全件を受け取り、サーバー側でページ分割します。
src/tools/paging.ts。テストは test/pagination.test.ts にあります。
構造化出力
list_channels、list_posts、get_post、get_credits、
list_waiting_approvals、check_approval_status、get_insight_summary、
list_files、list_spaces、get_storage_usage は outputSchema を宣言し、
structuredContent を返します。古いクライアント向けに、同じ JSON はテキストブロックにも含まれます。スキーマ(src/tools/outputs.ts)では、エージェントが依存するフィールドの名前と型を定義し、新しいフィールドも受け入れるため、API にフィールドが追加されても呼び出しは失敗しません。エラー結果には structuredContent は含まれず、エラーエンベロープがテキストに含まれます。
プロンプト
prompts/list / prompts/get では、すぐに使える 3 つのワークフローを提供します。それぞれ、既存のツールのみを使ってモデルに手順を示す 1 つのユーザーメッセージです(送信はすべて、引き続きツール独自のプレビューと confirm を経由します)。ユーザーが入力した引数は引用符で囲まれ、データとして明示されます。定義場所は src/prompts.ts です。
| プロンプト | 引数 | 使用するツール |
|---|---|---|
plan_week(「来週の計画」)— チャンネル向けに 1 週間分の投稿を下書きします(下書きのみ) | channel_id*、week_start、theme、posts(1~7) | list_channels、list_posts、suggest_caption、draft_post |
send_for_approval(「クライアントに承認を依頼」)— 下書きを 1 つの承認リンクにまとめます | approver_email*、post_ids(カンマ区切り)、client_name | list_posts、get_post、create_approval_link、check_approval_status |
weekly_results(「週間結果」)— 過去 7 日間(または 1 か月分)を集計し、共有リンクを作成します | month(過去 7 日間の代わりに指定する YYYY-MM)、share(yes|no) | get_insight_summary、create_insight_share_link |
monthly_report(「月次レポート」)— 1 か月分を集計し、共有リンクを作成します | month(YYYY-MM、デフォルトは先月)、share(yes|no) | get_insight_summary、create_insight_share_link |
レジストリメタデータ
mcp/server.json:公式 MCP レジストリエントリー(io.github.creatifren/creatif-space、リモートhttps://mcp.creatif.space/mcp、エントリーバージョン1.2.2)。パブリッシャーが提供する_metaには、OAuth の詳細(認可サーバー、保護されたリソースのメタデータ、スコープ)、すべてのツール、すべてのプロンプト、サーバーバージョンが記載されています。mcp/free-tools/server.json:無料ツールのエントリー(io.github.creatifren/creatif-space-free-tools、リモートhttps://mcp.creatif.space/free、認証なし、3 つのツール、エントリーバージョン1.1.0)。glama.json(リポジトリのルート):Glama のメンテナー。レジストリの名前空間と同じオーナーです。test/registry.test.tsでは、これらすべてがサーバーと一致していることを確認します。ツール、プロンプト、スコープ、バージョンが一致していること、README の Tools テーブル内のツール数が一致していること、スキーマフィールドのみであることを検証します。- 公開は手動で行い、このリポジトリでは実行しません:
.github/workflows/mcp-registry.ymlはworkflow_dispatchでのみ実行されます。公開は Rizal が行う公開操作です。両方のエントリーで使用する正確なコマンドはdocs/registry-publish.mdに記載されています。
リソース
resources/list と resources/read では、スコープ read の読み取り専用 JSON リソースを 2 つ提供します。定義場所は src/resources.ts です。
| URI | 内容 | 同じ形式のもの |
|---|---|---|
creatif://channels | 接続済みのチャンネルと、再接続が必要なチャンネル | list_channels(上限 100) |
creatif://schedule/next-7-days | 現在から現在 + 7 日までに予定されている投稿(最大 100 件)、日時が近い順、{from, to, count} を含む | list_posts の status scheduled |
- エラー: スコープが不足している場合や API エラーが発生した場合、
dataに通常の{code, message, next_step, details}エンベロープを含む JSON-RPC エラーになります。 - 監査: API 呼び出しには
X-MCP-Tool: resource.channels/resource.scheduleが付与されるため、監査ログとmcp:usageに表示されます。
無料ツール(/free)
同じプロセス上にある、2 つ目のステートレスな MCP サーバーです:check_caption、
approval_request_template、connect_guide。サインインは不要で、ユーザーデータは保存されません。
各呼び出しでは、既存の POSTHOG_KEY を使って PostHog に
free_tool_called {tool, network} を送信します(キャプションのテキストは送信しません)。文面と制限は
free-tools/*.json にあります(caption-rules.json、ニッチごとにキー付けされた
approval-templates.json、および file:line の根拠情報を含む connect-guides.json。この根拠情報が呼び出し元に送信されることはありません)。connect_guide は account_type も返します。各項目は
confirmed(コードを根拠として示す)または check in app(コードで確認できないため、
推測しない)です。レジストリのエントリー free-tools/server.json
(io.github.creatifren/creatif-space-free-tools)は、mcp/server.json のみを公開するレジストリのワークフローでは公開されません。
環境
| 変数 | デフォルト | 備考 |
|---|---|---|
PORT | 3010 | |
HOST | 127.0.0.1 | 前段に nginx を配置 |
V1_API_URL | https://api.creatif.space/api/v1 | |
MCP_RESOURCE_URL | https://mcp.creatif.space/mcp | コネクターの正確な URL = リソース ID。Laravel の MCP_RESOURCE_URL と同じ値 |
MCP_AUTHORIZATION_SERVER | https://api.creatif.space | |
MCP_INTROSPECT_SECRET | — | 実稼働モードでは必須。Laravel の値と同じ |
MCP_AUTH_MODE | real | stub はテスト専用で、NODE_ENV=production では拒否されます(トークンは stub:<user_ulid>:<scopes>) |
POSTHOG_KEY | — | 未設定の場合、分析データは送信されません |
POSTHOG_HOST | https://us.i.posthog.com | |
GLAMA_CLAIM | 公開済みのクレーム | GET /.well-known/glama.json および GET /mcp/.well-known/glama.json で配信されます(公開状態を維持する必要があります) |
OPENAI_APPS_CHALLENGE | — | OpenAI Apps のドメイン検証トークン。GET /.well-known/openai-apps-challenge で text/plain として配信されます。未設定の場合は 404 |
MCP_PUBLIC_DISCOVERY | オフ | true にすると、initialize、notifications/initialized、ping、tools/list がトークンなしで応答します(レジストリのクローラー、クライアントのプレビュー向け。IP ごとに 30 回/分)。tools/call とそれ以外のすべてのリクエストでは引き続き、サインインを求める 401 と WWW-Authenticate(resource_metadata)が返されます。トークン付きのリクエストは常に通常の認証を行います。QA で確認が済むまではオフにしておいてください。 |
開発
cd mcp
npm ci
npm run lint && npm run typecheck && npm test && npm run build
MCP_AUTH_MODE=stub npm start # local only
デプロイチェックリスト(QA)
- サーバーにNode 22 LTS(
node -v→ v22.x)と nginx がインストールされていること。DNS のmcp.creatif.spaceがこのホストを指し、TLS 証明書が発行済みであること(certbot --nginx -d mcp.creatif.space)。 - まず API 側を設定します。OAuth PR がデプロイされ、マイグレーションが実行済みであること。Laravel の
.envにMCP_INTROSPECT_SECRETとMCP_RESOURCE_URL=https://mcp.creatif.space/mcpが設定されていること。MCP_RESOURCE_URLは両方の環境(Laravel の.envと/etc/creatif-mcp.env)で、正確にhttps://mcp.creatif.space/mcpにする必要があります(オリジンのみの値は不可)。 /etc/creatif-mcp.env(モード 600、所有者 root)に、次の名前を設定します:PORT、HOST、V1_API_URL、MCP_RESOURCE_URL、MCP_AUTHORIZATION_SERVER、MCP_INTROSPECT_SECRET(Laravel と同じ値)、MCP_AUTH_MODE(real、または未設定)、POSTHOG_KEY、POSTHOG_HOST。ここではMCP_AUTH_MODE=stubを絶対に設定しないでください。cd /var/www/creatif.space-api && git pull && cd mcp && npm ci && npm run build && npm prune --omit=dev- 以下の systemd ユニットをインストールし、
systemctl daemon-reload && systemctl enable --now creatif-mcpを実行します。以降のデプロイではsystemctl restart creatif-mcpを実行します。 - 以下の nginx vhost をインストールし、
nginx -t && systemctl reload nginxを実行します。 - 動作確認:
curl -s https://mcp.creatif.space/health→{"ok":true,...}curl -si -X POST https://mcp.creatif.space/mcp | grep -i www-authenticate→Bearer resource_metadata="https://mcp.creatif.space/.well-known/oauth-protected-resource/mcp"curl -s https://mcp.creatif.space/.well-known/oauth-protected-resource/mcp→"resource":"https://mcp.creatif.space/mcp"journalctl -u creatif-mcp -n 20にlistening on http://127.0.0.1:3010 (auth: real)と表示されること
- Claude で、Settings → Connectors → Add custom connector →
https://mcp.creatif.space/mcpの順に進み、サインインしてlist_channelsを実行します。
使用状況レポート(日次起動チェック)
API ホストで実行します:php artisan mcp:usage --days=7(1~90。機械可読形式の出力を追加するには --json を指定します)。mcp_audit_logs から、ツールごとの API 呼び出し数、エラー(HTTP ≥ 400)、エラー率、上位のエラーコード(ステータスをモデルが認識する MCP コードにマッピング:402 → plan_required、404 → not_found、5xx → upstream_unavailable…)を集計します。集計データのみを扱い、ユーザー、トークン、IP、クライアント名は含みません。ツール呼び出しではなく API リクエスト数をカウントします(1 つのツールが複数のリクエストを行う場合があります)。また、不正な引数やスコープ不足などの理由でこのサーバー内で拒否された呼び出しは API に到達しないため、集計に含まれません。
レイテンシ:過去 24 時間のツールごとの p50/p95(計測対象の呼び出し数とエラー数も表示)。mcp_audit_logs.duration_ms から取得します。これは API が応答するまでにかかった時間で、EnforceTokenScope によって記録されます。このカラムが存在する前の行には計測時間がないため、対象外です。p95 が遅い順に並びます。--json では latency_24h です。
本番環境での実行
デプロイごとに一度だけビルドします:npm ci && npm run build(続いて npm prune --omit=dev を実行します)。
systemd — /etc/systemd/system/creatif-mcp.service
[Unit]
Description=creatif.space MCP server
After=network.target
[Service]
Type=simple
User=www-data
WorkingDirectory=/var/www/creatif.space-api/mcp
EnvironmentFile=/etc/creatif-mcp.env
Environment=NODE_ENV=production
ExecStart=/usr/bin/node dist/index.js
Restart=always
RestartSec=3
NoNewPrivileges=true
ProtectSystem=full
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload && sudo systemctl enable --now creatif-mcp
または pm2 — mcp/ecosystem.config.cjs
module.exports = {
apps: [{
name: 'creatif-mcp',
cwd: '/var/www/creatif.space-api/mcp',
script: 'dist/index.js',
env: { NODE_ENV: 'production', PORT: 3010 }, // secrets via the shell env / .env loader
max_memory_restart: '300M',
}],
};
nginx — mcp.creatif.space
SSE に対応:バッファリングなし、読み取りタイムアウトを長く設定し、アップストリームへの接続には HTTP/1.1 を使用します。
server {
listen 443 ssl http2;
server_name mcp.creatif.space;
ssl_certificate /etc/letsencrypt/live/mcp.creatif.space/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/mcp.creatif.space/privkey.pem;
client_max_body_size 2m;
location / {
proxy_pass http://127.0.0.1:3010;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Streamable HTTP / SSE
proxy_buffering off;
proxy_cache off;
chunked_transfer_encoding on;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
add_header X-Accel-Buffering no;
}
}
server {
listen 80;
server_name mcp.creatif.space;
return 301 https://$host$request_uri;
}
確認:curl -s https://mcp.creatif.space/health と
curl -si -X POST https://mcp.creatif.space/mcp | grep -i www-authenticate。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。