Lang2SQL on Chat service - CausalInferenceLab/Lang2SQL GitHub Wiki

Lang2SQL ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๋ฉด์„œ ๊ณ ์„ฑ๋Šฅ ํ”„๋ก ํ‹ฐ์–ด ๋ชจ๋ธ์ด๋‚˜ ๊ฐ’๋น„์‹ผ API๋ฅผ ํ™œ์šฉํ•˜์ง€ ๋ชปํ•˜๋Š” ์ ์ด ๋Š˜ ์•„์‰ฌ์› ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ณ ๋ฏผ์€ "์–ด๋–ป๊ฒŒ ํ•˜๋ฉด ๊ฒฝ์ œ์ ์œผ๋กœ Lang2SQL์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์„๊นŒ?"๋ผ๋Š” ์งˆ๋ฌธ์œผ๋กœ ์ด์–ด์กŒ๊ณ , ๋ณ„๋„์˜ API ๋น„์šฉ ์—†์ด ๋งŽ์€ ์‚ฌ๋žŒ์ด ์‚ฌ์šฉํ•˜๋Š” ์ฑ„ํŒ… ์„œ๋น„์Šค์—์„œ ๋™์ž‘ํ•œ๋‹ค๋ฉด ์ €๋ ดํ•˜๊ฒŒ ์„œ๋น„์Šค๋ฅผ ์šด์˜ํ•  ์ˆ˜ ์žˆ๊ฒ ๋‹ค๋Š” ์•„์ด๋””์–ด๋กœ ๋ฐœ์ „ํ–ˆ์Šต๋‹ˆ๋‹ค.

MCP.-.1080WebShareName.mov

#MCP #Supabase #Agentic #MCP_super_assistant

RAG with Model Context Protocol

๊ธฐ์กด Lang2SQL์—์„œ๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ํ…Œ์ด๋ธ” ์ •๋ณด๋ฅผ ๊ฒ€์ƒ‰ํ•  ์ˆ˜ ์žˆ๋Š” RAG(Retrieval Augmented Generation) ๊ธฐ๋Šฅ์ด ๊ตฌํ˜„๋˜์–ด ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ๋‹น์‹œ RAG์˜ Vector DB๋Š” Faiss๋กœ ๊ตฌํ˜„๋˜์—ˆ์ง€๋งŒ, ์ด๋ฒˆ ๊ธฐํšŒ์— Supabase์˜ PostgreSQL์„ ํ™œ์šฉํ•˜์—ฌ Vector DB๋ฅผ ๊ตฌ์ถ•ํ•˜๊ณ , RAG๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ์ฝ”๋“œ๋ฅผ MCP(Model Context Protocol)๋กœ ๋งŒ๋“ค์–ด ํ™œ์šฉ์„ฑ์„ ๋†’์˜€์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ์•„์‰ฝ๊ฒŒ๋„ ํ˜„์žฌ MCP๋ฅผ ๊ณต์‹์ ์œผ๋กœ ์ง€์›ํ•˜๋Š” ์„œ๋น„์Šค๋Š” Anthropic์˜ Claude๊ฐ€ ์œ ์ผํ•˜์—ฌ ChatGPT, Gemini, Grok ๋“ฑ ๋‹ค๋ฅธ LLM ์‚ฌ์šฉ์ž๋“ค์€ MCP์˜ ์ด์ ์„ ๋ˆ„๋ฆฌ๊ธฐ ์–ด๋ ค์šด ์ƒํ™ฉ์ž…๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด MCP SuperAssistant ์„œ๋น„์Šค๊ฐ€ ๋“ฑ์žฅํ–ˆ์Šต๋‹ˆ๋‹ค.

MCP SuperAssistant ์†Œ๊ฐœ

MCP SuperAssistant๋Š” Chrome ํ™•์žฅ ํ”„๋กœ๊ทธ๋žจ์œผ๋กœ ์„ค์น˜ํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ํ™•์žฅ ํ”„๋กœ๊ทธ๋žจ์€ ๊ฐ ์ฑ„ํŒ… ์„œ๋น„์Šค(์˜ˆ: ChatGPT) ๋‚ด์—์„œ ํด๋ผ์ด์–ธํŠธ ์—ญํ• ์„ ์ˆ˜ํ–‰ํ•˜๋ฉฐ, ์„œ๋ฒ„์—์„œ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ MCP ๋„๊ตฌ๋“ค์„ ํ™•์ธํ•˜๊ณ  ์—ฐ๋™ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

