一、MCP配置前期準備
(一)創建個人令牌/群組令牌
我這里是創建個人令牌,去到首頁左上角,點擊頭像——>偏好設置——>訪問令牌——>添加新令牌
(二)配置mcp信息
去到魔塔社區,點擊mcp廣場,然后搜索gitlab,把剛剛生成的個人令牌粘貼進去
這里的url如果是你自己部署的話,就替換前面的域名即可,比如https://gitlab.com/api/v4就換成http://ip:端口/api/v4,配置完后就會生成對應的sse配置信息
二、Claude Code SDK 配置
這里有一個巨巨巨巨巨坑,正常我們在終端使用claude的時候,偶爾會彈出讓你是否確認創建某個文件夾或者其他的操作等信息,如下:
這是cc的一個權限機制,在claude code的文檔里面也有提到:
更詳細的可以看這篇文章:Claude Code權限模式詳解:Default、AcceptEdits、Plan、BypassPermissions四種模式 - 博客 - Hrefgo AI
(一)代碼示例
import asyncio
import os
import tracebackfrom datetime import datetime, timedeltafrom claude_code_sdk import ClaudeSDKClient, ClaudeCodeOptions
from claude_code_sdk.types import (ResultMessage, AssistantMessage, TextBlock,ToolUseBlock, ToolResultBlock
)
from claude_code_sdk._errors import CLIConnectionErroros.environ["ANTHROPIC_API_KEY"] = "你的api key"
os.environ["ANTHROPIC_BASE_URL"] = "https://api.moonshot.cn/anthropic"async def chat():"""Claude Code 聊天助手(每次請求獨立客戶端,避免流沖突)"""client = Noneresponses = []try:# 每次請求都創建新客戶端(避免復用導致的流沖突)mcp_servers = {"mcp-gitlab-server": {"type": "sse","url": "你在魔塔生成的url"}}options = ClaudeCodeOptions(cwd=".",permission_mode="bypassPermissions", # 繞過權限(!很重要,不然執行不了)mcp_servers=mcp_servers)client = ClaudeSDKClient(options=options)# 連接await client.connect()prompt = "使用mcp-gitlab-server這個mcp工具幫我在gitlab倉庫中創建一個名為camel_test的項目"await client.query(prompt, session_id="123456")try:async for message in client.receive_messages():if isinstance(message, AssistantMessage):for block in message.content:if isinstance(block, TextBlock):responses.append({"role": "assistant","content": block.text.strip(),"type": "text"})print({"role": "assistant","content": block.text.strip(),"type": "text"})elif isinstance(block, ToolUseBlock):responses.append({"role": "assistant","content": f"使用工具: {block.name}","type": "tool","metadata": {"tool_name": block.name, "parameters": block.input}})print({"role": "assistant","content": f"使用工具: {block.name}","type": "tool","metadata": {"tool_name": block.name, "parameters": block.input}})elif isinstance(message, ToolResultBlock):status = "成功" if not message.is_error else "失敗"responses.append({"role": "system","content": f"工具執行{status}: {message.content}","type": "tool_result","metadata": {"is_error": message.is_error, "tool_use_id": message.tool_use_id}})print({"role": "system","content": f"工具執行{status}: {message.content}","type": "tool_result","metadata": {"is_error": message.is_error, "tool_use_id": message.tool_use_id}})elif isinstance(message, ResultMessage):responses.append({"role": "system","content": "本輪響應結束","type": "result","metadata": {"input_tokens": message.usage.get("input_tokens"),"output_tokens": message.usage.get("output_tokens"),"cost_usd": message.total_cost_usd,"duration_ms": message.duration_ms}})print({"role": "system","content": "本輪響應結束","type": "result","metadata": {"input_tokens": message.usage.get("input_tokens"),"output_tokens": message.usage.get("output_tokens"),"cost_usd": message.total_cost_usd,"duration_ms": message.duration_ms}})break # 結束接收except Exception as e:if "another coroutine is already waiting" in str(e):print("流讀取沖突:可能客戶端被復用或并發調用")raiseexcept CLIConnectionError:raise Exception("無法連接到 Claude 服務,請檢查網絡或 API 密鑰配置")except Exception as e:print(f"聊天請求失敗: {e}")traceback.print_exc()raise Exception(f"內部錯誤: {str(e)}")finally:# 確保關閉客戶端if client:try:await client.disconnect()except:pass # 忽略關閉時的異常return responsesif __name__ == "__main__":# 生產環境建議使用 gunicorn + uvicorn 部署start_time = datetime.now()asyncio.run(chat())print(f"總耗時: {(datetime.now() - start_time).total_seconds()} 秒")
(二)重要配置
options = ClaudeCodeOptions(cwd=".",permission_mode="bypassPermissions", # 繞過權限(!很重要,不然執行不了)mcp_servers=mcp_servers)