mcp-chat

mcp-chat

Neo4j 기반 챗봇 MCP 서버로, 도메인 특화 tool과 Text2Cypher 방식을 조합해 안전하고 정확한 지식그래프 질의응답을 제공합니다.

Category
访问服务器

README

mcp-chat

공간 대관·행사 이력을 다루는 챗봇용 MCP 서버. NestJS + 공식 @modelcontextprotocol/sdk, Streamable HTTP 전용.

설계 배경과 구현 방식 비교는 DOCUMENT.md에 있다.

빠른 시작

docker compose up -d      # Neo4j (bolt 7687 / browser 7474)
pnpm install
pnpm start:dev            # http://localhost:3000/mcp

.env에 Neo4j 접속 정보가 있어야 한다. 값은 docker-compose.yml의 NEO4J_PASSWORD 기본값과 일치해야 한다. Neo4j 없이도 서버는 뜨고, Neo4j를 쓰는 tool만 실패한다.

노출하는 tool

두 갈래가 공존한다. 자주 쓰는 질문은 도메인 tool이 받고, 그것으로 답할 수 없는 질문만 read_cypher로 떨어진다.

tool 데이터 소스 하는 일
search_spaces in-memory 용도·수용인원·건물·키워드로 공간 검색
get_space in-memory 공간 하나의 상세 (id 필요)
get_building_structure in-memory 건물 목록 또는 층별 구성
search_events in-memory 브랜드·유형·시점으로 행사 이력 검색
get_schema Neo4j 그래프 스키마 조회
read_cypher Neo4j 검증을 통과한 읽기 전용 Cypher 실행

도메인 tool 4개는 모델이 쿼리를 쓰지 않는다. 쿼리는 코드에 있고 모델은 인자만 채운다.

read_cypher는 모델이 작성한 Cypher를 실행 전에 코드로 막는다 — 쓰기 구문 거부, 프로시저 허용목록, LIMIT 강제 주입. 문자열 리터럴이나 주석 안의 키워드는 오탐하지 않도록 따옴표 상태를 따라간다.

동작 방식

요청 한 번의 흐름

모델          "과거에 무신사 팝업 한 공간 알려줘"
  │
  │  tools/call  { name: "search_events",
  │                arguments: { brandName: "무신사", type: "팝업", period: "과거" } }
  ▼
POST /mcp     McpController — 요청마다 McpServer + Transport를 새로 만든다
  ▼
zod           inputSchema로 인자 검증. 타입·enum·범위가 안 맞으면 여기서 끝
  ▼
Service       EventService.searchEvents() — 필터링과 정렬. MCP를 모른다
  ▼
Formatter     결과 배열 → markdown 표
  ▼
모델          | 행사 | 브랜드 | 유형 | 기간 | 공간 | 건물 | spaceId |
              | 무신사 테라스 팝업 | 무신사 | 팝업 | 2025-05-01 ~ ... |

모델이 보는 것은 tool 이름, description, 인자 스키마, 그리고 돌아온 텍스트뿐이다. 쿼리도 데이터 구조도 보지 않는다.

두 갈래의 데이터 경로

                     ┌─ 도메인 tool 4개 ─→ SpaceService / EventService ─→ in-memory 배열
tools/call ─→ 라우팅 ─┤
                     └─ read_cypher ─→ 검증기 ─→ Neo4jService ─→ Neo4j
                        get_schema  ─→ SchemaService ─┘

도메인 tool은 모델에게서 쿼리 작성 권한을 뺏는다. 쿼리는 코드에 있고 모델은 인자만 채우므로 결과가 항상 정확하고 injection이 구조적으로 불가능하다. 대신 tool이 다루지 않는 질문에는 답할 수 없다.

**read_cypher**는 그 반대다. 어떤 질문이든 받을 수 있지만 모델이 쓴 쿼리를 믿을 수 없어서, 실행 전에 코드로 거른다.

모델이 쓴 Cypher
  ▼ 주석 제거          실행 쿼리에서 지운다. 안 그러면 뒤에 붙인 LIMIT이 주석에 먹힌다
  ▼ 문자열 리터럴 마스킹  n.name = 'DELETE' 를 쓰기 구문으로 오해하지 않도록
  ▼ 레이블·프로퍼티 마스킹 (n:Set), n.merge 를 키워드로 오해하지 않도록
  ▼ statement 개수      세미콜론으로 여러 개를 이어 붙였는지
  ▼ 쓰기 구문 15종       CREATE / MERGE / DELETE / SET / DROP ...
  ▼ 프로시저 허용목록     db.labels, db.schema.* 등 읽기 전용만
  ▼ LIMIT 보장          없으면 주입, 상한을 넘으면 낮춤
실행

