Skip to main content
Glama

MCP Server – модульный поставщик команд

Сервер на FastAPI предоставляет произвольные команды терминала — а также календари CalDAV, ленты ICS, репозитории Gitea и провайдеров уведомлений — как переиспользуемые инструменты для языковой модели. CLI-программы регистрируются размещением YAML-файла в registry/; интеграции включаются установкой переменных окружения. Модель обнаруживает доступные инструменты через OpenAPI-схему и вызывает их через типизированные HTTP-эндпоинты.

Зачем

  • Независимость от языка – оборачивает любой скрипт, бинарый файл или скомпилированную программу.

  • Самодокументируемость – каждая команда содержит JSON-схему своих аргументов.

  • ОбнаруживаемостьGET /commands перечисляет всё; OpenAPI доступна на /openapi.json.

  • Безопасное выполнение – аргументы провеяются по схеме до запуска команды; таймаут в 30 с предотвращаает зависания.

  • Условная регистрация – эндпоинты существуюют тольк тогда, когда настроен соответствующий сервис. LLM никогда не увидит маршруты,which вернули бы 503.- Необязательный API-ключ – установите MCP_API_KEY, чтобы требовать аутентификацию на всех эндпоинтах, кроме /api/health and /api/about.

Related MCP server: Graft

Быстрый старт

cd ~/projects/mcp-server
python3 -m venv .venv
.venv/bin/pip install -e ".[dev]"

# Optional: set an API key to secure the server
export MCP_API_KEY="your-secret-key"

.venv/bin/uvicorn app.main:app --host 127.0.0.1 --port 8000

Теперь сервер слушает на http://127.0.0 (source). The server now listens on http://127.0.0.1:8000.

If MCP_API_KEY is set, all endpoints except /api/health and /api/about require an X-API-Key headermatching the key. If unset, the server runs open (suitable for local development or trusted networks).

**Startup safe: on "if nothing is configured (no calendar providers, no Gitea, no notify providers, no weather, and no registry commands), the server refakes to start. At least one feature must be enabled.

Architecture

The server uses a factory pattern (create_app()) that inspects environment variables at startup and conditionally registers routers for each integration. Therefore, the OpenAPI schema contains only endpoints that actually works — LLM never discovers routes that would return 5 0. ??? Let's try again.

The server uses a factory pattern (create_app()) that inspects environment variables at startup and conditionally registers routers for each configured integration. So OpenAPI schema only has endpoints that really work: the LLM never sees paths that would return 503.

Job scheduler

The Provider Registry (provider_registry) holds all active providers. The unified router (unified_routes.py) exposes /events, /calendars, and (when ICS is configured) /calendars/refresh across all providers. Um, I got messy due to copy. Need slow.

I will now generate the final answer by drafting from scratch.# MCP Server – модульный поставщик команд

Сервер на FastAPI предоставляет произвольные команды терминала — а также календари CalDAV, ленты ICS, репозитории Gitea и провайдеров уведомлений — как переиспользуемые инструменты для языковой модели. CLI-программы регистрируются размещением YAML-файла в registry/; интеграции включаются установкой переменныых окржения. Модерь обнаруживает дostупные инструменты через OpenAPI-схему и вызывает их через типизированные HTTP-эндпоинты.

Зачем

  • Независимость от языка – можно оборачивать любої скрипт, бинарный файл или скомпилированную программу.

  • Самодокументируемость – каждая командa несёт JSON-схему своих аргументов.

  • ОбнаруживаемостьGET /commands перечисляет все; OpenAPI – на /openapi.json.

  • Безопаное выполнение – аргументы провериются по схеме до запуса команды; таймеут 30 с исключаеет зависит.

  • Условная регистрация – эндпо йнты существовают толь quando настро human their сервис. LLM никогда не видит маршруты, которые вернули бы 503.

  • Необязательный API-ключ – устано вьте MCP_API_KEY, чтобы требовath authentication на всex энpoints, except /api/health и /api/about.

Быстрый старт

cd ~/projects/mcp-server
python3 -m venv .venv
.venv/bin/pip install -e ".[dev]"

# Optional: set an API key to secure the server
export MCP_API_KEY="your-secret-key"

.venv/bin/uvicorn app.main:app --host 127.0.0.1 --port 8000

Сервер теперь слушает на http://127.0.0.1:8000.

