728x90
반응형

지난주에 Anthropic에서 새로운 Model Context Protocol(MCP)을 발표했어요. Claude 같은 LLM이 외부 데이터 소스와 통신하기 위한 프로토콜이라고 해요.

이 프로토콜을 사용하면 Claude.ai, Zed, Replit 같은 로컬 애플리케이션이 사용자와의 대화 중에 파일 시스템, API, 데이터베이스에 접근해서 추가 정보를 가져올 수 있어요. 질문에 답하거나, 더 자세한 정보를 얻거나, 코드 생성을 통해 즉석에서 차트나 시각 자료를 만들 때 유용하겠죠?

대화 예시를 한번 살펴볼까요?

Neo4j에서 데이터를 가져와 평점 히트맵을 렌더링하는 Claude

직접 테스트해보고 싶다면, 아래 설정을 claude_desktop_config.json에 추가하고 서버를 다시 시작하면 돼요. 읽기 전용 데모 데이터베이스를 가리키도록 설정되어 있답니다.

{"mcpServers": {
      "movies-neo4j": {
        "command": "uvx",
        "args": ["mcp-neo4j-cypher", 
                 "--db-url", "neo4j+s://demo.neo4jlabs.com", 
                 "--user", "recommendations", 
                 "--password", "recommendations"]
      }   
    }
 }

단순히 프로토콜만 공개한 게 아니에요. 커넥터(서버)를 오픈 소스로 공개해서 커뮤니티에서 더 많은 것을 추가할 수 있도록 초대하고 있어요!

Neo4j MCP 서버

저희도 바로 Neo4j MCP 서버 구현을 시작해서 어떤 모습일지 알아봤어요. 그리고 PyPI에도 게시했으니, 직접 실행해볼 수 있어요.

GitHub – neo4j-contrib/mcp-neo4j: Neo4j를 사용한 Model Context Protocol

공식 MCP 서버 저장소에도 포함되어 있답니다.

대화형 예

MCP를 사용해서 LLM에서 Neo4j 데이터베이스를 쿼리하는 간단한 예시를 보여드릴게요.

IMDB와 비슷한 영화, 배우, 감독, 장르, 영화 평점 데이터가 들어있는 Neo4j 데이터베이스가 있다고 상상해 보세요.

Claude.ai 데스크톱 설정에서 공개적으로 접근 가능한 데이터베이스를 구성하고 클라이언트를 다시 시작하면 준비 완료!

이제 쿠엔틴 타란티노가 감독한 영화가 뭔지 Claude에게 물어볼게요.

내 영화 데이터베이스에서 쿠엔틴 타란티노 감독의 영화를 확인해 줘.

Claude는 Neo4j 데이터베이스에 대한 쿼리를 허용할지 묻는 권한 대화 상자를 보여줄 거예요 (한 번만 허용할지, 아니면 전체 채팅에 대해 허용할지 선택할 수 있어요). 허용하면 쿼리를 실행하고 결과를 보기 좋게 반환해 준답니다.

그러면 Claude가 이렇게 대답할 거예요.

Claude 답변:
내 영화 데이터베이스에서 쿠엔틴 타란티노 감독의 영화를 확인해 줘.

쿠엔틴 타란티노 감독의 영화에 대한 데이터베이스 쿼리를 도와드릴게요.

Movies-neo4j(로컬)의 read-neo4j-cypher 결과 보기

{
  `query`: `
MATCH (d:Person {name: 'Quentin Tarantino'})-[:DIRECTED]->(m:Movie)
RETURN m.title, m.year
ORDER BY m.year
`
}

[{'m.title': 'Reservoir Dogs', 'm.year': 1992}, {'m.title': 'Pulp Fiction', 'm.year': 1994}, {'m.title': 'Four Rooms', 'm.year': 1995}, {'m.title': 'Jackie Brown', 'm.year': 1997}, {'m.title': 'Kill Bill: Vol. 1', 'm.year': 2003}, {'m.title': 'Kill Bill: Vol. 2', 'm.year': 2004}, {'m.title': 'Sin City', 'm.year': 2005}, {'m.title': 'Grindhouse', 'm.year': 2007}, {'m.title': 'Death Proof', 'm.year': 2007}, {'m.title': 'Inglourious Basterds', 'm.year': 2009}, {'m.title': 'Django Unchained', 'm.year': 2012}, {'m.title': 'The Hateful Eight', 'm.year': 2015}]

