mcpField
I
icp-builder

icp-builder

github.com/crustdataマーケティング・グロース11341 回インストール4 週間前に更新
リポジトリ

icp-builder について

LinkedInプロフィールからペルソナと推定ICPの設定ファイルを作り、関連する営業スキルで使えるようにするスキルです。Crustdataのデータと投稿から情報を導き、再利用可能なGTM設定を書き込みます。

主な機能

  1. 01LinkedInに基づくペルソナ作成
  2. 02プロフィールと企業情報からのICP推定
  3. 03投稿からの文体分析
  4. 04任意の営業ツール構成
  5. 05再利用可能なGTM設定ファイルの作成

活用シーン

  1. 01営業開拓ワークフロー用のGTM情報設定
  2. 02営業担当者のプロフィールから推定ICPを作成
  3. 03投稿からユーザーの文体を把握
  4. 04アカウント調査スキル向け設定ファイルの準備

MCP 対応

`execute`スクリプトを通じてCrustdata MCPツールを使い、人物と企業の情報を補完してソーシャル投稿を取得します。

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/crustdata/skills --skill icp-builder

インストール後、Claude Code で/icp-builderを入力して読み込まれたか確認します。

同梱ファイルevals/evals.jsonREADME.md

詳細

ICP ビルダー

LinkedIn URL を 1 つ入力するだけで、すぐに使える GTM 設定が作成されます。このスキルは、Crustdata を使ってユーザー自身のプロフィールを充実させ、config/persona-profile.md と config/gtm-config.md を作成します。これらのファイルは sales-prospecting と account-research が起動時に読み込みます。

手順は必ず次の順に進めます。

  1. スタック(任意。完全にスキップ可能):使用しているツールを確認します。
  2. ペルソナ:LinkedIn URL を 1 つ入力すると、Crustdata がユーザーの人物像、販売しているもの、推定 ICP、文体を割り出します。
  3. 設定を書き込み、引き継ぎます。

ユーザーに質問攻めをしないでください。「何を販売していますか」「ICP は誰ですか」「文体がわかるメールを貼り付けてください」などとは尋ねないでください。これらはすべて LinkedIn URL と投稿から導き出します。URL がインタビューのすべてです。


Step 0:既存の設定を確認する

作業ディレクトリに config/gtm-config.md または config/persona-profile.md がすでに存在する場合は、それらを読み込み、内容を 2 行で要約してから、ペルソナ全体を更新するか、特定のフィールドを更新するかを尋ねてください。ユーザーがすでに修正した設定を、黙って上書きしてはいけません。更新時は、既存のスタック項目を変更せずに引き継ぎ、ユーザーから変更を求められない限り、スタックについて再度尋ねないでください。ファイルがないのが通常の状態です。このスキルでファイルを作成します。

Step 1:歓迎の言葉と任意のスタックに関する質問

短い歓迎の言葉を 1 行で伝えてから、任意の質問を 1 つだけします。使用しているツールは何ですか? 各項目を一度確認し、ユーザーにツール名を挙げてもらうか、スキップしてもらいます。質問全体をスキップした場合は、すべての項目に none と記入して先に進みます。

  • データプロバイダー — このスキルが使用するデータソースである Crustdata(コネクターとして追加します。接続されていない場合は、以下のデータなしのフォールバックを使用します)
  • CRM — またはスキップ
  • カレンダー — またはスキップ
  • メール — またはスキップ
  • 通話録音ツール — またはスキップ
  • シーケンサー — またはスキップ
  • チームチャット — またはスキップ

この手順のルール:

  • 接続済みのコネクターを見て、スタックを推測してはいけません。 コネクターが接続済みでも、それがユーザーの選択とは限りません。質問するか、none と記入してください。
  • どの項目もスキップできます。辞退されたツールについて、強く勧めたり、再度尋ねたりしてはいけません。
  • スキップした項目は設定で none となり、後続のスキルはその項目を下書きのみで実行します。ツールへの登録ではなく、下書きと CSV エクスポートを行います(「シーケンサー用に CSV をエクスポートする」「CRM ではなくファイルに記録する」)。

Step 2:LinkedIn URL → ペルソナ

1 つだけ尋ねます。ユーザーの LinkedIn URL です。次に、1 つの execute スクリプトでペルソナを作成します。人物の検索を最初に行います。企業情報の充実と投稿の取得はどちらも人物検索に依存しますが、互いには依存しないため、この 2 つを parallelMap で並列実行します。

