Skip to main content
Glama
bsmahi

LQABR HubSpot MCP Server

by bsmahi

LQABR_MCP

LQABR セントラル HubSpot MCP サーバー。FastMCP 上に構築されており、スタンドアロンで動作します。LQABR モノレポへの依存はありません。

RUNNING.md — 実行方法:セットアップ、認証情報、両方のトランスポート、agentgateway、トラブルシューティング。 CONSUMING.md — メール/音声/スケジューリングエージェントがこれを呼び出す方法:ADK McpToolset、認証、ワイヤー契約、ツールスコーピング。 このファイルは設計の根拠です。上記の2つは手順書です。

LQABR_MCP/
├── hubspot-crm-mcp-server/
│   ├── __init__.py              (empty, per mcp.odt Step 4)
│   ├── hubspot_crm_server.py    the launcher — mcp.odt Step 5
│   ├── test_server.py           remote smoke test — handoff S8
│   ├── hubspot_mcp/             THE IMPLEMENTATION (vendored)
│   │   ├── __init__.py          provenance + drift warning — read this
│   │   ├── server.py            the FastMCP object + the two tools
│   │   ├── secrets.py           Secret Manager access
│   │   ├── obs/                 the four logs: system/process/audit/tokens
│   │   │   ├── __init__.py
│   │   │   ├── context.py       RunContext, run_id, lead_ref_id
│   │   │   └── loggers.py
│   │   └── hubspot/
│   │       ├── __init__.py
│   │       ├── crm.py           upsert_lead_profiles / get_lead_profile
│   │       ├── auth.py          get_hubspot_token(), short-lived M2M
│   │       ├── schema.py        LeadProfile, PushResult, property mapping
│   │       └── failures.py      failure taxonomy + CircuitBreaker
│   └── tests/                   61 tests ported from the mono-repo
├── .vscode/hubspot_mcp.json     stdio config — mcp.odt Steps 7–8
├── Dockerfile                   Cloud Run image — handoff S4
├── .dockerignore
├── pytest.ini
├── .python-version              3.12, matching the Dockerfile
├── .env.example                 mode switches + secret IDs (no values)
├── pyproject.toml
├── RUNNING.md                   step-by-step runbook — start here
├── CONSUMING.md                 client integration guide for other agents
└── README.md

これはフォークであり、移行ではありません

hubspot_mcp/ は、モノレポの実装をコピーしたものです。インポート行のみが書き換えられています。ロジック、フィールド名、HubSpot プロパティ名は変更されていません。差分確認済み — 全9ファイルにわたる差分行は以下のみです:

- from lqabr_core.obs import get_obs, utc_now_iso
+ from ..obs import get_obs, utc_now_iso
- from lqabr_core.leadgen.secrets import ...
+ from ..secrets import ...

モノレポには依然としてそのコピーが必要です。削除しないでください。

モジュール

その他の使用箇所

lqabr_core.obs

lead_profile/src 内の8ファイル、text_voice/src 内の2ファイル、lqabr_core/crm

lqabr_core.leadgen.*

12の lead_profile ファイル(call_mcp.py を含む)、および evals/run_eval.py

lqabr_core.leadgen.secrets

lead_profile の model.py、2つのテストファイル

結果として: 現在、HubSpot への書き込みパスが2つ存在し、同じフィールド名と HubSpot プロパティ名を保持しています。そしてデータ契約上、それらの名前が契約そのものです。crm.py への修正、認証の変更、HubSpot プロパティの名前変更は、すべて手動で両方に適用する必要があります。これを強制する仕組みはありません。このための予算を確保するか、いずれか一方を廃止する計画を立ててください。

Related MCP server: hubspot-mcp-server

なぜこれがモノレポの外にあるのか

LQABR リポジトリのルートには、文字通り mcp という名前のトップレベルパッケージが存在し、FastMCP が依存する mcp SDK をシャドウイングします。リポジトリ内から実行すると、FastMCP 自身のインポートが壊れます。

LQABR リポジトリのルートを PYTHONPATH に追加しないでください。

ライブラリ:公式SDKではなく FastMCP

依存関係は fastmcp>=3.4.7 です。mcp>=2.0 を追加しないでください — この2つは相互に排他的です:

  • fastmcp 3.4.7 は、推移的に mcp<2.0,>=1.24.0 を固定します(mcp 1.29 をインストールします)。

  • 公式SDKのサーバークラスである MCPServer は、mcp>=2.0 にのみ存在します。

