Skip to main content
Glama
ecarcamo

Sync Licensing MCP Server

by ecarcamo

Sync Licensing MCP Server

Локальный сервер Model Context Protocol, который предоставляет каталог и бизнес-логику музыкальной платформы sync-лицензирования: поиск треков по креативному брифу, проверка их правовой чистоты, расчёт стоимости лицензии по условным правилам ценообразования, выпуск контракта и регистрация использования.

Создан для CC3067 Redes (Universidad del Valle de Guatemala), проект 1. Поток сообщений MCP реализован напрямую поверх JSON-RPC 2.0 — без MCP SDK, без FastMCP, без фреймворков. Пакет сервера зависит только от стандартной библиотеки Python.


Содержание

  1. Бизнес-кейс

  2. Архитектура

  3. Требования

  4. Установка

  5. Сборка каталога

  6. Использование

  7. Справочник инструментов

  8. Правила ценообразования

  9. Детали протокола

  10. Откуда берутся данные

  11. Тестирование

  12. Структура проекта

  13. Статус проекта


Related MCP server: MusicBrainz MCP Server

1. Бизнес-кейс

Sync-лицензирование — это бизнес-модель таких платформ, как Epidemic Sound, Artlist и Musicbed: создатель контента или рекламное агентство обязаны купить лицензию перед использованием трека в аудиовизуальном контенте. В этом процессе есть три узких места:

  • Поиск трека, который соответствует креативному брифу и бюджету, занимает много времени.

  • Правовой статус трека не очевиден — он может содержать сэмплы, которые никогда не были очищены, или быть заморожен из-за спора об авторстве.

  • Цена не фиксирована. Один и тот же трек стоит одну сумму для поста в Instagram и совсем другую — для национальной телевизионной кампании.

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

2. Архитектура

        ┌────────────────────────┐
        │  Host (chatbot / CLI)  │
        └───────────┬────────────┘
                    │  spawns as a subprocess
        ┌───────────▼────────────┐
        │   MCP client           │   client/mcp_cli.py
        └───────────┬────────────┘
                    │  JSON-RPC 2.0 over stdio
                    │  (one JSON object per line)
        ┌───────────▼────────────┐
        │   MCP server           │   synclicense_mcp/
        │                        │
        │   jsonrpc.py  framing  │
        │   server.py   dispatch │
        │   tools.py    5 tools  │
        │   pricing.py  rate card│
        │   contracts.py contracts
        │   catalog.py  catalog  │
        └───────────┬────────────┘
                    │
        ┌───────────▼────────────┐
        │  data/catalog.json     │  built by scripts/seed_catalog.py
        │  data/usage_log.jsonl  │  append-only audit log
        └────────────────────────┘

stdout несёт только протокольный трафик; все диагностические сообщения сервер выводит в stderr, поэтому перенаправление вывода сервера никогда не повреждает поток.

3. Требования

  • Python 3.10 или новее (разработано на 3.11).

  • Других зависимостей для запуска сервера нет.

  • requests нужен только для получения реальных метаданных из Jamendo, а pytest — только для запуска тестов. Оба указаны в requirements.txt.

4. Установка

git clone https://github.com/ecarcamo/MCP-Local-Redes.git
cd MCP-Local-Redes

python3 -m venv .venv
source .venv/bin/activate          # Windows: .venv\Scripts\activate

pip install -r requirements.txt

Пакет не устанавливается: он импортируется из корня репозитория, поэтому все команды ниже выполняются из каталога проекта.

5. Сборка каталога

В репозитории уже есть каталог data/catalog.json с 800 реальными треками, полученными из API Jamendo, так что этот раздел можно пропустить и перейти сразу к Использованию. Пересобирайте его только в том случае, если нужен другой размер, другое зерно (seed) или каталог, не требующий учётных данных.

Офлайн-режим (по умолчанию, без учётных данных, без сети)

python scripts/seed_catalog.py --offline --count 800

Детерминированный: одно и то же --seed всегда даёт один и тот же каталог. Он также закрепляет три известных трека в начале (TRK-00001 — чистый, TRK-00002 — с ожидающими сэмплами, TRK-00003 — заблокированный), что упрощает демонстрацию сценариев отказа.

Режим Jamendo (реальные метаданные Creative Commons)

Зарегистрируйтесь на https://devportal.jamendo.com, чтобы получить client_id, затем:

cp .env.example .env
# edit .env and set JAMENDO_CLIENT_ID=your_client_id

python scripts/seed_catalog.py --jamendo --count 800

