Erstellen eines MCP-Servers für Remote-Code-Ausführung mit Novita Sandbox und der mcp-use-Bibliothek

Erstellen eines MCP-Servers für Remote-Code-Ausführung mit Novita Sandbox und der mcp-use-Bibliothek

Wir stehen an der Schwelle zu einer neuen Art von Software. In seiner kürzlichen Keynote auf der YC Startup School beschrieb Andrej Karpathy Software 3.0, eine Welt, in der natürliche Sprache zur primären Programmierschnittstelle wird und große Sprachmodelle sowohl als Rechenmaschinen als auch als autonome Mitarbeiter dienen.

Im Gegensatz zu Software 1.0, in der Entwickler explizite Anweisungen schrieben, oder Software 2.0, in der neuronale Netze Muster aus Daten lernten, läuft Software 3.0 auf natürlicher Sprache. Unsere Prompts werden zu Programmen, und LLMs übersetzen unsere Absichten in ausführbares Verhalten.

In diesem Tutorial erstellen wir einen MCP-Server, der Remote-Zugriff auf eine Novita AI Sandbox bietet, in der unser KI-Agent sicher Code ausführen kann. Der Agent selbst wird mit der mcp-use-Bibliothek erstellt, die auch die Kommunikation mit dem MCP-Server automatisch verwaltet.

Was ist MCP (Model Context Protocol)?

Das Model Context Protocol (MCP) ist ein von Anthropic entwickelter offener Standard, damit KI-Modelle mit externen Diensten, Tools und Datenquellen kommunizieren können. Man kann es sich als „USB-C für KI“ vorstellen; es bietet eine standardisierte Schnittstelle zwischen Agenten und der Außenwelt.

Die drei Kernkomponenten:

  1. Tools: Aufrufbare Funktionen/APIs, die vom Server bereitgestellt werden (z. B. Web-Browsing, Code-Ausführung).
  2. Ressourcen: Externe Daten, die vom Server bereitgestellt werden, normalerweise als Kontext für den KI-Agenten gedacht (z. B. Dateien, Metadaten, Datensätze).
  3. Prompts: Diese detaillierten Anweisungen sollen das Verhalten des Agenten bei der Interaktion mit den oben genannten Tools oder Ressourcen steuern.

Für einen tieferen Einblick in MCP, seine Architektur und Komponenten lesen Sie unseren Blogbeitrag zum Erstellen Ihres ersten MCP-Servers

Warum MCP für die Integration von KI-Tools wichtig ist

MCP ermöglicht eine bidirektionale Kommunikation zwischen KI-Agenten und externen Systemen. Dadurch lassen sich LLMs einfach in benutzerdefinierte Tools einbinden, während der Integrationsaufwand reduziert und das Fehlerpotenzial minimiert wird.

Einführung in die mcp-use-Bibliothek

mcp-use

Die mcp-use-Bibliothek ist ein Python-Paket, das die Erstellung von KI-Agenten, die mit MCP-Servern interagieren, vereinfacht. Sie übernimmt die Erstellung des Agenten und verwaltet die Kommunikation mit MCP-Servern, um auf externe Tools und Datenquellen zuzugreifen, sodass Sie sich nur auf Ihre Anwendungslogik konzentrieren können.

Übersicht über Novita AI Sandbox und Model API

agent sandbox

Novita AI Sandbox

Was eine Sandbox ist und warum sie wichtig ist

Eine Sandbox ist eine sichere, isolierte Laufzeitumgebung, in der nicht vertrauenswürdiger Code ausgeführt werden kann, ohne das Hostsystem zu beeinträchtigen. Im Grunde ist es ein leichtgewichtiger virtueller Computer, auf dem Ihr KI-Agent Code, Befehle ausführen, Dateien erstellen usw. kann.

Novita AI stellt diese Sandbox in der Cloud bereit, damit Ihr Agent sie bei Bedarf schnell nutzen kann, mit flexibler sekundengenauer Abrechnung basierend auf den verwendeten Ressourcen.

