MCPHero - новая библиотека/проект для Python для использования MCP tools как native tools в ИИ библиотеках типа openai, которые не поддерживают MCP сами по себе.

# В openai нельзя вызвать completions с MCP сервераами
response = client.chat.completions.create(
    model="gpt-4o",
    messages=messages,
    tools=tools,  # tools - должны быть специальные dict'ы, не ссылки до MCP
    # mcp_tools=my_mcs_tools  # такого аргумента, к  сожалению, нет
    # mcp_servers=my_mcp_servers  # такого аргумента, к сожалению, тоже нет
    tool_choice="auto"
)

Из-за этого возникает нужда либо переписать все на agentic библотеки(pydantic_ai, langchain, agents и тп), которые поддерживают MCP сервера, либо же писать свои адаптеры, которые пройдутся по lifecycle MCP, а потом замепят это все в формат openai:

Initialize -> Authorize -> List MCP Tools -> map_MCP_tool_to_openai_tool() -> openai_call

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

openai_response.tool_calls -> map_openai_tool_call_to_MCP_payload -> Call MCP Tool

Поддерживать такое желания нет, каких-либо решений в открытом доступе найдено не было.

Что MCPHero за библиотека?

У MCPHero одна задача - конвертировать и поддерживать mapping MCP в нативные ИИ либы и обратно, чтобы можно было использовать MCP как tools. Пример:

import asyncio
from openai import OpenAI
from mcphero import MCPToolAdapterOpenAI

async def main():
    adapter = MCPToolAdapterOpenAI("https://api.mcphero.app/mcp/your-server-id")
    # Здесь мы получаем тулы из MCP сервера, но сразу в формате openai
    tools = await adapter.get_tool_definitions()

    messages = [{"role": "user", "content": "What's the weather in London?"}]
    response = client.chat.completions.create(
        model="gpt-4o",
        messages=messages,
        tools=tools,  # openai не знает, что это MCP tools, он вызывает "свои"
    )

    if response.choices[0].message.tool_calls:
        tool_results = await adapter.process_tool_calls(
            response.choices[0].message.tool_calls
        )  # тут MCPHero обрабатывает openai tool_calls,
        # вызывая MCP сервер по HTTP по его tools

        messages.append(response.choices[0].message)
        messages.extend(tool_results)  # результаты тоже openai формата

        final_response = client.chat.completions.create(
            model="gpt-4o",
            messages=messages,
            tools=tools,
        )
        print(final_response.choices[0].message.content)

asyncio.run(main())

Также есть поддержка другой "немспшной" либы - google-genai (gemini)

import asyncio
from google import genai
from google.genai import types
from mcphero import MCPToolAdapterGemini

async def main():
    adapter = MCPToolAdapterGemini("https://api.mcphero.app/mcp/your-server-id")
    client = genai.Client(api_key="your-api-key")

    # Один тул(можно и get_tool_definitions())
    tool = await adapter.get_tool()

    response = client.models.generate_content(
        model="gemini-2.5-flash",
        contents="What's the weather in London?",
        config=types.GenerateContentConfig(
            tools=[tool],  # google-genai-compatible
            automatic_function_calling=types.AutomaticFunctionCallingConfig(
                disable=True
            ),
        ),
    )

    # Такая же логика, как в openai адаптере
    if response.function_calls:
        results = await adapter.process_function_calls(response.function_calls)

        contents = [
            types.Content(role="user", parts=[types.Part.from_text("What's the weather in London?")]),
            response.candidates[0].content,
            *results,
        ]

        final_response = client.models.generate_content(
            model="gemini-2.5-flash",
            contents=contents,
            config=types.GenerateContentConfig(tools=[tool]),
        )
        print(final_response.text)

asyncio.run(main())

Кому это может быть полезно

  • 1. Командам с production-кодом на openai / google-genai

    • где responses / chat.completions уже глубоко и легаси

    • и любое "давайте перепишем на langchain" = нереализуемая хотелка

      MCPHero позволяет добавить MCP без рефакторинга архитектуры

    2. Командам с большим количеством custom tools

    • CRM / ERP / billing / legacy API

    • куча похожих tool definitions

    • постоянные изменения схем

      Вынести tools в MCP сервер = меньше дублирования, меньше регрессий, чище код

    3. Командам, которые не хотят framework vendor lock'а

    • Есть личный опыт как я удалял pydantic-ai из всего проекта и переписывал из-за его не готовности к production, не хотите повторить - сидите на openai

      MCPHero — не фреймворк, а glue layer, особенно для openrouter и тп проектов

  • P.S если нужна генерация класнных MCP серверов с хостингом - попробуйте нашу облачную платформу https://mcphero.app - "lovable для MCP" - качественная генерация под любую спеку/АПИ/схему с поддержкой эфемерных переменных окружения, on-prem деплоя если надо и много другого.