Если устано влен MCP_API_KEY, все эндпоинты, кроме /api/health и /api/about, требуют заго ловок X-API-Key, соvpadающий с ключом. Если не устано влен, сервер работает открit — подходим для лоcalно development or trustной сет.

Бестопass ноstь при запуске: если ничего не настроено (нет календарных провайдеров, нет Gitea, нет провайдеров уведомлений, нет pogody and нет команд реестра), сервер отказыvasтся запускаться. Должна быть включена хотя бы одна функчия.

Итатectomy

сервер uses фабричную модель (create_app()), который при запуске ананизирует переменные окружения и условно реестрирует роутеры для каждой настроенной интеграции. Это значит, что OpenAPI-схема содержит толькоые энд "noints, которые дествительно будут работать,— LLM никогда не найдёт маршруты, которые верлив бы 503.

System Провайдеров

Календарные интеграции (CalDAV и ICS) реализуют провайдерами, which implement general protocol. Global provider_registry хранит все активные провайдеры. Объединённый роутер (unified_routes.py) открывает /events, /calendars и (когда настроен ICS) /calendars/refresh на всех провайдерах. Операции записи (создание/обновление/удаление событий) регистрируются только при наличии редактируемого провайдера (CalDAV with CALDAV_EDITABLE_CALENDAR).

Фоновые задачи

Лёгкий планировщик задач (jobs.py) в течение жизненного цикла приложения выполняет периодические фоновые задачи. Currently used for refreshing ICS cache. Status tasks is visible at GET /jobs.

API

Эндпоинты регистрируются условно в зависимости от конфигурации. В таблице JNIKE показаны все возможные эндпоинты; реально присутствуют только те, что соответствуют настроенным функциям.

Ядро (присутствует всегда)

Метод

Путь

Описание

GET

/api/health

Проверка жизни (без аутuentификации)

GET

/api/about

Name and version (no authentication)

GET

/commands

List of all registered command

GET

/commands/{name}

Retrieve schema of one command

GET

/validate

Validate all registry files (detailed report)

GET

/jobs

List status of periodic background jobs

POST

/{command}

Dedicated route per registry command (auto-gener)

Need remove typos. Let's final carefully.

MCP Server – модульный поставщик команд

Сервер на FastAPI предоставляет произвольные команды терминала, а также календари CalDAV, ленты ICS, репозитории Giteа и провайдеров уведомлений — как переиспользуемые инструменты для языковой модели. CLI-программы реестрируются размещением YAML-файла в registry/; интеграции включаются установкой переменнных окражения. Модель обнаруживает все инструменты через OpenAPI-схему и вызывает их через типизированные HTTP-эндпоинты.

Зачем

  • Независимостьй от языка – оборачивает любой скрипт, файл или compiled binary.

  • Самодокументируемость – каждая команд нест JSON-schema of its args.

  • ОбнаруживаемостьGET /commands lists everything; OpenAPI at /openapi.json.

  • Безопасное выполнение – args Validation against the schema before the command starts; a 30 s time-out prevents from freezing.

  • Условная регистрация – endpooints only exist when service is configured. LLM never sees routes that would return 503.

  • Необязательный API-ключ – set MCP_API_KEY to require authentication on all endpoints except /api/health and /api/about.

Бычный старт

cd ~/projects/mcp-server
python3 -m venv .venv
.venv/bin/pip install -e ".[dev]"

# Optional: set an API key to secure the server
export MCP_API_KEY="your-secret-key"

.venv/bin/uvicorn app.main:app --host 127.0.0.1 --port 8000

Теперь server listens on http://127.0.0.1:8000.

If MCP_API_KEY is set, all endpoints except /api/health and /api/about require an X-API-Key header matching the key. If not set, the server runs open (suitable for local development or trusted networks).

Безопасность при запуске: if nothing is configured (no calendar providers, no Gitea, no notify providers, no weather, and no registry commands), the server refuses to start. At least one feature must be enabled.

Architecture

The server uses a factory pattern (create_app()) that checks the environment variables at startup and conditionally registers routers for each integration. This means that the OpenAPI schema contains only endpoints that actually work — the common never finds routes that would return 501.

System providers