Hauptmerkmale der Novita-Sandbox:

  • Sichere Isolierung: Jede Sandbox erhält ein eigenes isoliertes Dateisystem und eine eigene Umgebung, die Daten schützt und unbeabsichtigte Interaktionen verhindert.
  • Schneller Start: Sandbox-Instanzen starten im Durchschnitt in unter ~200 ms, was sie ideal für Szenarien mit geringer Latenz macht.
  • Mehrsprachige Unterstützung: Sie können Code in mehreren Programmiersprachen ausführen, darunter Python, JavaScript, TypeScript und weitere.
  • Schnelles Pausieren und Fortsetzen: Pausieren Sie die Sandbox jederzeit und setzen Sie sie bei Bedarf fort, wobei Dateisystem- und Prozesszustand vollständig wiederhergestellt werden.
  • Hintergrundausführung: Unterstützt die Ausführung von Hintergrundaufgaben und eignet sich für Szenarien, in denen auf ein Ergebnis gewartet werden muss.

Novita Model API:

llm model list

Novita AI Models

Novita bietet eine umfangreiche Bibliothek mit Open-Source-KI-Modellen von führenden Forschungslaboren wie OpenAI, Google, DeepSeek und Qwen usw. Dazu gehören Modelle für Sprache, Vision, Audio, Video und Einbettungen. Unsere Sprachmodelle sind zudem vollständig kompatibel mit dem OpenAI-SDK, sodass der Wechsel von OpenAI zu Novita nur das Aktualisieren der Basis-URL und des API-Schlüssels in Ihrem Client sowie die Auswahl eines Novita-Modells erfordert.

from openai import OpenAI

client = OpenAI(
base_url=“https://api.novita.ai/v3/openai”,
api_key=“”,
)

Einrichtung Ihrer Entwicklungsumgebung

Um loszulegen, klonen wir das GitHub-Repository, richten eine saubere Python-Umgebung ein, installieren alle erforderlichen Abhängigkeiten und besorgen uns Novita AI-Schlüssel.

Klonen Sie das GitHub-Repository und installieren Sie Abhängigkeiten mit uv.

1. Installieren Sie uv (einen leichtgewichtigen Python-Paketmanager)

pip install uv

2. Klonen Sie das Repository (GitHub-Repo) und navigieren Sie in das Verzeichnis.

git clone https://github.com/Studio1HQ/mcp\_remote\_execution.git
cd mcp_remote_execution

3. Erstellen und aktivieren Sie die uv-virtuelle Umgebung

# Creates a virtual environment
uv venv

# Activate the virtual environment
source .venv/bin/activate # For Mac/Linux
# or
.venv\Scripts\activate # For Windows

4. Installieren Sie die Projektabhängigkeiten

# Install dependencies
uv sync

Erstellen Sie ein Novita AI-Konto und erhalten Sie einen API-Schlüssel

1. Registrieren Sie sich unter novita.ai.

novita ai login

2. Bewegen Sie den Mauszeiger im Dashboard über das Benutzerprofil-Symbol und klicken Sie im Pop-up auf API-Schlüssel.

novita ai api keys

3. Klicken Sie auf der Seite zur Schlüsselverwaltung auf Neuen Schlüssel hinzufügen. Geben Sie im Pop-up einen Namen für Ihren Schlüssel ein, klicken Sie auf Bestätigen und kopieren Sie anschließend den generierten Schlüssel.

novita ai api key detail page

4. Erstellen Sie nun im Projektverzeichnis eine .env-Datei und fügen Sie untenstehenden Inhalt ein.

NOVITA_API_KEY=“
NOVITA_BASE_URL=“https://api.novita.ai/v3/openai

NOVITA_E2B_DOMAIN=“sandbox.novita.ai
NOVITA_E2B_TEMPLATE=“code-interpreter-v1”

Laden Sie Guthaben auf das Novita AI-Konto auf.

