MCP Application ๊ตฌํํ๊ธฐ
MCP(Model Context Protocal)์ ์์ฑํ AI application์ด ์ธ๋ถ ๋ฐ์ดํฐ๋ฅผ ํ์ฉํ๋ ์ฃผ์ํ ์ธํฐํ์ด์ค๋ก ๋น ๋ฅด๊ฒ ํ์ฐ๋๊ณ ์์ต๋๋ค. 2024๋ 11์์ Anthropic์ ์คํ์์ค ํ๋ก์ ํธ๋ก ์์๋์๊ณ , ํ์ฌ Cursor๋ฟ ์๋๋ผ OpenAI์์๋ ์ง์ํ๊ณ ์์ต๋๋ค. ์ฌ๊ธฐ์์๋ MCP with LangChain์ ์ด์ฉํ์ฌ LangGraph๋ก ๋ง๋ application์ด MCP๋ฅผ ํ์ฉํ๋ ๋ฐฉ๋ฒ์ ๋ํด ์ค๋ช ํฉ๋๋ค. ์ฌ๊ธฐ์ ๊ตฌํํ RAG๋ Amazon์ ์์ ๊ด๋ฆฌํ RAG ์๋น์ค์ธ Knowledge base๋ก ๊ตฌํ๋์์ผ๋ฏ๋ก, ๋ฌธ์์ ํ ์คํธ ์ถ์ถ, ๋๊ธฐํ, chunking๊ณผ ๊ฐ์ ์์ ์ ์์ฝ๊ฒ ์ํํ ์ ์์ผ๋ฉฐ, ๋ฉํฐ๋ชจ๋ฌ์ ์ด์ฉํด ์ด๋ฏธ์ง/ํ๋ฅผ ๋ถ์ํ ์ ์์ต๋๋ค. ์ฌ๊ธฐ์์๋ MCP server์์ RAG์ ์์ฝ๊ฒ ์ ๊ทผํ ์ ์๋๋ก AWS Lambda๋ฅผ ์ด์ฉํด API๋ฅผ ๊ตฌ์ฑํ์์ต๋๋ค.
์๋ architecture๋ AWS ํ๊ฒฝ์์ MCP๋ฅผ ํฌํจํ Agent๋ฅผ ๊ตฌ์ฑํ๋๊ฒ์ ๋ณด์ฌ์ค๋๋ค. Agent๋ MCP server/client ๊ตฌ์กฐ๋ฅผ ํ์ฉํ์ฌ ์ธ๋ถ์ ๋ฐ์ดํฐ ์์ค๋ฅผ ํ์ฉํ ์ ์์ต๋๋ค. MCP client๋ MCP server์ JSON-RPC ํ๋กํ ์ฝ์ ๊ธฐ๋ฐํ์ฌ stdio/SSE๋ก ํต์ ์ ์ํํฉ๋๋ค. Stdio ์ฌ์ฉ์ MCP Server๋ python, java์ ๊ฐ์ ์ฝ๋๋ก ๊ตฌ์ฑ์ด ๋๊ณ , client์์ ์์ฒญ์ด ์ค๋ฉด RAG๋ ์ธํฐ๋ท๋ฑ์ ์ด์ฉํด ๋ฐ์ดํฐ๋ฅผ ์์งํ๊ฑฐ๋ ์ ๋ฌํ๋ ์ญํ ์ ์ํํฉ๋๋ค. SSE๋ก ํ ๊ฒฝ์ฐ์ MCP client์ server๋ IP๋ก ํต์ ์ ํ๊ฒ ๋ฉ๋๋ค. ์ฌ๊ธฐ์๋ Streamlit์ ์ด์ฉํด application์ UI๋ฅผ ๊ตฌ์ฑํ๊ณ , ์ฌ์ฉ์๋ ALB - CloudFront๋ฅผ ์ด์ฉํด HTTPS ๋ฐฉ์์ผ๋ก ๋ธ๋ผ์ฐ์ ๋ฅผ ํตํด application์ ์ด์ฉํฉ๋๋ค. ๋ํ, ์ฌ๊ธฐ์์๋ ์ปค์คํฐ๋ง์ด์ง์ด ์ ๋ฆฌํ LangGraph๋ฅผ ์ด์ฉํด MCP ๊ธฐ๋ฐ์ application์ ๊ฐ๋ฐํ๋๊ฒ์ ์ค๋ช ํฉ๋๋ค.
MCP ํ์ฉ
MCP Basic
์ฌ์ฉ์๋ ์์ ์ Computer์ ์ค์น๋ Claude Desktop, Cursor์ ๊ฐ์ AI ๋๊ตฌ๋ฟ ์๋๋ผ ์ฃผ๋ก Agentํํ๋ก ๊ฐ๋ฐ๋ ์ดํ๋ฆฌ์ผ์ด์ ์ ํตํด MCP ์๋ฒ์ ์ฐ๊ฒฐํ ์ ์์ต๋๋ค. MCP server๋ MCP client์ ์์ฒญ์ ์์ ์ด ํ ์ ์๋ ๊ธฐ๋ฅ์ capability๋ก ์ ๊ณตํ๊ณ client์ ์์ฒญ์ ์ํํฉ๋๋ค. MCP server๋ local computer์ ํ์ผ์ด๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์กฐํํ ์ ์์๋ฟ ์๋๋ผ ์ธํฐ๋ท์ ์๋ ์ธ๋ถ ์๋ฒ์ API๋ฅผ ์ด์ฉํด ํ์ํ ์ ๋ณด๋ฅผ ์กฐํํ ์ ์์ต๋๋ค. MCP Client๋ Server์ JSON-RPC 2.0 ํ๋กํ ์ฝ์ ์ด์ฉํด ์ฐ๊ฒฐ๋๋๋ฐ, stdio๋ SSE (Server-Sent Events)์ ์ ํํ์ฌ, Host์ ์์ฒญ์ MCP์ ์ ๋ฌํ ์ ์๊ณ , ์๋ต์ ๋ฐ์์ ํ์ฉํ ์ ์์ต๋๋ค.
MCP์ ์ฃผ์ ์์์ ์ ์์ ๋์์ ์๋์ ๊ฐ์ต๋๋ค.
- MCP Hosts: MCP ํ๋กํ ์ฝ์ ํตํด ๋ฐ์ดํฐ์ ์ ๊ทผํ๋ ํ๋ก๊ทธ๋จ/AI ๋๊ตฌ๋ก์ Claude Desktop, Cursor, User Agent Application์ด ํด๋น๋ฉ๋๋ค.
- MCP Clients: MCP Server์ 1:1๋ก ์ฐ๊ฒฐ์ ์ํํ๋ Client๋ก์ MCP Server์ stdio ๋๋ SSE ๋ฐฉ์์ผ๋ก ์ฐ๊ฒฐํ ์ ์์ต๋๋ค.
- MCP Servers: ํ์คํ๋ MCP๋ฅผ ํตํด Client์ Tool์ Capability๋ฅผ ์๋ ค์ฃผ๋ ๊ฒฝ๋ ํ๋ก๊ทธ๋จ์ผ๋ก Local Computer์ ํ์ผ์ด๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์กฐํํ ์ ์๊ณ , ์ธ๋ถ API๋ฅผ ์ด์ฉํด ์ ๋ณด๋ฅผ ์กฐํํ ์ ์์ต๋๋ค.
- Local data sources: MCP ์๋ฒ๊ฐ ์ ๊ทผํ ์ ์๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ก์ปฌ ๋ฐ์ดํฐ
- Remote services: API๋ฅผ ํตํด ์ ๊ทผ ๊ฐ๋ฅํ ์ธ๋ถ ์์คํ
MCP๋ฅผ ์ฌ์ฉํ๋ฉด ์๋์ ๊ฐ์ ์ฅ์ ์ด ์์ต๋๋ค.
- ํ์คํ๋ ๋ฐฉ์์ผ๋ก ๋ค์ํ ๋ฐ์ดํฐ ์์ค์ ์ ๊ทผ ๊ฐ๋ฅํฉ๋๋ค.
- ์ ํ๋ฆฌ์ผ์ด์ ์ฝ๋ ๋ณ๊ฒฝ ์์ด MCP ์๋ฒ ์ ๋ฐ์ดํธ๋ฅผ ํตํ ์๋ก์ด ๊ธฐ๋ฅ ์ถ๊ฐํ ์ ์์ต๋๋ค.
- ์กฐ์ง ์ ๋ฐ์ ๊ฑธ์ณ AI ์ง์ ๋ฐ ํ์ฅ์ด ์ฉ์ดํฉ๋๋ค.
MCP Server Components์๋ ์๋์ ๊ฐ์ ํญ๋ชฉ์ด ์์ต๋๋ค.
- Tools (Model-controlled): LLM์ด ํน์ ์์ ์ ์ํํ๊ธฐ ์ํด ํธ์ถํ ์ ์๋ ๊ธฐ๋ฅ(๋๊ตฌ)์ผ๋ก์, API์ ๊ฐ์ด ํน์ ํ action์ ์ํํฉ๋๋ค.
tools = await session.list_tools()
- Resources (Application-controlled): ์์ฑํ AI ์ดํ๋ฆฌ์ผ์ด์ ์ด ์ ๊ทผ ํ ์ ์๋ ๋ฐ์ดํฐ ์์ค์ ๋๋ค. ๋ณต์กํ ๊ณ์ฐ(significant computation)์ด๋ ๋ถ์์ฉ(side effect)์์ด ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ฌ ์ ์์ต๋๋ค.
resources = await session.list_resources()
- Prompts (User-controlled): tool๋ resource๋ฅผ ์ฌ์ฉํ ๋์ ์ด์ฉํ๋ ์ฌ์ ์ ์๋ ํ ํ๋ ์ผ๋ก์ ์ถ๋ก (inference)์ ์ ์ ํํ ์ ์์ต๋๋ค.
prompts = await session.list_prompts()
LangChain MCP Adapter
LangChain MCP Adapter๋ MCP๋ฅผ LangGraph agent์ ํจ๊ป ์ฌ์ฉํ ์ ์๊ฒ ํด์ฃผ๋ ๊ฒฝ๋์ ๋ฉํผ(lightweight wrapper)๋ก์ MIT ๊ธฐ๋ฐ์ ์คํ์์ค์ ๋๋ค. MCP Adapter์ ์ฃผ๋ ์ญํ ์ MCP server๋ฅผ ์ํ tool๋ค์ ์ ์ํ๊ณ , MCP client์์ tools์ ์ ๋ณด๋ฅผ ์กฐํํ๊ณ LangGraph์ tool node๋ก ์ ์ํ์ฌ ํ์ฉํ ์ ์๋๋ก ๋์์ค๋๋ค.
์ฌ์ ์ค๋น
MCP์ LangChain MCP Adapter๋ฅผ ์๋์ ๊ฐ์ด ์ค์นํฉ๋๋ค.
pip install mcp langchain-mcp-adapters
MCP Server
RAG ๊ฒ์์ ์ํ MCP server๋ ์๋์ ๊ฐ์ด ์ ์ํ ์ ์์ต๋๋ค. Server์ transport๋ฅผ "stdio"๋ก ์ง์ ํ๋ฉด server๋ฅผ ์ง์ ์คํ์ํค์ง ์๋๋ผ๋, client๊ฐ server์ python code๋ฅผ ์ง์ ์คํํ ์ ์์ด์ ํธ๋ฆฌํฉ๋๋ค.
from mcp.server.fastmcp import FastMCP
mcp = FastMCP(
name = "Search",
instructions=(
"You are a helpful assistant. "
"You can search the documentation for the user's question and provide the answer."
),
)
@mcp.tool()
def search(keyword: str) -> str:
"search keyword"
return retrieve_knowledge_base(keyword)
if __name__ =="__main__":
print(f"###### main ######")
mcp.run(transport="stdio")
Server๋ ์์ฒญ์ด ๋ค์ด์ค๋ฉด, retrieve_knowledge_base()๋ก RAG ๊ฒ์์ ์ํํฉ๋๋ค. Server์ python code๋ ๊ฒฝ๋(lightweight)์ด์ด์ผ ํ๋ฏ๋ก, ์๋์ ๊ฐ์ด lambda๋ฅผ triggerํ๋ ๋ฐฉ์์ผ๋ก ๊ตฌ์ฑํ์์ต๋๋ค. Lambda์์๋ retrieve, grade, generation์ ๋์์ ์ํํฉ๋๋ค. ์๋์ ๊ฐ์ด "model_name"์ ์ง์ ํ ์ ์๊ณ , ํ์์ ๋ฐ๋ผ์๋ "grading"์ ์ ํ์ ์ผ๋ก ์ฌ์ฉํ ์ ์์ต๋๋ค. ๋ํ ๋ณ๋ ฌ์ฒ๋ฆฌ๋ก ์๋๋ฅผ ๋น ๋ฅด๊ฒ ํ๊ณ ์ถ์ ๊ฒฝ์ฐ์์ "multi_region"์ "Enable"๋ก ์ค์ ํฉ๋๋ค. ์์ธํ ์ฝ๋๋ lambda-rag๋ฅผ ์ฐธ์กฐํฉ๋๋ค.
def retrieve_knowledge_base(query):
lambda_client = boto3.client(
service_name='lambda',
region_name=bedrock_region
)
functionName = f"lambda-rag-for-{projectName}"
payload = {
'function': 'search_rag',
'knowledge_base_name': knowledge_base_name,
'keyword': query,
'top_k': numberOfDocs,
'grading': "Enable",
'model_name': model_name,
'multi_region': multi_region
}
output = lambda_client.invoke(
FunctionName=functionName,
Payload=json.dumps(payload),
)
payload = json.load(output['Payload'])
return payload['response'], []
MCP Client
MCP client์ด ํ๋์ MCP server๋ง ๋ณผ ๊ฒฝ์ฐ์๋ ์๋์ ๊ฐ์ด stdio_client์ StdioServerParameters๋ฅผ ์ด์ฉํด ๊ตฌํํ ์ ์์ต๋๋ค. MCP server์ ๋ํ ์ ๋ณด๋ config.json์์ ์ฝ์ด์ค๊ฑฐ๋ streamlit์์ ์ฌ์ฉ์๊ฐ ์ ๋ ฅํ ์ ๋ณด๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค. load_mcp_server_parameters()์์๋ mcp_json์ ์ฝ์ด์์ StdioServerParameters์ ๊ตฌ์ฑํฉ๋๋ค. config.json์ MCP server์ ๋ํ ์ ๋ณด๋ AWS CDK๋ก ๋ฐฐํฌํ ์์ฑ๋๋ output์์ ๊ฐ์ ธ์ต๋๋ค.
from mcp import ClientSession, StdioServerParameters
def load_mcp_server_parameters():
mcp_json = json.loads(mcp_config)
mcpServers = mcp_json.get("mcpServers")
command = ""
args = []
if mcpServers is not None:
for server in mcpServers:
config = mcpServers.get(server)
if "command" in config:
command = config["command"]
if "args" in config:
args = config["args"]
break
return StdioServerParameters(
command=command,
args=args
)
์๋์ ๊ฐ์ด MCP server์ ๋ํ ์ ๋ณด๋ก stdio_client๋ฅผ ๊ตฌ์ฑํฉ๋๋ค. ์ด๋ tools์ ๋ํ ์ ๋ณด๋ฅผ load_mcp_tools๋ก ๊ฐ์ ธ์ต๋๋ค. Agent์์๋ tool ์ ๋ณด๋ฅผ bindํ๊ณ ainvoke๋ฅผ ์ด์ฉํด ์์ฒญ๋ ๋์์ ์ํํฉ๋๋ค.
from mcp.client.stdio import stdio_client
from langchain_mcp_adapters.tools import load_mcp_tools
async def mcp_rag_agent_single(query, st):
server_params = load_mcp_server_parameters()
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)
with st.status("thinking...", expanded=True, state="running") as status:
agent = create_agent(tools)
agent_response = await agent.ainvoke({"messages": query})
result = agent_response["messages"][-1].content
st.markdown(result)
st.session_state.messages.append({
"role": "assistant",
"content": result
})
return result
MCP client๋ ์๋์ ๊ฐ์ด ์คํํฉ๋๋ค. ๋น๋๊ธฐ์ ์ผ๋ก ์คํํ๊ธฐ ์ํด์ asyncio๋ฅผ ์ด์ฉํ์์ต๋๋ค. ์ดํ ์ฌ์ฉ์๊ฐ UI์์ MCP Config๋ฅผ ์ ๋ฐ์ดํธํ๋ฉด ์ ๋ณด๋ฅผ ์ ๋ฐ์ดํธ ํ ์ ์์ต๋๋ค.
asyncio.run(mcp_rag_agent_single(query, st))
์๋ฒ ์ ๋ณด๊ฐ ์ฌ๋ฟ์ธ ๊ฒฝ์ฐ์ langchain-mcp-adapters์์ ์ ๊ณตํ๋ MultiServerMCPClient์ ์ด์ฉํฉ๋๋ค. ๋จผ์ , ์๋์ ๊ฐ์ด ์๋ฒ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ต๋๋ค.
def load_multiple_mcp_server_parameters():
mcp_json = json.loads(mcp_config)
mcpServers = mcp_json.get("mcpServers")
server_info = {}
if mcpServers is not None:
command = ""
args = []
for server in mcpServers:
config = mcpServers.get(server)
if "command" in config:
command = config["command"]
if "args" in config:
args = config["args"]
server_info[server] = {
"command": command,
"args": args,
"transport": "stdio"
}
return server_info
์ดํ ์๋์ ๊ฐ์ด MCP server์ ๋ณด์ MultiServerMCPClient๋ก client๋ฅผ ์ ์ํฉ๋๋ค. MCP server๋ก ๋ถํฐ ๊ฐ์ ธ์จ tool ์ ๋ณด๋ client.get_tools()๋ก ๊ฐ์ ธ์์ agent๋ฅผ ์์ฑํ ๋์ ์ฌ์ฉํฉ๋๋ค. Single MCP server์ ๋ง์ฐฌ๊ฐ์ง๋ก ainvoke๋ก ์คํํ์ฌ ๊ฒฐ๊ณผ๋ฅผ ์ป์ ์ ์์ต๋๋ค.
from langchain_mcp_adapters.client import MultiServerMCPClient
asyncio.run(mcp_rag_agent_multiple(query, st))
async def mcp_rag_agent_multiple(query, st):
server_params = load_multiple_mcp_server_parameters()
async with MultiServerMCPClient(server_params) as client:
with st.status("thinking...", expanded=True, state="running") as status:
tools = client.get_tools()
agent = create_agent(tools)
response = await agent.ainvoke({"messages": query})
result = response["messages"][-1].content
st.markdown(result)
st.session_state.messages.append({
"role": "assistant",
"content": result
})
return result
์ฌ๊ธฐ์๋ customize๊ฐ ์ฉ์ดํ๋๋ก agent๋ฅผ ์ ์ํ์์ต๋๋ค.
def create_agent(tools):
tool_node = ToolNode(tools)
chatModel = get_chat(extended_thinking="Disable")
model = chatModel.bind_tools(tools)
class State(TypedDict):
messages: Annotated[list, add_messages]
def call_model(state: State, config):
system = (
"๋น์ ์ ์ด๋ฆ์ ์์ฐ์ด๊ณ , ์ง๋ฌธ์ ์น๊ทผํ ๋ฐฉ์์ผ๋ก ๋๋ตํ๋๋ก ์ค๊ณ๋ ๋ํํ AI์
๋๋ค."
"์ํฉ์ ๋ง๋ ๊ตฌ์ฒด์ ์ธ ์ธ๋ถ ์ ๋ณด๋ฅผ ์ถฉ๋ถํ ์ ๊ณตํฉ๋๋ค."
"๋ชจ๋ฅด๋ ์ง๋ฌธ์ ๋ฐ์ผ๋ฉด ์์งํ ๋ชจ๋ฅธ๋ค๊ณ ๋งํฉ๋๋ค."
"ํ๊ตญ์ด๋ก ๋ต๋ณํ์ธ์."
)
try:
prompt = ChatPromptTemplate.from_messages(
[
("system", system),
MessagesPlaceholder(variable_name="messages"),
]
)
chain = prompt | model
response = chain.invoke(state["messages"])
return {"messages": [response]}
def should_continue(state: State) -> Literal["continue", "end"]:
messages = state["messages"]
last_message = messages[-1]
if isinstance(last_message, AIMessage) and last_message.tool_calls:
return "continue"
else:
return "end"
def buildChatAgent():
workflow = StateGraph(State)
workflow.add_node("agent", call_model)
workflow.add_node("action", tool_node)
workflow.add_edge(START, "agent")
workflow.add_conditional_edges(
"agent",
should_continue,
{
"continue": "action",
"end": END,
},
)
workflow.add_edge("action", "agent")
return workflow.compile()
return buildChatAgent()
MCP Servers์ ํ์ฉ
Model Context Protocol servers์์๋ ์๋์ ๊ฐ์ ์๋ฒ๋ค์ ๋ํ ์ ๋ณด๋ฅผ ์ ๊ณตํ๊ณ ์์ต๋๋ค.
Smithery์์ MCP server๋ฅผ ์ฐพ์๋ณด๊ณ ํ์ํ ์๋ฒ๋ฅผ ์ฐพ์ผ๋ฉด ์ ์ํ ์ ์๋ MCP ์๋ฒ ์ ๋ณด๋ฅผ JSON ํํ๋ก ์กฐํํ ์ ์์ต๋๋ค.
Smithery - Google Search Server์์ ํ์ธํ ๊ตฌ๊ธ ๊ฒ์์ฉ MCP ์๋ฒ ์ ๋ณด๋ ์๋์ ๊ฐ์ต๋๋ค. ๊ฒ์์์ง ID์ API Key๋ฅผ ํ์๋ก ํฉ๋๋ค.
{
"mcpServers": {
"google-search-mcp-server": {
"command": "npx",
"args": [
"-y",
"@smithery/cli@latest",
"run",
"@gradusnikov/google-search-mcp-server",
"--config",
"{\"googleCseId\":\"b5cd8c527fbd64b72\",\"googleApiKey\":\"AIzbSyDQlYpck8-9TbBSuxoew1luOGVB6unRPNk\"}"
]
}
}
}
์๋์ ๊ฐ์ด json ํ์์ ์๋ฒ์ ๋ณด๋ฅผ ์ ๋ฐ์ดํธ ํ ์ ์์ต๋๋ค. ์๋์์๋ mcp-server.py์์ ์ ์ํ search๋ฅผ ์ด์ฉํ๊ณ ์์ต๋๋ค.
{
"mcpServers": {
"search": {
"command": "python",
"args": [
"application/mcp-server.py"
]
}
}
}
์คํํ๊ธฐ
Output์ environmentformcprag์ ๋ด์ฉ์ ๋ณต์ฌํ์ฌ application/config.json์ ์์ฑํฉ๋๋ค. "aws configure"๋ก credential์ด ์ค์ ๋์ด ์์ด์ผํฉ๋๋ค. ๋ง์ฝ visual studio code ์ฌ์ฉ์๋ผ๋ฉด config.json ํ์ผ์ ์๋ ๋ช ๋ น์ด๋ฅผ ์ฌ์ฉํฉ๋๋ค.
code application/config.json
์๋์ ๊ฐ์ด ํ์ํ ํจํค์ง๋ฅผ ์ค์นํฉ๋๋ค.
python3 -m venv venv
source venv/bin/activate
pip install streamlit streamlit_chat
pip install boto3 langchain_aws langchain langchain_community langgraph
deployment.md์ ๋ฐ๋ผ AWS CDK๋ก Lambda, Knowledge base, Opensearch Serverless์ ๋ณด์์ ํ์ํ IAM Role์ ์ค์นํฉ๋๋ค. ์ดํ ์๋์ ๊ฐ์ ๋ช ๋ น์ด๋ก streamlit์ ์คํํฉ๋๋ค.
streamlit run application/app.py
MCP Inspector
Development Mode์์ mcp server๋ฅผ ํ ์คํธ ํ๊ธฐ ์ํด MCP inspector๋ฅผ ์ด์ฉํ ์ ์์ต๋๋ค. ์๋์ ๊ฐ์ด cli๋ฅผ ์ค์นํฉ๋๋ค.
pip install 'mcp[cli]'
์ดํ ์๋์ ๊ฐ์ด ์คํํ๋ฉด ์ฝ๊ฒ mcp-server.py์ ๋์์ ํ ์คํธ ํ ์ ์์ต๋๋ค. ์คํ์ http://localhost:5173 ์ ๊ฐ์ URL์ ์ ๊ณตํฉ๋๋ค.
mcp dev mcp-server.py
AWS Cost Analysis
MCP tool๋ก์ ์๋์ ๊ฐ์ด AWS cost ์ ๋ณด๋ฅผ ๊ฐ์ ธ์์ ๋ถ์ํ ์ ์์ต๋๋ค.
from datetime import datetime, timedelta
import pandas as pd
def get_cost_analysis(days: str=30):
end_date = datetime.now()
start_date = end_date - timedelta(days=days)
ce = boto3.client('ce')
service_response = ce.get_cost_and_usage(
TimePeriod={
'Start': start_date.strftime('%Y-%m-%d'),
'End': end_date.strftime('%Y-%m-%d')
},
Granularity='MONTHLY',
Metrics=['UnblendedCost'],
GroupBy=[{'Type': 'DIMENSION', 'Key': 'SERVICE'}]
)
service_costs = pd.DataFrame([
{
'SERVICE': group['Keys'][0],
'cost': float(group['Metrics']['UnblendedCost']['Amount'])
}
for group in service_response['ResultsByTime'][0]['Groups']
])
# region cost
region_response = ce.get_cost_and_usage(
TimePeriod={
'Start': start_date.strftime('%Y-%m-%d'),
'End': end_date.strftime('%Y-%m-%d')
},
Granularity='MONTHLY',
Metrics=['UnblendedCost'],
GroupBy=[{'Type': 'DIMENSION', 'Key': 'REGION'}]
)
region_costs = pd.DataFrame([
{
'REGION': group['Keys'][0],
'cost': float(group['Metrics']['UnblendedCost']['Amount'])
}
for group in region_response['ResultsByTime'][0]['Groups']
])
# Daily Cost
daily_response = ce.get_cost_and_usage(
TimePeriod={
'Start': start_date.strftime('%Y-%m-%d'),
'End': end_date.strftime('%Y-%m-%d')
},
Granularity='DAILY',
Metrics=['UnblendedCost'],
GroupBy=[{'Type': 'DIMENSION', 'Key': 'SERVICE'}]
)
daily_costs = []
for time_period in daily_response['ResultsByTime']:
date = time_period['TimePeriod']['Start']
for group in time_period['Groups']:
daily_costs.append({
'date': date,
'SERVICE': group['Keys'][0],
'cost': float(group['Metrics']['UnblendedCost']['Amount'])
})
daily_costs_df = pd.DataFrame(daily_costs)
return {
'service_costs': service_costs,
'region_costs': region_costs,
'daily_costs': daily_costs_df
}
์คํ ๊ฒฐ๊ณผ
MCP๋ก RAG๋ฅผ ์กฐํํ์ฌ ํ์ฉํ๊ธฐ
error_code.pdf์ ๋ค์ด๋ก๋ ํ ํ์ ํ์ผ์ ์ ๋ก๋ํฉ๋๋ค. ์ดํ ์๋์ ๊ฐ์ด "๋ณด์ผ๋ฌ ์๋ฌ์ค ์์๊ณผ ๊ด๋ จ๋ ์๋ฌ ์ฝ๋๋ฅผ ๊ฒ์ํด์ฃผ์ธ์."์ ๊ฐ์ด ์ ๋ ฅํ๋ฉด mcp๋ฅผ ์ด์ฉํด tool์ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ค๊ณ , search tool๋ก ์ป์ด์ง ์ ๋ณด๋ฅผ ์ด์ฉํด ์๋์ ๊ฐ์ ์ ๋ณด๋ฅผ ๋ณด์ฌ์ค ์ ์์ต๋๋ค. ์ด๋ search tool์ lambda๋ฅผ ์คํํ๋๋ฐ lambda์์๋ ์์ ๊ด๋ฆฌํ RAG ์๋น์ค์ธ knowledge base๋ฅผ ์ด์ฉํ์ฌ ๊ฒ์์ด๋ฅผ ์กฐํํ๊ณ ๊ด๋ จ์ฑ์ ํ๊ฐํ ํ์ ๊ด๋ จ๋ ๋ฌธ์๋ง์ ์ ๋ฌํฉ๋๋ค. Agent๋ RAG๋ฅผ ์กฐํํ์ฌ ์ป์ด์ง ์ ๋ณด๋ก ๋ต๋ณ์ ์๋์ ๊ฐ์ด ๊ตฌํฉ๋๋ค.
MCP๋ก ์ธํฐ๋ท ๊ฒ์์ ํ์ฌ ํ์ฉํ๊ธฐ
smithery-Tavily์ ์ ์ํ์ฌ ํ๊ฒฝ์ ๋ง๋ ์ค์ ๊ฐ์ ์ป์ด์ต๋๋ค. ์๋๋ Mac/Linux์ JSON format์ ์ ์ ์ ๋ณด์ ๋๋ค.
{
"mcpServers": {
"mcp-tavily": {
"command": "npx",
"args": [
"-y",
"@smithery/cli@latest",
"run",
"mcp-tavily",
"--key",
"132c5abd-6f2e-4e42-89a1-d0b1fcb75613"
]
}
}
}
์๋๋ ๊ธฐ๋ณธ ์ค์ ๋ RAG๋ฅผ ์ํ ์ ๋ณด์ ๋๋ค.
{
"mcpServers": {
"search": {
"command": "python",
"args": [
"application/mcp-server.py"
]
}
}
}
์๋๋ multiple mcp server๋ฅผ ์ค์ ์ config ์ ๋๋ค.
{
"mcpServers":{
"RAG":{
"command":"python",
"args":[
"application/mcp-server.py"
]
},
"mcp-tavily":{
"command":"npx",
"args":[
"-y",
"@smithery/cli@latest",
"run",
"mcp-tavily",
"--key",
"132c5abd-6f2e-4e42-89a1-d0b1fcb75613"
]
}
}
}
์ด ์ ๋ณด๋ฅผ ์๋์ ๊ฐ์ด ์ผ์ชฝ ๋ฉ๋ด์ MCP Config์ ๋ณต์ฌํฉ๋๋ค.
์ดํ ๋ฉ๋ด์์ "Agent"๋ฅผ ์ ํํ์ ์๋์ ๊ฐ์ด "๊ฐ๋จ์ญ ๋ง์ง์?"๋ผ๊ณ ์ ๋ ฅํ ๊ฒฐ๊ณผ๋ฅผ ํ์ธํฉ๋๋ค.
AWS Cost Analysis
"์ง๋ ํ๋ฌ๊ฐ์ AWS ๋น์ฉ์ ์์ฝํด์ฃผ์ธ์." ์ ๋ ฅํ์ ๊ฒฐ๊ณผ๋ฅผ ํ์ธํฉ๋๋ค.
Reference
Using MCP with LangGraph agents
Understanding MCP From Scratch
"Vibe Coding" LangGraph apps with llms.txt and MCP
MCP LLMS-TXT Documentation Server
Model Context Protocol (MCP) and Amazon Bedrock
Model Context Protocol servers
Using LangChain With Model Context Protocol (MCP)
Cursor AI ๋ง๊ณ , ๋๋ง์ #MCP ์์ด์ ํธ ์ฑ ๋ง๋ค์ด ๋ณด๊ธฐ!