쿠엔틴 타란티노 감독의 영화를 연대순으로 나열해봤어요.

  1. 저수지의 개들(1992)
  2. 펄프픽션(1994)
  3. 포룸(1995)
  4. 재키 브라운(1997)
  5. 킬빌: Vol. 1(2003)
  6. 킬빌: Vol. 2(2004)
  7. 씬 시티(2005) …​

이 영화에 대해 더 자세히 알고 싶거나 타란티노 작품의 다른 측면을 탐구하고 싶다면 언제든지 물어봐 주세요!

킬빌 배우들이 출연한 다른 인기 영화는 무엇인가요?

클로드 답변:
킬빌 배우들이 출연한 다른 인기 영화는 무엇인가요?

Kill Bill: Vol. 1 및 킬빌: Vol. 2.

Movies-neo4j(로컬)의 read-neo4j-cypher 결과 보기

{
  `query`: `
MATCH (kb:Movie)
WHERE kb.title IN ['Kill Bill: Vol. 1', 'Kill Bill: Vol. 2']
MATCH (actor:Person)-[:ACTED_IN]->(kb)
MATCH (actor)-[:ACTED_IN]->(other:Movie)
WHERE other.title <> 'Kill Bill: Vol. 1'
AND other.title <> 'Kill Bill: Vol. 2'
RETURN DISTINCT actor.name, collect(DISTINCT other.title) as other_movies
ORDER BY actor.name
`
}
[{'actor.name': 'Daryl Hannah', 'other_movies': ['Clan of the Cave Bear, The', 'Tie That Binds, The', 'Addams Family Reunion', 'Summer Lovers', 'Legal Eagles', 'Reckless', 'Pope of Greenwich Village, The', 'Splash', 'Roxanne', 'Gingerbread Man, The', 'My Favorite Martian', 'Steel Magnolias', 'Walk to Remember, A']}, {'actor.name': 'Lucy Liu', 'other_movies': ['Afro Samurai: Resurrection', 'Lucky Number Slevin', 'Mulan II', 'Cypher', "Charlie's Angels: Full Throttle", 'Ballistic: Ecks vs. Sever', "Charlie's Angels", 'Shanghai Noon']}, {'actor.name': 'Michael Parks', 'other_movies': ['Tusk', 'Death Wish 5: The Face of Death']}, {'actor.name': 'Uma Thurman', 'other_movies': ['Misérables, Les', 'My Super Ex-Girlfriend', 'Even Cowgirls Get the Blues', 'Truth About Cats & Dogs, The', 'Batman & Robin', 'Gattaca', 'Avengers, The', 'Month by the Lake, A', 'Jennifer 8', 'Mad Dog and Glory', 'Johnny Be Good', 'Henry & June', 'Be Cool', 'Producers, The', 'Tape', 'Paycheck']}, {'actor.name': 'Vivica A. Fox', 'other_movies': ['Set It Off', 'Soul Food', 'Boat Trip', 'Juwanna Mann', 'Why Do Fools Fall In Love?']}]

주요 출연진이 제작한 몇 가지 주목할 만한 영화를 분석해볼게요.

Uma Thurman의 다른 주요 영화는 다음과 같아요.

Lucy Liu는 다음 작품에 출연했어요.  — Charlie's Angels and Charlie's Angels: Full Throttle — Shanghai Noon — Lucky Number Slevin — Mulan II

Michael Parks 출연: — Tusk — Death Wish 5: The Face of Death

이 배우나 특정 영화에 대해 더 자세히 알고 싶으신가요? 출시 연도, 감독, 기타 출연진 등 추가 정보를 물어볼 수 있어요.

Tusk에 대해 더 자세히 알려주세요. 볼만한 가치가 있나요? 데이터베이스 스키마를 사용하여 평점을 알아보세요.

클로드 답변:
Tusk에 대해 더 자세히 알려주세요. 지켜볼 가치가 있나요? 데이터베이스 스키마를 사용하여 평점을 알아보세요.