Метаданные треков берутся из API; базовая плата и правовой статус по-прежнему генерируются локально (см. раздел 10). Популярность берётся из собственной сортировки API popularity_total. Бесплатный тариф Jamendo ограничивает всплески запросов и отвечает на ограниченную страницу пустым списком результатов, а не ошибкой, поэтому скрипт делает паузы между страницами и повторяет запрос пустой страницы, прежде чем заключить, что каталог исчерпан.

Параметр

По умолчанию

Описание

--offline / --jamendo

--offline

Источник метаданных треков

--count N

800

Сколько треков записать

--seed N

23016

Зерно для имитации бизнес-уровня

--output PATH

data/catalog.json

Куда записать каталог

6. Использование

6.1 Запуск управляемой демонстрации

Сценарный сквозной прогон, полезный в качестве смоук-теста. Он запускает сервер, проигрывает полный диалог лицензирования и выводит каждое сообщение JSON-RPC, проходящее по каналу (--> отправлено, <-- получено):

python client/mcp_cli.py --demo

Демонстрация проходит через: рукопожатие → tools/list → поиск трека → проверку его правовой чистоты → расчёт стоимости → выпуск контракта → регистрацию использования → и три случая отказа (заблокированный трек, котировка, принадлежащая другому треку, и недопустимый аргумент).

Добавьте --quiet, чтобы скрыть необработанный протокольный трафик и видеть только ответы:

python client/mcp_cli.py --demo --quiet

6.2 Интерактивная сессия (основной способ использования)

REPL для управления сервером вручную, по одному инструменту за раз:

python client/mcp_cli.py --interactive

Команда

Описание

list

Инструменты, опубликованные сервером

schema <tool>

JSON Schema одного инструмента

call <tool> <json>

Вызвать инструмент с JSON-аргументами

vars

Идентификаторы, запомненные из ответов

ping

Отправить JSON-RPC ping

raw <method> [json]

Отправить любой метод JSON-RPC вручную

quit

Закрыть сессию

Идентификаторы запоминаются. Каждый *_id, возвращаемый инструментом, сохраняется и может быть использован как $name в следующем вызове, поэтому весь переговорный процесс по лицензированию можно ввести, не копируя ни одного идентификатора вручную:

mcp> call buscar_pista {"mood": "epico", "instrumental": true, "presupuesto_max": 100, "limite": 3}
   ...
   remembered: $pista_id=TRK-00312

mcp> call verificar_clearance {"pista_id": "$pista_id"}

mcp> call calcular_costo_licencia {"pista_id": "$pista_id", "tipo_uso": "publicidad_online", "territorio": "latam", "exclusividad": "sectorial", "duracion_meses": 12}
   ...
   remembered: $cotizacion_id=COT-719E615733

mcp> call generar_contrato {"pista_id": "$pista_id", "cliente": "Agencia Lumen S.A.", "cotizacion_id": "$cotizacion_id"}
   ...
   remembered: $contrato_id=CTR-F9D1D72B0D

mcp> call registrar_uso {"contrato_id": "$contrato_id", "plataforma": "YouTube", "url_proyecto": "https://youtube.com/watch?v=demo"}

mcp> vars
mcp> quit

$pista_id по умолчанию указывает на лучшего кандидата из последнего поиска. В любой момент используйте vars, чтобы увидеть, что сейчас запомнено.

6.3 Запуск сервера отдельно

python -m synclicense_mcp

Затем он ожидает сообщения JSON-RPC на stdin. Используйте --catalog PATH, чтобы указать другой файл каталога.

6.4 Общение с сервером вообще без клиента

Поскольку транспорт — это просто JSON с разделителями строк, сервером можно управлять прямо из оболочки:

printf '%s\n' \
  '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"shell","version":"0"}}}' \
  '{"jsonrpc":"2.0","method":"notifications/initialized"}' \
  '{"jsonrpc":"2.0","id":2,"method":"tools/list"}' \
  '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"verificar_clearance","arguments":{"pista_id":"TRK-00001"}}}' \
  | python -m synclicense_mcp

7. Справочник инструментов

Инструмент

Обязательные аргументы

Возвращает

buscar_pista

(нет — каждый фильтр необязателен)

Кандидаты-треки с id, названием, исполнителем, длительностью и базовой платой

verificar_clearance

pista_id

Правовой статус: чистый, ожидающие сэмплы или заблокированный

calcular_costo_licencia

pista_id, tipo_uso, territorio, exclusividad, duracion_meses

Полная разбивка стоимости, итог в USD и cotizacion_id

generar_contrato

pista_id, cliente, cotizacion_id

Контракт с объёмом, сроком, суммой, ограничениями и contrato_id

registrar_uso

contrato_id, plataforma, url_proyecto

Запись об использовании для роялти и аудита

7.1 buscar_pista

