Skip to main content
Glama

MCP Server – モジュール式コマンドプロバイダー

任意のターミナルコマンドに加え、CalDAVカレンダー、ICSフィード、Giteaリポジトリ、通知プロバイダーを、言語モデルの再利用可能なツールとして公開するFastAPIサーバーです。CLIプログラムはregistry/にYAMLファイルを置くことで登録され、インテグレーションは環境変数の設定によって有効になります。モデルはOpenAPIスキーマを通じて利用可能なツールを発見し、型付けされたHTTPエンドポイント経由でそれらを呼び出します。

なぜ

  • 言語非依存 – あらゆるスクリプト、バイナリ、コンパイル済みプログラムをラップできます。

  • 自己記述的 – 各コマンドは自分の引数のJSONスキーマを保持します。

  • 発見可能 – GET /commands すべてを一覧表示し、OpenAPIは/openapi.jsonにあります。

  • 安全な実行 – 引数はコマンド実行前にスキーマで検証されます。30秒のタイムアウトでハングアップを防止します。

  • 条件付き登録 – 対応するサービスが設定されている場合にのみエンドポイントが存在します。LLMが503を返すルートを見ることはありません。

  • オプションのAPIキー – MCP_API_KEYを設定すると、/api/healthと/api/aboutを除くすべてのエンドポイントで認証が必要になります。

Related MCP server: MCP Tool Server

クイックスタート

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ヘッダーが必要です。未設定の場合は、サーバーはオープンで動作します(ローカル開発や信頼できるネットワークに適しています)。

起動時の安全性: 何も設定されていない場合(カレンダープロバイダー、Gitea、通知プロバイダー、天気、レジストリコマンドのいずれもない場合)、サーバーは起動を拒否します。少なくとも1つの機能を有効にする必要があります。

アーキテクチャ

サーバーはファクトリパターン(create_app())を使用し、起動時に環境変数を検査して、設定された各インテグレーションのルーターを条件付きで登録します。つまり、OpenAPIスキーマには実際に動作するエンドポイントだけが含まれるため、LLMが503を返すルートを見つけることはありません。

プロバイダーシステム

カレンダーインテグレーション(CalDAVおよびICS)は、共通プロトコルを実装するプロバイダーとして実装されています。グローバルなprovider_registryが有効なプロバイダーをすべて保持します。統合ルーター(unified_routes.py)は、すべてのプロバイダーにまたがって/events、/calendars、(ICSが設定されている場合は)/calendars/refreshを公開します。書き込み操作(イベントの作成/更新/削除)は、編集可能なプロバイダー(つまりCALDAV_EDITABLE_CALENDARが設定されたCalDAV)が存在する場合にのみ登録されます。

バックグラウンドジョブ

軽量ジョブスケジューラー(jobs.py)が、アプリのライフサイクル中に定期的なバックグラウンドタスクを実行します。現在はICSキャッシュの更新に使用されています。ジョブの状態はGET /jobsで確認できます。

API

エンドポイントは構成に基づいて条件付きで登録されます。以下の表は考えられるすべてのエンドポイントです。表示されるのは、設定された機能に対応するものだけです。

コア(常に存在)h3>

メソッド

パス

説明

GET

/api/health

活性プローブ(認証不要)

GET

/api/about

アプリ名とバージョン(認証不要)

GET

/commands

登録されたすべてのコマンドを一覧表示

GET

/commands/{name}

1つのコマンドのスキーマを取得

GET

/validate

レジストリ内のすべてのファイルを検証(詳細レポート)

GET

/jobs

定期バックグラウンドジョブの状態を一覧表示

POST

/{command}

レジストリコマンドごとの専用ルート(自動生成)

カレンダー(CalDAVまたはICSが設定されている場合)

メソッド

パス

説明

GET

/events

すべてのカレンダープロバイダーのイベントを一覧表示

GET

/events/{uid}

UIDで単一のイベントを取得

GET

/calendars

アクセス可能なカレンダーをメタデータ付きで一覧表示

POST

/calendars/refresh

ICSキャッシュの更新(ICS設定時)

POST

/events

イベントを作成(編集可能なプロバイダーのみ)

PUT

/events/{uid}

