MCP 서버를 Agent에 연결하는 일은 몇 줄이면 됩니다. 조심할 일은 연결한 뒤에 생깁니다. 남이 만든 서버의 도구를 내 Agent가 내 권한으로 부르게 되기 때문입니다. 삭제하는 도구가 섞여 있을 수도 있고 서버가 갑자기 꺼질 수도 있고 도구가 오류를 낼 수도 있습니다.
그래서 Agent와 서버 사이에 관문을 둡니다. 허용한 도구만 통과시키고 서버가 응답하지 않을 때를 대비하고 오류 메시지는 모델이 읽을 수 있게 돌려줍니다. 아래에서 상황을 하나 골라 호출이 어디서 멈추는지 보세요.
설명을 위한 예시 장면입니다. 세 상황은 모두 langchain-mcp-adapters와 Python MCP SDK로 직접 실행해 확인했습니다.
langchain-mcp-adapters의 MultiServerMCPClient는 여러 MCP 서버에 한꺼번에 연결해 도구를 LangChain 도구로 바꿔 줍니다. 서버마다 이름과 연결 방식을 적습니다. 내 컴퓨터의 서버는 stdio로 명령을 주고 원격 서버는 streamable_http로 주소와 인증 헤더와 시간 한도를 줍니다.
앞 글에서 만든 티켓 서버를 이 방식으로 연결해 직접 실행했습니다. 어댑터 0.3.2는 MCP SDK 1.x를 함께 설치하는데 2.3으로 만든 서버에도 stdio와 HTTP 둘 다 연결됐습니다.
client = MultiServerMCPClient(
{"tickets": {"transport": "stdio", "command": "python",
"args": ["ticket_server.py"]}, # 1 내 컴퓨터의 서버
"wiki": {"transport": "streamable_http",
"url": "https://wiki.example.com/mcp", # 예시 주소
"headers": {"Authorization": f"Bearer {TOKEN}"},
"timeout": 10}}, # 2 원격 서버
tool_interceptors=[allowlist], # 3 호출 전에 거르기
)
tools = await client.get_tools() # 4 서버마다 도구 찾기
agent = create_agent(model, tools=tools)출력은 예시입니다. 위 결과는 티켓 서버(stdio, HTTP)로 확인했고 wiki 주소는 예시라 실행하지 않았습니다. Agent 답은 모의 서버로 만든 것입니다.
command와 args로 서버를 실행하는 명령을 줍니다. 이 명령이 내 권한으로 실행되므로 출처를 모르는 명령은 넣지 않습니다.get_tools()가 서버마다 tools/list를 불러 도구를 모읍니다. 이 도구들을 create_agent에 그대로 넘깁니다.ALLOW = {"get_ticket", "list_tickets"} # 1 읽기 도구만
async def allowlist(request, handler):
if request.name not in ALLOW: # 2 목록에 없으면
return CallToolResult(isError=True, content=[TextContent(
type="text", text=f"{request.name}은 허용 목록에 없어 실행하지 않았습니다")])
return await handler(request) # 3 있으면 그대로 통과handler(request)를 부르면 원래대로 서버에 호출이 나갑니다.티켓 서버에도 위키 서버에도 search라는 도구가 있을 수 있습니다. 두 서버를 함께 연결하면 모델이 보는 목록에 같은 이름이 둘 나옵니다. 어느 서버의 검색인지 구분할 수 없습니다.
tool_name_prefix=True를 주면 서버 이름을 앞에 붙입니다. 직접 실행해 티켓 서버의 도구가 tickets_get_ticket과 tickets_list_tickets로 바뀌는 것을 확인했습니다. 허용 목록의 인터셉터는 접두어가 붙기 전 서버 쪽 이름(get_ticket)을 받는 것도 확인했습니다. 서버가 여럿이면 request.server_name까지 함께 보고 거릅니다.
MCP 공식 보안 문서는 권한 범위를 줄이라고 거듭 말합니다. 처음에는 읽기 같은 위험이 낮은 것만 열고 필요할 때 한 단계씩 넓힙니다. 넓은 권한을 한 번에 받아 두면 토큰이나 도구 하나가 새는 순간 피해가 커지기 때문입니다.
티켓 시스템에 도구가 다섯 개 있다고 해 봅니다. 도구를 눌러 허용을 바꾸고 모델이 모두 호출해 보게 해 보세요.
HTTP로 연결하는 원격 서버가 사용자 데이터를 다룬다면 인증이 필요합니다. MCP 규격은 OAuth 2.1을 바탕으로 한 흐름을 정의합니다. 서버는 보호된 자원을 지키는 쪽이고 클라이언트는 사용자를 대신해 접근을 요청하는 쪽이며 사용자의 동의와 토큰 발급은 인증 서버가 맡습니다.
인증은 선택 사항입니다. 내 컴퓨터에서 도는 stdio 서버는 이 흐름을 따르지 않고 환경에서 자격 증명을 가져옵니다. 단계를 눌러 흐름을 따라가 보세요.
MCP 서버는 내 Agent에게 도구와 설명을 건네는 외부 프로그램입니다. 공식 문서는 도구는 임의의 코드 실행에 해당하니 신중히 다루고 도구 동작을 설명한 글은 믿을 만한 서버에서 온 것이 아니라면 믿지 말라고 말합니다. 도구를 실행하기 전에 사용자의 명시적인 동의를 받아야 한다고도 적혀 있습니다.
위험을 네 가지로 나눠 정리했습니다. 하나씩 눌러 무슨 일이 생기고 어떻게 막는지 보세요.
try:
tools = await client.get_tools() # 1 서버가 꺼져 있으면 여기서 실패
except Exception as e:
tools = [] # 2 도구 없이 시작하고
notice = f"일부 도구를 쓸 수 없습니다: {type(e).__name__}" # 사용자에게 알린다출력은 예시입니다. 응답하지 않는 주소로 연결해 확인한 결과이고 오류 이름은 어댑터 버전에 따라 다를 수 있습니다.
get_tools()가 예외 묶음(ExceptionGroup)을 던졌습니다. 잡지 않으면 Agent 프로그램 전체가 시작하지 못합니다.다음 글에서는 만든 Agent가 잘 동작하는지 점검하는 평가와 실행 기록(트레이싱)을 알아보겠습니다.