したがって、プロジェクトは FastMCP または MCPServer のいずれかを使用でき、両方は使用できません。これは FastMCP を使用します。ここで MCPServer をインポートすることはありません。

知っておくべき2つの結果:

  • トランスポート名が異なります。 FastMCP の HTTP トランスポートは "http" です("streamable-http" はエイリアスとして受け入れられます)。エンドポイントパスのキーワード引数は path= です。公式SDK では streamable_http_path= と表記します。

  • 型フィールドが異なります。 mcp が 1.x に固定されているため、バンドルされる型は camelCase を使用します:Tool.inputSchema(input_schema ではありません)。

モノレポの lqabr_core/leadgen/server.py は依然として MCPServer を使用しています。これにより、フォークに加えて、2つのコードベース間に新たな相違点が生じています。

実行方法

uv sync

# stdio — local ADK MCPToolset, or the VSCode config in .vscode/
uv run python hubspot-crm-mcp-server/hubspot_crm_server.py

# HTTP — what Cloud Run runs
uv run python hubspot-crm-mcp-server/hubspot_crm_server.py \
    --transport http --host 0.0.0.0 --port 8080

認証情報

tools/list には何も必要ありません。ツールの呼び出しには HubSpot トークンが必要であり、これは Secret Manager から取得されます — コンテキスト §7.6 / CLAUDE.md §5:シークレットはハードコードされず、コミットもされません。

cp .env.example .env                    # holds mode switches + secret IDs only
gcloud auth application-default login
uv sync --extra gcp --extra test        # both extras; --extra gcp alone drops pytest
export UV_ENV_FILE=.env

uv sync --extra <x> は、そのエクストラセットのみを正確に同期するため、--extra gcp 単独では pytest がアンインストールされます。test_server.py は pytest なしで CLI として実行されますが、uv run pytest は明らかに pytest を必要とします。

.env にはシークレット値は含まれていません — HUBSPOT_AUTH_MODE、LQABR_SECRET_PROJECT、およびシークレットの ID のみが含まれます。トークン自体は実行時に Secret Manager API 経由でフェッチされ、メモリ内に保持され、決してログに記録されず(監査記録には長さと最後の4文字のみが記録されます)、900秒間キャッシュされるため、ローテーションに再デプロイは必要ありません。

auth.py と secrets.py はどちらもフェイルクローズです — 未設定は明示的なエラーを意味し、黙ったままデフォルト値になることはありません。

LQABR_SECRET_BACKEND=env は、オフライン作業や CI のための最後の手段として存在します。secrets.py はこれを「ローカル開発、CI、およびテストのみ」に限定しており、これへの自動フォールバックはありません — 明示的に指定する必要があります。これにより、生の認証情報がディスク上のファイルに配置されます。Cloud Run では決して設定しないでください。

すべてのフラグには環境変数のデフォルト値(MCP_TRANSPORT、MCP_HOST、PORT、MCP_PATH)があるため、コンテナは引数なしで起動します — Cloud Run が PORT を注入します。

テスト

uv run pytest              # 61 tests, all passing, none touch real HubSpot

pytest.ini は hubspot-crm-mcp-server/ をパスに追加するため、import hubspot_mcp が解決されます — フォルダ自体はハイフンが含まれているためパッケージになることができません。

契約は9フィールドではなく10フィールドです

LeadProfile は10のフィールドを持ちます:全員が文書化する9つに加えて、contact_name(firstname/lastname マッピングのために追加されました)。モノレポの test_wrapper_shape_is_the_nine_fields_plus_ids は依然として9をアサートしており、そこで失敗していました — schema.py はバイト単位で同一であるため、このプロジェクトはそれを継承しました。

2026-08-18 に解決済み:コードは正しく、数値が古くなっていました。テストは test_wrapper_shape_is_the_contract_fields_plus_ids に名前が変更され、現在はカウントではなくフィールド名をアサートするため、次の追加時には読み取り可能なメッセージとともに失敗します。

同じ修正がモノレポにもまだ必要です — そこでのアサーションは変更されておらず、依然として赤です。「9フィールド」と記載されているドキュメントも修正されるべきです。

デプロイされたサーバーのテスト

# local
uv run python hubspot-crm-mcp-server/test_server.py

