Skip to main content
Glama
ranjit534

ontology-mcp

by ranjit534

Login Query Agent — 온톨로지 MCP & 지식 그래프

OWL/SHACL/SKOS 지식 그래프두 개의 MCP 서버를 사용하여 로그인 진단 쿼리를 SQL Server와 MongoDB에 걸쳐 라우팅하고, 조건부로 New Relic으로 에스컬레이션하는 POC입니다.


한눈에 보는 아키텍처

User prompt (VS Code Copilot)
        │
        ▼  LLM classifies category natively — no tool call
        │
  ontology-mcp  ──► Fuseki KG (SPARQL)
        │              get_diagnosis_plan(category)
        │              returns: capability_id, required_entities,
        │                       validation_sequence, newrelic_tool
        ▼
  data-mcp  ──► SQL Server  (UM_Users, UM_UserPartnermapping,
        │                    UM_UserMobileNumberVerified)
        ├──────► MongoDB     (users collection — 9 projected fields)
        ├──────► SHACL Validator  (shapes read from KG shacl graph, evaluated in sequence order)
        └──────► New Relic   (only when all_shapes_pass=true — 2-step NRQL)

Related MCP server: OntoRamp Graph Query

서비스 개요

서비스

유형

시작 주체

필요한 용도

Apache Jena Fuseki

로컬 프로세스

직접 (수동)

ontology-mcp KG 쿼리

ontology-mcp

stdio 자식 프로세스

VS Code가 자동 생성

진단 계획

data-mcp

stdio 자식 프로세스

VS Code가 자동 생성

DB 쿼리 + 검증

SQL Server

원격/LocalDB

이미 실행 중

데이터 쿼리

MongoDB

원격 서버

이미 실행 중

데이터 쿼리

New Relic

클라우드 서비스

항상 사용 가능

에스컬레이션 (모든 셰이프 통과)

Fuseki만 수동으로 시작하면 됩니다. 두 MCP 서버는 모두 VS Code가 자동으로 생성합니다.


사전 요구 사항

1. Java 11+

java -version

2. Apache Jena Fuseki JAR

JAR 파일은 git에서 제외되어 있습니다 (54 MB). jena.apache.org에서 다운로드하여 다음 위치에 배치하세요:

infra/fuseki/fuseki-server.jar

3. Python 3.12+

python --version

4. Python 의존성

cd c:\Ontology
python -m pip install -r requirements.txt

5. SQL Server용 ODBC 드라이버

아직 설치하지 않은 경우 Microsoft에서 SQL Server용 ODBC Driver 17 또는 18을 다운로드하세요.

6. GitHub Copilot (Agent mode)이 포함된 VS Code

GitHub Copilot 확장 기능이 포함된 VS Code 1.99+.


단계별 로컬 시작

1단계 — Fuseki 시작

cd c:\Ontology
java -jar infra\fuseki\fuseki-server.jar --config infra\fuseki\config\login-kg.ttl

이 터미널을 열어 두세요. http://localhost:3030에서 확인하세요.

2단계 — 지식 그래프 로드

최초 실행 시 또는 스키마/아티팩트가 변경된 후에 필요합니다.

$env:PYTHONIOENCODING = "utf-8"
python scripts/generate/generate.py --schema login --version 1.0.0
python scripts/kg/load_kg.py        --schema login --version 1.0.0
python scripts/kg/promote.py        --schema login --version 1.0.0

3단계 — 시크릿 구성

.env.example.env로 복사하고 값을 입력하세요:

SQL_SERVER_HOST=your-server
SQL_SERVER_DATABASE=your-database
SQL_SERVER_TRUSTED_CONNECTION=yes
SQL_SERVER_ENCRYPT=yes
SQL_SERVER_TRUST_CERT=yes

MONGODB_URI=mongodb://your-host:27017
MONGODB_DATABASE=your-database

NEW_RELIC_API_KEY=NRAK-xxxxxxxxxxxxxxxxxxxx
NEW_RELIC_ACCOUNT_ID=your-account-id
NEW_RELIC_REGION=US

APP_ENV=prod

4단계 — 두 MCP 서버 등록

