MCP. Как ИИ обрести руки для взаимодействия с внешним миром?
Много ли мы могли бы сделать будь у нас разум, знания, но не было бы тела? Пожалуй наверное не много. Поговорим о том как MCP позволяет обрести LLM руки для взаимодействия с внешним миром
Много ли мы могли бы сделать будь у нас разум, знания, но не было бы тела? Пожалуй наверное не много. Собственно это и есть основная проблема больших языковых моделей. У них есть "зайчатки" разума, но нет рук - инструментов с помощью которых LLM смогла бы взаимодействовать с внешним миром.
Представим ситуацию, пользователь задает нейросети простой вопрос:
- Привет нейросеть, подскажи как завтра лучше одеться с учетом погоды?
- ...
Увы, нейросеть не знает ни где пользователь находиться, ни какое сегодня число. О том какая за окном завтра будет погода, она и подавно не знает. Скорее всего она просто сочинит вам какой-то ответ, но не решит вашу задачу.
Здесь стоит отметить, что вероятно любая интеграция с языковой моделью сводиться к подмешиванию к исходному запросу некоторого контекста и "системных промптов". Представим что наше сообщение не уходит к нейросети напрямую, проходит через некоторое прокси который знает где мы находимся, какой сегодня день. Такой прокси может модифицировать исходное сообщение, например так:
- Информация о том, где находится пользователь и сегодняшняя дата записана в этом JSON { "city": "Tomsk", country: "Russian Federation", "currentDate": "03.11.2025" }, используя эти данные ответь на запрос пользователя: "Привет нейросеть, подскажи как завтра лучше одеться с учетом погоды?"
А вот собственно реальный ответ одной из моделей:

Уже ближе к решению нашей задачи. Вероятно многие уже догадались об основном принципе работы.
Итак, что бы нам потребовалось что бы реализовать нечто подобное:
- Некий "прокси" - ПО способное подмешать что-то к основному запросу пользователя. Наверняка вы слышали, о таком понятии как "агент" - в нашем контексте это именно он.
- Некий сервер - который смог бы сформировать JSON с информацией о погоде
- LLM - в качестве "мозга", который способен обработать эту информацию и дать пользователю вразумительный ответ
Model Context Protocol
Аббревиатура MCP расшифровывается как Model Context Protocol. Подробнее о самом протоколе можно прочитать здесь, я же остановлюсь на основных моментах.
Говоря простым языком MCP это набор правил определяющий взаимодействие этих трех компонентов. Агент - в контексте протокола называют MCP клиентом, сервер возвращающий некие данные - MCP сервером. Их взаимодействие основано на JSON-RPC 2.0. Взаимоействие может проходить путем различных транспортных протоколов, например c помощью: Streamable HTTP, WebSocket или путем стандартного ввода вывода stdin/stdout.
Протокол так же вводит понятия инструментов (tools) и ресурсов (resources). Они реализуются на стороне MCP сервера. MCP клиент запрашивает их в начале своей работы. В определенном смысле это "REST API для LLM". Tools определяют какие действия доступны, ресурсы - то над чем могут выполняться действия. Например, если мы создаем агента для написания кода в проекте, ресурсами будут файлы, инструментами же будут являться различные файловые операции - нашему агенту нужно читать содержимое файлов, каталогов, записывать и создавать файлы.
Здесь стоит пояснить, так как это не очевидно для нашего упрощенного примера, который я привел в начале статьи показывающего лишь основную идею. Итак, MCP клиент запрашивает с MCP-сервера набор доступных инструментов и сообщает его LLM. Утрируем до:
-Уважаемая LLM, у нас есть вот такой набор операций доступных для использования: ... , если эта операция поможет выполнить запрос пользователя сформируй JSON в вот таком то формате ... . Запрос пользователя: ...
В общем этой основной теории нам уже хватит что бы написать несложный MCP сервер. Перейдем к практике.
Погодный MCP сервер
Продолжим тематику нашего примера в начале статьи и сделаем MCP сервер способный получать данные о погоде в определенном городе. Благо в нашем распоряжении уже есть некоторый SDK. Я буду использовать NodeJS, TypeScript и пакет NPM пакет @modelcontextprotocol/sdk, но существуют пакеты и для других языков.
Начнем с главной задачи - получать погоду. Воспользуюсь сервисом https://open-meteo.com и пакетом openmeteo, что бы сделать функции для получения погоды:
import { fetchWeatherApi } from "openmeteo";
export async function getCityCoordinates(city: string) {
const url = `https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(
city
)}&count=1&language=en&format=json`;
const res = await fetch(url);
if (!res.ok) throw new Error(`Error getting coordinates: ${res.status}`);
const data = await res.json();
if (!data.results?.length) {
throw new Error(`"${city}" not found`);
}
const { latitude, longitude, name, country } = data.results[0];
return { latitude, longitude, name, country };
}
export async function getDailyWeather(lat: number, lon: number) {
const params = {
latitude: lat,
longitude: lon,
daily: [
"temperature_2m_max",
"temperature_2m_min",
"precipitation_sum",
"weathercode",
],
timezone: "auto",
};
const url = "https://api.open-meteo.com/v1/forecast";
const responses = await fetchWeatherApi(url, params);
const weather = responses[0];
const daily = weather.daily();
const result = {
maxTemp: daily.variables(0).valuesArray()[0],
minTemp: daily.variables(1).valuesArray()[0],
precipitation: daily.variables(2).valuesArray()[0],
weatherCode: daily.variables(3).valuesArray()[0],
};
return result;
}
export async function getDailyWeatherByCity(city: string) {
const { latitude, longitude } = await getCityCoordinates(city);
return getDailyWeather(latitude, longitude);
}
Код получения данных о погоде
Теперь займемся MCP сервером. В нашем случае все просто, я бы даже сказал примитивно:
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio";
import { z } from "zod";
import { getDailyWeatherByCity } from "./weather";
const server = new McpServer({
name: "weather",
version: "1.0.0",
});
server.registerTool(
"get-weather-in-city",
{
title: "Get weather",
description: "Get the weather forecast for the next day",
inputSchema: { city: z.string() },
},
async ({ city }) => {
const result = await getDailyWeatherByCity(city);
return {
content: [
{
type: "text",
text: `The weather in ${city} tomorrow: maximum temperature ${result.maxTemp}°C, minimum ${result.minTemp}°C, precipitation ${result.precipitation} mm, weather code ${result.weatherCode}.`,
},
],
structuredContent: { result },
};
}
);
const transport = new StdioServerTransport();
server.connect(transport);
Реализация MCP сервера
Создаем экзэмпляр McpServer-а, регистрируем инструмент. Даем ему имя, описание, описываем схему входных данных. Далее у нас функция обработчик возвращающая результат. В этом примере использую StdioServerTransport, что было обусловлено инструментом с помощью которого будем проверять результат.
Инструментом оказался ollama-mcp-bridge с которым пришлось повозиться. На данный момент судя по всему в OpenSource сообществе эта тема развита еще не сильно, инструментов не много их поддержка вероятно тоже не сильно активная.
P.S: в видео qwen2.5:7b безбожно тупит и не может все никак понять что от нее требуется. Вероятно это следствие того что модель сама по себе не большая, но вполне возможно что и сами промпты следует написать лучше, возможно есть какие то другие причины.
На этом пожалуй все увидимся в слудющих статьях где разберем еще что нибдуь интересное!