거부되면 예외를 던지지 않고 이유를 담은 텍스트를 isError: true로 돌려준다. 모델이 메시지를 읽고 스스로 고쳐 재시도해야 하기 때문이다. Neo4j 접속 정보가 없을 때도 마찬가지로, 서버는 정상 기동하고 DB를 쓰는 tool만 실패한다.

지금은 같은 데이터가 두 곳에 있다

pnpm load -- --force로 in-memory 데이터를 그래프에 적재한 상태라, 공간·행사 데이터가 코드와 Neo4j 양쪽에 있다. 도메인 tool은 코드를 보고, read_cypher는 그래프를 본다.

과도기이지만 의도한 배치다. 도메인 tool로 답할 수 없는 질문 — "그라운드를 거쳐간 브랜드는", "무신사와 같은 공간을 쓴 다른 브랜드는" 같은 역방향·다중 홉 탐색 — 을 read_cypher가 fallback으로 받는다. 그래프 모델은 이렇다.

(:Building)-[:HAS_FLOOR]->(:Floor)-[:HAS_SPACE]->(:Space)
(:Brand)-[:HELD]->(:Event)-[:AT]->(:Space)

세션을 두지 않는다

Streamable HTTP는 세션을 유지하는 모드와 그렇지 않은 모드가 있는데, 이 서버는 후자다. 요청마다 McpServer와 transport를 새로 만들고 응답이 끝나면 버린다. 서버가 들고 있는 대화 상태가 없으므로 인스턴스를 여러 대로 늘려도 그대로 동작한다. 대신 세션 기반 SSE 스트림(GET)과 세션 종료(DELETE)는 지원하지 않고 405를 돌려준다.

구조

src/
  main.ts                  진입점 — Nest HTTP 부트스트랩
  app.module.ts            ConfigModule(전역) + McpModule

  mcp/                     MCP 프로토콜 계층
    mcp.controller.ts        POST /mcp — 요청마다 server+transport 생성 (stateless)
    mcp-server.factory.ts    McpServer 조립 + Neo4j tool 등록
    tools/
      space-tools.registrar.ts   도메인 tool 4개 등록 (description = 프롬프트)

  space/                   도메인 계층 — DB 없이 도는 부분
    space.data.ts            건물·층·공간 (in-memory)
    event.data.ts            브랜드·행사 이력 (in-memory)
    space.service.ts         공간 조회
    event.service.ts         행사 조회 (시점 필터의 기준일을 주입받는다)
    space-formatter.ts       결과 → 표 / 키:값 블록

  neo4j/                   Neo4j 접근 계층
    neo4j.service.ts         드라이버 lazy 초기화, 읽기 전용 세션
    schema.service.ts        db.schema.* 로 스키마 수집 (APOC 불필요)

  cypher/                  Cypher 취급 유틸
    cypher-validator.ts      읽기 전용 검증 + LIMIT 강제
    result-formatter.ts      Neo4j 결과 → markdown 표 (formatRows는 공용)
    schema-formatter.ts      스키마 → 압축 텍스트

scripts/probe.mjs          실행 중인 서버에 붙어 tool을 차례로 호출

계층이 지키는 규칙 두 가지.

tool 계층은 얇게, 서비스 계층은 두껍게. tool은 인자 검증과 포맷만 하고, 로직은 MCP 없이 테스트되는 평범한 함수에 둔다. 그래서 테스트 67개 중 MCP를 띄우는 건 하나도 없다.

에러는 throw하지 않는다. 원인과 해결 방법을 담아 isError: true 결과로 돌려준다. 모델이 메시지를 읽고 스스로 고쳐 재시도해야 하기 때문이다.

데이터가 코드 안에 있는 이유

space.data.ts / event.data.ts는 임시다. tool을 몇 개로 쪼갤지, description을 어떻게 써야 모델이 올바른 tool을 고르는지는 저장소와 무관한 문제라, DB를 붙이기 전에 그것부터 확인하려고 코드에 뒀다.

교체 시점에는 SpaceService / EventService 내부만 바뀐다. tool 계층은 두 서비스의 메서드 시그니처에만 의존한다.

개발

pnpm test          # 67개 — 검증기, 포매터, 조회 로직
pnpm build
pnpm probe         # 서버가 떠 있을 때, tool 호출 결과를 눈으로 확인
pnpm inspector     # MCP Inspector UI (Streamable HTTP / http://localhost:3000/mcp)

세 가지가 각각 다른 것을 잡는다. pnpm test는 로직, pnpm probe는 배선(tool이 실제로 노출되는지, 결과가 어떤 텍스트로 도착하는지), 그리고 실제 모델에 붙이는 것은 description을 검증한다.

모델을 붙이려면:

claude mcp add --transport http mcp-chat http://localhost:3000/mcp

서버를 띄운 채로 새 세션에서 물어보면 된다. 모델이 엉뚱한 tool을 고르면 코드가 아니라 description을 고친다.

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选