작업 영역 루트에 .vscode/mcp.json을 만드세요:

{
  "servers": {
    "ontology-mcp": {
      "type": "stdio",
      "command": "python",
      "args": ["-m", "mcp_server.server"],
      "cwd": "c:\\Ontology",
      "env": {
        "PYTHONPATH": "c:\\Ontology\\src",
        "PYTHONIOENCODING": "utf-8"
      }
    },
    "data-mcp": {
      "type": "stdio",
      "command": "python",
      "args": ["-m", "mcp_server.diagnostic_server"],
      "cwd": "c:\\Ontology",
      "env": {
        "PYTHONPATH": "c:\\Ontology\\src",
        "PYTHONIOENCODING": "utf-8"
      }
    }
  }
}

VS Code를 다시 로드하세요 (Ctrl+Shift+PDeveloper: Reload Window).


전체 진단 흐름

User: "testgdpr1235@gep.com can't reset password"
        │
        │  LLM classifies: category = "password_reset"  (no tool call)
        │
        ▼
① ontology-mcp / get_diagnosis_plan(category="password_reset")
     Reads x_capability_registry from login.yaml (no Fuseki needed for this step)
     Returns: capability_id, required_entities, validation_sequence, newrelic_tool
        │
        ▼  (agent extracts username from user message; asks if missing)
        │
② data-mcp / query_sql_user(username, capability_id)
     SELECT from UM_Users → islocked, isactive, isdeleted, usertype, emailaddress, ...
        │
③ data-mcp / query_sql_mobile_verification(username, capability_id)
     SELECT from UM_UserMobileNumberVerified → ismobilenumberverified
        │
④ data-mcp / query_sql_partner_mappings(username, capability_id)
     SELECT from UM_UserPartnermapping → bpc, partnercode, isactive, contactcode
        │
⑤ data-mcp / query_mongo_user(username, capability_id)
     db.users.find_one({...}, { 9 diagnostic fields }) → MongoDB document
        │
⑥ data-mcp / validate_login_shapes(username, capability_id, validation_sequence)
     Runs only the shapes in validation_sequence (plan-scoped)
     Returns: per-shape PASS/FAIL, all_shapes_pass, advisories (e.g. dr_012)
        │
   ┌────┴──────────────────────────┐
violations found              all_shapes_pass = true
   │                               │
report per shape              ⑦a data-mcp / query_newrelic_login_mfa(username, capability_id)
with mapped rule                   OR
dr_003..dr_008                ⑦b data-mcp / query_newrelic_reset_password(username, capability_id)
                                    → Transaction → Log per traceId (max 7 days)

required_entities에 나열된 엔티티만 가져옵니다. 필요하지 않은 카테고리의 경우 ②–⑤ 단계는 건너뜁니다 (예: account_locked는 파트너 + 모바일 쿼리를 건너뜁니다).


MCP 도구 참조

ontology-mcp — 지식 그래프 계획 도구 (3개 도구)

도구

단계

입력

반환

get_diagnosis_plan

0 — 필수 최초 호출

category, schema

capability_id, required_entities, validation_sequence, newrelic_tool, required_parameters, datasources, additional_checks

list_capabilities

폴백 전용

schema

id, description, covers가 포함된 전체 8개 카테고리

get_entity_descriptor

요청 시

class_name, schema

KG 디스크립터 그래프의 전체 열/필드 매핑

get_diagnosis_plan은 기능 레지스트리를 login.yaml에서 직접 읽습니다 — Fuseki 호출이 필요 없습니다. get_entity_descriptor는 Fuseki 디스크립터 그래프를 쿼리합니다 — Fuseki가 실행 중이어야 합니다.


data-mcp — 실시간 데이터 도구 (7개 도구)

7개 도구 모두 get_diagnosis_plancapability_id가 필요합니다. 이것 없이 호출하면 구조화된 오류가 반환됩니다.

도구

단계

소스

반환

query_sql_user

1a

UM_Users

userid, username, emailaddress, usertype, authenticationtype, islocked, isactive, isdeleted, issystemuser, mobileno

query_sql_mobile_verification

1b

UM_UserMobileNumberVerified

