Skip to main content
Glama
baller-coder

mcp-federated-data

mcp-federated-data

관계형 메타데이터(MySQL)와 시계열 값(InfluxDB)을 단일 LLM 친화적 엔티티 계층 뒤에서 결합하는 연합 MCP 서버입니다.

License: MIT Version Node MCP

언어: English · 中文


문제점

LLM이 다음과 같은 질문에 답해야 할 때:

"A 구역에서 활성화된 센서의 지난 7일간 온도 추이를 보여줘"

LLM은 두 개의 저장소를 탐색해야 합니다:

  • 관계형 메타데이터 (어떤 센서가 존재하는지, 위치, 종류, 단위 등) — MySQL

  • 시계열 값 (시간에 따른 측정값) — InfluxDB

두 개의 독립적인 MCP 서버를 연결하면 LLM은 다음과 같은 과정을 거쳐야 합니다:

  1. MySQL 쿼리 → 일치하는 엔티티 찾기 → ID 추출

  2. 해당 ID를 InfluxDB 쿼리에 삽입

  3. 자신의 컨텍스트 내에서 두 결과 집합을 결합

LLM은 3단계에서 자주 오류를 범합니다. 특히 조인 키가 복합적인 경우(예: InfluxDB 태그가 두 개의 관계형 필드를 결합한 형태)에는 더욱 그렇습니다.

이 서버는 이 세 단계를 하나의 도구 호출로 통합합니다.


LLM이 보는 것

프롬프트에 SQL이나 Flux 없이 5개의 도구만 제공됩니다:

도구

목적

list_entities

필드별로 비즈니스 엔티티 필터링

get_entity

기본 키로 단일 엔티티 조회

list_related

엔티티 간 구성된 관계 탐색

get_entity_timeseries

연합 — 한 번의 호출로 메타데이터 + 시계열 데이터 조회

compare_timeseries

동일한 기간 동안 2~20개의 특정 엔티티 비교

모든 도구는 풍부한 JSON-Schema 설명을 포함하고 있어 LLM이 프롬프트 트릭 없이도 올바른 인자를 선택할 수 있습니다.


일반적인 두 서버 설정과의 차이점

시나리오

두 개의 독립적인 MCP 서버

mcp-federated-data

"A 구역 센서의 추이"

LLM: MySQL 쿼리 → ID 추출 → Flux에 삽입 → 머릿속에서 조인

하나의 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 파일에 정의됩니다. 세 개의 섹션으로 구성됩니다.

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 태그 값이 여러 관계형 필드의 복합체인 경우(예: 400001240.438000066과 같이 {deviceId}.{signalId}를 인코딩하는 IoT/산업 시스템에서 흔함) 다음과 같이 선언하세요:

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줄의 핵심 코드

모든 연합 도구는 동일한 세 단계를 따릅니다:

  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

저장소 간 조인

부분적 (자체 엔진)

복합 태그 컴포저

해당 없음

LLM 안전 SQL 가드

다양함

해당 없음

의미 계층으로서의 스키마

구성

YAML

env / args

env / args

전용 DSL

범위

좁지만 깊음

얇은 래퍼

얇은 래퍼

전체 BI 플랫폼


기여

이슈와 PR을 환영합니다. 오픈하기 전에 다음을 확인하세요:

  • 새로운 데이터 소스 어댑터의 경우 — 인터페이스를 맞출 수 있도록 먼저 이슈를 열어주세요.

  • 새로운 도구의 경우 — 기존 JSON-Schema + 감사 로그 패턴을 따르세요.

  • 공개 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