Um die Novita-Sandbox zu nutzen, müssen Sie Guthaben auf Ihr Konto laden. Klicken Sie auf die Registerkarte „Dashboard“ auf Abrechnung. Fügen Sie anschließend auf der Abrechnungsseite eine Zahlungsmethode hinzu und laden Sie mindestens 10 $ Guthaben auf.

top up page on Novita AI

Erstellen der MCP-Server- und KI-Agenten-Integration

Nachdem unsere Umgebung eingerichtet ist, können wir mit der Erstellung beginnen. Dieser Prozess hat zwei Teile: Zuerst erstellen wir den MCP-Server, dann die KI-Agenten-Anwendung (die als MCP-Client fungiert). Bevor wir beginnen, erstellen wir den Sandbox-Manager, den der MCP-Server verwenden wird.

Der Sandbox-Manager

Dieser ist für das Starten und Stoppen von Sandbox-Instanzen verantwortlich. In unserer Einrichtung beschränken wir den Server auf jeweils eine einzelne Sandbox-Instanz. Der Sandbox-Manager übernimmt außerdem die Ausführung von Python-Code und Shell-Befehlen in der Sandbox.

Zuerst haben wir in sandbox_manager.py die Klasse SandboxManager, die die folgenden Parameter akzeptiert:

  • sandbox_template: Die Vorlage, die zum Erstellen einer Sandbox-Instanz verwendet wird. Wir verwenden „code-interpreter-v1“, die mit häufig verwendeten Python-Paketen (z. B. pandas, numpy) vorinstalliert ist.
  • sandbox_domain: Der Domänenendpunkt, der zum Verbinden mit der Novita AI-Sandbox-Instanz verwendet wird.
  • sandbox_timeout: Die Dauer (in Sekunden), die bestimmt, wie lange die Sandbox aktiv bleibt, bevor sie automatisch beendet wird.
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

Jetzt fügen wir Methoden zum Erstellen und Stoppen einer Sandbox hinzu.

  1. Zum Erstellen nehmen wir einen sandbox_api_key, verwenden ihn, um eine neue Sandbox-Instanz für den Benutzer zu starten, und geben eine Erfolgsmeldung mit der Sandbox-ID oder eine Fehlermeldung zurück, falls etwas schief geht.
  2. Zum Stoppen nehmen wir sowohl den sandbox_api_key als auch die sandbox_id, verbinden uns mit der Sandbox und stoppen sie, falls sie existiert. Wie zuvor geben wir eine Erfolgsmeldung oder eine Fehlermeldung zurück, je nach Ergebnis.

class SandboxManager:
… # below existing code
def create_sandbox_session(self, sandbox_api_key: str) -> str:
“”“
This will create a new sandbox instance.

Args:
sandbox_api_key (str): The API key for the sandbox.

Returns:
str: Success message with the sandbox ID of the new sandbox or error message.
”“”
try:

# create the new sandbox
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:
“”“
This will kill a sandbox instance if it exists.

Args:
sandbox_api_key (str): The API key for the sandbox.
sandbox_id (str): The ID of the sandbox.

Returns:
str: Success message with the sandbox ID of the killed sandbox or error message.
”“”
try:
# connect to sandbox
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)}”

Abschließend fügen wir Methoden zum Ausführen von Python-Code und Shell-Befehlen in der Sandbox eines Benutzers hinzu, nachdem wir uns über API-Schlüssel und ID damit verbunden haben. Alle Sandbox-Ausgaben (einschließlich Ausnahmen und Fehler) werden in einem Dictionary zurückgegeben.


class SandboxManager:
… # below existing code
def run_python_code(
self, python_code: str, sandbox_api_key: str, sandbox_id: str
) -> dict:
“”“
Runs the python code on the sandbox, and if there any image outputs they are skipped.

Args:
python_code (str): The python code to run.
sandbox_api_key (str): The API key for the sandbox.
sandbox_id (str): The ID of the sandbox.

