Skip to main content
Glama
graysonlevino

Addepar MCP Server

Addepar MCP Server

MCP-сервер только для чтения, предоставляющий Claude данные Addepar по портфелям и структуре владения.

Создан для использования в финансовой отчётности в зарегистрированном инвестиционном консультанте. Руководящие принципы в порядке приоритета: надёжность, точность, безопасность, затем удобство.


Что гарантирует этот сервер

Он не гарантирует, что какое-либо число в реальном мире корректно. Ни один инструмент не может честно обещать этого, потому что сам Addepar несёт устаревшие отметки: запрос «на сегодняшнюю дату» обычно возвращает значение, помеченное на несколько недель раньше, потому что частные фонды переоцениваются ежеквартально.

Что он гарантирует — это полная честность в отношении происхождения данных:

  • Он никогда не выдумывает числа.

  • Он никогда молча не отбрасывает данные.

  • Он всегда сообщает о том, чего не знает.

Здесь намеренно нет оценок уверенности. Цифра с пометкой «уверенность 94%» — это ложная точность, а ложная точность в контексте комплаенса хуже, чем бесполезна. Вместо этого каждый ответ содержит структурированный массив caveats, который пуст, когда результат чист, так что его пустота является утвердительным заявлением, а не отсутствием проверки.

Правило null

Значение null и значение 0.0 — это разные факты, и они никогда не объединяются.

Подтверждено на живых данных: две позиции в одном домохозяйстве:

Позиция

Значение

Смысл

Leslie A Dahl, WRD Capital

0.0

Addepar вычислил значение, и оно равно нулю

W Robert Dahl, Goldman Sachs -400P

null

Значение не вычислено, причина не указана

Приведение этого null к нулю и суммирование даёт итог, который уверенно неверен и при этом выглядит вполне правдоподобно. Поэтому 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

Для этого типа объекта нет подтверждённого шаблона ссылки в интерфейсе


Инструменты

Инструмент

На какой вопрос отвечает

resolve_entity

Превратить имя в конкретный ID Addepar и тип объекта

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.

Только чтение, обеспечивается в коде

Клиент предоставляет только get и query, где 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 фирмы, а не через учётные данные, хранящиеся у внешней стороны.

Установите REQUIRE_AUTH=true, как только OAuth будет настроен. До этого сервер регистрирует вызовы как неприписанные; это честно, но не удовлетворяет требованию аудита на уровне пользователя.

Подводные камни развёртывания, о которых стоит знать заранее

  • URI перенаправления для размещённых поверхностей Claude: https://claude.ai/api/mcp/auth_callback.

  • Исходящий трафик Anthropic исходит из 160.79.104.0/21. И этот сервер, и конечные точки обнаружения сервера авторизации должны быть доступны из этого диапазона. Межсетевой экран перед поставщиком удостоверений нарушает поток, даже если сам MCP-сервер доступен.

  • С Entra ID URL MCP-сервера также должен быть зарегистрирован как URI идентификатора приложения в регистрации приложения, иначе запрос токена завершится ошибкой AADSTS9010010.

  • Claude выделяет примерно 10 секунд на конечные точки обнаружения и токена и 30 секунд на обновление. Медленные конечные точки выглядят как периодические сбои соединения, а не как явные ошибки.

Проверка подписи не реализована

auth.py декодирует утверждения JWT для целей аудита, но не проверяет подписи. Это приемлемо в доверенной сети и не приемлемо, как только сервер становится доступен недоверенным вызывающим. Замените это на настоящую проверку JWKS (получение ключей тенанта, проверка подписи, проверка издателя, аудитории и срока действия), прежде чем открывать доступ. Идентичность из непроверенного токена — это утверждение, а не факт. Это было оставлено намеренно незавершённым, а не заглушкой, чтобы выглядеть готовым.


Журнал аудита

Структурированные JSON Lines, по одному объекту на вызов инструмента, записываемые в AUDIT_LOG_PATH. Каждая запись содержит метку времени, инструмент, идентификацию вызывающего, аргументы, результат, длительность, ID запросов Addepar, затронутые сущности, количество строк, коды оговорок и любую ошибку.

Журнал должен храниться на стороне сервера. Транскрипт разговора — это не долговечная запись: пользователь может его удалить, а на некоторых поверхностях его вообще нельзя архивировать. Если единственный след обращения к данным живёт в окне чата, для целей комплаенса его не существует.