Необязательные фильтры: mood, genero, instrumental, duracion_seg_min, duracion_seg_max, presupuesto_max, limite (1–20, по умолчанию 5).

  • mood: alegre, epico, melancolico, relajado, tenso, energetico, inspirador, oscuro

  • genero: pop, rock, electronica, hip_hop, jazz, clasica, folk, ambient, cinematica, latina

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

7.2 verificar_clearance

Статус

Можно лицензировать

Эффект

libre

да

Нет обременений

samples_pendientes

да

+15% надбавка эскроу и оговорка об удержании

bloqueada

нет

Спор об авторстве; расчёт стоимости и контракт отклоняются

7.3 calcular_costo_licencia

Аргумент

Допустимые значения

tipo_uso

redes_sociales, evento_interno, podcast, web_corporativo, publicidad_online, videojuego, tv_nacional, cine

territorio

local, latam, europa, norteamerica, mundial

exclusividad

no, sectorial, total

duracion_meses

0 (бессрочно) или 1–120

Пример запроса и ответа:

--> {"jsonrpc":"2.0","id":5,"method":"tools/call","params":{
      "name":"calcular_costo_licencia",
      "arguments":{"pista_id":"TRK-00312","tipo_uso":"redes_sociales",
                   "territorio":"local","exclusividad":"no","duracion_meses":6}}}

<-- {"jsonrpc":"2.0","id":5,"result":{
      "content":[{"type":"text","text":"Quote for TRK-00312 \"Stop!\" ... TOTAL USD 94.50"}],
      "structuredContent":{
        "ok":true,
        "cotizacion_id":"COT-3D18B1547D",
        "pista_id":"TRK-00312",
        "alcance":{"tipo_uso":"redes_sociales","territorio":"local",
                   "exclusividad":"no","duracion_meses":6},
        "desglose":{"tarifa_base_usd":94.5,
                    "multiplicadores":{"tipo_uso":1.0,"territorio":1.0,
                                       "exclusividad":1.0,"vigencia":1.0},
                    "subtotal_usd":94.5,"recargo_escrow_usd":0.0,
                    "total_usd":94.5,"moneda":"USD"},
        "valida_hasta":"2026-09-19T18:15:54+00:00"},
      "isError":false}}

7.4 Цепочки инструментов

Инструменты сохраняют состояние в рамках сессии — в этом и заключается смысл сценария использования:

buscar_pista ──► pista_id
                    ├──► verificar_clearance      (can stop the whole flow)
                    └──► calcular_costo_licencia ──► cotizacion_id
                                                        └──► generar_contrato ──► contrato_id
                                                                                     └──► registrar_uso

generar_contrato отклоняет котировку, которая не существует, истекла (30 дней) или была выпущена для другого трека. registrar_uso отклоняет неизвестный или неактивный контракт. Котировки и контракты принадлежат одному соединению и не передаются между сессиями.

8. Правила ценообразования

subtotal = tarifa_base × mult_use × mult_territory × mult_exclusivity × mult_term
total    = subtotal + escrow surcharge (15% when the track has pending samples)

Тип использования

×

Территория

×

Эксклюзивность

×

Срок

×

redes_sociales

1.0

local

1.0

no

1.0

≤ 3 месяца

0.8

evento_interno

1.1

latam

1.8

sectorial

2.0

≤ 6 месяцев

1.0

podcast

1.3

europa

2.2

total

4.5

≤ 12 месяцев

1.5

web_corporativo

1.6

norteamerica

2.4

≤ 24 месяца

2.2

publicidad_online

2.5

mundial

3.2

≤ 36 месяцев

2.8

videojuego

4.0

> 36 месяцев

3.2

tv_nacional

6.0

бессрочно

3.5

cine

8.0

Шесть месяцев — это эталонный срок, поэтому он находится на уровне 1.0. Котировка сохраняет свою цену в течение 30 дней.

9. Детали протокола

Транспорт. stdio, одно сообщение JSON-RPC 2.0 на строку, UTF-8, без встроенных переводов строк. Сервер корректно завершает работу по EOF.

Версии протокола. 2025-11-25 (предпочтительная) и 2025-06-18. Если клиент запрашивает что-либо другое, сервер отвечает своей предпочтительной версией, а не завершает рукопожатие ошибкой.

Методы.

Метод

Результат

initialize

Согласованная версия, возможности, информация о сервере, инструкции

notifications/initialized

(уведомление — без ответа)

ping

{}

tools/list

Пять описаний инструментов с их JSON Schema

tools/call

content, structuredContent, isError

Коды ошибок.

Код

Значение

-32700

Ошибка разбора — строка не является корректным JSON

-32600

Недопустимый запрос — неверная обёртка