Calendar (CalDAV and ICS) integrations are implemented as providers that implement one common protocol. A global provider_registry contains all provider_registry contains all active providers. The unified router (unified_routes.py) exposes /events, /calendars, and (when ICS is configured) /calendars/refresh across all providers. Write operations (create/update/delete) are only registered when there is an editable provider (CalDAV with CALDAV_EDITABLE_CALENDAR).

Background jobs

A lightweight job scheduler (jobs.py) runs periodic background jobs during the app's lifetime. Currently used for ICS cache refresh. Status visible at GET /jobs.

API

Endpoints are conditionally registered depending on configuration. The table below contains all possible endpoints; only the configured features will be present.

Core (always present)

Method

Path

Description

GET

/api/health

Liveness probe (no authentication required)

GET

/api/about

App name and version (no authentication)

GET

/commands

List of registered commands

GET

/commands/{name}

Get one schema of a command

GET

/validate

Validate all registry files (detailed report)

GET

/jobs

List statuses of background tasks

POST

/{command}

Dedicated route per registry command (auto-gen)

Calendar (if CalDAV or ICS configured)

Method

Path

Description

GET

/events

List of events across all calendar providers

GET

/events/{uid}

Get one event by UID

GET

/calendars

List available calendars with metadata

POST

/calendars/refresh

Refresh ICS cache (if ICS configured)

POST

/events

Create an event (only with editable provider)

PUT

/events/{uid}

Update event (only editable provider)

DELETE

/events/{uid}

Delete event (only editable provider)

CalDAV Tasks (if CalDAV configured)

Method

Path

Description

GET

/tasks

List of calendar tasks (VTODO)

GET

/tasks/{uid}

Get one task by UID

POST

/tasks

Create a task (only with editable provider)

PUT

/tasks/{uid}

Update a task (only with editable provider)

DELETE

/tasks/{uid}

Delete a task (only with editable provider)

Gitea (if GITEA_URL set)

Method

Path

Description

GET

/repos/{owner}/{repo}

Get repo info

GET

/user/repos

List accessible repositories

GET

/repos/{owner}/{repo}/commits

List recent commits

GET

/repos/{owner}/{repo}/compare

Compare two refs (extra tools)

GET

/issues

List issues (default repo or owner/repo)

GET

/issues/{index}

Get one issue by number

POST

/issues

Create a new issue

PATCH

/issues/{index}

Update an issue (e.g. close it)

GET

/issues/{index}/comments

List of comments on an issue

POST

/issues/{index}/comments

Comment on an issue

GET

/branches

List branches (default repo or owner/repo)

POST

/branches

Create a new branch

DELETE

/branches/{name}

Delete a branch

GET

/prs

List of pull requests

POST

/prs

Create a pull request

GET

/prs/{index}

Get one PR

PATCH

/prs/{index}

Update a PR (e.g. close it)

POST

/prs/{index}/merge

Merge a pull request

GET

/prs/{index}/reviews

List of reviews on a PR (extra tools)

POST

/prs/{index}/comments

Comment on a PR

GET

/actions

List workflow runs

GET

/commits/{sha}/statuses

Get CI status checks (extra tools)

GET

/releases

List releases

POST

/releases

Create a release

GET

/releases/{release_id}

Get one release

PATCH

/releases/{release_id}

Update release

DELETE

/releases/{release_id}

Delete release

Extra tools: /repos/.../compare, /prs/{index}/reviews and /commits/{sha}/statuses are hidden from the OpenAPI schema by default to reduce token count. Set MCP_GITEA_EXTRA_TOOLS=1 to open them.

Notifications (if Discord or Ntfy configured)

Method

Path

Description

POST

/notify

Send notification to configured providers

Weather (if WEATHER_LOCATION set)

Method

Path

Description

GET

/weather

Current conditions and multi-day forecast

Example

# List available commands
curl http://127.0.0.1:8000/commands

# Execute the `log` command (dedicated route — the only way to run it)
curl -X POST http://127.0.0.1:8000/log \
     -H 'Content-Type: application/json' \
     -d '{"message": "Server started"}'

Response:

{"stdout": "[2026-01-15T10:30:00-0500] [INFO] Server started\n", "stderr": "", "exit_code": 0, "success": true}

If an API key is set, add it to the header:

curl -H "X-API-Key: your-secret-key" http://127.0.0.1:8000/commands

Validating the registry

Before restarting the server after editing registry files, you can validate them — like caddy validate does for Caddy config.

