Skip to main content
Glama
graysonlevino

Addepar MCP Server

Addepar MCP Server

Addepar 포트폴리오 및 소유권 데이터를 Claude에 노출하는 읽기 전용 MCP 서버.

등록 투자 자문사의 재무 보고를 위해 제작되었다. 우선순위에 따른 지배 원칙은 신뢰성, 정확성, 보안, 그다음 편의성이다.


이 서버가 보장하는 것

어떤 숫자가 실제 세계에서 정확하다는 것은 보장하지 않는다. 그런 것은 어느 도구도 정직하게 약속할 수 없다. Addepar 자체가 오래된 평가 시점을 지니고 있기 때문이다. "오늘 기준"으로 실행한 쿼리는 일상적으로 몇 주 전에 평가된 값을 반환하는데, 사모 펀드는 분기별로 평가하기 때문이다.

보장하는 것은 출처에 대한 완전한 정직성이다:

  • 숫자를 절대 만들어내지 않는다.

  • 데이터를 절대 조용히 버리지 않는다.

  • 모르는 것을 항상 명시한다.

의도적으로 신뢰도 점수는 없다. "94% 확신"이라는 수치는 거짓 정밀도이며, 거짓 정밀도는 컴플라이언스 맥락에서 쓸모없는 것보다 더 나쁘다. 대신 모든 응답은 구조화된 caveats 배열을 지니며, 결과가 깨끗할 때는 그 배열이 비어 있으므로, 비어 있음 자체가 점검 부재가 아니라 긍정적 진술이 된다.

null 규칙

null 값과 0.0 값은 서로 다른 사실이며 결코 병합되지 않는다.

실제 데이터에서 확인된, 같은 가구 내 두 포지션:

포지션

의미

Leslie A Dahl, WRD Capital

0.0

Addepar가 값을 계산했고 그 값은 0이다

W Robert Dahl, Goldman Sachs -400P

null

계산된 값 없음, 사유 미기재

그 null을 0으로 강제 변환하여 합산하면 자신 있게 틀린 합계가 나오고 전적으로 그럴듯해 보인다. 따라서 null은 합산에서 제외되고, 집계되며, NULL_VALUES_EXCLUDED에 명명된다.

주의 코드

코드

발생 조건

STALE_VALUATION

포지션이 요청일보다 35일 이상 전에 평가됨

NULL_VALUES_EXCLUDED

하나 이상의 포지션이 계산된 값을 반환하지 않음

AMBIGUOUS_MATCH

조회에서 그럴듯한 후보가 여러 개 발견됨

PATTERN_MATCH_USED

이름 일치가 사용됨, 본질적으로 비완전함

DEPTH_CAP_REACHED

순회가 조기에 중단됨, 순환 중첩을 시사

MIXED_VALUATION_DATES

합계가 서로 다른 날짜에 평가된 값을 결합함

RESULT_TRUNCATED

반환된 것보다 더 많은 행이 존재함. 합계는 여전히 모두 포함

UNVERIFIED_CITATION

이 객체 유형에 대해 확인된 UI 링크 패턴이 없음


도구

도구

답하는 질문

resolve_entity

이름을 특정 Addepar ID 및 객체 유형으로 변환

get_ownership_rollup

총 노출, 타겟 보유, 또는 수익적 소유권

get_group_exposure

관련 펀드 계열 전반의 노출

get_entity_attributes

한 고객의 보유 자산이 어떻게 분류되는지

list_views

어떤 저장된 보고서가 존재하는지

get_view_data

회사 자체 저장 보고서 중 하나를 실행

get_commitments

약정, 납입 요청, 미납입 자본

일곱 개 모두 read_only_hint=True를 선언하므로, 신뢰할 수 있는 클라이언트는 확인 프롬프트를 건너뛸 수 있다. 진짜 보장은 구조적이다. 아래를 보라.

도구 수를 절제하라. 도구 정의는 모든 요청에서 모델의 컨텍스트로 로드되므로, 사용 여부와 관계없이 각각 토큰을 소비하며, 비대해진 표면은 도구 선택을 눈에 띄게 저하시킨다. 거의 중복인 도구를 추가하는 것보다 기존 도구에 매개변수를 추가하는 것을 선호하라.


아키텍처

src/addepar_mcp/
  config.py       Settings from environment. No secrets in code.
  errors.py       Three failure classes. Extends the SDK ToolError.
  models.py       The response contract. Caveats, provenance, disclosure.
  client.py       Read-only HTTP client. Cannot construct a mutating request.
  tree.py         Traversal and null-safe arithmetic. No network dependency.
  citations.py    UI links, only for confirmed URL patterns.
  audit.py        Structured JSON Lines compliance record.
  auth.py         Per-request identity extraction. Entra ready.
  runtime.py      Shared runtime container.
  server.py       Entrypoint, transports, identity middleware.
  tools/          One module per tool, each exposing register(mcp).