ismobilenumberverified + 실행된 SQL

query_sql_partner_mappings

1c

UM_UserPartnermapping

전체 매핑 행, 전체 개수, 활성 개수

query_mongo_user

1d

users 컬렉션

9개 프로젝션 필드 + 실행된 쿼리

validate_login_shapes

2

SQL + MongoDB

셰이프별 PASS/FAIL, all_shapes_pass, advisories, next_step

query_newrelic_login_mfa

3a

New Relic NerdGraph

/Account/Login에 대한 트랜잭션 + 로그 (dr_010)

query_newrelic_reset_password

3b

New Relic NerdGraph

3개의 리셋 URI에 대한 트랜잭션 + 로그 (dr_011)


진단 카테고리 (8)

카테고리

트리거 조건

login_failure

로그인 / 인증 / 앱 접근 불가, SSO 실패, 자격 증명 거부

password_reset

리셋 링크 또는 비밀번호 찾기 이메일을 받지 못함

otp_email

리셋 중 OTP 이메일을 받지 못함

sms_otp

SMS OTP를 받지 못함 (모바일 인증됨)

account_state

계정 비활성화 / 비활성 / 정지 / 사용 중지

account_locked

여러 번의 실패한 시도 후 계정 잠김

partner_mapping

파트너 (BPC) 매핑 누락 / 비활성

data_sync

SQL과 MongoDB 필드 불일치


SHACL 셰이프 (8개, 시퀀스 순서로 평가)

#

셰이프

조건

규칙

1

LoginBlockShape

isLocked=1 OR isActive=0 OR isDeleted=1

dr_003

2

SystemUserShape

isSystemUser=1

dr_005

3

BuyerSSOShape

userType=Buyer AND authenticationType=SSO

dr_006

4

PartnerMappingShape

활성 파트너 매핑 행 없음

dr_004

5

SupplierPartnerMappingShape

활성 상태의 0이 아닌 BPC가 없는 공급업체

dr_007

6

EmailVerificationShape

유효한 등록 이메일 주소 없음 (리셋/OTP 흐름)

7

MobileConsistencyShape

SQL과 MongoDB의 isMobileNumberVerified 불일치

dr_002

8

PartnerMappingDataSyncShape

SQL과 MongoDB의 파트너 매핑 필드 불일치

dr_008

각 카테고리의 validation_sequence는 이 셰이프 중 관련 하위 집합만 실행합니다. advisories (예: dr_012 이메일 불일치)는 셰이프와 함께 반환되지만 all_shapes_pass에는 영향을 미치지 않습니다.


New Relic 쿼리 구조 (2단계)

Step 1: Transaction table (max 7 days lookback, filtered by APP_ENV)
  /Account/Login            → LoginUserName, traceId, RequiresTwoFactor, TwoFactorDetails
  /Account/RecoverPassword  → traceId, errorMessage, RecoveryUserName, RecoveryEmail
  /Account/PreResetPassword → traceId, errorMessage, PreResetUserName
  /Account/ResetPassword    → LoginUserName, traceId, errorMessage

Step 2: Log table (per traceId from Step 1)
  SELECT * FROM Log WHERE `trace.id` = '{traceId}' SINCE {transaction_timestamp}

지식 그래프 — 명명된 그래프

KG는 버전당 6개의 명명된 그래프와 1개의 메타 그래프를 저장합니다:

명명된 그래프 IRI

내용

사용처

urn:kg:login:v1.0.0:capabilities

진단 플레이북 — 8개 카테고리, 필수 엔티티, 검증 시퀀스

get_diagnosis_plan (0단계)

urn:kg:login:v1.0.0:descriptors

엔티티 열/필드 매핑

get_entity_descriptor + validate_login_shapes (머티리얼라이제이션)

urn:kg:login:v1.0.0:rules

결정 규칙 (dr_001..dr_012)

validate_login_shapes — 런타임에 읽는 셰이프→규칙 매핑

urn:kg:login:v1.0.0:shacl

SHACL 노드 셰이프 + 제약 조건

validate_login_shapes — 런타임에 셰이프를 읽고 실행 (KG 기반)