이제 통합에서 사용할 수 있는 다른 도구(get-neo4j-schema)를 사용해서 평가가 저장되는 위치와 방법을 결정하는 데 중요한 데이터베이스 스키마를 가져와 볼게요. `Node` 유형, 해당 `attribute`(인덱싱된 경우), 다른 `Node`와의 `relationship`을 반환해 준답니다.

먼저 데이터베이스 스키마를 확인해서 영화에 대해 어떤 등급 정보를 사용할 수 있는지 살펴볼까요?

Movies-neo4j(로컬)의 get-neo4j-schema 결과 보기

{}
[{'label': 'Movie', 'attributes': {'budget': 'INTEGER', 'movieId': 'STRING unique indexed', 'tmdbId': 'STRING unique indexed', 'plotEmbedding': 'LIST', 'imdbVotes': 'INTEGER', 'runtime': 'INTEGER', 'posterEmbedding': 'LIST', 'countries': 'LIST', 'imdbId': 'STRING indexed', 'url': 'STRING', 'plot': 'STRING indexed', 'released': 'STRING indexed', 'languages': 'LIST', 'imdbRating': 'FLOAT indexed', 'title': 'STRING indexed', 'poster': 'STRING', 'year': 'INTEGER indexed', 'revenue': 'INTEGER'}, 'relationships': {'IN_GENRE': 'Genre'}}, {'label': 'Genre', 'attributes': {'name': 'STRING unique indexed'}, 'relationships': {}}, {'label': 'User', 'attributes': {'name': 'STRING indexed', 'userId': 'STRING unique indexed'}, 'relationships': {'RATED': 'Movie'}}, {'label': 'Actor', 'attributes': {'born': 'DATE', 'bornIn': 'STRING', 'tmdbId': 'STRING', 'bio': 'STRING', 'died': 'DATE', 'name': 'STRING', 'poster': 'STRING', 'imdbId': 'STRING', 'url': 'STRING'}, 'relationships': {'ACTED_IN': 'Movie', 'DIRECTED': 'Movie'}}, {'label': 'Director', 'attributes': {'born': 'DATE', 'bornIn': 'STRING', 'tmdbId': 'STRING', 'bio': 'STRING', 'died': 'DATE', 'name': 'STRING', 'poster': 'STRING', 'imdbId': 'STRING', 'url': 'STRING'}, 'relationships': {'ACTED_IN': 'Movie', 'DIRECTED': 'Movie'}}, {'label': 'Person', 'attributes': {'born': 'DATE', 'bornIn': 'STRING', 'tmdbId': 'STRING unique indexed', 'bio': 'STRING indexed', 'died': 'DATE', 'name': 'STRING indexed', 'poster': 'STRING', 'imdbId': 'STRING', 'url': 'STRING'}, 'relationships': {'ACTED_IN': 'Movie', 'DIRECTED': 'Movie'}}]

이제 평점, 줄거리, 장르 등 Tusk에 대한 구체적인 정보를 `query`해 볼게요.

Movies-neo4j(로컬)의 read-neo4j-cypher 결과 보기

{
  `query`: `
MATCH (m:Movie {title: 'Tusk'})
MATCH (m)-[:IN_GENRE]->(g:Genre)
MATCH (d:Person)-[:DIRECTED]->(m)
MATCH (a:Person)-[:ACTED_IN]->(m)
RETURN m.title, m.year, m.imdbRating, m.plot, collect(DISTINCT g.name) as genres,
       collect(DISTINCT d.name) as directors, collect(DISTINCT a.name) as actors
`
}
[{'m.title': 'Tusk', 'm.year': 2014, 'm.imdbRating': 5.4, 'm.plot': 'When podcaster Wallace Bryton goes missing in the backwoods of Manitoba while interviewing a mysterious seafarer named Howard Howe, his best friend Teddy and girlfriend Allison team with an ex-cop to look for him.', 'genres': ['Comedy', 'Drama', 'Horror'], 'directors': ['Kevin Smith'], 'actors': ['Michael Parks', 'Haley Joel Osment', 'Genesis Rodriguez', 'Justin Long']}]

데이터베이스 정보를 바탕으로 Tusk에 대해 알려드릴 수 있는 내용은 다음과 같아요.

1. Kevin Smith(Clarks, Mallrats, Chasing Amy로 알려짐)가 감독한 호러 코미디 드라마로 2014년 9월에 개봉했어요.