도구를 추가한다는 것은 모듈 하나와 tools/__init__.py의 한 줄을 추가한다는 뜻이다.

코드로 강제되는 읽기 전용

클라이언트는 getquery만 노출하며, query는 읽기 전용 쿼리 엔드포인트의 고정 허용 목록으로 제한된 POST다. PATCH, PUT, DELETE를 발행할 수 있는 코드 경로는 없으며, 임의 경로로 POST할 방법도 없다. 시도하면 ReadOnlyViolationError가 발생한다.

이는 장식이 아니라 의도적이다. v1 사용 사례 중 쓰기가 없으며, 클라이언트의 소유 구조를 변형시키는 버그는 완전히 복구 가능하지 않을 것이다.

실패 시 폐쇄

작업 중 시간 초과나 속도 제한에 걸리면 도구는 오류를 반환하고 데이터를 반환하지 않는다. 부분 트리나 더 작은 합계를 절대 반환하지 않는데, 잘린 소유권 합계는 언뜻 보기에 올바른 합계와 구별할 수 없기 때문이다.


설정

python -m venv .venv
.venv/bin/pip install -e ".[dev]"
cp .env.example .env      # then fill in credentials
.venv/bin/python -m pytest tests/ -q

stdio로 로컬 실행:

TRANSPORT=stdio .venv/bin/python -m addepar_mcp.server

HTTP로 실행:

TRANSPORT=http HOST=0.0.0.0 PORT=8080 .venv/bin/python -m addepar_mcp.server

GET /healthz에서 상태 확인. MCP 엔드포인트는 /mcp.


배포 및 인증

워크스테이션마다 하나가 아니라 운영할 인스턴스 하나가 있도록 HTTPS로 원격 배포하라.

신원, 그리고 그것이 중요한 이유

두 개의 분리된 신원 계층이 있으며, 이를 혼동하면 나중에 혼란이 생긴다:

  • 호출자 신원: 도구를 호출한 사람. 요청마다 추출되며 모든 감사 기록에 기록된다.

  • 업스트림 신원: Addepar 자체 로그에 표시되는 것. 누가 요청했는지와 관계없이 단일 서비스 자격 증명이다.

즉, 서버 측 감사 로그가 "누가 클라이언트 데이터를 보았는가"에 대한 권위 있는 답이다. Addepar의 로그는 사용자 수준에서 이를 뒷받침하지 않는다.

지원되는 두 가지 모드:

모드

사용자별 귀속

공유 조직 자격 증명(static_headers)

아니요. 관리자가 자격 증명 하나를 입력하며, 모든 사용자의 요청이 그것을 담고 있으므로 모든 사용자를 구별할 수 없다.

사용자별 OAuth

예. 각 사용자가 개별적으로 동의하므로 요청이 그들을 식별한다.

컴플라이언스가 "누가 무엇을 요청했는가"에 답해야 한다면 OAuth는 선택 사항이 아니다. 그 답을 생성하는 유일한 구성이다.

이 배포에서 자연스러운 권한 부여 서버는 회사의 Entra ID 테넌트인데, 이미 Microsoft 365를 운영하고 있기 때문이다. 이를 통해 접근이 실제 기업 계정에 묶이고, 외부 당사자가 보유한 자격 증명이 아니라 회사 자체 SSO를 통해 관리 가능해진다.

OAuth가 구성되면 REQUIRE_AUTH=true를 설정하라. 그때까지 서버는 호출을 귀속 없이 기록하는데, 이는 정직하지만 사용자별 감사 요구를 충족하지는 않는다.

미리 알아두면 좋은 배포 함정

  • 호스팅된 Claude 플랫폼의 리디렉션 URI는 https://claude.ai/api/mcp/auth_callback이다.

  • Anthropic 이그레스 트래픽은 160.79.104.0/21에서 발생한다. 이 서버와 권한 부여 서버의 검색 엔드포인트 모두 해당 범위에서 도달 가능해야 한다. ID 공급자 앞의 방화벽은 MCP 서버 자체에 도달 가능하더라도 흐름을 끊는다.

  • Entra ID에서는 MCP 서버 URL도 앱 등록의 애플리케이션 ID URI로 등록해야 한다. 그렇지 않으면 토큰 요청이 AADSTS9010010으로 실패한다.

  • Claude는 검색 및 토큰 엔드포인트에 약 10초, 갱신에 30초를 허용한다. 느린 엔드포인트는 명백한 시간 초과라기보다 간헐적 연결 실패로 나타난다.

서명 검증은 구현되지 않음