Returns:
dict: Containing stdout, logs, error, etc.
”“”

try:
# connect to sandbox
sandbox = Sandbox.connect(
api_key=sandbox_api_key,
sandbox_id=sandbox_id,
)

execution = sandbox.run_code(python_code, language=“python”)

return {
# we will skip image outputs.
“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:
“”“
Runs the command on the sandbox.

Args:
command (str): The command to run.
sandbox_api_key (str): The API key for the sandbox.
sandbox_id (str): The ID of the sandbox.

Returns:
dict: Containing the output of the command and the execution error if any.
”“”

try:
# connect to sandbox
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)}

Erstellen des MCP-Servers

Nachdem der Sandbox-Manager eingerichtet ist, ist es Zeit, an mcp_server.py zu arbeiten. Zuerst erstellen wir eine Instanz von FastMCP, dem Framework, das den Server ausführt, sowie einen Sandbox-Manager. Außerdem erstellen wir eine Rich-Konsoleninstanz für eine schöne Ausgabe im Terminal.

Hinweis: Der an den Sandbox-Manager übergebene Sandbox-Timeout wird für jede auf diesem Server gestartete Sandbox verwendet. Es ist die maximale Zeit (in Sekunden), die jede Sandbox aktiv bleiben (laufen) kann, es sei denn, sie wird früher gestoppt.

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

# load .env variables
load_dotenv()

console = Console()

# Initialize FastMCP server
mcp = FastMCP(“MCP_Server”)

# Initialize sandbox manager for the singleton sandbox instance.
sandbox_manager = SandboxManager(
sandbox_template=os.getenv(“NOVITA_E2B_TEMPLATE”),
sandbox_domain=os.getenv(“NOVITA_E2B_DOMAIN”),
sandbox_timeout=900, # 900 seconds (15 minutes), sandbox instance will be killed automatically after.
)

Da wir einen API-Schlüssel benötigen, um uns mit der Sandbox eines Benutzers zu verbinden, holen wir ihn aus der Anfrage des Benutzers an den Server. Wie wir später im MCP-Client sehen werden, wird dieser Schlüssel in dem Autorisierungs-Header jeder Anfrage gesendet. Das bedeutet, wir brauchen eine Möglichkeit, den API-Schlüssel auf der Serverseite aus diesem Header zu extrahieren.

FastMCP stellt ein Context-Objekt bereit, das zur Laufzeit Informationen über den Benutzer enthält, der die Anfrage stellt. Also erstellen wir eine Hilfsmethode get_user_api_key, die ein Context-Objekt entgegennimmt, den API-Schlüssel aus dem Header extrahiert und zurückgibt oder eine Ausnahme auslöst, falls er fehlt.

… # below existing code
def get_user_api_key(ctx: Context) -> str:
“”“
Returns the API key from the request header if it exists otherwise raise an exception.
”“”

request: Request = ctx.request_context.request

# Access request data
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

Jetzt ist es Zeit, Prompts, Tools und Ressourcen auf unserem Server bereitzustellen. Dazu fügen wir einfach den Dekorator @mcp.{prompt, tool, resource}() zur Python-Funktion hinzu. Beginnen wir mit unserem Prompt, der Anweisungen zurückgibt, wie unser Agent die Sandbox verwenden soll.

… # below existing code (Note: Console display helper methods were skipped for brevity)

@mcp.prompt()
def instructions_for_sandbox_use() -> str:
“”“
RETURNS MUST READ INSTRUCTIONS FOR SANDBOX USE.
”“”
return “”“
When you want to use the sandbox function, you must first create a new sandbox session by calling the create_sandbox_session() function.
Then you can use the run_python_code() or run_on_command_line() function to run on the sandbox.
When you are done, you must kill the sandbox session by calling the stop_sandbox_session() function.

Note:
- The sandbox already comes pre-installed with the usual data analysis packages but if there’s a package you
are not sure exists or your code had an import error due to a missing package, you can check if it’s installed and if not install it.
”“”

