우리는 새로운 종류의 소프트웨어의 문턱에 서 있습니다. Andrej Karpathy는 최근 YC Startup School 기조 연설에서 자연어가 주요 프로그래밍 인터페이스가 되고 대규모 언어 모델이 계산 엔진이자 자율 협력자 역할을 하는 Software 3.0 세상을 설명했습니다.
개발자가 명시적 명령어를 작성했던 Software 1.0, 신경망이 데이터에서 패턴을 학습했던 Software 2.0과 달리 Software 3.0은 자연어 위에서 실행됩니다. 우리의 프롬프트가 프로그램이 되고, LLM이 우리의 의도를 실행 가능한 행동으로 변환합니다.
이 튜토리얼에서는 Novita AI 샌드박스에 원격 접근 권한을 제공하는 MCP 서버를 구축하여 AI 에이전트가 안전하게 코드를 실행할 수 있게 합니다. 에이전트 자체는 mcp-use 라이브러리로 생성되며, 이 라이브러리는 MCP 서버와의 통신도 자동으로 관리합니다.
MCP(모델 컨텍스트 프로토콜)란?
MCP(Model Context Protocol)는 AI 모델이 외부 서비스, 도구, 데이터 소스와 통신할 수 있도록 Anthropic이 개발한 오픈 표준입니다. "AI를 위한 USB-C"라고 생각하면 됩니다. 에이전트와 외부 세계 사이의 표준 인터페이스를 제공합니다.
세 가지 핵심 구성 요소:
- 도구(Tools): 서버가 노출하는 호출 가능한 함수/API(예: 웹 브라우징, 코드 실행).
- 리소스(Resources): 서버가 제공하는 외부 데이터로, 일반적으로 AI 에이전트의 컨텍스트로 사용됩니다(예: 파일, 메타데이터, 데이터셋).
- 프롬프트(Prompts): 위 도구나 리소스와 상호작용할 때 에이전트의 행동을 안내하는 상세 지침입니다.
MCP의 아키텍처와 구성 요소에 대한 자세한 내용은 첫 MCP 서버 구축 블로그를 확인하세요.
AI 도구 통합에서 MCP가 중요한 이유
MCP는 AI 에이전트와 외부 시스템 간의 양방향 통신을 구축합니다. 이를 통해 LLM을 맞춤형 도구에 쉽게 "연결"할 수 있으며, 통합 작업을 줄이고 오류 가능성을 최소화합니다.
mcp-use 라이브러리 소개

mcp-use 라이브러리는 MCP 서버와 상호작용하는 AI 에이전트 구축을 단순화하는 Python 패키지입니다. 에이전트 생성과 MCP 서버와의 통신을 처리하여 외부 도구와 데이터 소스에 접근할 수 있게 해주므로, 애플리케이션 로직에만 집중할 수 있습니다.
Novita AI 샌드박스 및 모델 API 개요

샌드박스란 무엇이며 왜 중요한가
샌드박스는 신뢰할 수 없는 코드를 호스트 시스템에 영향을 주지 않고 실행할 수 있는 안전하고 격리된 런타임 환경입니다. 기본적으로 AI 에이전트가 코드, 명령어를 실행하고 파일을 생성하는 등의 작업을 할 수 있는 경량 가상 컴퓨터입니다.
Novita AI는 이 샌드박스를 클라우드에서 제공하여 에이전트가 필요할 때 빠르게 접근할 수 있도록 하며, 사용된 리소스에 따라 초 단위로 유연하게 과금됩니다.
Novita 샌드박스의 주요 기능:
- 안전한 격리: 각 샌드박스는 격리된 파일 시스템과 환경을 가지므로 데이터를 보호하고 의도치 않은 상호작용을 방지합니다.
- 빠른 시작: 샌드박스 인스턴스는 평균 약 200ms 이내에 시작되므로 지연 시간이 짧은 시나리오에 이상적입니다.
- 다국어 지원: Python, JavaScript, TypeScript 등 여러 프로그래밍 언어로 코드를 실행할 수 있습니다.
- 빠른 일시 중지 및 재개: 언제든지 샌드박스를 일시 중지하고 필요할 때 재개할 수 있으며, 파일 시스템과 프로세스 상태가 완전히 복원됩니다.
- 백그라운드 실행: 백그라운드 작업 실행을 지원하며 결과를 기다려야 하는 시나리오에 적합합니다.
Novita 모델 API:

Novita는 OpenAI, Google, DeepSeek, Qwen 등 주요 연구소의 방대한 오픈 소스 AI 모델 라이브러리를 제공합니다. 여기에는 언어, 비전, 오디오, 비디오, 임베딩을 위한 모델이 포함됩니다. 또한 당사의 언어 모델은 OpenAI SDK와 완벽하게 호환되므로, 클라이언트에서 기본 URL과 API 키만 업데이트하고 Novita 모델을 선택하면 OpenAI에서 Novita로 전환할 수 있습니다.
| from openai import OpenAI client = OpenAI( base_url=“https://api.novita.ai/v3/openai”, api_key=“ ) |
개발 환경 설정
시작하려면 GitHub 저장소를 클론하고, 깨끗한 Python 환경을 설정하고, 모든 필수 종속성을 설치하고, Novita AI 키를 확보합니다.
GitHub 저장소를 클론하고 uv로 종속성 설치하기
1. uv 설치(경량 Python 패키지 관리자)
| pip install uv |
2. 저장소(GitHub repo)를 클론하고 해당 디렉토리로 이동합니다.
| git clone https://github.com/Studio1HQ/mcp\_remote\_execution.git cd mcp_remote_execution |
3. uv 가상 환경을 생성하고 활성화합니다.
| # 가상 환경 생성 uv venv # 가상 환경 활성화 source .venv/bin/activate # Mac/Linux의 경우 # 또는 .venv\Scripts\activate # Windows의 경우 |
4. 프로젝트 종속성 설치
| # 종속성 설치 uv sync |
Novita AI 계정 생성 및 API 키 얻기
1. novita.ai에서 가입합니다.

2. 대시보드에서 사용자 프로필 아이콘에 마우스를 올리고 팝업에서 API Keys를 클릭합니다.

3. 키 관리 페이지에서 Add New Key를 클릭합니다. 팝업에 키 이름을 입력하고 Confirm을 클릭한 후 생성된 키를 복사합니다.

4. 프로젝트 디렉토리 안에 .env 파일을 만들고 아래 내용을 붙여넣습니다.
| NOVITA_API_KEY=“<여기에 NOVITA API KEY를 붙여넣으세요>” NOVITA_BASE_URL=“https://api.novita.ai/v3/openai” NOVITA_E2B_DOMAIN=“sandbox.novita.ai” NOVITA_E2B_TEMPLATE=“code-interpreter-v1” |
Novita AI 계정에 크레딧 추가
Novita 샌드박스를 사용하려면 계정에 크레딧을 추가해야 합니다. 대시보드 탭에서 **‘Billing’**을 클릭합니다. 그런 다음 결제 페이지에서 결제 수단을 추가하고 최소 $10 크레딧을 충전합니다.

MCP 서버와 AI 에이전트 통합 구축
이제 환경이 준비되었으니 구축을 시작하겠습니다. 이 과정은 두 부분으로 나뉩니다. 먼저 MCP 서버를 생성하는 과정을 살펴보고, 그런 다음 AI 에이전트 애플리케이션(MCP 클라이언트 역할)을 구축합니다. 하지만 시작하기 전에 MCP 서버가 사용할 샌드박스 관리자를 먼저 만듭니다.
샌드박스 관리자
이는 샌드박스 인스턴스를 시작하고 중지하는 역할을 합니다. 설정에서 서버를 한 번에 하나의 샌드박스 인스턴스로 제한합니다. 샌드박스 관리자는 샌드박스에서 Python 코드 실행과 셸 명령 실행도 처리합니다.
먼저 sandbox_manager.py에서 다음 매개변수를 사용하는 SandboxManager 클래스를 만듭니다.
- sandbox_template: 샌드박스 인스턴스를 생성하는 데 사용되는 템플릿입니다. 일반적으로 사용되는 Python 패키지(예: pandas, numpy)가 미리 설치된 "code-interpreter-v1"을 사용합니다.
- sandbox_domain: Novita AI 샌드박스 인스턴스에 연결하는 데 사용되는 도메인 엔드포인트입니다.
- sandbox_timeout: 샌드박스가 자동으로 종료되기 전까지 활성 상태로 유지되는 시간(초)입니다.
| from novita_sandbox.code_interpreter import Sandbox class SandboxManager: def __init__( self, sandbox_template: str, sandbox_domain: str, sandbox_timeout: int, ): self.sandbox_template = sandbox_template self.sandbox_domain = sandbox_domain self.sandbox_timeout = sandbox_timeout |
이제 샌드박스를 생성하고 중지하는 메서드를 추가합니다.
- 생성의 경우 sandbox_api_key를 받아 사용자의 새 샌드박스 인스턴스를 시작하고, 샌드박스 ID와 함께 성공 메시지 또는 문제가 발생한 경우 예외 메시지를 반환합니다.
- 중지의 경우 sandbox_api_key와 sandbox_id를 모두 받아 샌드박스에 연결하고 존재하면 중지합니다. 이전과 마찬가지로 결과에 따라 성공 메시지 또는 예외 메시지를 반환합니다.
| … class SandboxManager: … # 기존 코드 아래 def create_sandbox_session(self, sandbox_api_key: str) -> str: “”“ 새로운 샌드박스 인스턴스를 생성합니다. Args: sandbox_api_key (str): 샌드박스의 API 키입니다. Returns: str: 새 샌드박스의 샌드박스 ID가 포함된 성공 메시지 또는 오류 메시지. ”“” try: # 새 샌드박스 생성 sandbox = Sandbox.create( template=self.sandbox_template, api_key=sandbox_api_key, domain=self.sandbox_domain, timeout=self.sandbox_timeout, ) return f"Successfully created sandbox. Sandbox ID: {sandbox.sandbox_id}“ except Exception as e: return f"Failed to create new sandbox:{str(e)}” def stop_sandbox_session(self, sandbox_api_key: str, sandbox_id: str) -> str: “”“ 존재하는 샌드박스 인스턴스를 종료합니다. Args: sandbox_api_key (str): 샌드박스의 API 키입니다. sandbox_id (str): 샌드박스의 ID입니다. Returns: str: 종료된 샌드박스의 샌드박스 ID가 포함된 성공 메시지 또는 오류 메시지. ”“” try: # 샌드박스에 연결 sandbox = Sandbox.connect( api_key=sandbox_api_key, sandbox_id=sandbox_id, ) sandbox.kill() return f"Successfully killed Sandbox ID: {sandbox_id}“ except Exception as e: return f"Failed to kill Sandbox ID: {sandbox_id}\ {str(e)}” |
마지막으로, API 키와 ID를 통해 사용자의 샌드박스에 연결한 후 Python 코드와 셸 명령을 실행하는 메서드를 추가합니다. 모든 샌드박스 출력(예외 및 오류 포함)은 딕셔너리로 반환됩니다.
| … class SandboxManager: … # 기존 코드 아래 def run_python_code( self, python_code: str, sandbox_api_key: str, sandbox_id: str ) -> dict: “”“ 샌드박스에서 Python 코드를 실행합니다. 이미지 출력이 있으면 건너뜁니다. Args: python_code (str): 실행할 Python 코드입니다. sandbox_api_key (str): 샌드박스의 API 키입니다. sandbox_id (str): 샌드박스의 ID입니다. Returns: dict: stdout, 로그, 오류 등을 포함합니다. ”“” try: # 샌드박스에 연결 sandbox = Sandbox.connect( api_key=sandbox_api_key, sandbox_id=sandbox_id, ) execution = sandbox.run_code(python_code, language=“python”) return { # 이미지 출력은 건너뜁니다. “outputs”: [result for result in execution.results if not result.png], “logs”: execution.logs, “error”: execution.error, } except Exception as e: return {“error”: str(e)} def run_on_command_line( self, command: str, sandbox_api_key: str, sandbox_id: str ) -> dict: “”“ 샌드박스에서 명령어를 실행합니다. Args: command (str): 실행할 명령어입니다. sandbox_api_key (str): 샌드박스의 API 키입니다. sandbox_id (str): 샌드박스의 ID입니다. Returns: dict: 명령어의 출력과 실행 오류가 있으면 포함합니다. ”“” try: # 샌드박스에 연결 sandbox = Sandbox.connect( api_key=sandbox_api_key, sandbox_id=sandbox_id, ) result = sandbox.commands.run(command) return { “output”: { “stdout”: result.stdout, “stderr”: result.stderr, “exit_code”: result.exit_code, “error”: result.error, }, “execution error”: None, } except Exception as e: return {“output”: None, “execution error”: str(e)} |
MCP 서버 생성
이제 Sandbox Manager가 설정되었으니 mcp_server.py 작업을 할 차례입니다. 먼저 서버를 실행할 프레임워크인 FastMCP 인스턴스와 Sandbox Manager를 생성합니다. 또한 터미널에 아름답게 출력하기 위한 rich 콘솔 인스턴스를 만듭니다.
참고: Sandbox Manager에 전달되는 샌드박스 타임아웃은 이 서버에서 시작되는 모든 샌드박스에 사용됩니다. 각 샌드박스가 더 일찍 중지되지 않는 한 활성 상태(실행 중)로 유지될 수 있는 최대 시간(초)입니다.
| import asyncio import os from dotenv import load_dotenv from mcp.server.fastmcp import Context, FastMCP from rich.console import Console from rich.panel import Panel from rich.table import Table from starlette.requests import Request from sandbox_manager import SandboxManager # .env 변수 로드 load_dotenv() console = Console() # FastMCP 서버 초기화 mcp = FastMCP(“MCP_Server”) # 싱글톤 샌드박스 인스턴스용 샌드박스 관리자 초기화 sandbox_manager = SandboxManager( sandbox_template=os.getenv(“NOVITA_E2B_TEMPLATE”), sandbox_domain=os.getenv(“NOVITA_E2B_DOMAIN”), sandbox_timeout=900, # 900초(15분), 이후 샌드박스 인스턴스가 자동으로 종료됩니다. ) |
이제 사용자의 샌드박스에 연결하려면 API 키가 필요하므로, 서버에 대한 사용자 요청에서 이를 가져옵니다. 나중에 MCP 클라이언트에서 볼 수 있듯이, 이 키는 모든 요청의 인증 헤더에 전송됩니다. 즉, 서버 측에서 이 헤더에서 API 키를 추출하는 방법이 필요합니다.
FastMCP는 런타임에 요청을 보낸 사용자에 대한 정보를 보유하는 Context 객체를 제공합니다. 따라서 컨텍스트 객체를 받아 헤더에서 API 키를 추출하고 반환하거나, 키가 없으면 예외를 발생시키는 도우미 메서드 get_user_api_key를 만듭니다.
| … # 기존 코드 아래 def get_user_api_key(ctx: Context) -> str: “”“ 요청 헤더에서 API 키를 반환합니다. 없으면 예외를 발생시킵니다. ”“” request: Request = ctx.request_context.request # 요청 데이터 접근 auth_header = request.headers.get(“Authorization”) if auth_header: auth_header = auth_header.split(" ")[1] if not auth_header: raise Exception(“Missing API Key in Authorization Bearer header”) return auth_header |
이제 서버에 프롬프트, 도구, 리소스를 노출할 차례입니다. 이렇게 하려면 Python 함수에 @mcp.{prompt, tool, resource}() 데코레이터를 추가하기만 하면 됩니다. 에이전트가 샌드박스를 어떻게 사용해야 하는지에 대한 지침을 반환하는 프롬프트부터 시작하겠습니다.
| … # 기존 코드 아래 (참고: Console 표시 도우미 메서드는 간결성을 위해 생략됨) @mcp.prompt() def instructions_for_sandbox_use() -> str: “”“ 샌드박스 사용에 대한 필수 지침을 반환합니다. ”“” return “”“ 샌드박스 기능을 사용하려면 먼저 create_sandbox_session() 함수를 호출하여 새 샌드박스 세션을 생성해야 합니다. 그런 다음 run_python_code() 또는 run_on_command_line() 함수를 사용하여 샌드박스에서 실행할 수 있습니다. 작업이 끝나면 stop_sandbox_session() 함수를 호출하여 샌드박스 세션을 종료해야 합니다. 참고: - 샌드박스에는 일반적인 데이터 분석 패키지가 미리 설치되어 있지만, 특정 패키지가 설치되어 있는지 확실하지 않거나 누락된 패키지로 인해 코드에서 import 오류가 발생한 경우 설치 여부를 확인하고 설치할 수 있습니다. ”“” |
도구의 경우 sandbox_manager 인스턴스를 사용하여 사용자의 샌드박스를 생성, 중지 및 코드나 명령을 실행하는 메서드를 노출합니다.
참고: 아래 도구 메서드가 받는 인수 중 ctx: Context를 포함합니다. 이는 FastMCP에 요청 컨텍스트를 해당 매개변수에 자동으로 삽입하도록 지시하는데, 이는 의존성 주입이라고 하는 프로세스입니다. 그런 다음 이 컨텍스트를 도우미 메서드(get_user_api_key)에 전달하여 API 키가 존재하는지 확인합니다.
| … # 기존 코드 아래 @mcp.tool() def create_sandbox_session(ctx: Context) -> str: “”“ 샌드박스 인스턴스를 생성하고 샌드박스 ID가 포함된 성공 메시지 또는 오류 메시지를 반환합니다. ”“” try: return sandbox_manager.create_sandbox_session(get_user_api_key(ctx)) except Exception as e: return e @mcp.tool() def stop_sandbox_session(sandbox_id: str, ctx: Context) -> str: “”“ 존재하는 샌드박스 인스턴스를 종료합니다. ”“” try: return sandbox_manager.stop_sandbox_session(get_user_api_key(ctx), sandbox_id) except Exception as e: return e @mcp.tool() def run_python_code(python_code: str, sandbox_id: str, ctx: Context) -> dict: “”“ 샌드박스에서 Python 코드를 실행합니다. 이미지 출력이 있으면 건너뜁니다. Args: python_code (str): 실행할 Python 코드입니다. sandbox_id (str): 샌드박스의 ID입니다. 참고: ctx (Context)는 자동으로 전달되는 의존성 주입 객체입니다. Returns: dict: stdout, 로그, 오류 등을 포함합니다. ”“” console.print( Panel( python_code, title=“Agent Executing Python Code”, border_style=“blue”, ) ) try: result = sandbox_manager.run_python_code( python_code, get_user_api_key(ctx), sandbox_id ) # 결과 표시. 참고: 프로덕션이 아닌 테스트에서만 수행. display_sandbox_code_output(result) return result except Exception as e: return {“error”: str(e)} @mcp.tool() def run_on_command_line(command_line: str, sandbox_id: str, ctx: Context) -> dict: “”“ 샌드박스에서 명령어를 실행합니다. Args: command_line (str): 실행할 명령어입니다. sandbox_id (str): 샌드박스의 ID입니다. 참고: ctx (Context)는 자동으로 전달되는 의존성 주입 객체입니다. Returns: dict: 명령어의 출력과 실행 오류가 있으면 포함합니다. ”“” console.print( Panel( command_line, title=“Agent Executing Command Line”, border_style=“blue”, ) ) try: result = sandbox_manager.run_on_command_line( command_line, get_user_api_key(ctx), sandbox_id ) # 결과 표시. 참고: 프로덕션이 아닌 테스트에서만 수행. display_sandbox_command_output(result) return result except Exception as e: return {“execution error”: str(e)} |
이제 나중에 볼 데모 시나리오 중 하나를 위한 단일 리소스를 노출하겠습니다. 이 리소스는 사용자의 주식 포트폴리오 모의 데이터를 반환합니다. 프롬프트나 도구와 달리 리소스는 접근 가능한 URL을 지정해야 합니다.
| … # 기존 코드 아래 @mcp.resource(“data://user_stock_portfolio”) def get_user_portfolio() -> dict: “”“ 사용자의 주요 지수 ETF 및 개별 주식 포트폴리오 보유 현황을 반환합니다. Returns: dict: 티커 심볼, 수량, 평균 매수 가격이 포함된 포트폴리오 ”“” portfolio = { “holdings”: [ # 주요 지수 ETF { “ticker”: “SPY”, “name”: “SPDR S&P 500 ETF”, “quantity”: 4, “avg_purchase_price”: 670.13, “asset_type”: “ETF”, }, … # 간결성을 위해 생략 ] } return portfolio |
마지막으로 서버를 시작하는 코드를 추가합니다. stdio MCP 전송은 사용하지 않을 것입니다. Rich 콘솔이 터미널에 출력하는데, 이는 stdio를 차단하는 작업이기 때문입니다. 대신 streamable-http MCP 전송을 사용합니다(이것은 프로덕션에서도 사용할 전송 방식으로, 클라이언트와 서버 간의 원격 연결에 가장 적합합니다).
| … # 기존 코드 아래 if __name__ == “__main__”: # 서버 실행 # 참고: stdio 대신 streamable-http를 전송 프로토콜로 사용합니다. 콘솔에 출력하는데, 이는 stdio를 차단하기 때문입니다. # 또한 프로덕션에서는 stdio보다 SSE 또는 streamable-http를 사용해야 합니다. asyncio.run(mcp.run(transport=“streamable-http”)) |
휴, 이제 MCP 서버를 시작하여 실행 중인 URL을 얻을 수 있습니다. 이 URL은 AI 에이전트를 연결하는 데 필요합니다. 터미널에서 아래 명령어를 실행하세요.
| uv run mcp_server.py |
서버가 실행 중인 것을 확인할 수 있습니다. 실행 중인 URL을 기록해 두세요.

MCP 서버에 AI 에이전트 통합
이제 mcp_client.py에서 AI 에이전트 작업을 시작합니다. mcp-use 라이브러리는 이 과정을 쉽게 만들어 줍니다. 먼저 디버그 레벨을 INFO로 설정하여 에이전트가 무엇을 하고 있는지 확인할 수 있게 합니다. main 메서드에서 mcp 클라이언트의 config 딕셔너리를 만듭니다. 사용 가능한 mcp 서버를 지정하며, 이름(여기서는 “stock&sandbox”)과 mcp 서버가 실행 중인 URL(*/mcp를 추가하는 것을 잊지 마세요)을 포함합니다. 또한 사용자의 API 키를 “auth” 값으로 포함하는데, 이는 mcp-use에 의해 모든 요청의 Authorization Bearer 헤더에 자동으로 삽입됩니다.
mcp-use는 langchain-openai에 의존하므로 novita 기본 URL, API 키 및 LLM 모델 이름을 전달합니다. 이는 Novita가 OpenAI와 호환되기 때문에 작동합니다.
그리고 에이전트의 응답 외에도 서버에서 사용한 샌드박스의 ID(있다면)를 포함하고 싶습니다(이유는 나중에 설명합니다). 이를 위해 응답 형식을 나타내는 Pydantic 클래스를 정의합니다.
| import asyncio import os from datetime import datetime from typing import Optional import mcp_use from dotenv import load_dotenv from langchain_openai import ChatOpenAI from mcp_use import MCPAgent, MCPClient from pydantic import BaseModel, Field from rich.console import Console from rich.panel import Panel from rich.prompt import Prompt # 환경 변수 로드 load_dotenv() console = Console() # 참고: 1은 INFO 레벨, 2는 전체 상세 DEBUG 레벨, 0은 디버그 출력 없음. mcp_use.set_debug(1) class ResponseFormat(BaseModel): response: str id_of_used_sandbox: Optional[str] = Field( …, description=“사용된 샌드박스의 ID (있는 경우)” ) async def main(model: str, base_url: str, api_key: str): # 설정 딕셔너리 생성 config = { “mcpServers”: { “stock&sandbox”: { # mcp 서버가 실행 중인 URL이 다르면 아래를 변경하고, # /mcp를 추가하는 것을 잊지 마세요. “url”: “http://127.0.0.1:8000/mcp”, “auth”: api_key, } } } # 설정 딕셔너리로부터 MCPClient 생성 client = MCPClient(config) # LLM 생성 llm = ChatOpenAI(model=model, base_url=base_url, api_key=api_key) … |
그런 다음 LLM, MCP 클라이언트, max_steps(에이전트가 응답하기 전에 취할 수 있는 작업 수 제한)를 전달하고 memory_enabled를 True로 설정하여 mcp-use가 대화 기록을 처리하도록 합니다. 또한 현재 날짜와 시간을 포함하고 샌드박스 사용에 대한 사용자 지정 지침이 포함된 시스템 프롬프트를 제공합니다(일부 모델이 서버에 노출된 지침 프롬프트를 읽는 것을 잊어버리기 때문에 추가했습니다).
마지막으로 표준 대화 루프를 설정합니다. 사용자 입력을 받아 agent.run()에 전달하고 응답을 출력합니다. 샌드박스가 사용된 경우 서버에서 stop 메서드를 수동으로 호출하는 세션을 생성하여 안전 조치로 샌드박스를 닫습니다(모델이 닫는 것을 잊은 경우를 대비).
| … async def main(model: str, base_url: str, api_key: str): … # 기존 코드 아래 # 클라이언트로 에이전트 생성 agent = MCPAgent( llm=llm, client=client, max_steps=25, memory_enabled=True, # mcp-use가 대화 기록을 자동으로 처리합니다. system_prompt=f"“” 당신은 유용한 어시스턴트이며 현재 날짜는 {datetime.now().strftime(‘%Y-%m-%d’)}입니다. 반드시 기억하세요: - 도구 호출 전에 먼저 instructions_for_sandbox_use()를 호출하여 지침을 읽으십시오. - 사용자에게 응답하기 전에 샌드박스 사용 후 반드시 stop_sandbox_session()을 호출하십시오. “”“, ) console.print( Panel( ”[bold green]MCP 세션 시작됨[/bold green]\ 종료하려면 'quit()'를 입력하세요.“, title=“MCP Session”, border_style=“green”, ) ) while True: user_input = Prompt.ask(”\ [bold yellow]>>> 사용자 메시지[/bold yellow]“) if user_input.lower().strip() == “quit()”: break # 쿼리를 에이전트에 전달하고 응답을 기다립니다. response_obj = await agent.run(user_input, output_schema=ResponseFormat) console.print( f”\ [bold green]>>> 어시스턴트 응답: {response_obj.response} [/]" ) if response_obj.id_of_used_sandbox: # 샌드박스가 여전히 활성 상태이면 MCP 서버에서 종료를 트리거합니다. session = await client.create_session(“stock&sandbox”) await session.call_tool( name=“stop_sandbox_session”, arguments={“sandbox_id”: response_obj.id_of_used_sandbox}, ) await session.disconnect() |
마지막으로 클라이언트를 시작하는 코드를 추가합니다.
| … # 기존 코드 아래 if __name__ == “__main__”: asyncio.run( main( model=“qwen/qwen3-coder-480b-a35b-instruct”, base_url=os.getenv(“NOVITA_BASE_URL”), api_key=os.getenv(“NOVITA_API_KEY”), ) ) |
MCP AI 에이전트 테스트 실행:
터미널에서 아래 명령어를 실행하여 AI 에이전트 애플리케이션을 시작할 수 있습니다.
| uv run mcp_client.py |
다음은 프롬프트에 대한 데모 실행 동영상 링크입니다.
- 사용자 프롬프트 1: “저는 2,000달러가 있습니다. 지난 6개월간 미국 주요 주가 지수의 성과를 yfinance에서 가져오고, ML 모델을 실행하여 향후 2개월 동안 수익을 극대화할 수 있도록 이 투자금을 어떻게 배분할지 예측하세요.”(여기에 링크 삽입)
- 사용자 프롬프트 2: “미국 경제 디플레이션 위기의 여러 시뮬레이션을 실행하고, 가장 가능성 높은 시나리오를 선택하여 내 주식 포트폴리오에 미칠 영향을 설명하세요.”(여기에 링크 삽입)
프로덕션 MCP 서버를 위한 팁
이 튜토리얼은 Novita Sandbox로 작동하는 MCP 서버 구축에 초점을 맞추었지만, 프로덕션에 배포하려면 추가 고려 사항이 필요합니다.
올바른 전송 사용: *“stdio”*는 로컬 개발에 적합하지만, 프로덕션 MCP 서버는 위에서 한 것처럼 원격 연결을 위해 *“streamable-http”*를 사용해야 합니다.
인증 구현: 위에서 한 것처럼 mcp 서버 엔드포인트를 인증으로 보호하세요. 각 클라이언트가 필요한 도구와 리소스에만 접근할 수 있는 권한을 갖도록 하세요. 더 많은 인증 방법은 FastMCP 인증에서 확인할 수 있습니다.
로깅 활성화: 로거를 사용하여 서버 활동을 모니터링하고, 문제를 디버깅하며, 사용 패턴을 추적하세요. 이는 유지보수와 문제 해결에 필수적입니다.
속도 제한 및 할당량: 속도 제한과 할당량을 구현하여 서버를 남용으로부터 보호하세요. 이는 리소스 집약적인 도구를 노출할 때 특히 중요합니다.
문서화 및 버전 관리: MCP 서버의 API에 대한 명확한 문서와 버전 관리를 유지하여 개발자와 LLM이 더 쉽게 통합할 수 있도록 하세요.
결론
휴, 이제 AI 에이전트가 자연어 지침을 통해 원격으로 코드를 실행할 수 있는 MCP 서버를 구축할 수 있게 되었습니다. 이는 Software 3.0이 실제로 구현된 사례입니다.
이 튜토리얼에서 코드 실행 기능이 있는 MCP 서버를 구축하고, 샌드박스 생명 주기를 관리하며, mcp-use를 사용하여 서버에 연결되는 AI 에이전트를 만드는 방법을 배웠습니다. 다음으로 데이터베이스 접근, 웹 검색을 추가하거나 여러 서버를 하나의 에이전트에 연결하여 확장해 보세요. Novita를 방문하세요. AI 에이전트를 구축하는 데 필요한 모든 도구가 준비되어 있습니다.
Novita AI는 개발자가 간단한 API를 사용하여 AI 모델을 쉽게 배포할 수 있는 AI 클라우드 플랫폼이며, 동시에 구축과 확장을 위한 저렴하고 안정적인 GPU 클라우드를 제공합니다.