auth.py는 감사 목적으로 JWT 클레임을 디코딩하지만 서명은 검증하지 않는다. 이는 신뢰할 수 있는 네트워크에서는 허용되며, 서버가 신뢰할 수 없는 호출자에게 도달 가능해지면 허용되지 않는다. 노출 전에 실제 JWKS 검증(테넌트 키 가져오기, 서명 확인, 발급자, 대상 및 만료 확인)으로 교체하라. 검증되지 않은 토큰의 신원은 사실이 아니라 주장이다. 이는 완성된 것처럼 보이도록 임시로 채워두기보다는 의도적으로 미완성으로 남겨두었다.


감사 로깅

구조화된 JSON Lines, 도구 호출당 객체 하나, AUDIT_LOG_PATH에 기록. 각 레코드는 타임스탬프, 도구, 호출자 신원, 인수, 결과, 지속 시간, Addepar 요청 ID, 접촉한 엔터티, 행 수, 주의 코드 및 모든 오류를 담는다.

로그는 서버 측에 있어야 한다. 대화 기록은 지속적인 기록이 아니다. 사용자가 삭제할 수 있고, 일부 플랫폼에서는 전혀 보관할 수 없다. 데이터 접근의 유일한 흔적이 채팅 창에만 있다면 컴플라이언스 목적상 존재하지 않는 것이다.

컴플라이언스 대화에서 이것을 제기하라: 이 레코드에는 엔터티 이름, 달러 금액 및 접근 패턴이 포함된다. 따라서 로그는 기본 클라이언트 데이터와 동일한 컴플라이언스 경계 안에 있으며, 동일한 보존 및 접근 질문이 따라붙는다. 자체 저장소에 기록할지 기존 아카이빙 파이프라인으로 내보낼지 조기에 결정하라. 동일한 클라이언트 데이터의 저장소 두 개는 컴플라이언스 표면을 두 배로 만들기 때문이다.


인용

규칙: 객체 유형과 ID 네임스페이스가 모두 확인된 경우에만 링크를 내보낸다. 그렇지 않으면 재현 가능한 쿼리를 내보낸다. 자신 있게 틀린 인용은 없는 것보다 나쁘다. 권위 있어 보이고 누군가를 잘못된 곳으로 보내기 때문이다.

객체

패턴

상태

엔터티 상세

/app/tools/details/entity/{entity_id}

확인됨

엔터티의 뷰

/app/tools/portfolio/entity/{portfolio_id}/view/{view_id}

확인됨

그룹의 뷰

/app/tools/portfolio/group/{group_id}/view/{view_id}

추론됨, 내보내지 않음

포지션 상세

알 수 없음, 존재하지 않을 수 있음

내보내지 않음

총 노출과 같은 계산된 집계는 Addepar 객체로 존재하지 않으며 기본 URL이 없다. 동일한 포트폴리오에 뿌리를 둔 저장된 뷰로 딥 링크하여 인용하는데, 이는 사용자를 회사가 만들고 이미 신뢰하는 보고서로 안내한다.

이 패턴은 프로그래밍 방식으로 검증할 수 없다. Addepar 웹 앱은 모든 경로에 대해 HTTP 200을 반환하는 단일 페이지 애플리케이션이며, 의도적인 무의미한 경로도 포함하므로 curl은 유효한 경로와 무효한 경로를 구별할 수 없다. 새 패턴은 반드시 사람이 실제 UI에서 실제 URL을 복사하여 확인해야 한다.


검증된 동작

2026-08-26에 실제 테넌트에서 검증됨. 이것들은 tests/test_regression_fixtures.py의 회귀 픽스처다. 리팩터링이 이 중 하나라도 바꾸면, 반대가 증명될 때까지 그 리팩터링은 잘못된 것이다.

단언

Dahl 가구 합계

486,034,402.38

Loon Point Holdings II LLC, 타겟팅, 4개 발생 합산

21,427,660.34

Pacific Lake 계열, 스캔된 4,121개 중 6개 일치

15,229,060.19

공유 LLC에서 Charlotte의 지분

5,356,915.09

실제 최대 소유권 깊이

5

회사의 가구 수

9

두 가지 교차 검증이 이것들을 단순히 기록된 것이 아니라 신뢰할 수 있게 만든다:

  1. 가구 합계는 ownership(중첩 법적 계층) 그룹화로 도달하든 security(평면적 보유) 그룹화로 도달하든 동일하다. 완전히 다른 두 쿼리 형태, 센트까지 같은 숫자.

  2. 공유 LLC 자체의 합계는 네 형제 신탁의 지분 합계와 동일하며, 반대 순회 방향에서 도달하고 이중 계산이 없다.


Addepar API 참고 사항