์ž‘๋™ ์›๋ฆฌ๋ฅผ ๊ฐ„๋‹จํžˆ ์„ค๋ช…ํ•˜์ž๋ฉด, ์ฑ„ํŒ… ์„œ๋น„์Šค ๋‚ด์—์„œ ์ง์ ‘ MCP๊ฐ€ ๋™์ž‘ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, MCP ํ™œ์šฉ์„ ์œ„ํ•œ ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ž๋™์œผ๋กœ ํ…์ŠคํŠธ ํŒŒ์ผ ํ˜•ํƒœ๋กœ ์ƒ์„ฑํ•˜๊ณ  ์ด๋ฅผ ์ฑ„ํŒ…์— ์ฒจ๋ถ€ํ•˜์—ฌ MCP ๋„๊ตฌ ํ˜ธ์ถœ(tool calling)์„ ์œ ๋„ํ•ฉ๋‹ˆ๋‹ค. ์ดํ›„ ๋„๊ตฌ ํ˜ธ์ถœ์ด ๊ฐ์ง€๋˜๋ฉด ํ™•์žฅ ํ”„๋กœ๊ทธ๋žจ์ด ์ด๋ฅผ ์ธ์ง€ํ•˜๊ณ  ์‚ฌ์šฉ์ž์—๊ฒŒ ํ•จ์ˆ˜ ์‹คํ–‰ ๊ถŒํ•œ์„ ์š”์ฒญํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž๊ฐ€ ์Šน์ธํ•˜๋ฉด ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋˜๊ณ , ๊ทธ ๊ฒฐ๊ณผ ์—ญ์‹œ ํ”„๋กฌํ”„ํŠธ ํ˜•ํƒœ๋กœ ๋ณ€ํ™˜๋˜์–ด ๋‹ค์Œ ๋ช…๋ น์œผ๋กœ ์ด์–ด์ ธ ์ตœ์ข…์ ์œผ๋กœ ์‚ฌ์šฉ์ž๊ฐ€ ์š”์ฒญํ•œ ๋‚ด์šฉ์ด ํ•ด๊ฒฐ๋˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค.

์„ค์ • ๊ณผ์ •

image

1. Supabase ๊ธฐ๋ฐ˜ RAG ๊ตฌ์ถ•

Supabase๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ฐฑ์—”๋“œ๋ฅผ ์†์‰ฝ๊ฒŒ ๊ตฌ์ถ•ํ•˜๊ณ  ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ์ง€์›ํ•˜๋Š” ์˜คํ”ˆ์†Œ์Šค ํ”Œ๋žซํผ์ž…๋‹ˆ๋‹ค. ๋ฐฑ์—”๋“œ์˜ ํ•ต์‹ฌ ์š”์†Œ์ธ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์‹œ์ž‘์œผ๋กœ Edge function, Authentication ๋“ฑ ๋‹ค์–‘ํ•œ ๊ธฐ๋Šฅ์„ ๋ณ„๋„์˜ ์„œ๋ฒ„ ๊ตฌ์ถ• ์—†์ด ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋•์Šต๋‹ˆ๋‹ค. ์ด๋ฒˆ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” Supabase์˜ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๊ธฐ๋Šฅ์„ ํ™œ์šฉํ•˜๋ฉฐ, ํŠนํžˆ PostgreSQL ๊ธฐ๋ฐ˜์ด๋ฏ€๋กœ pgvector ํ™•์žฅ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜์—ฌ RAG๋ฅผ ์œ„ํ•œ Vector DB๋ฅผ ๊ตฌ์„ฑํ•ฉ๋‹ˆ๋‹ค.

๊ธฐ์กด Vector DB(Faiss)์—์„œ Documents ์ถ”์ถœ

