KeiStory

반응형

LangChain 을 이용한 Streamlit 채팅에 Smithery MCP 추가하기

 

이전 포스팅에서 Langchain 과 내가 구축한 MCP 연결하여 Streamlit 로 채팅창을 만들었습니다.

2025.06.03 - [코딩/Python_AI] - LangChain MCP 와 Streamlit 으로 채팅창 만들기

 

이번에는 Smithery에서 제공하는 다양한 MCP 도구를 연결하는 방법을 다루겠습니다.

Smithery MCP란?

Smithery는 여러 유용한 MCP 도구를 모아둔 공개 레지스트리로, 예를 들어 code-mcp, text-enhancer, filesystem 등의 도구를 제공합니다. 이 MCP들은 LangChain과 호환되며, npx 명령어를 통해 로컬에서 실행 가능합니다.

Smithery의 MCP 도구를 로컬에서 npx 명령으로 실행하는 구성하는 경우 LangChain MCP에서 stdio 기반의 MCP 도구 실행 방식과 연결됩니다.

전제조건은 

  • npx가 시스템에 설치되어 있어야 하며, 해당 명령이 실행 가능한 환경이어야 합니다.
  • 실행 환경에서 **Node.js와 @smithery/cli**가 작동해야 하며, 방화벽/프록시 등 외부 호출이 차단되어 있지 않아야 합니다.

이전 포스팅의 코드에서 아래 코드를 추가하면됩니다.

smithery_mcp_servers = {
    "code-mcp": {
        "command": "npx",
        "args": [
            "-y",
            "@smithery/cli@latest",
            "run",
            "@block/code-mcp",
            "--key",
            "4b***-***-***"
        ],
        "transport": "stdio",
        "enabled": False
    },
    "filesystem": {
        "command": "npx",
        "args": [
            "-y",
            "@modelcontextprotocol/server-filesystem",
            "C:\\Users\\junij\\Downloads\\pic"
        ],
        "transport": "stdio",
        "enabled": False
    }
 }
 
 # 모든 MCP 서버 병합: 기본 + Smithery
if "mcp_config" not in st.session_state:
    st.session_state.mcp_config = {
        **smithery_mcp_servers
    }

 

아래는 전체 코드입니다.

MCP 도구 선택 UI를 사이드바로 구성했고, 체크박스를 통해 실행할 MCP를 동적으로 선택할 수 있습니다.

# pip install streamlit langchain-openai langchain langchain-mcp-adapters
# pip install nest_asyncio
import streamlit as st
import os
from dotenv import load_dotenv
import asyncio
import nest_asyncio
import sys

from langchain_openai import ChatOpenAI
from langgraph.prebuilt import create_react_agent
from langchain_mcp_adapters.client import MultiServerMCPClient

nest_asyncio.apply()
load_dotenv()

# Windows 운영체제 호환성을 위한 이벤트 루프 정책 설정
if sys.platform == "win32":
    asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy())

# OpenAI API 키 로드
openai_key = os.getenv("OPENAI_API_KEY")
if not openai_key:
    st.error("❌ OPENAI_API_KEY 가 .env에 설정되어 있지 않습니다.")
    st.stop()

# MCP 서버 정의 (토글용)
default_mcp_servers = {
    "math": {
        "url": "http://localhost:8020/mcp",
        "transport": "streamable_http",
        "enabled": True
    },
    "weather": {
        "url": "http://localhost:8010/mcp",
        "transport": "streamable_http",
        "enabled": True
    }
}

st.title("🔧 LangChain MCP 채팅")
st.markdown("OpenAI GPT-4o + MCP 도구 연동")

# 세션 상태 초기화
if "chat_history" not in st.session_state:
    st.session_state.chat_history = []

# if "mcp_config" not in st.session_state:
#     st.session_state.mcp_config = default_mcp_servers.copy()

smithery_mcp_servers = {
    "code-mcp": {
        "command": "npx",
        "args": [
            "-y",
            "@smithery/cli@latest",
            "run",
            "@block/code-mcp",
            "--key",
            "4bf83a94-4b96-4dc1-b052-fad63748ccff"
        ],
        "transport": "stdio",
        "enabled": False
    },
    "filesystem": {
        "command": "npx",
        "args": [
            "-y",
            "@modelcontextprotocol/server-filesystem",
            "C:\\Users\\junij\\Downloads\\pic"
        ],
        "transport": "stdio",
        "enabled": False
    }
 }

# 모든 MCP 서버 병합: 기본 + Smithery
if "mcp_config" not in st.session_state:
    st.session_state.mcp_config = {
        **default_mcp_servers,
        **smithery_mcp_servers
    }

# MCP 도구 토글 UI
st.sidebar.title("🧩 MCP 도구 설정")
for name, config in st.session_state.mcp_config.items():
    config["enabled"] = st.sidebar.checkbox(name, value=config["enabled"])

# 사용자 입력
user_input = st.chat_input("질문을 입력하세요...")

# 메인 비동기 처리
async def handle_query(query):
    # 사용 중인 MCP 도구만 필터링
    active_tools = {
        name: {k: v for k, v in config.items() if k != "enabled"}
        for name, config in st.session_state.mcp_config.items() if config["enabled"]
    }

    client = MultiServerMCPClient(active_tools)
    tools = await client.get_tools()

    model = ChatOpenAI(openai_api_key=openai_key, model="gpt-4o", temperature=0)
    agent = create_react_agent(model=model, tools=tools)

    response = await agent.ainvoke({"messages": [{"role": "user", "content": query}]})

    tool_used = None
    final_answer = None

    for message in response.get("messages", []):
        if hasattr(message, "tool_calls") and message.tool_calls:
            for tool_call in message.tool_calls:
                tool_used = tool_call.get("name")
        if hasattr(message, "content") and message.content:
            final_answer = message.content

    return tool_used, final_answer

# 채팅 처리
if user_input:
    st.session_state.chat_history.append(("user", user_input))
    tool, answer = asyncio.run(handle_query(user_input))
    tool_msg = f"🔧 MCP 도구 사용됨: `{tool}`" if tool else "🧠 도구 사용 없이 응답함"
    st.session_state.chat_history.append(("assistant", f"{tool_msg}\n\n{answer}"))

# 채팅 UI 렌더링
for sender, message in st.session_state.chat_history:
    with st.chat_message(sender):
        st.markdown(message)

 

아래는 filesystem 을 이용해 로컬 파일의 내용을 변경해 본 결과 입니다.

filesystem MCP를 사용하면 로컬 디렉터리 내의 파일을 분석하거나 조작할 수 있습니다. 예를 들어, 특정 폴더 내의 이미지 파일을 불러오고 설명을 생성하는 작업이 가능합니다.

 

왼쪽에 체크박스를 해제하면 해당 mcp 는 사용하지 않습니다.

 

https://smithery.ai/

 

Smithery - Model Context Protocol Registry

@isnow890/naver-search-mcp A MCP server based on Naver Search API. Enables searching various content types (news, cafe, blogs, shopping, web search, etc.) and analyzing search/shopping trends via DataLab API. Shopping analytics provide consumer behavior pa

smithery.ai

https://github.com/langchain-ai/langchain

 

GitHub - langchain-ai/langchain: 🦜🔗 Build context-aware reasoning applications

🦜🔗 Build context-aware reasoning applications. Contribute to langchain-ai/langchain development by creating an account on GitHub.

github.com

 

728x90

공유하기

facebook twitter kakaoTalk kakaostory naver band