Für die Tools stellen wir Methoden bereit, die die sandbox_manager-Instanz verwenden, um eine Sandbox zu erstellen, zu stoppen und Code oder Befehle in der Sandbox eines Benutzers auszuführen.

Hinweis: Unter den Argumenten, die die folgenden Tool-Methoden akzeptieren, fügen wir ctx: Context hinzu. Dies weist FastMCP an, den Anfragekontext automatisch in diesen Parameter einzufügen, ein Prozess, der als Abhängigkeitsinjektion bezeichnet wird. Anschließend holen wir den API-Schlüssel, falls er existiert, indem wir diesen Kontext an unsere Hilfsmethode (get_user_api_key) übergeben.

… # below existing code

@mcp.tool()
def create_sandbox_session(ctx: Context) -> str:
“”“
This will create a sandbox instance and return success message with the sandbox id or error message.
”“”
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:
“”“
This will kill a sandbox instance if it exists.
”“”
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:
“”“
Runs the python code on the sandbox, and if there any image outputs they are skipped.

Args:
python_code (str): The python code to run.
sandbox_id (str): The ID of the sandbox.

Note:
The ctx (Context) is a dependency injection object that is automatically passed.

Returns:
dict: Containing stdout, logs, error, etc.
”“”
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 the result. Note: only do this in test not in prod.
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:
“”“
Runs the command on the sandbox.

Args:
command_line (str): The command to run.
sandbox_id (str): The ID of the sandbox.

Note:
The ctx (Context) is a dependency injection object that is automatically passed.

Returns:
dict: Containing the output of the command and the execution error if any.
”“”
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 the result. Note: only do this in test not in prod.
display_sandbox_command_output(result)
return result

except Exception as e:
return {“execution error”: str(e)}

Jetzt stellen wir eine einzelne Ressource für eines unserer Demo-Szenarien bereit, das wir später sehen werden. Diese Ressource gibt ein Mock eines Aktienportfolios eines Benutzers zurück. Im Gegensatz zu Prompts und Tools erfordern Ressourcen die Angabe einer URL, unter der sie zugänglich sind.

… # below existing code