๊ธฐ์กด์— langchain์œผ๋กœ ์ €์žฅ๋œ Faiss Vector DB๋ฅผ ๋กœ๋“œํ•  ๋•Œ๋Š” ์ž„๋ฒ ๋”ฉ ํ•จ์ˆ˜๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ๋Š” ์‹ค์ œ ์ž„๋ฒ ๋”ฉ์„ ์ˆ˜ํ–‰ํ•˜์ง€ ์•Š๊ณ  Document ๊ฐ์ฒด๋งŒ ์ถ”์ถœํ•˜๊ธฐ ์œ„ํ•ด fake_embeddings ํ•จ์ˆ˜๋ฅผ ์ •์˜ํ•˜์—ฌ ํ™œ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ดํ›„ ์ถ”์ถœ๋œ Document ๊ฐ์ฒด๋“ค์„ ๋ฆฌ์ŠคํŠธ์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

from typing import List
from langchain_community.vectorstores import FAISS
from langchain.schema import Document # Document ํƒ€์ž…์„ ๋ช…์‹œ์ ์œผ๋กœ import

def fake_embeddings(texts: List[str] = None, embeddings: List[float] = None): # ํŒŒ๋ผ๋ฏธํ„ฐ๋ช…๊ณผ ํƒ€์ž…์„ ๋ณด๋‹ค ๋ช…ํ™•ํžˆ ์ˆ˜์ •
    # ์ด ํ•จ์ˆ˜๋Š” ์‹ค์ œ ์ž„๋ฒ ๋”ฉ์„ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š๊ณ , FAISS ๋กœ๋“œ ์‹œ ํ˜•์‹์ ์œผ๋กœ๋งŒ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
    return None

# <vector_db_path>๋ฅผ ์‹ค์ œ Faiss DB๊ฐ€ ์ €์žฅ๋œ ๊ฒฝ๋กœ๋กœ ๋ณ€๊ฒฝํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
index = FAISS.load_local(
    "<vector_db_path>", fake_embeddings, allow_dangerous_deserialization=True
)
docstore_dict = index.docstore._dict

docs = list()
for doc_id, document in docstore_dict.items():
    docs.append(document)

์ถ”์ถœ๋œ Document๋ฅผ ์ž„๋ฒ ๋”ฉํ•˜์—ฌ Supabase์— ์—…๋กœ๋“œ

๋จผ์ € ํ•„์š”ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์„ค์น˜ํ•ฉ๋‹ˆ๋‹ค.

pip install supabase langchain-openai

์ด์ œ ์ถ”์ถœํ•œ docs๋ฅผ OpenAI ์ž„๋ฒ ๋”ฉ ๋ชจ๋ธ์„ ์‚ฌ์šฉํ•ด ์ž„๋ฒ ๋”ฉํ•˜๊ณ  Supabase DB documents Table์— ์—…๋กœ๋“œํ•ฉ๋‹ˆ๋‹ค.

Supabase์— documents Table์„ ์ƒ์„ฑํ•˜๋Š” ๋‚ด์šฉ์€ ์•„๋ž˜ ํ™•์žฅ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ ํ™•์ธํ•˜์„ธ์š”

Supabase ํ”„๋กœ์ ํŠธ documents ํ…Œ์ด๋ธ” ๋งŒ๋“ค๊ธฐ

documents๋ผ๋Š” ์ด๋ฆ„์„ ๊ฐ–๋Š” Table์„ ์ •์˜ํ•˜๋Š” SQL์œผ๋กœ Supabase dashboard์˜ SQL editor์—์„œ ์•„๋ž˜ SQL์„ ์‹คํ–‰ํ•˜๋ฉด Table์ด ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค. ์•„๋ž˜ SQL์—๋Š” Table ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ RAG์—์„œ ์‚ฌ์šฉํ•˜๊ฒŒ ๋  retrieve ํ•จ์ˆ˜๋„ ๊ฐ™์ด ์ •์˜ํ•ฉ๋‹ˆ๋‹ค. ํ•„์š”์— ๋”ฐ๋ผ retrieve ํ•จ์ˆ˜๋ฅผ ๋ณ€๊ฒฝํ•˜์—ฌ hybrid search๋„ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. image

-- Enable the pgvector extension to work with embedding vectors
create extension if not exists vector;

-- Create a table to store your documents
create table
  documents (
    id uuid primary key,
    content text, -- corresponds to Document.pageContent
    metadata jsonb, -- corresponds to Document.metadata
    embedding vector (1536) -- 1536 works for OpenAI embeddings, change as needed
  );