Мотивация к созданию

Мы писали очень много кастомных интеграций в рамках стартапа https://aimalabs.io - звонки + WhatsApp ИИ с кастомными действиями. У каждого энтерпрайз клиента есть свои системы, с которыми надо коннектиться ИИшке в реальном времени - СРМка, старая апишка, база данных и тп. Писать постоянные tools стало муторно, у нас образовались внутренние тулы для автоматизации этого процесса, их было двое и оба мы вывели в мир:

Сначала появился генератор + хостинг MCP серверов по спеке/описанию - https://mcphero.app, который позволяет генерировать MCP сервера под различные кейсы за минуты, что очень удобно, своеобразный lovable для MCP серверов.

Но в кусках проекта, где все было на openai - мы не могли использовать MCP.

openai поддерживает только следующий формат tools:

CALENDAR_GET_AVAILABLE_SLOTS_TOOL_DEFINITION = {
        "type": "function",
        "function": {
            "name": "get_available_slots",
            "strict": True,
            "description": "Get available time slots for scheduling appointments. Returns a list of available time slots based on business hours and existing calendar events.",
            "parameters": {
                "type": "object",
                "properties": {
                    "start_date": {
                        "type": "string",
                        "description": "Start date in YYYY-MM-DD format (inclusive)",
                    },
                    "end_date": {
                        "type": "string",
                        "description": "End date in YYYY-MM-DD format (inclusive). If not provided, defaults to 7 days from start_date.",
                    },
                },
                "required": ["start_date"],
            },
        },
    }

Проект был обмазан такими definitions. Это сложно поддерживать и не очень приятно типизируется. В итоге мы поизучали как же агентские библиотеки/проекты используют MCP под капотом, и истина была очень проста - они все конвертируют их в tools так или иначе, но не выносят эту часть в opensource. Поэтому тот mapper, что мы использовали внутри, был зарежилен как библиотека:

https://pypi.org/project/mcphero/

https://github.com/stepacool/mcphero

Фичи и Возникшие челленджи

Первое - поддержка нескольких серверов и разрешение коллизий. У серверов может быть tools с одинаковыми названиями - "search", "query", "find" и т.п. MCPHero имеет внутренню систему подстановки минимальных префиксов, чтобы не запутывать LLM всяческими anti_collision_hash, но в тоже время сохранить уникальность и смысловую нагрузку. Пример:

adapter = MCPToolAdapterOpenAI([
    MCPServerConfig(url="https://api.mcphero.app/mcp/weather", name="weather"),
    MCPServerConfig(url="https://api.mcphero.app/mcp/calendar", name="calendar"),
])

tools = await adapter.get_tool_definitions()
# "search" станет "weather__search" и "calendar__search"

Второе - гибкая обработка ошибок. Так как несколько МСП серверов, да даже один - это много вызовов к third party API, ошибки могут возникать. Есть режим "пропустить" ошибочные вызовы, есть режим "вернуть ИИшке детали ошибки", а есть - уронить программу целиком(raise Exception'а).

Третье - параллелизация. ИИ всегда возвращает список tool_calls, и хоть там обычно только один, их также может быть и несколько. Они могут вызываться параллельно.

Roadmap

  1. streaming / async tool_calls - обработка тяжелых тулов в бекграунде, не блокируя основной интерпретатор, стриминг

  2. Больше библиотек, сейчас только openai и google-genai

  3. Возможно переписать интерфейс, чтобы выглядел более "магически" - много магии под капотом, очень implicit, но сейчас такая мода/meta. Что-то типа

    MCPHero.from_url("example.com/mcp").as_openai_tools()

  4. Привести opensource проект в более приличный вид

Заключение

Если у вас уже есть продакшен код на openai, но вы хотите MCP без переписывания архитектур�� — MCPHero именно для этого.