# Cloud Run — mints a Google ID token via ADC
uv run python hubspot-crm-mcp-server/test_server.py \
    --url https://lqabr-mcp-server-xxxx.a.run.app/mcp --auth google

# one real read against HubSpot — writes nothing
... --auth google --employee-id EMP-00042

設計上、読み取り専用です:upsert_lead_profile を呼び出すことはありません。X-LQABR-Run-Id を送信し、サーバーの監査ログがその呼び出しを属性として記録できるようにします(B10 修正)。

ID トークンの対象者は、サービスベース URL の /mcp を除いたものです。スクリプトが自動的に除去します。

クライアントは fastmcp.Client を使用し、これが初期化ハンドシェイクを処理するため、このファイルにはセッション配管はありません。ヘッダーは StreamableHttpTransport に乗せられます。これで、リファレンスサンプルのライブラリと一致しました。

Cloud Run へのデプロイ

2段階の uv ビルド、非 root の mcp ユーザー、PID 1 は Python であるため SIGTERM はクリーンにドレインされます。自己完結型:兄弟フォルダや git 依存関係はありません。

docker build -t lqabr-mcp-server .

uv.lock をコミットし、本番環境の前に同期を --frozen に切り替えてください。

次に S5–S8:mcp-server-sa を作成し、lqabr-hubspot-access-token に対して secretmanager.secretAccessor を付与し、--no-allow-unauthenticated でデプロイし、3つのエージェントサービスアカウントに roles/run.invoker を付与し、test_server.py をそのサーバーに向けます。

公開されるツール

ツール

方向

備考

upsert_lead_profile

書き込み

会社の upsert → 連絡先の upsert → 関連付け。冪等。

get_lead_profile

読み取り

契約フィールド + contact_hs_id + company_hs_id。

重複排除:連絡先は employee_id、会社は company_id で行います。メールはカスタム email_id プロパティに格納されます。

未解決項目。 登録されているツール名は upsert_lead_profile(単数形)ですが、設計ドキュメント、セッションハンドオフ、プロジェクトの指示はすべて upsert_lead_profiles(複数形)であり、基盤となる関数も複数形です。これはワイヤー契約です — クライアントが配線する前に解決してください。

認証情報

2つあり、混同されることはありません:

  • Google ID トークンは、エージェント → このサーバー を証明します(Cloud Run のサービス間通信)。

  • HubSpot M2M トークンは、このサーバー → HubSpot を証明し、サーバー内部で呼び出しごとに発行されます。呼び出し元がこれを見ることはありません。

このサービスは、HubSpot 認証情報の唯一の保持者です。

検証済み

fastmcp 3.4.7(これにより mcp 1.29 が導入される)、requests、pytest のみを含むクリーンな venv で、lqabr_core が存在せず(ModuleNotFoundError 確認済み)、MCPServer が存在しない(ImportError 確認済み)環境において:

  • プロジェクト内の lqabr_core インポートはゼロ

  • 移植済みテストスイート:61 パス、0 失敗

  • stdio — tools/list は両方のツールを返し、PYTHONPATH は完全に除去済み

  • --transport http — ホスト/ポート/パスにバインド、完全な fastmcp.Client セッション

  • --transport streamable-http — エイリアスが受け入れられ、同じエンドポイントを提供

  • test_server.py — 実行中のサーバーに対して PASS、終了コード 0

  • pytest 下の test_server.py — サーバーありで3パス、サーバーなしで3スキップ

  • ライブ call_tool が実際のチェーンに到達:transport → tool → crm.py → auth.py → secrets.py、意図的な AuthConfigError / SecretConfigError ガード(テスト環境に GCP 設定がない)でのみ失敗。配線はエンドツーエンドで確認済み。

未検証: Docker イメージは一度もビルドされていません — これらのファイルが作成された環境では Docker デーモンが利用できませんでした。実際の HubSpot に触れたものはなく、すべてのテストはフェイクを使用しています。

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables comprehensive HubSpot CRM integration through the Model Context Protocol with 15+ tools for managing contacts, companies, and deals. Supports multiple transport protocols (HTTP, SSE, STDIO) with session management and real-time access to CRM data.
    3
    MIT
  • F
    license
    Not graded
    quality
    D
    maintenance
    Implements Universal Commerce Protocol (UCP) primitives backed by HubSpot CRM, enabling buyer profile, product catalog, cart, and order operations via MCP tools.
    -