-- Create a function to search for documents
create function match_documents (
  query_embedding vector (1536),
  filter jsonb default '{}'
) returns table (
  id uuid,
  content text,
  metadata jsonb,
  similarity float
) language plpgsql as $$
#variable_conflict use_column
begin
  return query
  select
    id,
    content,
    metadata,
    1 - (documents.embedding <=> query_embedding) as similarity
  from documents
  where metadata @> filter
  order by documents.embedding <=> query_embedding;
end;
$$;
from supabase import create_client, Client # Client ํƒ€์ž…์„ ๋ช…์‹œ์ ์œผ๋กœ import
from langchain_openai import OpenAIEmbeddings
from langchain_community.vectorstores import SupabaseVectorStore

# Supabase ์ ‘์† ์ •๋ณด (์‹ค์ œ ๊ฐ’์œผ๋กœ ๋Œ€์ฒด ํ•„์š”)
supabase_url = "<insert_your_supabase_url>"
supabase_key = "<insert_your_supabase_key>"
supabase: Client = create_client(supabase_url, supabase_key)

# OpenAI API ํ‚ค (์‹ค์ œ ๊ฐ’์œผ๋กœ ๋Œ€์ฒด ํ•„์š”)
openai_api_key = "<insert_your_openai_api_key>" 
embeddings = OpenAIEmbeddings(
    model="text-embedding-3-small", openai_api_key=openai_api_key
)

# Document์™€ ์ž„๋ฒ ๋”ฉ ๊ฐ’์„ Supabase์— ์—…๋กœ๋“œ
vectorstore = SupabaseVectorStore.from_documents(
    docs,
    embeddings,
    client=supabase,
    table_name="documents", # Supabase์— ์ƒ์„ฑ๋  ํ…Œ์ด๋ธ”๋ช…
)

์œ„ ์ ˆ์ฐจ๋ฅผ ๋งˆ์น˜๋ฉด Supabase์˜ Table Editor์—์„œ ์—…๋กœ๋“œ๋œ ๋ฐ์ดํ„ฐ์™€ ๋ฒกํ„ฐ๊ฐ’์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

image

2. RAG ๋„๊ตฌ๋ฅผ MCP๋กœ ์ •์˜ํ•˜๊ธฐ

์—…๋กœ๋“œ๋œ Vector DB๋ฅผ ํ™œ์šฉํ•˜์—ฌ RAG์˜ ๊ฒ€์ƒ‰(retrieve) ๊ธฐ๋Šฅ์„ ์ •์˜ํ•˜๊ณ , LLM์ด ์ด ํ•จ์ˆ˜๋ฅผ ๋„๊ตฌ๋กœ ์ธ์‹ํ•˜๊ณ  ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋„๋ก docstring์„ ์ƒ์„ธํžˆ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. ์ดํ›„, ์ •์˜๋œ ๋„๊ตฌ๋ฅผ ํ™œ์„ฑํ™”ํ•˜๋Š” MCP ์„œ๋ฒ„ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์™„์„ฑํ•˜๋ฉด MCP๋ฅผ ์‚ฌ์šฉํ•  ์ค€๋น„๊ฐ€ ๋๋‚ฉ๋‹ˆ๋‹ค.

MCP ์„œ๋ฒ„ ํ™˜๊ฒฝ ์„ค์ •์€ uv๋ฅผ ํ™œ์šฉํ•˜๋Š” ๊ฒƒ์ด ๊ถŒ์žฅ๋ฉ๋‹ˆ๋‹ค. ์ž‘์—… ๊ณต๊ฐ„์—์„œ uv init์„ ์‹คํ–‰ํ•˜์—ฌ ์ดˆ๊ธฐํ™”ํ•œ ํ›„, ๋‹ค์Œ ๋ช…๋ น์–ด๋กœ ํ•„์š”ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์„ค์น˜ํ•ฉ๋‹ˆ๋‹ค. uv add "mcp[cli]" ์ด์™ธ์— MCP ์„ค์น˜๊ฐ€ ํ•„์š”ํ•˜๋‹ค๋ฉด uv add langchain๊ณผ ๊ฐ™์€ ๋ช…๋ น์–ด๋กœ ์„ค์น˜ํ•˜๋ฉด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

mcp_server.py

from mcp.server.fastmcp import FastMCP
from dotenv import load_dotenv
from supabase import create_client, Client
from langchain_openai import OpenAIEmbeddings
from langchain_community.vectorstores import SupabaseVectorStore
import os
from langchain.schema import Document