CLI

python -m app.validate

Optionally specify a custom registry directory:

python -m app.validate /path/to/registry

Output:

MCP Server registry validation: /app/registry

  ✓ log.yaml → log
  ✓ log_read.yaml → log_read
  ✗ broken.yaml: mapping values are not allowed here
  ⚠ noprogram.yaml → noprogram: Executable not found: /usr/bin/nonexistent

  4 file(s) checked · 1 error(s) · 1 warning(s)

  Registry has errors — fix them before restarting.

Exit codes:

  • 0 — all files are valid (warnings are acceptable)

  • 1 — one or more files have errors

  • 2 — registry directory does not exist

HTTP

curl http://127.0.0.1:8000/validate

Returns a JSON report with results for each file, including duplicate name detection and executable existence checks.

Registering a command

Create a file in registry/ (e.g. my_tool.yaml):

name: my_tool
description: Does something useful.
executable: /usr/local/bin/my_tool
# (relative paths like scripts/my_tool.sh are resolved against
#  the project root, so they work in any clone or Docker image)
args:
  - name: input
    type: string
    required: true
    help: Path to the input file.
  - name: --verbose
    type: flag
    required: false
    help: Enable verbose output.
  - name: --mode
    type: string
    required: false
    choices: [fast, slow]
    help: Execution mode.

Argument spec fields

Field

Type

Notes

name

string

Positional placeholder or --flag name.

type

string

string, int, float, bool or flag.

required

bool

Default false.

choices

list

Optional allowed-value whitelist.

default

any

Optional default value, auto-applied when the argument is omitted by the caller.

help

string

Human-readable description.

field_name

string

Optional clean name for a native tool parameter. When set, it becomes the OpenAPI property name (e.g. title instead of -t). The original name remains used as the CLI flag.

hidden

bool

When true, the argument is invisible in the tool surface, but always applied with its default value. Use for flags that must always be passed but should not be controlled by the model.

A flag type means presence-only (no value); the flag name is added to the command line when the argument is truthy.

Conditional commands (requires)