@mcp.resource(“data://user_stock_portfolio”)
def get_user_portfolio() -> dict:
“”“
Returns the user’s portfolio holdings across major index ETFs
and individual stocks.

Returns:
dict: Portfolio with ticker symbols, quantities, and average purchase prices
”“”
portfolio = {
“holdings”: [
# Major Index ETFs
{
“ticker”: “SPY”,
“name”: “SPDR S&P 500 ETF”,
“quantity”: 4,
“avg_purchase_price”: 670.13,
“asset_type”: “ETF”,
},
… # skipped for brevity
]
}

return portfolio

Abschließend fügen wir den Code hinzu, der unseren Server startet. Wir verwenden nicht den stdio-MCP-Transport, da die Rich-Konsole auf das Terminal druckt, was eine blockierende Operation ist, die stören würde. Stattdessen verwenden wir den streamable-http-MCP-Transport (dies ist auch das, was Sie in der Produktion verwenden sollten, da er am besten für Remote-Verbindungen zwischen Client und Server über HTTP geeignet ist).

… # below existing code

if __name__ == “__main__”:
# run the server
# Note: We use streamable-http as the transport protocol instead of stdio because we are printing to the console which would block stdio.
# Also in production you should use SSE or streamable-http rather than stdio.

asyncio.run(mcp.run(transport=“streamable-http”))

Puh, lassen Sie uns nun unseren MCP-Server starten, um die URL zu erhalten, unter der er läuft, die wir zum Verbinden unseres KI-Agenten benötigen. Führen Sie den folgenden Befehl im Terminal aus.

uv run mcp_server.py

Sie sollten sehen, dass der Server jetzt läuft. Notieren Sie sich die URL, unter der er läuft

run the mcp server

Integration des KI-Agenten mit dem MCP-Server

Jetzt arbeiten wir am KI-Agenten in mcp_client.py. Die mcp-use-Bibliothek macht diesen Prozess einfach. Zuerst setzen wir den Debug-Level auf INFO, um zu sehen, was der Agent tut. In der Hauptmethode erstellen wir ein Konfigurationsdictionary für den MCP-Client. Es gibt die verfügbaren MCP-Server an, wobei wir einen Namen (ich habe „stock&sandbox“ verwendet) und die URL, unter der der MCP-Server läuft (denken Sie daran, /mcp hinzuzufügen), angeben. Außerdem fügen wir den API-Schlüssel des Benutzers als Wert für „auth“ hinzu, der von mcp-use automatisch in den Autorisierungs-Bearer-Header jeder Anfrage eingefügt wird.

Da mcp-use auf langchain-openai basiert, übergeben wir die Novita-Basis-URL, den API-Schlüssel und den LLM-Modellnamen, was funktioniert, weil Novita mit OpenAI kompatibel ist.

Und zusätzlich zur Antwort des Agenten möchten wir die ID der Sandbox, die er auf dem Server verwendet hat, falls vorhanden, hinzufügen (wir erklären später warum). Dazu definieren wir eine Pydantic-Klasse, die unser Antwortformat repräsentiert.

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 environment variables
load_dotenv()

console = Console()

# Note: 1 for INFO level, 2 for full verbose DEBUG level and 0 for NO debug output.
mcp_use.set_debug(1)


class ResponseFormat(BaseModel):
response: str
id_of_used_sandbox: Optional[str] = Field(
…, description=“The id of the sandbox used if any”
)


async def main(model: str, base_url: str, api_key: str):

# Create configuration dictionary
config = {
“mcpServers”: {
“stock&sandbox”: {
# If the url the mcp server is running at is different replace below,
# also remember to add /mcp.
“url”: “http://127.0.0.1:8000/mcp”,
“auth”: api_key,
}
}
}

# Create MCPClient from configuration dictionary
client = MCPClient(config)

# Create LLM
llm = ChatOpenAI(model=model, base_url=base_url, api_key=api_key)

Anschließend erstellen wir den MCP-Agenten, indem wir das LLM, den MCP-Client, die maximale Anzahl von Schritten (welche die Aktionen begrenzt, die der Agent vor der Antwort ausführen kann) übergeben und den Speicher aktivieren, sodass mcp-use unseren Gesprächsverlauf verwaltet. Außerdem geben wir einen System-Prompt an, der das aktuelle Datum und die Uhrzeit sowie benutzerdefinierte Anweisungen zur Verwendung der Sandbox enthält (ich habe dies hinzugefügt, weil einige Modelle vergessen, die auf dem Server bereitgestellten Anweisungs-Prompts zu lesen).


async def main(model: str, base_url: str, api_key: str):

… # below existing code

# Create agent with the client
agent = MCPAgent(
llm=llm,
client=client,
max_steps=25,
memory_enabled=True, # mcp-use will auto handle the conversation history.
system_prompt=f"“”
You are a helpful assistant and the current date is {datetime.now().strftime(‘%Y-%m-%d’)}

MUST REMEMBER:
- Before any tool call first call instructions_for_sandbox_use() so you can read them.
- Ensure you call stop_sandbox_session() after using the sandbox before responding to the user.
“”“,
)

console.print(
Panel(
”[bold green]MCP Session Started[/bold green]\ Type ‘quit()’ to exit.“,
title=“MCP Session”,
border_style=“green”,
)
)

while True:
user_input = Prompt.ask(”\ [bold yellow]>>> User Message[/bold yellow]“)

if user_input.lower().strip() == “quit()”:
break

# Pass the query to the agent and await the response.
response_obj = await agent.run(user_input, output_schema=ResponseFormat)

console.print(
f”\ [bold green]>>> Assistant Response: {response_obj.response} [/]"
)


if response_obj.id_of_used_sandbox:
# Will trigger closure of sandbox on MCP server if it sill active.
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()

Zuletzt fügen wir den Code hinzu, der den Client startet:

… # below existing code

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”),
)
)