2. 줄거리는 Howard Howe라는 신비한 선원을 인터뷰하던 중 매니토바에서 사라진 Wallace Bryton이라는 팟캐스터를 따라가죠. 그의 여자친구와 가장 친한 친구는 전직 경찰과 협력해서 그를 찾고요.

3. 영화의 IMDb 평점은 5.4/10으로 상대적으로 낮은 편인데, 이는 부정적인 반응이 섞여 있다는 걸 보여줘요.

….

IMDb 등급이 낮다는 건 모든 사람을 위한 영화는 아니지만, 특이한 공포 영화 팬들 사이에서 컬트적인 인기를 얻었다는 의미이기도 해요.

대신 여러분이 즐길 수 있는 비슷한 영화를 데이터베이스에서 찾아볼까요?

흠, 알겠습니다. Kill Bill 배우들이 출연한 영화 중에서 세부 정보가 포함된 최고의 영화를 알려주세요.

클로드 답변:
흠, 알겠습니다. Kill Bill 배우들이 출연한 영화 중에서, 세부 정보가 포함된 최고의 영화를 알려주세요.

해당 영화와 평점을 검색해서 가장 높은 평점을 받은 영화를 찾아볼게요.

{
  `query`: `
MATCH (a:Person)-[:ACTED_IN]->(kb:Movie)
WHERE kb.title IN ['Kill Bill: Vol. 1', 'Kill Bill: Vol. 2']
MATCH (a)-[:ACTED_IN]->(m:Movie)
WHERE m.title <> 'Kill Bill: Vol. 1' AND m.title <> 'Kill Bill: Vol. 2'
MATCH (m)-[:IN_GENRE]->(g:Genre)
MATCH (d:Person)-[:DIRECTED]->(m)
RETURN DISTINCT m.title, m.year, m.imdbRating, m.plot,
       collect(DISTINCT g.name) as genres,
       collect(DISTINCT d.name) as directors,
       collect(DISTINCT a.name) as actors
ORDER BY m.imdbRating DESC
LIMIT 1
`
}
[{'m.title': 'Gattaca', 'm.year': 1997, 'm.imdbRating': 7.8, 'm.plot': 'A genetically inferior man assumes the identity of a superior one in order to pursue his lifelong dream of space travel.', 'genres': ['Thriller', 'Sci-Fi', 'Drama'], 'directors': ['Andrew Niccol'], 'actors': ['Uma Thurman']}]

앞서 찾은 영화 중에서 IMDb 등급이 7.8/10으로 가장 높은 영화는 Gattaca(1997)에요. 이 영화에 대한 추가 세부 정보를 알려드릴게요.

{
  `query`: `
MATCH (m:Movie {title: 'Gattaca'})
MATCH (p:Person)-[:ACTED_IN]->(m)
RETURN m.runtime, collect(p.name) as cast
`
}
[{'m.runtime': 106, 'cast': ['Xander Berkeley', 'Gore Vidal', 'Uma Thurman', 'Ethan Hawke']}]

Gattaca가 눈에 띄는 이유는 다음과 같아요.

1. 줄거리: 유전적으로 '열등'하게 태어난 남자가 우주 여행의 꿈을 이루기 위해 유전적으로 우월한 사람으로 위장해서 살아가는 SF 드라마에요. 이 이야기는 유전적 차별, 결단력, 인간 잠재력에 대한 주제를 탐구하죠.

…..

Gattaca를 좋아한다면 즐길 수 있는 유사한 영화를 데이터베이스에서 찾아볼까요?

Gattaca의 다른 평균, 최소, 최대 사용자 평점은 무엇인가요?

클로드 답변:
Gattaca의 다른 평균, 최소, 최대 사용자 평점은 무엇인가요?

Gattaca에 대한 사용자 평가 통계를 찾아볼게요.

{
  `query`: `
MATCH (m:Movie {title: 'Gattaca'})
MATCH (u:User)-[r:RATED]->(m)
RETURN
  m.title,
  count(r) as number_of_ratings,
  round(avg(r.rating)*10)/10 as avg_rating,
  min(r.rating) as min_rating,
  max(r.rating) as max_rating
`
}
[{'m.title': 'Gattaca', 'number_of_ratings': 84, 'avg_rating': 3.7, 'min_rating': 1.0, 'max_rating': 5.0}]