Поднимите этот вопрос в разговоре о комплаенсе: эти записи содержат имена сущностей, денежные суммы и паттерны доступа. Поэтому журнал находится внутри того же комплаенс-периметра, что и лежащие в основе данные клиентов, с теми же вопросами хранения и доступа. Решите заранее, пишет ли он в собственное хранилище или передаёт данные в существующий конвейер архивирования, потому что два хранилища одних и тех же клиентских данных удваивают комплаенс-поверхность.


Цитирование

Правило: выдавайте ссылку только тогда, когда подтверждены и тип объекта, и пространство имён 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 не может отличить действительный маршрут от недействительного. Любой новый шаблон должен быть подтверждён человеком, копирующим реальный URL из живого интерфейса.


Проверенное поведение

Проверено на живом тенанте 26 августа 2026 года. Это регрессионные фикстуры в tests/test_regression_fixtures.py. Если рефакторинг меняет любое из них, рефакторинг ошибочен, пока не доказано обратное.

Проверяемое утверждение

Значение

Итог по домохозяйству Dahl

486,034,402.38

Loon Point Holdings II LLC, по целевым позициям, 4 вхождения суммированы

21,427,660.34

Семейство Pacific Lake, 6 совпадений из 4 121 проверенных

15,229,060.19

Доля Шарлотты в общей LLC

5,356,915.09

Реальная максимальная глубина владения

5

Домохозяйств в фирме

9

Две перекрёстные проверки делают эти значения заслуживающими доверия, а не просто зафиксированными:

  1. Итог по домохозяйству идентичен независимо от того, получен ли он группировкой по ownership (вложенная юридическая иерархия) или по security (плоские позиции). Две совершенно разные формы запроса — одно и то же число с точностью до цента.

  2. Общий итог общей LLC равен сумме долей в ней четырёх родственных трастов, полученной при обходе с противоположных направлений, без двойного подсчёта.


Заметки об API Addepar

Поведение, доставшееся дорогой ценой, задокументировано, чтобы не переоткрывать его мучительно.

  • Каждая конечная точка требует заголовок Addepar-Firm, включая /v1/users/me.

  • filter[name] для /v1/entities молча игнорируется. Это не настоящий фильтр: он возвращает произвольные сущности, а не совпадения по имени, что хуже ошибки, потому что выглядит как успех. filter[entity_types] настоящий и работает.

  • Без фильтра GET /v1/entities возвращает 400 ("cache is not responsible for firm 2142"). Добавление любого параметра фильтра позволяет этого избежать. Баг на стороне Addepar; мы обошли его, а не сообщили о нём.

  • Поиск по имени работает в POST /v1/groups/query посредством display_names. Это единственный работающий поиск по имени в API.

  • Группировка ownership обходит только юридические лица. Она останавливается на листьях типа холдинговых счетов и не спускается к ценным бумагам внутри них. Используйте группировку security для фактических инвестиционных позиций.

  • Дискретные фильтры работают только по точному совпадению. Ни префиксного, ни подстрочного сопоставления нет, поэтому частичное имя возвращает ноль строк вместо нечёткого совпадения.

  • Ошибки понятные и конкретные, например "Invalid grouping attribute: nonsense_grouping". Они передаются без изменений.

  • Задержка варьируется. Сводка по домохозяйству обычно выполняется примерно за 3 секунды. Один запуск занял 47,8 секунды при потолке Addepar в 60 секунд. Тайм-аут клиента установлен на 55 секунд, чтобы возникала явная ошибка, а не обрыв соединения на середине ответа.

  • Лимиты запросов действуют на всю фирму, 50 запросов за 15 минут и 1000 за 24 часа, общие для всех остальных интеграций в фирме. Поэтому лимит может сработать из-за активности, не связанной с этим сервером.

Коллизии одинаковых имён

Три случая были обнаружены за одну сессию — это говорит о том, что перед нами особенность данных, а не невезение:

Имя

Объекты

Dahl 2012 Dynasty Trust

сущность PERSON_NODE 31643590 и сущность TRUST 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 теперь — это MCPServer из mcp.server.mcpserver.

  • Поля ToolAnnotations переехали с camelCase на snake_case (readOnlyHint стало read_only_hint).

  • stateless_http и json_response перенесены с конструктора на streamable_http_app().

  • Пользовательские исключения должны наследоваться от ToolError из SDK. Всё остальное считается сбоем, и его сообщение остаётся на стороне сервера, поэтому модель получает только общую ошибку. Это молча ломает любую ошибку, которая должна была передавать информацию обратно, например список кандидатов при неоднозначности.


Известные пробелы

  • get_commitments и get_entity_attributes следуют тем же проверенным шаблонам, что и другие инструменты, но не были опробованы на живых данных. Столбцы commitment во время более ранних проверок возвращали 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