LangChain/LangGraph AI 에이전트를 ClickHouse MCP 서버로 빌드하기

LangChain/LangGraph AI 에이전트를 ClickHouse MCP 서버로 빌드하기

이 가이드에서는 ClickHouse의 MCP 서버를 사용해 ClickHouse의 SQL 플레이그라운드와 상호작용할 수 있는 LangChain/LangGraph AI 에이전트를 빌드하는 방법을 배워요.

출처: 문서

본문

이 가이드에서는 ClickHouse의 MCP 서버를 사용해 ClickHouse의 SQL 플레이그라운드와 상호작용할 수 있는 LangChain/LangGraph AI 에이전트를 빌드하는 방법을 배워요.

예제 노트북 이 예제는 examples 리포지토리에서 노트북으로 찾아볼 수 있어요.

전제 조건 (Prerequisites)

  • 시스템에 Python이 설치되어 있어야 해요.
  • 시스템에 pip이 설치되어 있어야 해요.
  • Anthropic API 키 또는 다른 LLM 제공자의 API 키가 있어야 해요.

다음 단계는 Python REPL 또는 스크립트를 통해 실행할 수 있어요.

1. 라이브러리 설치하기

다음 명령을 실행해 필요한 라이브러리를 설치하세요:

pip install -q --upgrade pip
pip install -q langchain-mcp-adapters langgraph "langchain[anthropic]"

2. 자격 증명 설정하기

다음으로 Anthropic API 키를 제공해야 해요:

import os, getpass
os.environ["ANTHROPIC_API_KEY"] = getpass.getpass("Enter Anthropic API Key:")

응답:

Enter Anthropic API Key: ········

다른 LLM 제공자 사용하기 Anthropic API 키가 없고 다른 LLM 제공자를 사용하려면 Langchain Providers 문서에서 자격 증명 설정 지침을 찾을 수 있어요.

3. MCP 서버 초기화하기

이제 ClickHouse MCP 서버가 ClickHouse SQL 플레이그라운드를 가리키도록 구성해요:

from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client

server_params = StdioServerParameters(
    command="uv",
    args=[
        "run",
        "--with", "mcp-clickhouse",
        "--python", "3.13",
        "mcp-clickhouse"
    ],
    env={
        "CLICKHOUSE_HOST": "sql-clickhouse.clickhouse.com",
        "CLICKHOUSE_PORT": "8443",
        "CLICKHOUSE_USER": "demo",
        "CLICKHOUSE_PASSWORD": "",
        "CLICKHOUSE_SECURE": "true"
    }
)

4. 스트림 핸들러 구성하기

Langchain과 ClickHouse MCP 서버를 함께 사용할 때 쿼리 결과는 단일 응답이 아닌 스트리밍 데이터로 반환되는 경우가 많아요. 처리에 시간이 걸릴 수 있는 대용량 데이터셋이나 복잡한 분석 쿼리의 경우, 스트림 핸들러를 구성하는 것이 중요해요. 제대로 처리하지 않으면 이 스트리밍 출력을 애플리케이션에서 다루기 어려울 수 있어요. 소비하기 쉽도록 스트리밍 출력용 핸들러를 구성해요:

class UltraCleanStreamHandler:
    def __init__(self):
        self.buffer = ""
        self.in_text_generation = False
        self.last_was_tool = False
        
    def handle_chunk(self, chunk):
        event = chunk.get("event", "")
        
        if event == "on_chat_model_stream":
            data = chunk.get("data", {})
            chunk_data = data.get("chunk", {})
            
            # Only handle actual text content, skip tool invocation streams
            if hasattr(chunk_data, 'content'):
                content = chunk_data.content
                if isinstance(content, str) and not content.startswith('{"'):
                    # Add space after tool completion if needed
                    if self.last_was_tool:
                        print(" ", end="", flush=True)
                        self.last_was_tool = False
                    print(content, end="", flush=True)
                    self.in_text_generation = True
                elif isinstance(content, list):
                    for item in content:
                        if (isinstance(item, dict) and 
                            item.get('type') == 'text' and 
                            'partial_json' not in str(item)):
                            text = item.get('text', '')
                            if text and not text.startswith('{"'):
                                # Add space after tool completion if needed
                                if self.last_was_tool:
                                    print(" ", end="", flush=True)
                                    self.last_was_tool = False
                                print(text, end="", flush=True)
                                self.in_text_generation = True
                                
            elif event == "on_tool_start":
                if self.in_text_generation:
                    print(f"\n🔧 {chunk.get('name', 'tool')}", end="", flush=True)
                    self.in_text_generation = False
                    
            elif event == "on_tool_end":
                print(" ✅", end="", flush=True)
                self.last_was_tool = True

5. 에이전트 호출하기

마지막으로 에이전트를 호출해서 누가 ClickHouse에 가장 많은 코드를 커밋했는지 물어봐요:

async with stdio_client(server_params) as (read, write):
    async with ClientSession(read, write) as session:
        await session.initialize()
        tools = await load_mcp_tools(session)
        agent = create_react_agent("anthropic:claude-sonnet-4-0", tools)
        
        handler = UltraCleanStreamHandler()        
        async for chunk in agent.astream_events(
            {"messages": [{"role": "user", "content": "Who's committed the most code to ClickHouse?"}]}, 
            version="v1"
        ):
            handler.handle_chunk(chunk)
            
        print("\n")

아래와 비슷한 응답이 보여야 해요:

응답:

I'll help you find who has committed the most code to ClickHouse by exploring the available databases and tables to locate git commit data.
🔧 list_databases ✅ I can see there's a `git` database which likely contains git commit information. Let me explore the tables in that database:
🔧 list_tables ✅ Perfect! I can see the `clickhouse_commits` table in the git database contains ClickHouse commit data with 80,644 commits. This table has information about each commit including the author, lines added/deleted, files modified, etc. Let me query this table to find who has committed the most code based on different metrics.
🔧 run_select_query ✅ Let me also look at just the lines added to see who has contributed the most new code:
🔧 run_select_query ✅ Based on the ClickHouse git commit data, **Alexey Milovidov** has committed the most code to ClickHouse by several measures:

## Key Statistics:

1. **Most Total Lines Changed**: Alexey Milovidov with **1,696,929 total lines changed** (853,049 added + 843,880 deleted)
2. **Most Lines Added**: Alexey Milovidov with **853,049 lines added**
3. **Most Commits**: Alexey Milovidov with **15,375 commits**
4. **Most Files Changed**: Alexey Milovidov with **73,529 files changed**

## Top Contributors by Lines Added:

1. **Alexey Milovidov**: 853,049 lines added (15,375 commits)
2. **s-kat**: 541,609 lines added (50 commits) 
3. **Nikolai Kochetov**: 219,020 lines added (4,218 commits)
4. **alesapin**: 193,566 lines added (4,783 commits)
5. **Vitaly Baranov**: 168,807 lines added (1,152 commits)

Alexey Milovidov is clearly the most prolific contributor to ClickHouse, which makes sense as he is one of the original creators and lead developers of the project. His contribution dwarfs others both in terms of total code volume and number of commits, with nearly 16,000 commits and over 850,000 lines of code added to the project.

더 알아보기 (Learn more)