# .env ํŒŒ์ผ์—์„œ ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ๋กœ๋“œ (OPENAI_API_KEY, SUPABASE_URL, SUPABASE_KEY ๋“ฑ)
load_dotenv()

# MCP ์„œ๋ฒ„ ์ด๋ฆ„ (์ž์œ ๋กญ๊ฒŒ ์ •์˜ ๊ฐ€๋Šฅ)
mcp = FastMCP("lang2SQL_MCP")

def docs_to_str(docs: list[Document]) -> str:
    """
    ๊ฒ€์ƒ‰๋œ Document ๋ฆฌ์ŠคํŠธ๋ฅผ ๋‹จ์ผ ๋ฌธ์ž์—ด๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
    """
    return "\n".join([doc.page_content for doc in docs])

@mcp.tool()
async def retrieve_table(question: str) -> str:
    """
    RAG ์‹œ์Šคํ…œ์˜ ์ผ๋ถ€๋กœ, SQL ์ฟผ๋ฆฌ ์ƒ์„ฑ์„ ์œ„ํ•ด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ํ…Œ์ด๋ธ” ์ •๋ณด๋ฅผ ๊ฒ€์ƒ‰ํ•ฉ๋‹ˆ๋‹ค.

    Args:
        question: ํ…Œ์ด๋ธ” ์ •๋ณด๋ฅผ ๊ฒ€์ƒ‰ํ•˜๊ธฐ ์œ„ํ•œ ์‚ฌ์šฉ์ž ์งˆ๋ฌธ์ž…๋‹ˆ๋‹ค.

    Returns:
        ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ๊ฒ€์ƒ‰๋œ ํ…Œ์ด๋ธ” ์ •๋ณด ๋ฌธ์ž์—ด์ž…๋‹ˆ๋‹ค.
    """
    supabase_url: str = os.getenv("SUPABASE_URL")
    supabase_key: str = os.getenv("SUPABASE_KEY")
    supabase: Client = create_client(supabase_url, supabase_key)

    embeddings = OpenAIEmbeddings(
        model="text-embedding-3-small",
        openai_api_key=os.getenv("OPENAI_API_KEY"), # ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋ช… ์ผ๊ด€์„ฑ ์žˆ๊ฒŒ ์ˆ˜์ • (OPEN_AI_LLM_KEY -> OPENAI_API_KEY)
    )

    vector_db = SupabaseVectorStore(
        client=supabase, # ํŒŒ๋ผ๋ฏธํ„ฐ ์ˆœ์„œ ๋ณ€๊ฒฝ (client๊ฐ€ ๋จผ์ €)
        embedding=embeddings, # ํŒŒ๋ผ๋ฏธํ„ฐ๋ช… ๋ณ€๊ฒฝ (embeddings -> embedding)
        table_name="documents",
        query_name="match_documents", # Supabase์—์„œ ์‚ฌ์šฉํ•  ํ•จ์ˆ˜๋ช… (pgvector ์„ค์น˜ ์‹œ ์ž๋™ ์ƒ์„ฑ๋˜๋Š” ํ•จ์ˆ˜ ํ™œ์šฉ ๊ฐ€๋Šฅ)
    )

    retriever = vector_db.as_retriever()
    retrieved_docs = retriever.get_relevant_documents(question) # ๋ณ€์ˆ˜๋ช… ๋ณ€๊ฒฝ (docs -> retrieved_docs)

    return docs_to_str(retrieved_docs)

def run_server(transport: str = "stdio"):
    """MCP ์„œ๋ฒ„๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

    Args:
        transport: ํ†ต์‹  ๋ฐฉ์‹ ("stdio" ๋˜๋Š” "sse")
    """
    mcp.run(transport=transport)

if __name__ == "__main__":
    # ์ผ๋ฐ˜์ ์œผ๋กœ ์›น ๊ธฐ๋ฐ˜ ์ƒํ˜ธ์ž‘์šฉ์„ ์œ„ํ•ด "sse" (Server-Sent Events)๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
    run_server(transport="sse")

3. MCP SuperAssistant ์„ค์ •

