Skip to main content
Glama
baller-coder

mcp-federated-data

mcp-federated-data

フェデレーションMCPサーバー。リレーショナルメタデータ(MySQL)と時系列値(InfluxDB)を、LLMフレンドリーな単一のエンティティレイヤーの背後で結合します。

License: MIT Version Node MCP

言語: English · 中文


課題

LLMが次のような質問に答える必要がある場合:

「ゾーンAのアクティブなセンサーの過去7日間の温度トレンドを表示して」

LLMは2つのストアを横断する必要があります:

  • リレーショナルメタデータ(どのセンサーが存在し、どこにあり、種類や単位は何か) — MySQL

  • 時系列値(時間の経過に伴う測定値) — InfluxDB

2つの独立したMCPサーバーを接続すると、LLMは以下の手順を強いられます:

  1. MySQLをクエリ → 一致するエンティティを検索 → IDを抽出

  2. それらのIDをInfluxDBのクエリに投入

  3. 自身のコンテキスト内で2つの結果セットを結合する

LLMはステップ3で確実につまずきます。特に結合キーが複合的な場合(例:InfluxDBのタグが2つのリレーショナルフィールドを連結したもの)は顕著です。

このサーバーは、これら3つのステップを1回のツール呼び出しに集約します。


LLMから見えるもの

5つのツール。プロンプト内にSQLやFluxは不要です:

ツール

目的

list_entities

ビジネスエンティティをフィールドでフィルタリング

get_entity

プライマリキーで単一のエンティティを検索

list_related

エンティティ間の設定されたリレーションを辿る

get_entity_timeseries

フェデレーション — メタデータと時系列データを1回の呼び出しで取得

compare_timeseries

2〜20個の特定のエンティティを同じ期間で比較

すべてのツールには詳細なJSONスキーマ記述が付属しているため、LLMはプロンプトの工夫なしで適切な引数を選択できます。


単純な2サーバー構成との違い

シナリオ

2つの独立したMCPサーバー

mcp-federated-data

「ゾーンAのセンサーのトレンド」

LLM: MySQLクエリ → ID抽出 → Fluxに投入 → 頭の中で結合

1回の get_entity_timeseries 呼び出し

{deviceId}.{signalId} のような複合タグ

LLMがプロンプト内で文字列を構成 — エラーが発生しやすい

YAMLで composer: "{deviceId}.{signalId}" と定義、サーバーが実行

メタデータ ↔ 時系列の整合性

LLMが結合を行うため、ペアリングミスが頻発

サーバーが設定されたキーで結合

データ量の爆発

無防備

最大エンティティ数制限 + 自動ダウンサンプリング + エンティティごとのポイント上限

LLM向けのビジネスセマンティクス

生の CREATE TABLE のみ

description 付きのYAMLフィールド

監査証跡

なし

呼び出しごとの構造化された監査ログ


クイックスタート

git clone https://github.com/baller-coder/mcp-federated-data.git
cd mcp-federated-data
pnpm install

# Sample environment (MySQL + InfluxDB in Docker, with seeded data)
docker compose -f examples/industrial-monitoring/docker-compose.yml up -d
pnpm seed

# Start the MCP server over stdio
pnpm dev -- --config examples/industrial-monitoring/config.yaml

任意のMCPクライアント(Claude Desktop、Cursor、mcp-inspector)から接続します。

試してみる

// list active sites
{
  "name": "list_entities",
  "arguments": {
    "entity": "site",
    "filters": [{ "field": "status", "op": "eq", "value": "active" }]
  }
}

// list sensors attached to site 1
{
  "name": "list_related",
  "arguments": {
    "source_entity": "site",
    "source_id": 1,
    "target_entity": "sensor"
  }
}

// federated query — metadata + timeseries in ONE call
{
  "name": "get_entity_timeseries",
  "arguments": {
    "entity": "sensor",
    "filters": [
      { "field": "site_id", "op": "eq", "value": 1 },
      { "field": "kind",    "op": "eq", "value": "temperature" }
    ],
    "time_range":  { "start": "-7d" },
    "aggregation": { "window": "1h", "fn": "mean" }
  }
}

// compare 3 specific sensors over the same window
{
  "name": "compare_timeseries",
  "arguments": {
    "entity": "sensor",
    "ids":    [101, 201, 301],
    "time_range":  { "start": "-24h" },
    "aggregation": { "window": "10m", "fn": "mean" }
  }
}

設定

サーバーの動作全体は単一のYAMLファイルで定義されます。3つのセクションがあります。

1. データソース

datasources:
  - name: business
    type: mysql
    host: localhost
    port: 3306
    database: my_db
    username: readonly_user
    password: secret

  - name: timeseries
    type: influxdb
    url: http://localhost:8086
    token: my-token
    org: my_org
    bucket: my_bucket

2. エンティティ

各エンティティはリレーショナルテーブルまたはビューにバインドされ、オプションのリレーションと時系列バインディングを持つことができます。