urn:kg:login:v1.0.0:ontology

OWL 클래스 + 속성

검사용으로 사용 가능

urn:kg:login:v1.0.0:skos

SKOS 개념 체계 + 레이블

검사용으로 사용 가능

urn:kg:login:meta

활성 버전 포인터

모든 Fuseki 쿼리 (그래프 디스커버리)

Fuseki는 모든 진단의 두 단계에서 쿼리됩니다:

  1. get_diagnosis_plan (0단계) — get_active_graphs (메타 그래프) + get_capability_plan (캐퍼빌리티 그래프) → 전체 진단 플레이북

  2. validate_login_shapes (2단계) — shacl 그래프(셰이프), descriptors 그래프(머티리얼라이제이션을 위한 필드/타입 매핑), rules 그래프(셰이프→규칙)를 읽습니다 — 검증기는 KG 기반입니다

폴백 (각각 경고를 로깅): Fuseki에 연결할 수 없으면 get_diagnosis_planlogin.yaml에서 x_capability_registry를 읽고, validate_login_shapes는 프로그램 방식의 shacl_validator.py로 폴백합니다.


아티팩트 재생성

YAML 스키마 파일이 변경되면:

$env:PYTHONIOENCODING = "utf-8"
python scripts/generate/generate.py --schema login --version 1.0.0
python scripts/kg/load_kg.py        --schema login --version 1.0.0
python scripts/kg/promote.py        --schema login --version 1.0.0

프로젝트 구조

c:\Ontology\
├── src/
│   └── mcp_server/                        # PYTHONPATH=c:\Ontology\src
│       ├── server.py                      # ontology-mcp entrypoint (KG planning tools)
│       ├── diagnostic_server.py           # data-mcp entrypoint (DB/NR tools)
│       ├── tool_meta.py                   # loads config/tool_descriptions.yaml
│       ├── connectors/
│       │   ├── sql_connector.py           # pyodbc — UM_Users, UM_UserPartnermapping, ...
│       │   ├── mongo_connector.py         # pymongo — users collection (projected)
│       │   └── newrelic_connector.py      # NerdGraph GraphQL — 2-step NRQL
│       ├── diagnostics/
│       │   ├── data_fetcher.py            # orchestrates SQL + MongoDB fetch
│       │   ├── kg_shacl_validator.py      # KG-driven SHACL interpreter (PRIMARY)
│       │   └── shacl_validator.py         # programmatic evaluation (Fuseki-down fallback)
│       ├── tools/
│       │   ├── get_diagnosis_plan.py      # ontology-mcp: reads x_capability_registry
│       │   ├── list_capabilities.py       # ontology-mcp: lists all 8 categories
│       │   ├── get_descriptor.py          # ontology-mcp: SPARQL descriptors graph
│       │   ├── fetch_user_data.py         # data-mcp: 4 individual SQL/Mongo queries
│       │   ├── validate_shapes.py         # data-mcp: shape evaluation + advisories
│       │   └── query_newrelic.py          # data-mcp: NR login + reset handlers
│       ├── kg/
│       │   └── sparql_client.py           # Fuseki HTTP client + graph discovery
│       └── registry/
│           └── schema_registry.py         # registry.yaml + load_capability_registry()
│
├── ontology/
│   ├── schemas/
│   │   ├── registry.yaml
│   │   └── login/v1.0.0/
│   │       ├── login.yaml                 # root: x_capability_registry + x_shacl_rules + x_decision_rules
│   │       ├── shared/types.yaml
│   │       ├── shared/enums.yaml          # AuthenticationTypeEnum, UserTypeEnum
│   │       ├── shared/subsets.yaml
│   │       └── entities/
│   │           ├── abstract_user.yaml
│   │           ├── user.yaml              # SQL UM_Users
│   │           ├── partner_mapping.yaml   # SQL UM_UserPartnermapping
│   │           ├── mobile_verification.yaml # SQL UM_UserMobileNumberVerified
│   │           └── user_document.yaml     # MongoDB users collection
│   └── sparql/
│       ├── get_entity_descriptor.sparql
│       └── get_decision_rules.sparql
│
├── artifacts/login/v1.0.0/
│   ├── owl/login.owl.ttl
│   ├── shacl/login.shacl.ttl
│   ├── skos/login.skos.ttl
│   ├── rules/login.rules.ttl
│   ├── descriptors/login.descriptors.json
│   └── jsonld/login.context.jsonld + login.agent_template.json
│
├── scripts/
│   ├── generate/generate.py + gen_*.py + _yaml_loader.py
│   └── kg/load_kg.py + promote.py
│
├── config/
│   └── tool_descriptions.yaml             # single source of truth for all MCP tool descriptions
│
├── infra/fuseki/
│   ├── fuseki-server.jar                  # not committed — download separately
│   ├── config/login-kg.ttl
│   └── data/                              # TDB2 storage — gitignored
│
├── .github/copilot-instructions.md        # Copilot workspace instructions (auto-loaded)
├── CLAUDE.md                              # Claude Code workspace instructions (auto-loaded)
├── .vscode/mcp.json                       # MCP server registration (2 servers)
├── .env / .env.example                    # secrets — .env never committed to git
└── requirements.txt