MCP SuperAssistant๋ฅผ ํ™œ์šฉํ•˜๋ ค๋ฉด Chrome ํ™•์žฅ ํ”„๋กœ๊ทธ๋žจ ์„ค์น˜์™€ ์‚ฌ์šฉํ•˜๋ ค๋Š” MCP์˜ ํ™˜๊ฒฝ ์„ค์ •(config) ์ •์˜๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์„ค์ •์ด ์™„๋ฃŒ๋˜๋ฉด npx ๋ช…๋ น์–ด๋กœ ํด๋ผ์ด์–ธํŠธ๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

MCP SuperAssistant Chrome ํ™•์žฅ ํ”„๋กœ๊ทธ๋žจ ์„ค์น˜

MCP SuperAssistant Chrome Extension ์„ค์น˜ ๋งํฌ๋ฅผ ํ†ตํ•ด Chrome์— ํ™•์žฅ ํ”„๋กœ๊ทธ๋žจ์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

MCP Config ์ •์˜

MCP Config๋Š” JSON ํ˜•ํƒœ๋กœ ์ €์žฅํ•ด์•ผ ํ•˜๋ฉฐ, ์ด๋ฒˆ ๊ธ€์—์„œ ์ •์˜ํ•œ RAG MCP ์™ธ์—๋„ ์™ธ๋ถ€ MCP๋ฅผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. lang2SQL_MCP ์ •์˜๋ฅผ ์œ„ํ•ด์„œ๋Š” MCP ์„œ๋ฒ„ ์Šคํฌ๋ฆฝํŠธ(mcp_server.py)๊ฐ€ ์œ„์น˜ํ•œ ๊ฒฝ๋กœ(<insert_your_mcp_path>)๋ฅผ ์ •ํ™•ํžˆ ๋ช…์‹œํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

rag_mcp_config.json

{
    "mcpServers": {
        "sequential-thinking": {
            "command": "npx",
            "args": [
                "-y",
                "@modelcontextprotocol/server-sequential-thinking"
            ]
        },
        "lang2SQL_MCP": {
            "command": "uv",
            "args": [
                "--directory",
                "<insert_your_mcp_path>",
                "run",
                "mcp_server.py"
            ]
        }
    }
}
MCP ํด๋ผ์ด์–ธํŠธ ์‹คํ–‰

๋‹ค์Œ ๋ช…๋ น์–ด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ MCP ํด๋ผ์ด์–ธํŠธ๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

npx @srbhptl39/mcp-superassistant-proxy@latest --config ./rag_mcp_config.json
MCP SuperAssistant์™€ ์ฑ„ํŒ… ์„œ๋น„์Šค ์—ฐ๋™ ์‹คํ–‰

Chrome ํ™•์žฅ ํ”„๋กœ๊ทธ๋žจ ์„ค์น˜ ํ›„ Gemini ํ™ˆํŽ˜์ด์ง€ ๋“ฑ์— ์ ‘์†ํ•˜๋ฉด, ์ฑ„ํŒ… ์ž…๋ ฅ์ฐฝ ๊ทผ์ฒ˜์— MCP ๋ฒ„ํŠผ์ด ์ƒˆ๋กญ๊ฒŒ ์ƒ์„ฑ๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

image

MCP ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด ํŒ์—…์ฐฝ์ด ๋‚˜ํƒ€๋‚˜๋ฉฐ, MCP ๋„๊ตฌ ํ˜ธ์ถœ์„ ์œ„ํ•œ ํ”„๋กฌํ”„ํŠธ๊ฐ€ ์ž๋™์œผ๋กœ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.

image

MCP๋ฅผ ํ™œ์šฉํ•˜๊ธฐ ์œ„ํ•ด "Attach" ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด, "Instructions" ์•„๋ž˜์— ๋ณด์ด๋Š” ํ”„๋กฌํ”„ํŠธ๊ฐ€ ํ˜„์žฌ ์‚ฌ์šฉ ์ค‘์ธ ์ฑ„ํŒ… ์„œ๋น„์Šค์˜ ์ž…๋ ฅ์ฐฝ์— ์ž๋™์œผ๋กœ ์ฒจ๋ถ€๋ฉ๋‹ˆ๋‹ค.

image

