LQABR MCP HubSpot Server
LQABR_MCP
LQABR 중앙 HubSpot MCP 서버. FastMCP 기반이며 독립형 — LQABR 모노레포에 대한 의존성 없음.
RUNNING.md — 실행 방법: 설정, 자격 증명, 두 전송 방식, agentgateway, 문제 해결. CONSUMING.md — 이메일/음성/일정 에이전트가 호출하는 방법: ADK
McpToolset, 인증, 와이어 계약, 도구 범위 지정. 이 파일은 설계 근거 문서이며, 위 두 파일은 절차 문서입니다.
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이것은 포크(fork)이지, 이동이 아닙니다
hubspot_mcp/는 모노레포 구현의 복사본입니다. import 라인만 다시 작성되었습니다. 로직, 필드 이름 또는 HubSpot 속성 이름은 변경되지 않았습니다. diff로 확인됨 — 모든 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 ...모노레포는 여전히 자신의 복사본이 필요합니다. 삭제하지 마십시오.
모듈 | 다른 사용처 |
| lead_profile/src의 8개 파일, text_voice/src의 2개 파일, |
|
|
| lead_profile |
결과: 이제 동일한 필드 이름과 동일한 HubSpot 속성 이름을 사용하는 두 개의 HubSpot 쓰기 경로가 존재하며, 데이터 계약에 따르면 해당 이름이 계약 그 자체입니다. crm.py의 수정, 인증 변경, HubSpot 속성 이름 변경은 모두 수동으로 두 곳에 적용되어야 합니다. 이를 강제하는 것은 없습니다. 이에 대한 비용을 예산에 반영하거나, 한쪽을 폐지할 계획을 세우십시오.
Related MCP server: HubSpot MCP Server
왜 이 모노레포 외부에 있는가
LQABR 저장소는 루트에 문자 그대로 mcp라는 이름의 최상위 패키지를 가지고 있으며, 이는 FastMCP가 의존하는 mcp SDK를 가립니다. 저장소 내부에서 실행하면 FastMCP 자체의 import가 깨집니다.
LQABR 저장소 루트를 PYTHONPATH에 추가하지 마십시오.
라이브러리: 공식 SDK가 아닌 FastMCP
의존성은 fastmcp>=3.4.7입니다. mcp>=2.0을 추가하지 마십시오 — 두 라이브러리는 상호 배타적입니다:
fastmcp3.4.7은 전이적으로mcp<2.0,>=1.24.0을 고정합니다 (mcp 1.29를 설치함).공식 SDK의 서버 클래스인
MCPServer는mcp>=2.0에만 존재합니다.
따라서 프로젝트는 FastMCP 또는 MCPServer 중 하나만 사용할 수 있으며, 둘 다 사용할 수 없습니다. 이 프로젝트는 FastMCP를 사용합니다. 여기서 MCPServer를 import하는 것은 없습니다.
알아두어야 할 두 가지 결과:
전송 이름이 다릅니다. FastMCP의 HTTP 전송은
"http"입니다 ("streamable-http"는 별칭으로 허용됨). 엔드포인트 경로 키워드 인수는path=입니다. 공식 SDK는streamable_http_path=로 표기합니다.타입 필드가 다릅니다. mcp가 1.x로 고정되어 있기 때문에 번들로 제공되는 타입은 camelCase를 사용합니다:
Tool.inputSchema(input_schema가 아님).
모노레포의 lqabr_core/leadgen/server.py는 여전히 MCPServer를 사용합니다. 이제 이것은 포크 외에 두 코드베이스 간의 두 번째 차이점입니다.
실행하기
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는 분명히 필요합니다.
.env에는 비밀 값이 없습니다 — HUBSPOT_AUTH_MODE, LQABR_SECRET_PROJECT 및 비밀의 ID만 있습니다. 토큰 자체는 런타임에 Secret Manager API를 통해 가져오며, 메모리에 보관되고, 절대 기록되지 않으며(감사 라인은 길이와 마지막 네 문자만 기록), 900초 동안 캐시되어 회전 시 재배포가 필요하지 않습니다.
auth.py와 secrets.py는 모두 실패 시 닫힙니다(fail closed) — 설정되지 않으면 명시적 오류가 발생하며, 조용한 기본값이 없습니다.
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 HubSpotpytest.ini는 hubspot-crm-mcp-server/를 경로에 추가하여 import hubspot_mcp가 해결되도록 합니다 — 폴더 자체는 하이픈 때문에 패키지가 될 수 없습니다.
계약은 9개가 아닌 10개 필드입니다
LeadProfile은 10개를 가집니다: 모두가 문서화하는 9개에 contact_name(이름/성 매핑을 위해 추가됨)이 더해집니다. 모노레포의 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 토큰 audience는 서비스 기본 URL에서
/mcp를 제외한 것입니다. 스크립트가 자동으로 제거합니다.
클라이언트는 fastmcp.Client를 사용하며, 이는 초기화 핸드셰이크를 처리하므로 이 파일에는 세션 파이프라인이 없습니다. 헤더는 StreamableHttpTransport에 실려 전송됩니다. 이제 참조 샘플의 라이브러리와 일치합니다.
Cloud Run에 배포하기
2단계 uv 빌드, 비루트 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로 배포, 세 에이전트 서비스 계정에 roles/run.invoker 부여, test_server.py를 해당 서버에 연결.
노출된 도구
도구 | 방향 | 설명 |
| 쓰기 | 회사 upsert → 연락처 upsert → 연결. 멱등성(idempotent). |
| 읽기 | 계약 필드 + |
중복 제거: 연락처는 employee_id, 회사는 company_id. 이메일은 사용자 정의 email_id 속성에 저장됨.
미해결 사항. 등록된 도구 이름은
upsert_lead_profile(단수)이지만, 설계 문서, 세션 핸드오프 및 프로젝트 지침은 모두upsert_lead_profiles(복수)라고 말하며, 기본 함수는 복수형입니다. 이는 와이어 계약 문제입니다 — 클라이언트가 연결되기 전에 해결하십시오.
자격 증명
두 가지, 절대 혼동되지 않음:
Google ID 토큰은 에이전트 → 이 서버를 증명합니다 (Cloud Run 서비스 간).
HubSpot M2M 토큰은 이 서버 → HubSpot을 증명하며, 서버 내부에서 호출 시마다 생성됩니다. 호출자는 이를 절대 볼 수 없습니다.
이 서비스는 HubSpot 자격 증명의 유일한 보유자입니다.
검증됨
오직 fastmcp 3.4.7 (이로 인해 mcp 1.29가 설치됨), requests 및 pytest만 포함된 깨끗한 가상 환경에서 — lqabr_core가 없고(ModuleNotFoundError 확인됨), MCPServer가 없고(ImportError 확인됨):
프로젝트 내 어디에도
lqabr_coreimport 없음포팅된 테스트 스위트: 61개 통과, 0개 실패
stdio —
tools/list가 두 도구를 반환,PYTHONPATH완전히 제거됨--transport http— 호스트/포트/경로 바인딩, 전체fastmcp.Client세션--transport streamable-http— 별칭 허용됨, 동일한 엔드포인트 제공test_server.py— 실행 중인 서버에 대해 PASS, 종료 코드 0test_server.pyunder pytest — 서버와 함께 3개 통과, 서버 없이 3개 건너뜀실제
call_tool이 실제 체인에 도달함: 전송 → 도구 →crm.py→auth.py→secrets.py, 의도적인AuthConfigError/SecretConfigError가드에서만 실패 (테스트 환경에 GCP 구성 없음). 배선이 종단 간 입증됨.
검증되지 않음: Docker 이미지는 한 번도 빌드되지 않았습니다 — 이 파일들이 조합된 곳에서는 Docker 데몬을 사용할 수 없었습니다. 실제 HubSpot을 건드린 것은 없으며, 모든 테스트는 가짜(fake)를 사용합니다.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- AlicenseBqualityFmaintenanceEnables AI models to interact with HubSpot CRM data and operations through a standardized interface, supporting contact and company management.16127MIT
- AlicenseAqualityBmaintenanceExposes HubSpot CRM data and actions as tools for AI agents, enabling contact lookup, company search, contact creation, and activity logging via natural language.4182MIT
- AlicenseAqualityBmaintenanceEnables AI agents to safely operate HubSpot CRM contacts, deals, and pipelines via MCP, with caching, idempotency, audit trails, and robust error handling.15MIT
- AlicenseBqualityBmaintenanceEnables AI assistants to interact with a HubSpot CRM account via natural language, starting with read-only lookups and optionally enabling write operations like creating contacts, deals, and notes.11MIT
Related MCP Connectors
LeadConnector / GoHighLevel MCP Pack — wraps the GoHighLevel CRM for AI agents.
Agent-native CRM. 25 tools — contacts, deals, sequences, enrichment waterfall, audit log.
Connect AI to your Attio CRM. Manage contacts, companies, deals, and sales pipelines. Create tasks…
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/TNE736/LQABR_MCP'
If you have feedback or need assistance with the MCP directory API, please join our Discord server