힘들게 얻은 동작을 기록해 두어 고통스럽게 재발견되지 않도록 한다.

  • 모든 엔드포인트는 Addepar-Firm 헤더를 요구한다, 여기에는 /v1/users/me도 포함된다.

  • /v1/entitiesfilter[name]은 조용히 무시된다. 실제 필터가 아니다: 이름 일치 대신 임의의 엔티티를 반환하는데, 이는 작동한 것처럼 보이기 때문에 오류보다 더 나쁘다. filter[entity_types]는 실제이며 작동한다.

  • 필터 없는 GET /v1/entities는 400을 반환한다 ("cache is not responsible for firm 2142"). 필터 매개변수를 추가하면 피할 수 있다. Addepar 쪽 버그로, 보고하지 않고 우회했다.

  • 이름 검색은 POST /v1/groups/query에서 display_names를 통해 작동한다. 이것이 API에서 유일하게 작동하는 이름 검색이다.

  • ownership 그룹화는 법인 엔티티만 탐색한다. 보유 계좌 형태의 말단(leaf)에서 멈추며, 그 내부의 증권까지 내려가지 않는다. 실제 투자 라인에는 security 그룹화를 사용하라.

  • 개별 필터는 정확히 일치하는 경우만 지원한다. 접두사 또는 부분 문자열 일치가 없으므로, 부분 이름은 퍼지 일치 대신 0개의 행을 반환한다.

  • 오류 메시지는 명확하고 구체적이다. 예를 들어 "Invalid grouping attribute: nonsense_grouping"이 있다. 이는 원문 그대로 전달된다.

  • 지연 시간은 변동적이다. 가계 롤업(household rollup)은 보통 약 3초 안에 완료된다. 한 번은 Addepar의 60초 상한에 맞서 47.8초가 걸렸다. 클라이언트 타임아웃은 55초로 설정되어 있어, 응답 도중 연결이 끊기는 대신 명확한 오류가 표시된다.

  • 속도 제한은 펌(firm) 전체에 적용된다. 15분당 50회, 24시간당 1,000회이며, 펌의 다른 모든 통합과 공유된다. 따라서 이 서버와 무관한 활동 때문에도 제한이 촉발될 수 있다.

동일 이름 충돌

세 건이 단일 세션에서 발견되었는데, 이는 단순한 불운이 아니라 데이터의 형태임을 보여준다.

이름

객체

Dahl 2012 Dynasty Trust

PERSON\_NODE 엔티티 31643590TRUST 엔티티 31643598

Pacific Lake Partners Long-Term Hold Fund One, L.P.

두 번 나타남

Dahl Family

GROUP 3192711 및 HOUSEHOLD 엔티티 31647552

따라서 모든 응답은 이름, ID, 그리고 객체 유형을 공개한다. 서로 다른 네임스페이스의 ID는 서로 교환할 수 없으며, portfolio_type은 일치해야 한다.


SDK 버전 참고

이 문서는 MCP Python SDK 2.x를 대상으로 한다. 이 조직의 이전 코드를 포팅하는 경우:

  • FastMCP는 이제 mcp.server.mcpserverMCPServer이다.

  • ToolAnnotations 필드는 camelCase에서 snake_case로 이동했다 (readOnlyHintread_only_hint가 되었다).

  • stateless_httpjson_response는 생성자에서 streamable_http_app()으로 이동했다.

  • 사용자 정의 예외는 SDK의 ToolError를 상속해야 한다. 그 외의 것은 충돌로 처리되며 해당 메시지는 서버 측에 유지된다. 따라서 모델은 일반적인 실패만 받는다. 이는 모호성 후보 목록처럼 정보를 다시 전달해야 하는 오류를 조용히 깨뜨린다.


알려진 미비점

  • get_commitmentsget_entity_attributes는 다른 도구들과 동일한 검증된 패턴을 따르지만 실제 데이터로는 테스트되지 않았다. 이전 탐색 중 커밋먼트 열이 0.0을 반환했으며, 펌의 저장된 뷰가 사용하는 기간 인자가 필요할 수 있다.

  • JWT 서명 검증은 구현되지 않았다. 위를 참조하라.

  • 그룹을 루트로 하는 뷰 URL 패턴은 추론된 것이며 일부러 출력되지 않는다.

  • 자격 증명이 여러 작업 세션에 걸쳐 평문으로 노출되었다. 코드는 환경 변수에서 읽으므로 교체는 설정 변경으로 처리되지만, 교체 자체는 프로덕션 사용 전에 여전히 수행해야 한다.

-
license - not tested
Not graded
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

  • Read-only public financial evidence from LiquiLens, Undertow, Seiche and Palimpsest.

  • Read-only access to your VortexIQ store data: audits, KPIs, alerts, Brand DNA, reports, Ask VIQ.

  • Read-only NuMetric.work accounting & ERP data: statements, KPIs, reports, invoices, documents.

View all MCP Connectors

Latest Blog Posts

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/graysonlevino/oakridge-addepar'

If you have feedback or need assistance with the MCP directory API, please join our Discord server