์ด์ œ ๋ชจ๋“  ์ค€๋น„๊ฐ€ ์™„๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ฒจ๋ถ€๋œ ํ”„๋กฌํ”„ํŠธ์™€ ํ•จ๊ป˜ ์งˆ๋ฌธ์„ ์ž…๋ ฅํ•˜๋ฉด, ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์šฐ๋ฆฌ๊ฐ€ ์ •์˜ํ•œ MCP ๋„๊ตฌ(retrieve_table)๊ฐ€ ํ˜ธ์ถœ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

image

ํ˜ธ์ถœ๋œ ๋„๊ตฌ ์˜†์˜ "Run" ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋˜๊ณ , ์‹คํ–‰์ด ์™„๋ฃŒ๋˜๋ฉด ๋ฒ„ํŠผ์ด "Insert"์™€ "Attach File" ๋ฒ„ํŠผ์ด ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค. "Insert" ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ๋ฅผ ๋‹ค์Œ ๋ช…๋ น์–ด(LLM์—๊ฒŒ ์ „๋‹ฌ๋˜๋Š” ํ”„๋กฌํ”„ํŠธ)์— ํฌํ•จํ•˜์—ฌ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

image

์œ„์™€ ๊ฐ™์ด ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ๋ฅผ ํฌํ•จํ•œ ๋ช…๋ น์„ ์‹คํ–‰ํ•˜๋ฉด, ์•„๋ž˜์ฒ˜๋Ÿผ ํ˜„์žฌ ์‚ฌ์šฉ ์ค‘์ธ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์Šคํ‚ค๋งˆ์— ๋งž๋Š” SQL ์ฟผ๋ฆฌ๊ฐ€ ์ƒ์„ฑ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

image

์š”์•ฝ ๋ฐ ์†Œ๊ฐ

๊ณผ๊ฑฐ์—๋Š” Anthropic์˜ Claude๋ฅผ ์ฃผ๋กœ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•„ Cursor ์™ธ์—๋Š” MCP๋ฅผ ํ™œ์šฉํ•  ๊ธฐํšŒ๊ฐ€ ๋งŽ์ง€ ์•Š์•„ ์•„์‰ฌ์›€์ด ์ปธ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ MCP SuperAssistant ๋•๋ถ„์— ๋‹ค์–‘ํ•œ ํ™˜๊ฒฝ์—์„œ MCP๋ฅผ ๊ฒฝํ—˜ํ•ด๋ณผ ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. Cursor์—์„œ์˜ MCP ๊ฒฝํ—˜๋„ ํ›Œ๋ฅญํ–ˆ์ง€๋งŒ, Cursor๋Š” '์ฝ”๋”ฉ'์ด๋ผ๋Š” ํŠน์ • ์ž‘์—…์— ์ดˆ์ ์„ ๋งž์ถ˜ ์„œ๋น„์Šค์ด๊ธฐ์— MCP ๊ธฐ์ˆ ์˜ ๋‹ค์–‘ํ•œ ํ™œ์šฉ ๊ฐ€๋Šฅ์„ฑ์„ ์ง์ ‘์ ์œผ๋กœ ์ฒด๊ฐํ•˜๊ธฐ์—๋Š” ํ•œ๊ณ„๊ฐ€ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฒˆ ๊ธ€์„ ํ†ตํ•ด MCP๊ฐ€ ์ฝ”๋”ฉ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๋‹ค์–‘ํ•œ ๋ถ„์•ผ์™€ ์„œ๋น„์Šค์—์„œ ์œ ์šฉํ•˜๊ฒŒ ํ™œ์šฉ๋  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ž ์žฌ๋ ฅ์„ ํ™•์ธํ•˜๊ฒŒ ๋˜์–ด ๋งค์šฐ ์˜๋ฏธ ์žˆ๋Š” ๊ฒฝํ—˜์ด์—ˆ์Šต๋‹ˆ๋‹ค. ์•ž์œผ๋กœ MCP ์ƒํƒœ๊ณ„๊ฐ€ ๋”์šฑ ํ™•์žฅ๋˜์–ด ๋” ๋งŽ์€ ์‚ฌ์šฉ์ž๊ฐ€ ๊ทธ ์ด์ ์„ ๋ˆ„๋ฆด ์ˆ˜ ์žˆ๊ธฐ๋ฅผ ๊ธฐ๋Œ€ํ•ฉ๋‹ˆ๋‹ค.

โš ๏ธ **GitHub.com Fallback** โš ๏ธ