Gattaca에 대한 사용자 평가 통계는 다음과 같아요.
– 평균 사용자 평점: 5점 만점에 3.68점
– 최소 등급 : 1.0
– 최대 등급 : 5.0
– 평가 수: 사용자 84명

이 평균 등급 3.68/5(약 7.4/10에 해당)은 앞서 본 IMDb 등급 7.8/10과 꽤 잘 맞는 것 같아요. 이 영화는 가능한 모든 점수(1~5)를 받았는데, 이는 대부분의 사람들이 이 영화를 높게 평가하지만 다양한 의견도 있다는 걸 보여주죠. 데이터베이스에 84개의 등급이 있으니까, 분석하기에 적절한 샘플 크기를 제공하는 것 같아요.

알겠습니다. Gattaca를 보고 정말 좋아했어요. 이와 유사한 다른 영화는 무엇인가요? mesirii라는 ID로 사용자를 생성하고 내 평점을 10점 만점에 8점으로 저장할 수 있나요(영화의 다른 평점에 맞게 정규화)?

쓰기 명령문을 작성하고 쓰기 작업 도구에 대한 또 다른 권한 확인을 받습니다. Claude가 Cypher 문에서 작은 구문 실수를 저지르고 즉시 수정한 것은 다음과 같아요. 제 데이터베이스는 읽기 전용이라서 실제로 쓸 수는 없지만, 다음에 볼 수 있는 다른 영화를 제공해 드릴게요.

데이터베이스의 평가 척도와 일관성을 유지하기 위해 8/10에서 4/5로 정규화해서 먼저 평가를 추가하도록 도와드릴게요.

사용자 등급 생성 오류에 대해 죄송해요. 데이터베이스에 새 사용자를 생성할 권한이 없는 것 같아요. 하지만 Gattaca와 비슷한 영화를 찾는 데 도움을 드릴 수는 있어요.

Movies-neo4j(로컬)의 write-neo4j-cypher 결과 보기

{
  `query`: `
MERGE (u:User {userId: 'mesirii', name: 'mesirii'})
MERGE (m:Movie {title: 'Gattaca'})
CREATE (u)-[:RATED {rating: 4.0}]->(m)
RETURN u.name, m.title
`
}

오류가 발생해서 죄송해요. 새 사용자 기록을 생성할 권한이 없는 것 같아요. 대신 Gattaca와 비슷한 영화를 찾는 데 집중할게요. 비슷한 장르, 주제, 등급을 공유하는 영화를 검색해 볼게요.

Movies-neo4j(로컬)의 read-neo4j-cypher 결과 보기

{
  `query`: `
MATCH (m:Movie)-[:IN_GENRE]->(g:Genre)
WHERE g.name IN ['Sci-Fi', 'Drama']
AND m.title <> 'Gattaca'
AND m.imdbRating >= 7.0
WITH m, collect(DISTINCT g.name) as genres
WHERE size(genres) >= 2
RETURN m.title, m.year, m.imdbRating, m.plot, genres
ORDER BY m.imdbRating DESC
LIMIT 5
`
}
[{'m.title': 'Inception', 'm.year': 2010, 'm.imdbRating': 8.8, 'm.plot': 'A thief, who steals corporate secrets through use of dream-sharing technology, is given the inverse task of planting an idea into the mind of a CEO.', 'genres': ['Drama', 'Sci-Fi']}, {'m.title': 'Black Mirror', 'm.year': None, 'm.imdbRating': 8.8, 'm.plot': 'A television anthology series that shows the dark side of life and technology.', 'genres': ['Drama', 'Sci-Fi']}, {'m.title': "Dr. Horrible's Sing-Along Blog", 'm.year': 2008, 'm.imdbRating': 8.7, 'm.plot': 'An aspiring supervillain must balance his career and his pursuit of a beautiful do-gooder.', 'genres': ['Drama', 'Sci-Fi']}, {'m.title': 'Battlestar Galactica', 'm.year': 2003, 'm.imdbRating': 8.7, 'm.plot': 'A re-imagining of the original series in which a rag-tag fugitive fleet of the last remnants of mankind flees pursuing robots while simultaneously searching for their true home, Earth.', 'genres': ['Drama', 'Sci-Fi']}, {'m.title': 'Prestige, The', 'm.year': 2006, 'm.imdbRating': 8.5, 'm.plot': 'Two stage magicians engage in competitive one-upmanship in an attempt to create the ultimate stage illusion.', 'genres': ['Sci-Fi', 'Drama']}]

