Как упаковать LangGraph с помощью uv для автоматического запуска MCP серверов
Узнайте, как упаковать Python-приложения LangGraph с помощью uv для автоматического запуска необходимых MCP серверов, таких как Kubernetes. Полное руководство для устранения ручного управления зависимостями.
Как я могу упаковать Python-приложение LangGraph с помощью uv так, чтобы оно автоматически запускало серверы-предпосылки, такие как сервер Kubernetes MCP, вместо того чтобы требовать от пользователей вручную запускать эти зависимости перед использованием инструмента?
Упаковка приложения LangGraph с uv для автоматического запуска предварительных серверов
Чтобы упаковать приложение Python LangGraph с uv так, чтобы предварительные серверы, такие как Kubernetes MCP-сервер, запускались автоматически, необходимо настроить точки входа в файле pyproject.toml и создать скрипты-обертки, которые обрабатывают запуск зависимостей. Этот подход устраняет необходимость для пользователей вручную запускать предварительные службы перед использованием вашего приложения.
- Настройка структуры проекта
- Настройка точек входа
- Создание оберток для MCP-серверов
- Упаковка с uv
- Установка и использование
- Расширенная настройка
Настройка структуры проекта
Начните с правильной структуры проекта для вашего приложения LangGraph с интеграцией MCP-сервера:
my-langgraph-app/
├── pyproject.toml
├── src/
│ └── my_app/
│ ├── __init__.py
│ ├── main.py
│ ├── cli.py
│ └── mcp_servers/
│ ├── __init__.py
│ ├── k8s_server.py
│ └── server_manager.py
├── scripts/
│ └── start_mcp_servers.py
└── requirements.txt
Ваш файл pyproject.toml должен включать необходимые зависимости и конфигурацию:
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
name = "my-langgraph-app"
version = "0.1.0"
description = "LangGraph приложение с автоматическим запуском MCP-сервера"
requires-python = ">=3.11"
dependencies = [
"langgraph",
"langchain",
"langchain-mcp-adapters",
"uv",
]
[project.scripts]
my-app = "my_app.cli:main"
Настройка точек входа
Ключ к автоматическому запуску сервера находится в разделе [project.scripts] файла pyproject.toml. Здесь определяются точки входа для вашего приложения. Однако для автоматического запуска предварительных серверов вам потребуется создать скрипт-обертку, который обрабатывает как запуск сервера, так и выполнение приложения.
Согласно документации uv, точки входа - это официальный термин для того, чтобы установленный пакет рекламировал интерфейсы, включая интерфейсы командной строки в таблице [project.scripts].
Создайте модуль CLI, который обрабатывает последовательность запуска сервера:
# src/my_app/cli.py
import subprocess
import sys
import time
from pathlib import Path
def start_mcp_servers():
"""Запуск предварительных MCP-серверов"""
servers = [
("kubernetes", "uvx --from . my_app.mcp_servers.k8s_server"),
# Добавьте другие MCP-серверы здесь
]
processes = []
for name, command in servers:
print(f"Запуск {name} MCP-сервера...")
try:
process = subprocess.Popen(
command.split(),
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
processes.append((name, process))
time.sleep(2) # Даем серверам время на запуск
except Exception as e:
print(f"Не удалось запустить {name} сервер: {e}")
return processes
def main():
"""Основная точка входа, которая запускает серверы и выполняет приложение"""
print("Запуск моего приложения LangGraph...")
# Запуск MCP-серверов
server_processes = start_mcp_servers()
try:
# Импорт и запуск основного приложения LangGraph
from my_app.main import run_app
run_app()
except KeyboardInterrupt:
print("\nЗавершение работы...")
finally:
# Очистка процессов серверов
for name, process in server_processes:
process.terminate()
process.wait()
print(f"{name} сервер остановлен")
Создание оберток для MCP-серверов
Создайте отдельные модули для каждого MCP-сервера. Для Kubernetes MCP-сервера:
# src/my_app/mcp_servers/k8s_server.py
import asyncio
from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp.types import Tool
# Инициализация вашего Kubernetes MCP-сервера
server = Server("kubernetes-mcp")
@server.list_tools()
async def list_tools() -> list[Tool]:
"""Список доступных инструментов Kubernetes"""
return [
Tool(
name="kubectl-get-pods",
description="Получение подов Kubernetes",
inputSchema={
"type": "object",
"properties": {
"namespace": {"type": "string", "default": "default"}
}
}
)
]
@server.call_tool()
async def call_tool(name: str, arguments: dict) -> str:
"""Обработка вызовов инструментов"""
if name == "kubectl-get-pods":
namespace = arguments.get("namespace", "default")
# Реализуйте вашу логику Kubernetes здесь
return f"Получение подов из пространства имен: {namespace}"
raise ValueError(f"Неизвестный инструмент: {name}")
async def main():
"""Запуск Kubernetes MCP-сервера"""
async with stdio_server() as (read_stream, write_stream):
await server.run(read_stream, write_stream)
Создайте менеджер серверов для координации нескольких MCP-серверов:
# src/my_app/mcp_servers/server_manager.py
import asyncio
import subprocess
from typing import Dict, List, Tuple
class MCPManager:
def __init__(self):
self.servers: Dict[str, subprocess.Popen] = {}
async def start_server(self, name: str, command: str) -> bool:
"""Запуск MCP-сервера"""
try:
process = subprocess.Popen(
command.split(),
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
self.servers[name] = process
await asyncio.sleep(2) # Даем серверу время на запуск
return True
except Exception as e:
print(f"Не удалось запустить {name} сервер: {e}")
return False
async def stop_server(self, name: str) -> bool:
"""Остановка MCP-сервера"""
if name in self.servers:
self.servers[name].terminate()
self.servers[name].wait()
del self.servers[name]
return True
return False
async def stop_all(self):
"""Остановка всех запущенных серверов"""
for name in list(self.servers.keys()):
await self.stop_server(name)
Упаковка с uv
Используйте uv для упаковки вашего приложения. Сначала установите uv, если вы еще этого не сделали:
# Установка uv
curl -LsSf https://astral.sh/uv/install.sh | sh
Затем настройте свой проект и соберите пакет:
# Инициализация uv проекта
uv init my-langgraph-app
# Добавление зависимостей
uv add langgraph langchain langchain-mcp-adapters
# Установка в редактируемом режиме (для разработки)
uv pip install -e .
# Сборка пакета
uv build
Команда uv build создаст дистрибутивные файлы в директории dist/:
dist/
├── my_langgraph_app-0.1.0-py3-none-any.whl
└── my_langgraph_app-0.1.0.tar.gz
Согласно руководству Real Python, uv может автоматически запускать скрипты точек входа после настройки проекта.
Установка и использование
Установите ваше упакованное приложение для конечных пользователей:
# Установка из wheel-файла
uv pip install dist/my_langgraph_app-0.1.0-py3-none-any.whl
# Или установка из исходного кода
uv pip install git+https://github.com/yourusername/my-langgraph-app.git
Пользователи теперь могут запускать ваше приложение напрямую, и оно автоматически запустит предварительные MCP-серверы:
# Приложение автоматически запустит MCP-серверы
my-app
Для разработки вы также можете использовать uv run:
# Запуск в режиме разработки
uv run my-app
# Или запуск напрямую
uv run python -m my_app.cli
Расширенная настройка
Для более сложных настроек вы можете добавить поддержку переменных окружения и управление конфигурацией:
# src/my_app/config.py
import os
from pathlib import Path
class Config:
K8S_MCP_SERVER_CMD = os.getenv("K8S_MCP_CMD", "uvx --from . my_app.mcp_servers.k8s_server")
SERVER_STARTUP_TIMEOUT = int(os.getenv("SERVER_TIMEOUT", "10"))
LOG_LEVEL = os.getenv("LOG_LEVEL", "INFO")
Обновите ваш CLI для использования конфигурации:
# src/my_app/cli.py
from .config import Config
from .mcp_servers.server_manager import MCPManager
def start_mcp_servers():
"""Запуск предварительных MCP-серверов с конфигурацией"""
manager = MCPManager()
servers = [
("kubernetes", Config.K8S_MCP_SERVER_CMD),
# Добавьте другие серверы из конфигурации
]
processes = []
for name, command in servers:
if asyncio.run(manager.start_server(name, command)):
print(f"✓ {name} MCP-сервер запущен")
else:
print(f"✗ Не удалось запустить {name} MCP-сервер")
return manager
Для производственного развертывания рассмотрите возможность создания файла службы systemd:
# my-langgraph-app.service
[Unit]
Description=Мое приложение LangGraph с MCP-серверами
After=network.target
[Service]
Type=simple
User=appuser
WorkingDirectory=/opt/my-langgraph-app
Environment=PATH=/opt/my-langgraph-app/.venv/bin
ExecStart=/opt/my-langgraph-app/.venv/bin/my-app
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
Этот подход обеспечивает полное решение для упаковки приложений LangGraph с uv, которые автоматически запускают предварительные MCP-серверы, обеспечивая бесшовный пользовательский опыт и устраняя необходимость в ручном управлении серверами.
Источники
- Документация по конфигурации проектов uv
- Real Python - Управление Python проектами с uv
- TIL Simon Willison - Использование uv для разработки Python приложений командной строки
- Руководство по реализации MCP-сервера
- GitHub LangChain MCP Adapters
- Документация по системе сборки uv
- Stack Overflow - Точки входа с uv
Заключение
Упаковка приложения LangGraph с uv для автоматического запуска предварительных MCP-серверов включает несколько ключевых шагов:
- Правильная структура проекта с отдельными модулями для MCP-серверов и центральным CLI
- Конфигурация pyproject.toml с точками входа, которые оркестрируют запуск сервера
- Скрипты-обертки, которые обрабатывают как инициализацию сервера, так и выполнение приложения
- Упаковка с uv для легкой дистрибуции и установки
- Управление конфигурацией для гибких параметров запуска сервера
Основное преимущество этого подхода заключается в том, что пользователи получают бесшовный опыт, когда все предварительные службы запускаются автоматически при запуске вашего приложения. Это устраняет сложность ручного управления серверами и делает ваш инструмент более удобным для пользователя и профессиональным.
Для производственных развертываний рассмотрите возможность добавления правильного ведения журналов, обработки ошибок и интеграции с системными службами для обеспечения надежной работы в различных средах.