イベントを更新(編集可能なプロバイダーのみ)

DELETE

/events/{uid}

イベントを削除(編集可能なプロバイダーのみ)

CalDAVタスク(CalDAVが設定されている場合)

メソッド

パス

説明

GET

/tasks

カレンダータスク(VTODO)を一覧表示

GET

/tasks/{uid}

UIDで単一のタスクを取得

POST

/tasks

タスクを作成(編集可能なプロバイダーのみ)

PUT

/tasks/{uid}

タスクを更新(編集可能なプロバイダーのみ)

DELETE

/tasks/{uid}

タスクを削除(編集可能なプロバイダーのみ)

Gitea(GITEA_URLが設定されている場合)

メソッド

パス

説明

GET

/repos/{owner}/{repo}

リポジトリ情報を取得

GET

/user/repos

アクセス可能なリポジトリを一覧表示

GET

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

最近のコミットを一覧表示

GET

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

2つのrefを比較(追加ツール)

GET

/issues

問題を一覧表示(デフォルトのリポジトリかowner/repo)

GET

/issues/{index}

Numberを指定して単一のIssueを取得

POST

/issues

新しいIssueを作成

PATCH

/issues/{index}

Issueを更新(例: クローズ)

GET

/issues/{index}/comments

Issueのコメントを一覧表示

POST

/issues/{index}/comments

Issueにコメントを投稿

GET

/branches

ブランチを一覧表示(デフォルトのリポジトリかowner/repo)

POST

/branches

新しいブランチを作成

DELETE

/branches/{name}

ブランチを削除

GET

/prs

プルリクエストを一覧表示

POST

/prs

プルリクエストを作成

GET

/prs/{index}

単一のPRを取得

PATCH

/prs/{index}

PRを更新(例: クローズ)

POST

/prs/{index}/merge

プルリクエストをマージ

GET

/prs/{index}/reviews

PRのレビューを一覧表示(追加ツール)

POST

/prs/{index}/comments

PRにコメントを投稿

GET

/actions

CIワークフローの実行を一覧表示

GET

/commits/{sha}/statuses

CIステータスチェックを取得(追加ツール)

GET

/releases

リリースを一覧表示

POST

/releases

リリースを作成

GET

/releases/{release_id}

単一のリリースを取得

PATCH

/releases/{release_id}

リリースを更新

DELETE

/releases/{release_id}

リリースを削除

追加ツール: /repos/.../compare、/prs/{index}/reviews、 /commits/{sha}/statusesは、デフォルトではトークン数を減らすためにOpenAPIスキーマから 隠されています。これらを公開するにはMCP_GITEA_EXTRA_TOOLS=1を設定します。

通知(DiscordまたはNtfyが設定されている場合)

メソッド

パス

説明

POST

/notify

設定済みプロバイダーに通知を送信

天気(WEATHER_LOCATIONが設定されている場合)

メソッド

パス

説明

GET

/weather

現在の状況と複数日間の予報

例

# 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"}'

レスポンス:

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

APIキーを設定してある場合は、ヘッダーに次のように含めます:

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

レジストリの検証

レジストリファイルを編集した後、サーバーを再起動する前に、それらを検証できます。caddy validate がCaddyの設定に対して行うのと同じです。

CLI

python -m app.validate

オプションで、カスタムのレジストリディレクトリを指定できます:

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

出力:

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.

終了コード:

  • 0 — すべてのファイルが有効(警告は問題ありません)

  • 1 — 1つ以上のファイルにエラーがあります

  • 2 — レジストリディレクトリが存在しません

HTTP

curl http://127.0.0.1:8000/validate

ファイルごとの結果を含むJSONレポートを返します。重複名の検出と実行可能ファイルの存在チェックが含まれます。

コマンドの登録