주제, 장르, 등급이 비슷한 영화를 검색해 볼게요.

{
  `query`: `
MATCH (m:Movie {title: 'Gattaca'})
MATCH (m)-[:IN_GENRE]->(g:Genre)
MATCH (other:Movie)-[:IN_GENRE]->(g)
WHERE other.title <> 'Gattaca' 
  AND other.imdbRating >= 7.0
  AND exists(other.plot)
RETURN DISTINCT other.title, other.imdbRating, other.plot, 
  collect(DISTINCT g.name) as genres
ORDER BY other.imdbRating DESC
LIMIT 5
`
}

Error: {code: Neo.ClientError.Statement.SyntaxError} {message: The property existence syntax `... exists(variable.property)` is no longer supported. Please use `variable.property IS NOT NULL` instead. (line 7, column 7 (offset: 174))
"  AND exists(other.plot)"
       ^}

구문 오류가 있어서 죄송해요. 쿼리를 수정할게요.

Gattaca와 같은 SF 및 스릴러 요소에 더욱 구체적으로 초점을 맞추기 위해 이 검색을 더 자세하게 만들어볼게요.

{
  `query`: `
MATCH (m:Movie {title: 'Gattaca'})
MATCH (m)-[:IN_GENRE]->(g:Genre)
MATCH (other:Movie)-[:IN_GENRE]->(g)
WHERE other.title <> 'Gattaca' 
  AND other.imdbRating >= 7.0
  AND other.plot IS NOT NULL
RETURN DISTINCT other.title, other.imdbRating, other.plot, 
  collect(DISTINCT g.name) as genres
ORDER BY other.imdbRating DESC
LIMIT 5
`
}

Gattaca를 재밌게 보셨다면, 비슷한 주제나 요소를 공유하는 높은 평점을 받은 추천 영화는 다음과 같아요.

1. 블랙미러 (8.8/10)
— Gattaca처럼 기술이 사회에 미치는 어두운 영향을 탐구하는 시사점을 주는 SF 앤솔로지 시리즈에요.
— 각 에피소드에서는 기술이 인간 사회에 어떤 영향을 미칠 수 있는지에 대한 다양한 이야기를 보여주죠.

….

이 영화들은 모두 SF에 대한 Gattaca의 사려 깊은 접근 방식을 공유하며 액션보다는 인간 드라마와 윤리적 질문에 더 중점을 둬요. 그들은 모두 Gattaca의 중심이었던 정체성, 인간성, 기술/과학이 사회에 미치는 영향이라는 주제를 탐구하죠.

이러한 권장 사항에 대해 더 자세히 알고 싶으신가요?

이것이 MCP와 Neo4j 커넥터에 대한 저의 첫 경험이었는데요. 정말 멋지죠? 정말 좋은 경험이었고, 이것이 Claude와 같은 LLM과의 대화 경험을 향상하는 데 어떻게 사용될 수 있는지 알 수 있어요.

모델 컨텍스트 프로토콜

내부적으로는 어떻게 작동할까요?

modelcontextprotocol.io 사이트에는 MCP에 대한 포괄적인 문서가 있지만, 간략하게 한번 살펴볼게요.

MCP 문서의 아키텍처 다이어그램

MCP는 다음의 클라이언트-서버 아키텍처를 따르고 있어요:

  • : 연결을 시작하고 클라이언트를 사용하는 LLM 애플리케이션(예: Claude Desktop 또는 IDE)이에요.
  • 클라이언트: 호스트 애플리케이션 내에서 서버와의 전송 프로토콜을 사용하여 1:1 연결을 유지하죠.
  • : 고객에게 상황, 도구, 메시지를 제공해요.

프로토콜 계층은 메시지 프레이밍, 요청/응답 연결, 알림 및 고급 통신 패턴을 처리해요.