entities:
  - name: site
    description: Physical monitoring location.
    source:
      datasource: business
      table: sites
      primary_key: id
      fields:
        - { name: id,     type: number }
        - { name: name,   type: string, description: Display name }
        - { name: region, type: string }
        - { name: status, type: string, description: "active / inactive / maintenance" }

  - name: sensor
    description: A sensor attached to a site.
    source:
      datasource: business
      table: sensors
      primary_key: id
      fields:
        - { name: id,      type: number }
        - { name: site_id, type: number }
        - { name: name,    type: string }
        - { name: kind,    type: string, description: "temperature / humidity / voltage / ..." }
        - { name: unit,    type: string }
    relations:
      - target: site
        type: many-to-one
        local_key: site_id
        foreign_key: id
    timeseries:
      datasource: timeseries
      measurement: sensor_data
      value_field: value
      join_key:
        local: id
        remote_tag: sensor_id

3. デフォルト(ガードレール)

defaults:
  max_entities_per_query: 50
  max_points_per_entity: 500
  query_timeout_ms: 15000

複合結合キー(v0.2のハイライト)

InfluxDBのタグ値が複数のリレーショナルフィールドの複合体である場合(IoT/産業システムで一般的。400001240.438000066 のようなタグが {deviceId}.{signalId} をエンコードしている場合など)、以下のように宣言します:

timeseries:
  measurement: sensor_data
  value_field: value
  join_key:
    local: [device_id, signal_id]
    remote_tag: signal_id
    composer: "{device_id}.{signal_id}"

サーバーの動作:

  1. MySQLからメタデータを取得(コンポーザーのローカルフィールドは SELECT に自動的に含まれます)。

  2. テンプレートを使用して各行のタグ値を構成します。

  3. 構成されたリストをInfluxDBのタグフィルターに投入します。

  4. 同じテンプレートを使用して結果を結合します。

単一フィールドのバインディング(v0.1の形式)もそのまま動作します。サーバーはそれらを1要素の複合体として扱うため、すべてのパスが統一されます。


仕組み — 50行のコア

すべてのフェデレーションツールは、同じ3つのステップに従います:

  1. メタデータの取得 — ビジネスストアに対するリレーショナルクエリ。安全な識別子チェックとパラメータ化された WHERE を使用。許可されるフィルターフィールドは、エンティティ設定で宣言されたものに制限されます。

  2. 時系列データの取得 — ステップ1から結合キー値を取得し、時系列ストアに対するタグフィルターに投入。オプションの集計と呼び出しごとのポイント上限が適用されます。

  3. マージ — 時系列ポイントをリモートタグ値でグループ化し、各メタデータ行とソートされた系列を結合します。

SQLパーサーはありません。ストア横断のクエリプランナーもありません。意図的な設計です。


アーキテクチャ

┌──────────────────────────────────┐
│  MCP client (Claude / Cursor)    │
└────────────┬─────────────────────┘
             │ stdio  (JSON-RPC)
             ▼
┌──────────────────────────────────┐
│       mcp-federated-data         │
│  ┌────────────────────────────┐  │
│  │  Tools  (5 tools)          │  │
│  ├────────────────────────────┤  │
│  │  Entity registry           │  │
│  │  Join-key normalizer       │  │
│  │  Composer engine           │  │
│  │  Guards (limits/timeout)   │  │
│  │  Audit logger              │  │
│  ├────────────────────────────┤  │
│  │  Datasource adapters       │  │
│  └─────────┬────────┬─────────┘  │
└────────────┼────────┼────────────┘
             ▼        ▼
        ┌──────┐ ┌──────────┐
        │MySQL │ │InfluxDB  │
        └──────┘ └──────────┘

適用範囲

mcp-federated-dataスキーマ駆動型であり、ドメイン固有ではありません。ビジネスメタデータがリレーショナルストアにあり、観測値が時系列ストアにあるあらゆる場所で適用可能です:

  • IoTデバイスのテレメトリ

  • 産業プロセスの監視

  • 資産パフォーマンス管理

  • ビルオートメーション

  • エネルギー/電力監視

  • 環境センサーネットワーク

  • ネットワークデバイス監視

スタックが MySQL + InfluxDB であり、LLMにそれらを推論させたい場合、このサーバーが最適です。


関連プロジェクトとの比較

mcp-federated-data

mcp-server-mysql

mcp-server-influxdb

Wren AI / Vanna

ストア横断結合

部分的 (独自エンジン)

複合タグコンポーザー

n/a

LLM安全なSQLガード

様々

n/a

セマンティックレイヤーとしてのスキーマ

設定

YAML

環境変数 / 引数

環境変数 / 引数

専用DSL

スコープ

狭いが深い

薄いラッパー

薄いラッパー

フルBIプラットフォーム


コントリビューション

IssueやPRを歓迎します。作成前に以下を確認してください:

  • 新しいデータソースアダプターの場合 — インターフェースを合わせるため、まずIssueを作成してください。

  • 新しいツールの場合 — 既存のJSONスキーマ + 監査ログパターンに従ってください。

  • 公開APIは、マイナーバージョン内での後方互換性を維持する必要があります。


謝辞


ライセンス

MIT

A
license - permissive license
-
quality - not tested
C
maintenance

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/baller-coder/mcp-federated-data'

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