문제 해결

오류

원인

수정

sparql_failed

Fuseki가 실행 중이 아님

Fuseki 시작(1단계)

capability_id_required

에이전트가 get_diagnosis_plan을 건너뜀

대화 다시 시작; CLAUDE.md / copilot-instructions.md가 순서를 강제함

schema_not_found

registry.yaml에 스키마 항목이 없음

ontology/schemas/registry.yaml 확인

registry_load_failed

login.yamlx_capability_registry가 없음

login.yaml에 해당 블록이 있는지 확인

SQL Server connection error

.env의 호스트/자격 증명이 잘못됨

SQL_SERVER_HOST, TRUSTED_CONNECTION 확인

No module named 'pyodbc'

종속성 누락

pip install pyodbc

UnicodeEncodeError

Windows 콘솔 인코딩

$env:PYTHONIOENCODING = "utf-8" 추가

Fuseki 그래프가 비어 있음

재시작 후 새 Fuseki 시작

load_kg.py + promote.py 실행


일일 워크플로

# 1. Start Fuseki
java -jar infra\fuseki\fuseki-server.jar --config infra\fuseki\config\login-kg.ttl

# 2. Load KG (only after schema or artifact changes)
$env:PYTHONIOENCODING = "utf-8"
python scripts/kg/load_kg.py --schema login --version 1.0.0
python scripts/kg/promote.py --schema login --version 1.0.0

# 3. Open VS Code — both MCP servers start automatically

스키마 확장

새 엔터티 추가(새 SQL 테이블 또는 MongoDB 컬렉션)

  1. ontology/schemas/login/v1.0.0/entities/new_entity.yaml 생성

  2. login.yaml 임포트에 - entities/new_entity 추가

  3. generate + load + promote 실행

진단 범주 추가 또는 변경

  1. login.yaml에서 x_capability_registry 편집

  2. x_shacl_rules(login.yaml)에서 일치하는 셰이프 추가/업데이트 — KG 기반 검증기는 shacl 그래프에서 이를 읽습니다. sh_in/sh_property/sparql/cross_source 셰이프에는 Python 편집이 필요 없습니다

  3. generate + load + promote 실행(새 셰이프/규칙이 KG에 들어가도록)

  4. MCP 서버 다시 시작

SHACL 셰이프 추가 또는 변경

셰이프는 코드가 아닌 KG에서 실행됩니다. login.yaml에서 x_shacl_rules를 편집한 다음 regenerate + reload를 수행하세요. kg_shacl_validator.py(일반 엔진)는 완전히 새로운 제약 조건 유형을 도입하지 않는 한 변경할 필요가 없습니다.

새 스키마 버전 추가

  1. ontology/schemas/login/v1.0.0/v1.1.0/ 복사

  2. v1.1.0/에서 엔터티 파일 편집

  3. v1.1.0에 대해 generate + load + promote 실행

두 버전 모두 KG에 공존합니다 — 롤백은 항상 promote.py로 가능합니다.

Related MCP Connectors

Related MCP Servers