MCP는 다양한 전송 프로토콜을 허용하는데요. 현재 지원되는 것은 HTTPS(서버-클라이언트 메시지용 SSE(Server-Sent-Events) 및 클라이언트-서버용 HTTP POST 포함)와 서버가 클라이언트에 의해 시작되고 stdin/stdout을 통해 통신할 수 있는 로컬 서버용 STDIO(표준 입력/출력)에요.

모든 전송 메시지 교환은 에 따라 JSON-RPC 2.0을 사용하므로 다른 언어나 전송 계층으로 프로토콜을 구현하도록 권장되고 있어요.

기반 메시지 유형은 다음과 같아요:

  • : 사용자 또는 AI 모델이 사용할 컨텍스트 및 데이터
  • : 사용자를 위한 템플릿 기반 메시지 및 워크플로
  • : AI 모델이 실행할 기능
  • : 서버에서 시작되는 에이전트 동작 및 재귀적 LLM 상호 작용

추가 관련 측면에는 구성, 진행률 추적, 취소, 오류 보고, 로깅이 포함돼요.

프로토콜 사양에서는 LLM의 외부 데이터 소스 액세스를 허용할 때 중요한 보안과 신뢰도 고려 사항을 강조하고 있어요. 데이터베이스, 파일 시스템, 로컬로 실행되는 서버에 대한 쓰기 액세스와 악성 코드 실행 가능성이 있으므로 보안이 최우선적으로 고려되어야 하죠. 기초 모델은 적대적 공격, 즉각적인 주사, 환각에 취약한 것으로 알려져 있어요.

LLM 사용자는 기술적 지식이 없는 경우가 많으며 AI 모델이 자신의 데이터에 액세스하도록 허용하는 것과 관련된 위험을 인식하지 못할 수도 있어요.

이것이 바로 프로토콜이 다음과 같은 주요 원칙을 사용하는 이유에요:

  • 사용자 동의 및 제어: 사용자는 서버 및 데이터 액세스를 승인해야 하며 어떤 데이터가 전송되고 수신되었는지 항상 식별할 수 있어야 해요. 클라이언트 구현에는 이러한 인증을 위한 명확한 UI가 필요하죠.
  • 사용자 데이터에 대한 데이터 개인 정보 보호 액세스 제어, 호스트 및 서버에 의한 다른 서비스로의 데이터 유출 없음.
  • 도구 안전은 악성 코드 실행을 방지하고 도구가 실행하기에 안전하며 부작용이 없는지 확인하는 데 사용돼요. 도구는 사용자가 각 도구의 기능을 명확하게 이해할 수 있도록 구성되어야 하죠.
  • LLM 샘플링 제어: 프로토콜은 사용자 프롬프트에 대한 서버 액세스를 제한해요. 사용자는 샘플링과 서버로 전송되는 데이터 및 메시지를 제어할 수 있어요.

Neo4j MCP 서버 구현

Neo4j MCP 서버를 구현할 때 다음 세 가지 구성 요소를 구현해야 했어요:

  1. Neo4j 데이터베이스 연결 및 Cypher 쿼리 실행
  2. 사용 가능한 도구 등록 및 나열
  3. 도구 실행 요청 처리

Neo4j 데이터베이스와의 연결 및 Cypher 실행

저희의 경우 데이터베이스에 연결하고 명령문을 실행하며 결과를 JSON 텍스트 블록으로 렌더링하기 위해 Neo4j Python 드라이버를 보유하는 작은 neo4jDatabase 클래스를 작성했어요.

def _execute_query(self, query: str, params: dict[str, Any] | None = None) -> list[dict[str, Any]]: """Execute a Cypher query and return results as a list of dictionaries""" logger.debug(f"Executing query: {query}") try: result = self.driver.execute_query(query, params) if is_write_query(query): counters = vars(result.summary.counters) logger.debug(f"Write query affected {counters}") return [counters] else: results = [dict(r) for r in result.records] logger.debug(f"Read query returned {len(results)} rows") return results except Exception as e: logger.error(f"Database error executing query: {e}n{query}") raise

데이터베이스와 상호작용하기 위해 사용 가능한 도구 등록

이러한 도구는 나중에 LLM에서 선택해서 사용할 수 있어요.

  • get-neo4j-schema
  • read-neo4j-cypher
  • write-neo4j-cypher