registry/内にファイルを作成します(例: 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.

引数仕様フィールド

Field

Type

備考

name

string

位置指定プレースホルダー、または --flag 名。

type

string

string、int、float、bool、または flag。

required

bool

デフォルト false。

choices

list

許可される値の省略可能なホワイトリスト。

default

any

省略可能なデフォルト値。引数を省略した場合、

自動的に適用されます。

help

string

人間が読める説明。

field_name

string

ネイティブツールのパラメータ名のための任意の指定名。

設定すると、OpenAPIのプロパティ名になります。

(例: -t の代わりに title)。元の name は

CLIフラグとして引き続き使用されます。

hidden

bool

true の場合、その引数はツール上で非表示になりますが

default の値で常に適用されます。

常に渡す必要があるが、モデルが制御すべきでない

フラグに使用します。

flag 型は存在だけを意味します(値持ちません)。引数が真の場合、フラグ名がコマンドラインに追加されます。

条件付きコマンド(requires)

コマンドは、環境変数の条件の requires リストを宣言できます。条件が満たされない場合、コマンドは読み込まれますが、そのルートは登録されません(GET /commands には表示されません)。

requires:
  - "MCP_LOG_ENABLED != false"

これは、MCP_LOG_ENABLED=false によってログ設定が無効化されたときに、log と log_read が非表示になるようにするために使用されます。

デフォルト

任意の引数に default 値を設定できます。呼び出し側がその引数を省略すると、実行側が自動的にそれを埋めます。常にオンにする必要があるフラグ(例: クワイエットモードの discord.sh -q)を強制するのに便利です:

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

レジストリコマンド用のネイティブルート

registry/ で定義された各コマンドは、自動的に専用の FastAPI ルート(POST /{command_name})として公開されます。リクエストモデルは YAML の引数仕様から生成された Pydantic モデルです。つまり、プラットフォームは OpenAPI スキーマを読み取り、各コマンドを ネイティブルール として適切な型付けされたパラメータ(文字列、列挙型、フラグ、デフォルト)で表示できます。

これらの専用ルートは、レジストリコマンドを実行する 唯一の 方法です。汎用の POST /execute エンドポイントはありません。レジストリファイルは引き続き GET /commands と GET /validate に反映され、コマンドの発見や検査が可能ですが、実行は型付きのコマンド単位のルートでのみ行われます。

不明なフィールドは extra: forbid で 422 レスポンスとともに拒否され、必須引数が不足している場合も 422 を返します。

field_name YAMLキーは、モデルに表示されるパラメータ名を制御します。省略した場合は、引数 name が使用されます(先頭のダッシュを除いた)。

レジストリのコマンド名が既存のルートと衝突する場合(例: 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")

クライアントは、カレンダー、タスク、Gitea API向けの型付き便利メソッド(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

認証

エンドポイントのAPIキー(未設定 = オープンアクセス)

MCP_REGISTRY_DIR

レジストリ

カスタムレジストリディレクトリ

MCP_LOG_FILE

ロギング

ログファイルのパス

MCP_LOG_DIR

ロギング

ログディレクトリ(ファイルはその中のディレクトリmcp.log)

MCP_LOG_LEVEL

ロギング

ログレベル(デフォルト: INFO)

MCP_LOG_ENABLED

ロギング

falseに設定するとコマンドを無効化

CALDAV_URL

CalDAV

CalDAVサーバーのURL

CALDAV_USERNAME

CalDAV

CalDAVユーザー名

CALDAV_PASSWORD

CalDAV

CalDAVパスワード

CALDAV_EDITABLE_CALENDAR

CalDAV

編集可能なカレンダー名(未設定 = すべて読み取り専用)

CALDAV_READONLY_CALENDARS

CalDAV

カンマ区切りの読み取り専用カレンダー名

ICS_CALENDAR_URL

ICS

読み取り専用のICSフィードURL

ICS_CALENDAR_NAME

ICS

ICSフィードの表示名

ICS_REFRESH_INTERVAL

ICS

キャッシュ更新間隔(秒、デフォルト300)

GITEA_URL

Gitea

GiteaサーバーのURL

GITEA_TOKEN

Gitea

APIトークン

GITEA_DEFAULT_OWNER

Gitea

デフォルトのリポジトリ所有者

GITEA_DEFAULT_REPO

Gitea

デフォルトのリポジトリ名

MCP_GITEA_EXTRA_TOOLS

Gitea

OpenAPIスキーマにニッチなエンドポイントを公開

DISCORD_*_HOOK

通知

DiscordウェブフックURL(重大度レベルごと)

DISCORD_SERVER_NAME

通知

ボット表示名の上書きの上書き

DISCORD_TITLE_SUFFIX

通知

Discordメッセージのタイトル接尾辞

NTFY_*_TOPIC

通知

Ntfyトピック(重大度レベルごと)

NTFY_TOKEN

通知

Ntfyアクセストークン

NTFY_USERNAME / NTFY_PASSWORD

通知

Ntfyのベーシック認証

NTFY_TITLE_SUFFIX

通知

ntfyメッセージのタイトル接尾辞

WEATHER_LOCATION

天気

天気データ用の「緯度,経度」

TZ

サーバー

タイムゾーン(デフォルト: UTC)

CalDAVカレンダー

サーバーはCalDAVサーバー(例: Radicale、Baikal、Nextcloud)に接続して、カレンダーイベントとタスクを管理できます。設計は1つの編集可能なカレンダー(イベントとタスクの作成、更新、削除が可能)と複数の読み取り専用カレンダー(表示はできるが書き込み不可)を使用します。

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サーバーが操作中に到達不可能になった場合、サービスは自動的に接続をリセットして1回再試行します。DAVError、ConnectionError、TimeoutError、OSErrorを捕捉します。

  • カレンダーのキャッシュ: カレンダー一覧は接続ごとに1回取得されキャッシュされるため、冗長なサーバーラウンドトリップを回避します。

  • 明示的なUUID: 作成されたイベントとタスクには常にuuid4 UIDが付与され、作成直後に更新または削除できることが保証されます。

ICSカレンダー(読み取り専用)

サーバーは、読み取り専用のICSカレンダーフィード(例: Outlook公開カレンダー、GoogleカレンダーのiCal)を、CalDAVイベントとともに統合された/eventsエンドポイントに統合できます。

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インスタンスに接続して、リポジトリ、イシュー、プルリクエスト、ブランチ、リリース、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

イシュー、ブランチ、PR、リリースの各エンドポイントは、オプションのownerとrepoクエリパラメータを受け付けます(既定値は設定値)。リポジトリ情報、コミット、比較の各エンドポイントはパスパラメータ(/repos/{owner}/{repo}/...)を使用します。

通知

サーバーはDiscordウェブフックやNtfyを介して通知を送信できます。複数のプロバイダーを同時に有効にでき、/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

このサーバーには、amd64とarm64に対応したマルチアーキテクチャのDockerfileが同梱されています。

ビルド

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(マルチアーキテクチャ)

  • システム依存: curl, jq(スクリプト用)、tini

  • 実行ユーザー: 非ルートユーザー 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

その後、/usr/bin/rubyを指すregistry/ruby_eval.yamlを追加します。

テスト

プロジェクトには、モデル、エグゼキュータ、レジストリ、APIエンドポイント、クライアントライブラリ、認証、CalDAV操作、ICS解析、Gitea連携、通知、天気、ロギング、バックグラウンドジョブ、条件付きエンドポイント登録をカバーする包括的なpytestスイートが含まれています。

# 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を設定すると、/api/healthと/api/aboutを除くすべてのエンドポイントでX-API-Keyヘッダーが必須となります。未設定の場合はオープンです。

  • エラーメッセージはサニタイズされます — 内部詳細はサーバー側にログされますが、HTTPレスポンスには公開されません(エラーがLLMのコンテキストウィンドウに流れるため重要です)。

  • サーバーは制限付きユーザーアカウントで実行してください。sudoを付与しないでください。

  • サーバーのファイルシステムを内視したり任意コードを実行するコマンドは意図的に削除されています — はっきりと許可されたコマンドだけを登録すべきです。


Lyraにより構築 — あなたをそばで支える銀髪のアシスタント。✨

Related MCP Connectors

Related MCP Servers

  • 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
  • F
    license
    Not graded
    quality
    B
    maintenance
    Enables AI agents to dynamically discover and call backend tools for arithmetic, SQLite-backed task management, GitHub repository lookups, and text statistics, while also exposing the same functionality through a REST API.
    -
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables an AI assistant to invoke local file operations, multi-engine web search, weather, system commands, developer utilities, and code execution over MCP, and includes a web dashboard for managing endpoints, testing tools, and viewing live logs.
    36 npm
    1
    MIT