Другое

Как упаковать LangGraph с помощью uv для автоматического запуска MCP серверов

Узнайте, как упаковать Python-приложения LangGraph с помощью uv для автоматического запуска необходимых MCP серверов, таких как Kubernetes. Полное руководство для устранения ручного управления зависимостями.

Как я могу упаковать Python-приложение LangGraph с помощью uv так, чтобы оно автоматически запускало серверы-предпосылки, такие как сервер Kubernetes MCP, вместо того чтобы требовать от пользователей вручную запускать эти зависимости перед использованием инструмента?

Упаковка приложения LangGraph с uv для автоматического запуска предварительных серверов

Чтобы упаковать приложение Python LangGraph с uv так, чтобы предварительные серверы, такие как Kubernetes MCP-сервер, запускались автоматически, необходимо настроить точки входа в файле pyproject.toml и создать скрипты-обертки, которые обрабатывают запуск зависимостей. Этот подход устраняет необходимость для пользователей вручную запускать предварительные службы перед использованием вашего приложения.

Настройка структуры проекта

Начните с правильной структуры проекта для вашего приложения 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 должен включать необходимые зависимости и конфигурацию:

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, который обрабатывает последовательность запуска сервера:

python
# 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-сервера:

python
# 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-серверов:

python
# 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, если вы еще этого не сделали:

bash
# Установка uv
curl -LsSf https://astral.sh/uv/install.sh | sh

Затем настройте свой проект и соберите пакет:

bash
# Инициализация 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 может автоматически запускать скрипты точек входа после настройки проекта.

Установка и использование

Установите ваше упакованное приложение для конечных пользователей:

bash
# Установка из 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-серверы:

bash
# Приложение автоматически запустит MCP-серверы
my-app

Для разработки вы также можете использовать uv run:

bash
# Запуск в режиме разработки
uv run my-app

# Или запуск напрямую
uv run python -m my_app.cli

Расширенная настройка

Для более сложных настроек вы можете добавить поддержку переменных окружения и управление конфигурацией:

python
# 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 для использования конфигурации:

python
# 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:

ini
# 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-серверы, обеспечивая бесшовный пользовательский опыт и устраняя необходимость в ручном управлении серверами.

Источники

  1. Документация по конфигурации проектов uv
  2. Real Python - Управление Python проектами с uv
  3. TIL Simon Willison - Использование uv для разработки Python приложений командной строки
  4. Руководство по реализации MCP-сервера
  5. GitHub LangChain MCP Adapters
  6. Документация по системе сборки uv
  7. Stack Overflow - Точки входа с uv

Заключение

Упаковка приложения LangGraph с uv для автоматического запуска предварительных MCP-серверов включает несколько ключевых шагов:

  1. Правильная структура проекта с отдельными модулями для MCP-серверов и центральным CLI
  2. Конфигурация pyproject.toml с точками входа, которые оркестрируют запуск сервера
  3. Скрипты-обертки, которые обрабатывают как инициализацию сервера, так и выполнение приложения
  4. Упаковка с uv для легкой дистрибуции и установки
  5. Управление конфигурацией для гибких параметров запуска сервера

Основное преимущество этого подхода заключается в том, что пользователи получают бесшовный опыт, когда все предварительные службы запускаются автоматически при запуске вашего приложения. Это устраняет сложность ручного управления серверами и делает ваш инструмент более удобным для пользователя и профессиональным.

Для производственных развертываний рассмотрите возможность добавления правильного ведения журналов, обработки ошибок и интеграции с системными службами для обеспечения надежной работы в различных средах.

Авторы
Проверено модерацией
Модерация