각각에는 설명과 가능한 매개변수가 있는데요 (이 경우 Cypher 도구에 대한 필수 "query" 매개변수만 있죠). 노드의 집계된 이웃 가져오기, 최단 경로 찾기 또는 그래프 알고리즘 실행과 같은 Graph Database에 대한 다양한 추가 일반 도구를 상상할 수 있어요.

write-neo4j-cypher 도구의 정의는 다음과 같아요.

@server.list_tools()
    async def handle_list_tools() -> list[types.Tool]:
        """List available tools"""
        return [
            types.Tool(
                name="write-neo4j-cypher",
                description="Execute a write Cypher query on the neo4j database",
                inputSchema={
                    "type": "object",
                    "properties": {
                        "query": {"type": "string", "description": "Cypher write query to execute"},
                    },
                    "required": ["query"],
                },
            ),
#            ...
        ]

등록된 도구의 실행

사용자가 Claude에게 데이터베이스 쿼리를 요청하면 Claude는 사용자에게 권한을 요청하고, 서버가 아직 로컬 서버로 실행되고 있지 않은 경우 서버를 시작한 다음, 전송 프로토콜을 통해 도구 이름 및 매개변수와 함께 MCP 서버에 요청을 보내요.

도구 구현에서는 이 클래스를 사용하여 명령문을 실행하는데요. 읽기 도구에서는 읽기 문만 허용하고 그 반대의 경우도 허용한다는 작은 검사가 있어요 (쓰기 도구는 업데이트 통계만 반환해요).

@server.call_tool()
    async def handle_call_tool(
        name: str, arguments: dict[str, Any] | None
    ) -> list[types.TextContent | types.ImageContent | types.EmbeddedResource]:
        """Handle tool execution requests"""
        try:
            if name == "get-neo4j-schema":
                results = db._execute_query(
                    """
CALL apoc.meta.data() yield label, property, type, other, unique, index, elementType
WHERE elementType = 'node'
RETURN label,
    collect(case when type <> 'RELATIONSHIP' then [property, type] end) as attributes,
    collect(case when type = 'RELATIONSHIP' then [property, head(other)] end) as relationships
                    """
                )
                return [types.TextContent(type="text", text=str(results))]

따라서 선택한 도구에 대해 MCP 서버를 구현하는 것이 매우 간단하다는 것을 알 수 있죠?

대화부터 코드까지

MCP 도구 결과와 Claude의 코드 생성 및 실행 기능을 결합하면 상호 작용이 한 단계 더 발전할 수 있어요.

상호 작용에서 이미 인상적인 점 중 하나는 이전 도구 호출 데이터 결과가 대화 기록의 일부이므로 LLM이 이를 사용하여 추가 서버 상호 작용을 위한 쿼리 및 입력 매개 변수를 형성한다는 것이에요.

그러나 결과를 차트, 네트워크로 쉽게 렌더링하거나 내보낼 파생 데이터를 계산할 수 있는 코드 생성 기능을 사용하면 이보다 훨씬 더 뛰어날 거예요. 직접 렌더링하고 시각화할 수 있는 차트 라이브러리와 결합된 React 또는 기타 라이브러리를 사용하여 JavaScript의 아티팩트를 생성하는 거죠.

다음은 영화별 또는 평점별로 히트맵을 생성하는 두 가지 예시입니다.

Tarantino 영화의 히트맵 렌더링

사실 저는 평점과 연도를 정사각형 히트맵으로 표시하고 싶었어요.

평점 값당 평점 수의 정사각형 히트 맵

마지막으로 대화의 네트워크 시각화입니다.

쿠엔틴 타란티노의 영화부터 추천, 최종 제안까지 지금까지의 대화에 대한 그래프 시각화를 생성합니다. 렌더링의 대비가 높은지 확인하세요.

요약

Neo4j MCP 서버 구현을 테스트하고 경험을 공유해 주시면 좋겠어요. GitHub에 대한 피드백, 그리고 자신만의 기사를 작성해 보는 것도 좋겠죠?

즐거운 실험 되세요!


  • mcp

에이치시스템즈LogTree는 Neo4j 기반 GraphRAG 플랫폼으로, 데이터를 자동으로 지식그래프화하고 자연어 질의로 즉시 답을 제공합니다.

👉 에이치시스템즈 홈페이지

728x90
반응형

+ Recent posts