すべてのスクリプトは、ソースを明記したクエリコメント(// user query: ... または // model query: ...)から始める必要があります。これがないスクリプトは、実行前に却下され、費用は発生しません。

// user query: set up my GTM config — my LinkedIn is https://www.linkedin.com/in/example
const url = "https://www.linkedin.com/in/example";

// Stage 1: the person. Base cost 1 credit. `fields` is a response WHITELIST —
// the result carries ONLY the groups listed here; an omitted group reads as
// undefined later and looks like missing data. basic_profile + experience covers
// the persona; social_handles carries the canonical profile URL the posts pull
// is keyed on; contact groups only add cost.
const pr = await callTool("person_enrich", {
  professional_network_profile_urls: [url],
  fields: ["basic_profile", "experience", "social_handles"],
});
if (!pr.ok) return { error: pr.message };
const person = pr.data[0]?.matches?.[0]?.person_data;
if (!person) return { error: "no_match" }; // → confirm the URL, then no-data fallback

const canonicalUrl = profileUrl(person) ?? url; // preloaded accessor
const current = person.experience?.employment_details?.current?.[0] ?? {};
const companyId = currentCompanyIds(person)[0]; // preloaded accessor

// Stage 2: company + posts are independent of each other — fan them out.
const calls = [
  { name: "social_post_list_live",
    params: { professional_network_profile_url: canonicalUrl, limit: 10 } }, // 1 cr/post — cap deliberately
];
if (companyId) {
  calls.push({ name: "company_enrich",
    params: { crustdata_company_ids: [companyId], exact_match: true,
              fields: ["basic_info", "taxonomy"] } }); // 2 cr, exactly one match
}
const results = await parallelMap(calls, async (c) => ({ name: c.name, r: await callTool(c.name, c.params) }));

const postsR = results.find(x => x.name === "social_post_list_live")?.r;
const companyR = results.find(x => x.name === "company_enrich")?.r;

// Posts are optional: a failed or empty pull means neutral voice, not a failed run.
const posts = postsR && postsR.ok
  ? (postsR.data.posts ?? []).map(p => ({
      text: p.text,
      date: p.date_posted,
      reactions: p.engagement?.total_reactions,
      comments: p.engagement?.total_comments,
    }))
  : [];

const company = companyR && companyR.ok
  ? pick(companyR.data[0]?.matches?.[0]?.company_data ?? {}, ["basic_info", "taxonomy"])
  : null;

// Return the smallest projection — only what the script returns reaches the model.
return {
  identity: {
    name: person.basic_profile?.name,
    title: person.basic_profile?.current_title,
    location: person.basic_profile?.location,
    company: current.name,
    company_domain: current.company_website_domain,
    start_date: current.start_date, // tenure = today minus this
  },
  past_roles: (person.experience?.employment_details?.past ?? []).slice(0, 5)
    .map(e => ({ company: e.name, title: e.title })),
  company,
  posts,
};

このスクリプトに関する注意事項:

  • person_enrich で preview: true を設定しないでください。 プランに依存するため、一部のアカウントでは 400 エラーが返されます。このフローがこれに依存してはいけません。いずれにしても基本コストは 1 クレジットです。
  • person_enrich のフィールドは basic_profile、experience、social_handles のみにしてください。 許可リストに social_handles がないと、profileUrl アクセサーが undefined を読み込み、投稿の取得でユーザーが直接入力した URL にフォールバックします。一部のグループ(certifications、honors、updated_at)はプランによって制限されています。制限対象のフィールドを指定すると、そのフィールド名を示す 403 エラーが発生し、呼び出し全体が失敗します。その場合はフィールドを削除して、再実行してください。
  • レスポンスのパスはフィルターのパスとは異なります。役職は basic_profile.current_title、現在の勤務先は experience.employment_details.current[].name、正規のプロフィール URL は social_handles.professional_network_identifier.profile_url にあります(profileUrl アクセサーがこれを読み込みます)。
会社のフォールバック:プロフィールに会社 ID がない場合

現在の職歴に会社 ID がない場合は、まずドメイン(または名前)で会社を特定します。company_identify は無料であいまい検索を行うため、1 つの識別子から複数の会社が返されることがあります。confidence_score が最も高い候補を選び、exact_match: true を指定して ID で詳細情報を取得します。これが最も安価で正確な方法です。無料の特定と、正確に 1 件の詳細情報取得に 2 クレジットを使います。

// model query: resolve and enrich the user's current company by domain
const idr = await callTool("company_identify", { domains: ["example.com"] }); // ONE identifier type per call
if (!idr.ok) return { error: idr.message };
const matches = idr.data[0]?.matches ?? [];
const top = matches.slice().sort((a, b) => (b.confidence_score ?? 0) - (a.confidence_score ?? 0))[0];
if (!top) return { error: "no_company_match" };
const id = top.company_data?.basic_info?.crustdata_company_id ?? top.company_data?.crustdata_company_id;

const er = await callTool("company_enrich", {
  crustdata_company_ids: [id],
  exact_match: true,
  fields: ["basic_info", "taxonomy"],
});
if (!er.ok) return { error: er.message };
return pick(er.data[0]?.matches?.[0]?.company_data ?? {}, ["basic_info", "taxonomy"]);

company_identify では social_profiles を指定しないでください。プランの制限対象であり、指定すると呼び出し全体が 403 エラーになります。

返されたデータからペルソナを導き出す
  • アイデンティティ:名前、役職、会社、在籍期間(start_date から)、過去の職歴に基づく経歴の要約(1 行)。
  • 会社と販売するもの:basic_info と taxonomy から製品とカテゴリを特定します。会社の説明とユーザーの投稿トピックから、モニタリングするキーワードを決めます。
  • 声:実際の投稿から、文の長さ、一人称か三人称か、専門用語のレベル、絵文字の使用、書き出し方など、口調や文体に関するメモを作成します。投稿が空の場合は「ニュートラル」と記入して先に進みます。
  • 関心のあるトピック:投稿で繰り返し扱われるテーマを、エンゲージメントを考慮してまとめます。
推定 ICP — 推定であることを明記し、フィルターに使える形にする

会社が販売するものと、一般的な購入者像から ICP を導き出します。業界、従業員数の範囲、地域、資金調達ステージ、購入者の役職、購入者の職位を含めます。必ず inferred とラベル付けしてください。これはユーザーが修正するための仮説であり、事実ではありません。

後続の検索でそのまま使える ICP の値を記入します。カテゴリフィールドは選択肢が限定されており、もっともらしくても間違った値を指定すると、エラーなく結果が 0 件になることがあります。そのため、設定に記入する前にオートコンプリート(無料)で値を確認してください。

// model query: resolve filter-ready values for the inferred ICP
const probes = [
  { tool: "company_autocomplete", params: { field: "basic_info.industries", query: "software" } },
  { tool: "person_autocomplete",  params: { field: "experience.employment_details.current.seniority_level", query: "vice" } },
];
return await parallelMap(probes, async (p) => {
  const r = await callTool(p.tool, p.params);
  // Returns shape is { suggestions: [{ value }] } — project to the value strings.
  return { field: p.params.field, values: r.ok ? (r.data.suggestions ?? []).map(s => s.value) : [], error: r.ok ? null : r.message };
});

購入者の職位には、experience.employment_details.current.seniority_level の正確な語彙を使う必要があります:Entry Level、Entry Level Manager、Experienced Manager、Senior、Director、Vice President、CXO、Owner / Partner、In Training、Strategic。確信が持てない場合は推測せず、person_autocomplete で確認してください。

正確さは絶対条件です

このプロフィールは後続のすべてのスキルに影響するため、誤った情報がすべてを損ないます。

  • ソースデータで裏付けられる内容だけを記入します。確認できないことは推測せず、その旨を伝えます。
  • 推定にはすべてラベルを付けます(ICP には必ず inferred とラベル付けします)。
  • ファイルを書き込む前に、ペルソナをユーザーに確認します:「あなたについて、こう理解しました。違っているところがあれば教えてください。」修正を反映してから書き込みます。

ステップ 3:設定ファイルを書き込む

作業ディレクトリに両方のファイルを書き込みます。config/persona-profile.md はペルソナの全体版です。config/gtm-config.md には会社/ICP/声の要点に加えて技術スタックを記載し、どのスキルからも一度の読み込みで確認できるようにします。

config/persona-profile.md
# Persona Profile
Built by icp-builder on <YYYY-MM-DD>. Read by sales-prospecting, account-research, sales-outreach, and meeting-prep.

## Identity
- Name:
- Title:
- Company: <name> (<domain>)
- Tenure: since <start date>
- Background: <one line from past roles>

## Company & what we sell
- Product:
- Category:
- Keywords to monitor:

## Inferred ICP
Label: inferred from <what the company sells + typical buyers>. User-confirmed: <yes/no>
- Industries: <filter-ready values>
- Headcount:
- Geography:
- Funding stage:
- Buyer titles:
- Buyer seniority: <exact seniority vocabulary values>

## Voice
- Tone:
- Style notes:
- Always: no em dashes; never "delve", "leverage", or "streamline"; no filler;
  write like a colleague.

## Topics they care about
- <from posts, weighted by engagement>
config/gtm-config.md
# GTM Config
Read by sales-prospecting, account-research, sales-outreach, and meeting-prep at startup.

## Stack
- Data provider: crustdata | none
- CRM: <tool> | none
- Calendar: <tool> | none
- Email: <tool> | none
- Call recorder: <tool> | none
- Sequencer: <tool> | none
- Team chat: <tool> | none

`none` = that slot runs draft-only: drafts and CSV exports instead of pushing to the tool.

## What we sell
<one or two lines>

## ICP (inferred)
- Industries:
- Headcount:
- Geography:
- Funding stage:
- Buyer titles:
- Buyer seniority:

## Customers
none yet — add names or domains as you close; sales-prospecting uses them for lookalikes.

## Voice
<tone in one line>. No em dashes; never "delve", "leverage", or "streamline"; no filler;
write like a colleague.
引き継ぎ

技術スタックのうち接続したものとスキップしたもの、ペルソナの要約(2~3 行)、inferred とラベル付けした項目をまとめます。その後、次のように伝えます。

セットアップが完了しました。sales-prospecting(「私の ICP に合うリストを作って」)または account-research(「 を調査して」)を試してください。どちらもこの設定を自動的に読み込みます。


データがない場合のフォールバック

Crustdata が接続されていない場合、または詳細情報が乏しい場合(一致なし、プロフィール情報が少ない、投稿が 0 件)は、次のように対応します。

  • ユーザーから 2~3 行だけ聞きます。名前と役割、会社が何をしているか、誰に販売しているかを確認します。聞くのはこれだけです。長い質問票は絶対に実施しないでください。
  • その内容をもとに両方の設定ファイルを書き込みます。声は「ニュートラル」と、スロップを避けるルールにします。ICP には引き続き inferred とラベル付けします。
  • 詳細情報が一部しか得られなかった場合は、確認できた内容を残し、推定できなかった内容を具体的に伝え、その部分だけユーザーに追記してもらいます。

コスト

  • person_enrich で basic_profile + experience + social_handles を指定:1 クレジット。
  • company_identify、company_autocomplete、person_autocomplete:無料。
  • exact_match: true を指定して ID で company_enrich を実行:1 件の一致につき 2 クレジット。
  • social_post_list_live:投稿 1 件につき 1 クレジット。limit は必ず意図的に設定してください (文体の把握には 10 件で十分です)。
  • 一般的なフル実行:約 13 クレジット。すべての execute レスポンスには credits と credits_remaining が含まれます。account_credits(無料)で残高を確認できます。

エラー処理

  • すべてのスクリプトで r.ok に応じて分岐してください。 呼び出しに失敗してもスクリプトは中断されません。失敗を確認しないまま処理が進むと、空のデータが使われ、「結果なし」のように見えます。
  • person_enrich で一致するものがない場合 → URL に誤りがないか(タイプミス、バニティスラッグの変更)ユーザーに確認してから、データがない場合のフォールバックを使用します。
  • フィールド名が示された 403 エラーは、プランによって制限されたプロジェクションを意味します。そのフィールドを除外して再実行してください。
  • 投稿の呼び出しが失敗した場合や、投稿が空の場合もエラーではありません。文体はニュートラルになります。
  • company_enrich に失敗した場合 → 人物データだけを使ってペルソナを維持し、不足している情報を記載してください。

ルール

  • まず歓迎の言葉を伝えます。任意のスタックに関する質問は1つまで。インタビューはURLだけで完結させます。
  • 接続済みのコネクターからスタックを推測してはいけません。 尋ねるか、none と記述します。
  • 何を販売しているか、ICP、ブランドの口調について尋ねてはいけません。 そこから推測します。エンリッチメントの情報が乏しい場合は、2~3行にまとめ、インタビュー全体にはしません。
  • ファイルを書き込む前に、ペルソナの内容を本人に示して確認・修正してもらいます。
  • 推測にはラベルを付けます。 スキップしたツールには none と記述します。スタックやペルソナの詳細を捏造してはいけません。
  • 文体には常に「粗雑な文章にしない」ルールを適用します: emダッシュは使わない。「delve」「leverage」「streamline」は使わない。余計な言葉を避け、同僚に話しかけるように書きます。
  • 設定がなくても、作業を妨げてはいけません。このスキルが設定を作成し、設定がない場合は後続のスキルからこのスキルを参照します。
  • コンテンツに合わせてレイアウトを調整し、何も隠さないようにします。 ブランドシステムは固定ですが、レイアウトは固定ではありません。実際のコンテンツが収まらない場合、たとえば会社名や人名が長い場合、タイトルが12語の場合、行数が200行の場合は、コンテンツではなくレイアウトを変更します。カードを広げる、切り捨てずに折り返す、1列にする、列幅を広げる、上限を引き上げる、または横幅の広い要素専用のスクロール領域を設けるなどの方法があります。カードを切り取る、名前を省略記号で切り詰める、行を黙って削除するといった方法で、表示上の問題を解決してはいけません。上限がどうしても避けられない場合は、読者が表示されていない内容を把握できるよう、UIに「214件中、上位50件を表示」のように明記します。レンダリング結果を確認し、欠けている部分を修正してから引き渡します。
  • レンダリング結果のアイコン:ダッシュボードのアイコンセットであるLucideを、currentColor のストロークを持つインラインSVGとして使います。成果物のUIに絵文字は使いません。
  • ペルソナ本人の写真も無料です:basic_profile.profile_picture_permalink は、Step 2の person_enrich がすでに返す basic_profile グループに含まれています。ペルソナの概要ページは人物についてのものです。写真はBase64でインライン化し(同じ binary/octet-stream のルールを適用)、写真がない場合はモノグラムを表示します。
  • 会社ロゴは無料です。レンダリングされたペルソナページに使用します。 basic_info.logo_permalink は、無料の company_identify と、ペルソナ向けにすでに実行する company_enrich から取得できます。メディアCDNがこれらを binary/octet-stream として配信するため、リモートの <img src> は空白で表示されます。data:image/jpeg;base64,... URIとしてBase64でインライン化し、ロゴがない場合はモノグラムを表示します。
  • 成果物のブランディング:設定ファイルはプレーンなMarkdownのままにし、機械が読み取るファイルにブランディングのノイズを加えません。ただし、ペルソナをページや文書(ペルソナの概要ページ、ICPの要約文書など)としてレンダリングする場合は、ヘッダーまたはフッターにCrustdataのブランドロックアップを入れます。小さな大文字の「Powered by」を上に添え、crustdata.comへのリンクを設定した公式のCrustdataワードマークを配置します。ワードマークのペアは、このスキルの assets/ にあります。crustdata-logo-light.png(明るい背景用の濃い文字)と crustdata-logo-dark.png(暗い背景用の白い文字)で、app.crustdata.comのヘッダーに表示されるものと同じです。テーマに適したバリエーションを高さ約17pxでBase64インライン化し、ホットリンクは使いません。レンダリングされた成果物はリモート画像を取得できません。ブランドアクセントカラーは #5547E2(製品のプライマリカラー。暗い背景では #8387FF)です。埋め込み可能なら本文フォントにGeistを使い、それ以外の場合はシステムフォントスタックを使います。マークを入れるだけのために成果物をレンダリングしてはいけません。

ツールの依存関係

このスキルには、以下が必要です。

  • Crustdata MCP サーバー(install.crustdata.com/mcp): list_tools、get_schema、execute を公開する単一の Code Mode MCP です。すべての Crustdata データツールには、プレーンな JavaScript スクリプトの execute({ code }) 内で await callTool(name, params) を呼び出してアクセスします。get_schema の型付きサーフェスを基に 作成しますが、スクリプト本文には型注釈を一切含めないでください(型注釈があると パースエラーになり、実行全体が失敗します)。ここで使用するツール:person_enrich、 company_identify、company_enrich、social_post_list_live、 company_autocomplete、person_autocomplete、account_credits。
  • 作業ディレクトリへの書き込み権限 — config/persona-profile.md と config/gtm-config.md を作成します。

sales-prospecting および account-research とともに提供され、これらは本スキルが書き込む設定を読み込みます。

コメント