> ## Documentation Index
> Fetch the complete documentation index at: https://clickhouse.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# 如何使用 ClickHouse MCP 服务器构建 LangChain/LangGraph AI 代理。

> 了解如何使用 ClickHouse MCP 服务器构建一个能够与 ClickHouse SQL Playground 交互的 LangChain/LangGraph AI 代理。

在本指南中，你将了解如何构建一个 [LangChain/LangGraph](https://github.com/langchain-ai/langgraph) AI 代理，
使其能够通过 [ClickHouse MCP 服务器](https://github.com/ClickHouse/mcp-clickhouse) 与 [ClickHouse 的 SQL Playground](https://sql.clickhouse.com/) 交互。

<Info>
  **示例笔记本**

  你可以在 [examples 代码库](https://github.com/ClickHouse/examples/blob/main/ai/mcp/langchain/langchain.ipynb) 中找到此示例的 notebook。
</Info>

<div id="prerequisites">
  ## 前置条件
</div>

* 你的系统中需要已安装 Python。
* 你的系统中需要已安装 `pip`。
* 你需要一个 Anthropic API 密钥，或其他 LLM 提供商的 API 密钥

你可以在 Python REPL 中或通过脚本执行以下步骤。

<Steps>
  <Step title="安装库" id="install-libraries">
    运行以下命令，安装所需的库：

    ```python theme={null}
    pip install -q --upgrade pip
    pip install -q langchain-mcp-adapters langgraph "langchain[anthropic]"
    ```
  </Step>

  <Step title="配置凭据" id="setup-credentials">
    接下来，您需要提供 Anthropic API 密钥：

    ```python theme={null}
    import os, getpass
    os.environ["ANTHROPIC_API_KEY"] = getpass.getpass("Enter Anthropic API Key:")
    ```

    ```response title="Response" theme={null}
    Enter Anthropic API Key: ········
    ```

    <Info>
      **使用其他 LLM 提供商**

      如果你没有 Anthropic API 密钥，但想使用其他 LLM 提供商，
      可以在 [Langchain Providers 文档](https://python.langchain.com/docs/integrations/providers/) 中找到配置凭据的说明。
    </Info>
  </Step>

  <Step title="初始化 MCP 服务器" id="initialize-mcp-and-agent">
    现在配置 ClickHouse MCP 服务器，使其指向 ClickHouse SQL Playground：

    ```python theme={null}
    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"
        }
    )
    ```
  </Step>

  <Step title="配置 stream handler" id="configure-the-stream-handler">
    使用 Langchain 和 ClickHouse MCP 服务器时，查询结果通常会
    以流式数据的形式返回，而不是一次性返回单个响应。对于大型数据集或
    处理起来可能需要一些时间的复杂分析查询，配置
    stream handler 非常重要。如果没有妥善处理，这类流式输出
    在应用程序中可能会难以使用。

    为流式输出配置 handler，以便更容易处理：

    ```python theme={null}
    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
    ```
  </Step>

  <Step title="调用 agent" id="call-the-agent">
    最后，调用你的 agent，并问它是谁向 ClickHouse 提交了最多的代码：

    ```python theme={null}
    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")
    ```

    你应该会看到如下所示的类似响应：

    ```response title="Response" theme={null}
    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.
    ```
  </Step>
</Steps>