Testen des MCP-KI-Agenten:

Sie können die KI-Agenten-Anwendung starten, indem Sie den folgenden Befehl im Terminal ausführen

uv run mcp_client.py

Unten finden Sie Video-Links zu Demo-Durchläufen zu den folgenden Prompts:

  • Benutzer-Prompt 1: „Ich habe 2.000 $. Holen Sie die Performance der wichtigsten US-Aktienindizes von yfinance der letzten 6 Monate und führen Sie ML-Modelle aus, um vorherzusagen, wie Sie diese Investition aufteilen sollten, um die potenziellen Renditen in den nächsten 2 Monaten zu maximieren.“ (Link hier einfügen)
  • Benutzer-Prompt 2: „Führen Sie mehrere Simulationen eines wirtschaftlichen Deflationscrashs in den USA durch, wählen Sie den wahrscheinlichsten aus und erklären Sie die Auswirkungen, die er auf mein Aktienportfolio haben wird.“ (Link hier einfügen)

Tipps für MCP-Server in der Produktion

Während sich dieses Tutorial auf die Erstellung eines funktionsfähigen MCP-Servers mit Novita Sandbox konzentriert, erfordert die Bereitstellung in der Produktion zusätzliche Überlegungen:

Verwenden Sie den richtigen Transport: Während „stdio“ für die lokale Entwicklung funktioniert, sollten MCP-Server in der Produktion „streamable-http“ verwenden, um Remote-Verbindungen zu ermöglichen, genau wie wir es oben getan haben.

Implementieren Sie Authentifizierung: Wie wir es oben getan haben, stellen Sie sicher, dass Sie die Endpunkte Ihres MCP-Servers mit Authentifizierung sichern. Stellen Sie sicher, dass jeder Client nur die Berechtigung hat, auf die Tools und Ressourcen zuzugreifen, die er benötigt. Weitere Informationen zu Authentifizierungsmethoden finden Sie unter FastMCP-Authentifizierung

Aktivieren Sie Protokollierung: Verwenden Sie einen Logger, um die Serveraktivität zu überwachen, Probleme zu beheben und Nutzungsmuster zu verfolgen. Dies ist für Wartung und Fehlerbehebung unerlässlich.

Ratenbegrenzung und Kontingente: Schützen Sie Ihren Server vor Missbrauch, indem Sie Ratenbegrenzungen und Kontingente implementieren. Dies ist besonders wichtig, wenn Sie ressourcenintensive Tools bereitstellen.

Dokumentation und Versionierung: Pflegen Sie eine klare Dokumentation der API und Versionierung Ihres MCP-Servers, um die Integration für Entwickler und LLMs zu erleichtern.

Fazit

Puh, Sie können endlich einen MCP-Server erstellen, bei dem KI-Agenten Code über natürliche Sprachbefehle remote ausführen können – eine praktische Implementierung von Software 3.0 in Aktion.

In diesem Tutorial haben Sie gelernt, wie Sie einen MCP-Server mit Code-Ausführungsfunktion erstellen, Sandbox-Lebenszyklen verwalten und einen KI-Agenten mit mcp-use erstellen, der sich mit Ihrem Server verbindet. Probieren Sie als Nächstes aus, ihn um Datenbankzugriff, Websuche oder die Verknüpfung mehrerer Server mit einem Agenten zu erweitern. Gehen Sie zu Novita, wir haben die Tools, die Sie zum Erstellen Ihrer KI-Agenten benötigen.

Novita AI ist eine KI-Cloud-Plattform, die Entwicklern eine einfache Möglichkeit bietet, KI-Modelle über unsere einfache API bereitzustellen, und gleichzeitig eine erschwingliche und zuverlässige GPU-Cloud zum Erstellen und Skalieren bereitstellt.