-32601

Метод не найден

-32602

Недопустимые параметры — отсутствующий, неверного типа или вне перечисления аргумент, либо неизвестный инструмент

-32603

Внутренняя ошибка

-32002

Сервер не инициализирован — запрос поступил до рукопожатия

Ошибки протокола и бизнес-ошибки. Некорректный вызов возвращается как JSON-RPC error. Корректно сформированный вызов, который отклоняют правила лицензирования — заблокированный трек, истёкшая котировка, неизвестный контракт — возвращается как успешный ответ с isError: true и понятным объяснением, чтобы модель могла прочитать причину и скорректировать действия, а не видеть сбой транспорта.

Полная спецификация приведена в docs/SERVER_SPEC.md.

10. Откуда берутся данные

Метаданные треков (название, исполнитель, длительность, жанр, настроение, лицензия, рейтинг популярности) берутся из публичного Jamendo API, который предоставляет каталог Creative Commons. Каталог, поставляемый в этом репозитории, был создан именно так. Офлайн-генератор воспроизводит ту же структуру локально, поэтому проект работает без учётных данных и без доступа к сети.

Бизнес-уровень намеренно имитируется. Ни одна платформа не публикует свой прайс-лист или внутренний юридический статус каждого трека, поэтому tarifa_base_usd и estado_derechos генерируются из фиксированного зерна с реалистичным распределением (82% — очищено, 13% — образцы на рассмотрении, 5% — заблокировано). Множители прайс-листа были разработаны на основе публичных прайс-листов роялти-фри платформ, таких как Jamendo Licensing. Эта область была рассмотрена и одобрена преподавателем курса.

11. Тестирование

python -m pytest tests/ -v

Набор покрывает правила прайс-листа, структуру JSON-RPC, рукопожатие, коды ошибок, цепочку инструментов и её отказы, генератор зерна, а также один сквозной тест, который запускает реальный процесс сервера и общается с ним через stdio-транспорт. Тесты ищут треки по статусу прав, а не по фиксированному id, поэтому они проходят на любом каталоге: офлайн, Jamendo или перегенерированном с другим зерном.

12. Структура проекта

MCP-Local-Redes/
├── synclicense_mcp/          MCP server package (standard library only)
│   ├── __main__.py           entry point: python -m synclicense_mcp
│   ├── jsonrpc.py            JSON-RPC 2.0 framing over stdio
│   ├── server.py             MCP method dispatch
│   ├── tools.py              the five tools: schemas, validation, handlers
│   ├── pricing.py            conditional rate card
│   ├── contracts.py          contracts and usage registration
│   ├── catalog.py            catalog loading and search
│   └── errors.py             business-rule failures
├── client/mcp_cli.py         manual JSON-RPC client (demo + REPL)
├── scripts/seed_catalog.py   catalog builder (offline / Jamendo)
├── data/catalog.json         generated catalog
├── tests/                    pytest suite
└── docs/                     proposal, assignment brief, server specification

13. Статус проекта

Поставлено на этом этапе:

  • Локальный MCP-сервер через stdio с пятью инструментами одобренного сценария.

  • JSON-RPC 2.0 и рукопожатие MCP, реализованные вручную.

  • Командный клиент со скриптовой демонстрацией и интерактивным REPL.

  • Заполнение каталога в офлайн- и Jamendo-режимах.

  • Набор тестов.

Запланировано на остальную часть проекта:

  • Чат-бот на Anthropic API с контекстом сессии и видимым журналом каждого взаимодействия с MCP.

  • Интеграция с официальными MCP-серверами Filesystem и Git.

  • Тот же сервер, развёрнутый удалённо через HTTP.

  • Захват Wireshark и послойный анализ удалённого трафика.


Автор: Esteban Cárcamo (23016) — CC3067 Redes, Section 20

F
license - not found
Not graded
quality - not tested
B
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 Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    An MCP server for Spotify control and synchronized lyrics retrieval that enables playback management, queue navigation, and music search capabilities. It also features perception tools for real-time track analysis, including BPM, key detection, and timestamped lyrics.
    129
    3
    Apache 2.0
  • F
    license
    Not graded
    quality
    C
    maintenance
    A remote MCP server for the Arxpot processing core, enabling music search, metadata retrieval, and download management with remote storage delivery.

View all related MCP servers

Related MCP Connectors

  • Personal MCP server for humans who create. Proof of authorship, license control.

  • A paid remote MCP for CLI tool MCP, built to return verdicts, receipts, usage logs, and audit-ready

  • A paid remote MCP for hosted MCP server, built to return verdicts, receipts, usage logs, and audit-r

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/ecarcamo/MCP-Local-Redes'

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