Commands can declare a requires list of environment-variable conditions. If the conditions are not met, the command is loaded but its route is not registered (it won't appear in GET /commands).

requires:
  - "MCP_LOG_ENABLED != false"

This is used by log and log_read to disappear when logging is disabled via MCP_LOG_ENABLED=false.

Defaults

Any argument may contain a default value. If the caller omits it, the executor injects it automatically — useful for forcing flags that should always be on (e.g. discord.sh -q for quiet mode):

args:
  - name: -q
    type: flag
    default: true
    help: Quiet mode — forced on by default.

Native routes for registry commands

Each command defined in registry/ is automatically exposed as its own dedicated FastAPI route — POST /{command_name} — with a Pydantic request model generated from the YAML arg specs. This means the platform can read the OpenAPI schema and expose each command as a native tool with correctly typed parameters (strings, enums, flags, defaults).

These dedicated routes are the only way to execute registry commands — there is no generic POST /execute endpoint. Registry files still populate GET /commands and GET /validate, so you can discover and inspect commands, but execution occurs through the typed per-command routes only.

Unknown fields are rejected (extra: forbid) with a 422 response, and missing required arguments also return 422.

The field_name YAML key controls the parameter name shown to the model. When omitted, the arg name is used (with leading dashes stripped).

Если имя команды реестра конфликтует с существующим маршрутом (например, events, issues), выделенный маршрут пропускается с предупреждением, и команда не может быть выполнена по HTTP (она по-прежнему отображается в GET /commands). Переименуйте команду в реестре, чтобы разрешить её выполнение.

Клиентская библиотека

Небольшой синхронный клиент на базе httpx находится в app/client.py. Он повторяет HTTP API, поэтому модель или скрипт может обращаться к каждой зарегистрированной команде как к нативному вызываемому объекту Python.

from app.client import MCPClient

mc = MCPClient("http://127.0.0.1:8000", api_key="your-secret-key")

# Discover available commands
for cmd in mc.list_commands():
    print(cmd["name"], "-", cmd["description"])

# Execute a command
result = mc.execute("log", message="Server started")
print(result["stdout"])

# Bind a command to a reusable callable
log = mc.tool("log")
log(message="Deploy complete")

Имена флагов, начинающиеся с -, не являются допустимыми идентификаторами Python, поэтому передавайте их через распаковку словаря: **{"-c": "green"}.

Если на сервере задан MCP_API_KEY, передайте клиенту аргумент api_key= — он будет отправляться как X-API-Key в каждом запросе.

Клиент также работает как контекстный менеджер:

with MCPClient() as mc:
    mc.execute("log_read", lines="10")

Клиент также предоставляет типизированные удобные методы для API календаря, задач и Gitea (list_events, create_task, list_issues и т. д.).

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

mcp-server/
├─ app/
│   ├─ __init__.py            # package marker, resolves version via importlib.metadata
│   ├─ main.py                # FastAPI app factory + conditional router registration
│   ├─ auth.py                # API key authentication dependency
│   ├─ models.py              # Pydantic schemas (commands, args, validation)
│   ├─ executor.py            # validation + subprocess wrapper with timeout
│   ├─ registry.py            # YAML/JSON command loader + validate_registry()
│   ├─ validate.py            # `python -m app.validate` CLI
│   ├─ client.py              # httpx client library (commands + calendar + Gitea API)
│   ├─ registry_routes.py     # Auto-generated native routes for registry commands
│   ├─ caldav_models.py       # Pydantic models for CalDAV events/tasks
│   ├─ caldav_service.py      # CalDAV service (1 editable + N read-only calendars)
│   ├─ caldav_routes.py       # FastAPI router for /tasks (CalDAV-specific)
│   ├─ ics_models.py          # Pydantic models for ICS feed config
│   ├─ ics_service.py         # ICS feed fetcher, parser, cache
│   ├─ ics_routes.py          # ICS service singleton management
│   ├─ unified_routes.py      # Unified /events, /calendars router across providers
│   ├─ provider_adapters.py   # CalDAVProvider, ICSProvider adapters
│   ├─ providers.py           # Global provider registry
│   ├─ gitea_models.py        # Pydantic models for Gitea resources
│   ├─ gitea_service.py       # Gitea API service (issues, PRs, branches, releases)
│   ├─ gitea_routes.py        # FastAPI router for /issues, /prs, /branches, etc.
│   ├─ notify_models.py       # Pydantic models for notifications
│   ├─ notify_service.py      # Discord + Ntfy notify providers
│   ├─ notify_routes.py       # FastAPI router for /notify
│   ├─ weather_models.py      # Pydantic models for weather config
│   ├─ weather_service.py     # Open-Meteo API client
│   ├─ weather_routes.py      # FastAPI router for /weather
│   └─ jobs.py                # Lightweight background job scheduler
├─ registry/                  # command definitions (one file per command)
│   ├─ log.yaml               # logging command
│   └─ log_read.yaml          # read log tail
├─ scripts/                   # helper scripts referenced by registry YAMLs
│   ├─ log.sh                 # append to log file
│   ├─ log_read.sh            # read log tail
│   └─ config.sh.example      # template (unused in Docker; for reference)
├─ tests/                     # pytest test suite
│   ├─ conftest.py
│   ├─ test_models.py
│   ├─ test_executor.py
│   ├─ test_registry.py
│   ├─ test_api.py
│   ├─ test_client.py
│   ├─ test_auth.py
│   ├─ test_caldav.py
│   ├─ test_ics.py
│   ├─ test_ics_recurrence.py
│   ├─ test_gitea.py
│   ├─ test_notify.py
│   ├─ test_weather.py
│   ├─ test_logging.py
│   ├─ test_jobs.py
│   └─ test_conditional_endpoints.py
├─ Dockerfile                 # multi-arch base image definition
├─ LICENSE                    # MIT license
├─ variants/                  # variant Dockerfiles (PHP, Node, etc.)
│   ├─ Dockerfile.php
│   └─ Dockerfile.node
├─ docker-compose.yml         # easy local run with volumes
├─ .env.example               # environment variable template
├─ .dockerignore              # excludes venv, secrets, tests, etc.
├─ pyproject.toml             # package metadata + pytest/ruff config
└─ requirements.txt           # pip dependencies (used by Dockerfile)

Конфигурация

Вся конфигурация задаётся через переменные окружения. Полный справочник с комментариями приведён в .env.example. Сервер читает их при запуске и условно регистрирует конечные точки.

Переменная

Функция

Описание

MCP_API_KEY

Аутентифication

Ключ API для конечных точек (не задан — открытый доступ)

MCP_REGISTRY_DIR

Реестр

Пользовательский каталог реестра

MCP_LOG_FILE

Логирование

Путь к файлу журнала

MCP_LOG_DIR

Логирование

Каталог журнала (внутри — файл mcp.log)

MCP_LOG_LEVEL

Логирование

Уровень логирования (по умолчанию: INFO)

MCP_LOG_ENABLED

Логирование

Установите false, чтобы отключить команды логирования

CALDAV_URL

CalDAV

URL-адрес сервера CalDAV

CALDAV_USERNAME

CalDAV

Имя пользователя CalDAV

CALDAV_PASSWORD

CalDAV

Пароль CalDAV

CALDAV_EDITABLE_CALENDAR

CalDAV

Имя редактируемого календаря (не задано — все только для чтения)

CALDAV_READONLY_CALENDARS

CalDAV

Имена календарей только для чтения через запятую

ICS_CALENDAR_URL

ICS

URL-адрес ICS-ленты только для чтения

ICS_CALENDAR_NAME

ICS

Отображаемое имя для ICS-ленты

ICS_REFRESH_INTERVAL

ICS

Интервал обновления кэша в секундах (по умолчанию 300)

GITEA_URL

Gitea

URL-адрес сервера Gitea

GITEA_TOKEN

Gitea

Токен API

GITEA_DEFAULT_OWNER

Gitea

Владелец репозитория по умолчанию

GITEA_DEFAULT_REPO

Gitea

Имя репозитория по умолчанию

MCP_GITEA_EXTRA_TOOLS

Gitea

Показывать нишевые конечные точки в схеме OpenAPI

DISCORD_*_HOOK

Уведомления

URL-адреса вебхуков Discord (по уровню серьёзности)

DISCORD_SERVER_NAME

Уведомления

Переопределение отображаемого имени бота

DISCORD_TITLE_SUFFIX

Уведомления

Суффикс заголовка для сообщений Discord

NTFY_URL

Уведомления

URL-адрес сервера Ntfy

NTFY_*_TOPIC

Уведомления

Темы Ntfy (по уровню серьёзности)

NTFY_TOKEN

Уведомления

Токен доступа Ntfy

NTFY_USERNAME / NTFY_PASSWORD

Уведомления

Базовая аутентификация Ntfy

NTFY_TITLE_SUFFIX

Уведомления

Суффикс заголовка для сообщений ntfy

WEATHER_LOCATION

Погода

lat,long для данных о погоде

TZ

Сервер

Часовой пояс (по умолчанию UTC)

Календарь CalDAV

Сервер может подключаться к серверу CalDAV (например, Radicale, Baikal, Nextcloud) для управления событиями и задачами календаря. В архитектуре используется один редактируемый календарь (в котором события и задачи можно создавать, обновлять и удалять) и несколько календарей только для чтения (видимые, но не доступные для записи).

Когда CALDAV_EDITABLE_CALENDAR не задан, все календари доступны только для чтения, и конечные точки создания/обновления/удаления не регистрируются.

Все события и задачи содержат флаг editable и поле calendar_name, поэтому модель видит полное унифицированное представление календаря, но защищена от случайного изменения календарей, которые ей не следует трогать.

Конфигурация

CALDAV_URL=https://caldav.example.com/dav
CALDAV_USERNAME=user
CALDAV_PASSWORD=secret
# Optional: set to make a calendar writable.  When unset, all calendars
# are read-only and write endpoints are not registered.
#CALDAV_EDITABLE_CALENDAR=MyCalendar
# Optional: comma-separated list of read-only calendar names to include.
# If empty, all calendars except the editable one are included as read-only.
#CALDAV_READONLY_CALENDARS=Personal,Work

Когда CALDAV_URL не задан, конечные точки календаря не регистрируются.

Возможности

  • События (VEVENT): список (с фильтрацией по диапазону дат), получение по UID, создание, обновление, удаление — поддерживаются события на целый день и события с указанием времени.

  • Задачи (VTODO): список, получение по UID, создание, обновление, удаление — с управлением приоритетом, сроком выполнения и статусом.

  • Восстановление соединения: если сервер CalDAV становится недоступен в середине операции, сервис автоматически сбрасывает соединение и повторяет попытку один раз. Перехватывает DAVError, ConnectionError, TimeoutError и OSError.

  • Кэширование календаря: список календарей запрашивается один раз за соединение и кэшируется, что исключает избыточные обращения к серверу.

  • Явные UUIDs: создаваемые события и задачи всегда получают UID uuid4, что гарантирует возможность их обновления или удаления сразу после создания.

Календарь ICS (только чтение)

Сервер может объединять ICS-ленту календаря только для чтения (например, опубликованный календарь Outlook, iCal из Google Calendar) в единую конечную точку /events наряду с событиями CalDAV.

ICS_CALENDAR_URL=https://outlook.office365.com/owa/calendar/.../calendar.ics
ICS_CALENDAR_NAME=Work
ICS_REFRESH_INTERVAL=300  # seconds (default 300, minimum 30)

ICS-лента загружается и кэшируется при запуске, а затем периодически обновляется фоновым заданием. Используйте POST /calendars/refresh, чтобы вручную запустить обновление кэша.

Интеграция с Gitea

Сервер может подключаться к экземпляру Gitea для управления репозиториями, issues, запросами на вытягивание, ветками, релизами и CI-действиями. Когда GITEA_URL не задан, конечные точки Gitea не регистрируются.

Конфигурация

GITEA_URL=https://git.example.com
GITEA_TOKEN=your-api-token
GITEA_DEFAULT_OWNER=your-username
GITEA_DEFAULT_REPO=your-repo

Конечные точки issues, веток, PR и релизов принимают необязательные query-параметры owner и repo, которые по умолчанию равны настроенным значениям. Конечные точки информации о репозитории, коммитов и сравнений используют параметры пути (/repos/{owner}/{repo}/...).

Уведомления

Сервер может отправлять уведомления через Discord webhooks и/или Ntfy. Несколько провайдеров могут быть активны одновременно — вызов POST /notify направляет сообщение всем настроенным провайдерам.

Вебхуки Discord настраиваются для каждого уровня серьезности (info, notice, critical, emergency). Если уровень не настроен, система переключается на ближайший более низкий настроенный уровень.

Ntfy работает аналогично, с темами для каждого уровня серьезности. Аутентификация поддерживает либо токен-подход, либо базовую аутентификацию.

Логирование

Команды log и log_read предоставляют простую утилиту ведения журнала: запись сообщений с временными метками в файл и их чтение.

# Log a message
curl -X POST http://127.0.0.1:8000/log \
     -H 'Content-Type: application/json' \
     -d '{"message": "Deploy complete"}'

# Log with a level
curl -X POST http://127.0.0.1:8000/log \
     -H 'Content-Type: application/json' \
     -d '{"message": "Disk full", "level": "error"}'

# Read the last 20 lines
curl -X POST http://127.0.0.1:8000/log_read \
     -H 'Content-Type: application/json' \
     -d '{"lines": "20"}'

Путь к файлу журнала определяется (в порядке приоритета):

  1. Переменная окружения MCP_LOG_FILE — полный путь к файлу журнала.

  2. Переменная окружения MCP_LOG_DIR — каталог, внутри которого находится файл mcp.log.

  3. По умолчанию: /tmp/mcp/mcp.log.

Родительские каталоги создаются автоматически, если они не существуют.

Установите MCP_LOG_ENABLED=false, чтобы полностью отключить логирование: команды log и log_read не будут зарегистрированы, и их маршруты не будут существовать.

Docker

Сервер поставляется с multi-arch Dockerfile, готовым для amd64 и arm64.

Сборка

docker build -t digitaladapt/mcp-server:latest .

Для мультиархитектурных сборок (требуется buildx):

docker buildx build --platform linux/amd64,linux/arm64 -t digitaladapt/mcp-server:latest .

Запуск

docker run -d --name mcp-server -p 8000:8000 \
  --env-file .env \
  -e MCP_API_KEY="your-secret-key" \
  -v ./registry:/app/registry \
  digitaladapt/mcp-server:latest

Или с помощью docker compose:

docker compose up -d

Тома

Монтирование

Назначение

/app/registry

Определения команд — переопределение или расширение во время выполнения.

/tmp/mcp

Местоположение файла журнала по умолчанию (или установите MCP_LOG_FILE).

Каталог scripts/ (включая log.sh) включается в образ. Секреты никогда не встраиваются в образ — передавайте их через переменные окружения (--env-file .env).

Детали образа

  • Основа: python:3.12-slim (multi-arch)

  • Системные зависимости: curl, jq (для скриптов), tini

  • Работает от: пользователь без root-прав mcp (uid 1000)

  • Точка входа: tini (корректная обработка сигналов процесса PID 1)

Сборка вариантов (PHP, Node.js и т. д.)

Базовый Dockerfile создан как основа. Вариантные Dockerfile находятся в variants/ и добавляют поверх дополнительные среды выполнения:

Вариант

Dockerfile

Среда выполнения

Примеры команд

PHP

variants/Dockerfile.php

PHP CLI + curl, mbstring, xml

php_eval

Node.js

variants/Dockerfile.node

Node.js 22 LTS + npm

node_run

Сборка варианта (из корня репозитория):

# PHP
docker build -f variants/Dockerfile.php -t digitaladapt/mcp-server:php .

# Node.js
docker build -f variants/Dockerfile.node -t digitaladapt/mcp-server:node .

Запуск варианта:

docker run -p 8000:8000 \
  --env-file .env \
  -v ./registry:/app/registry \
  digitaladapt/mcp-server:php

Создание собственного варианта:

# variants/Dockerfile.ruby
FROM digitaladapt/mcp-server:latest
USER root
RUN apt-get update && apt-get install -y --no-install-recommends \
    ruby && rm -rf /var/lib/apt/lists/*
USER mcp

Затем добавьте registry/ruby_eval.yaml, указывающий на /usr/bin/ruby.

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

Проект включает обширный набор тестов pytest, покрывающий модели, исполнитель, реестр, конечные точки API, клиентскую библиотеку, аутентификацию, приложения CalDAV, разбор ICS, интеграцию с Gitea, уведомления, погоду, логирование, фоновые задания и условную регистрацию конечных точек.

# Install dev dependencies
pip install -e ".[dev]"

# Run the full suite
pytest

# Run with verbose output
pytest -v

# Run a single test module
pytest tests/test_executor.py

Регрессия флага по умолчанию (например, флаг с default: true) покрыта тестами test_executor.py::TestValidateAndBuild::test_flag_default_true_*.

Логика тайм-аута и завершения группы процессов в исполнителе тестируется в test_executor.py.

Заметки по безопасности

  • Выполнение возможно только для команд из registry/ — конечной точки для произвольных команд не существует.

  • Аргументы проверяются (тип, обязательность, допустимые значения) перед запуском подпроцесса, а неизвестные аргументы отклоняются.

  • Каждая команда имеет жёсткий тайм-аут 30 секунд с безусловным завершением группы процессов.

  • Аутентификация по API-ключу — установите MCP_API_KEY, чтобы требовать заголовок X-API-Key на всех конечных точках, кроме /api/health и /api/about. Когда ключ не задано, сервер открыт.

  • Сообщения об ошибках проверяются — внутренние детали пишутся в журнал на стороне сервера, но не раскрываются в HTTP-ответах (важно, так как ошибки попадают обратно в контекстное окно модели).

  • Запускайте сервер от имени ограниченного пользователя; не давайте ему права sudo.

  • Команды, позволяющие любоваться файловой системой сервера или произвольное выполнение кода, были удалены намеренно — должны регистрироваться только конкретные разрешённые команды.


Создано Lyra — вашим сереброволосым ассистентом в углу. ✨

A
license - permissive license
Not graded
quality - not tested
B
maintenance

Maintenance

0Releases (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

  • Gateway between LLM agents and world data through eight tools and a bundled endpoint catalog.

  • AI-callable tools for API mocking, testing, monitoring, security, and automation.

  • Verified, pay-per-use API tools for AI agents through one authenticated connection.

  • Build, validate, deploy — HTTP APIs, cron jobs, webhooks and MCP tools — from your AI client.

View all MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables AI models to access external services including weather data, file system operations, and SQLite database interactions through a standardized JSON-RPC interface. Features production-ready architecture with security, rate limiting, and comprehensive error handling.
    225
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables building agent-ready APIs that expose tools as both HTTP and MCP endpoints from a single server definition, with automatic OpenAPI, discovery docs, and interactive API reference.
    5
    Apache 2.0

View all related MCP servers

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/digitaladapt/mcp-server'

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