Вышел MCP C# SDK 2.0: без состояния по умолчанию и MCP9005 на старом коде
ModelContextProtocol 2.0.0 вышел 2026-07-28 с включённым по умолчанию транспортом HTTP без состояния, с Multi Round-Trip Requests вместо инициируемой сервером elicitation и с предупреждением анализатора на ElicitAsync и SampleAsync.
2026-07-28 Джефф Хэндли анонсировал v2.0 официального MCP C# SDK, выпущенного в тот же день, когда ревизия протокола 2026-07-28 стала финальной. ModelContextProtocol 2.0.0 лежит в NuGet как стабильная версия и поддерживает net8.0, net9.0, net10.0 и netstandard2.0. Если сервер построен на 1.x, это не то обновление версии, которое можно принять, не прочитав diff.
Рукопожатия больше нет
Главное изменение архитектурное, и оно является вычитанием. В ревизии 2026-07-28 нет ни рукопожатия initialize, ни Mcp-Session-Id. Клиенты вызывают server/discover, а каждый последующий запрос несёт версию протокола, сведения о клиенте и возможности в поле _meta самого запроса. Именно поэтому MCP-сервер GitHub смог удалить своё хранилище сессий в Redis.
В C# SDK это проявляется как смена значения по умолчанию. HttpServerTransportOptions.Stateless теперь равно true, поэтому сервер, созданный сегодня, масштабируется горизонтально без маршрутизации с привязкой к сессии. Вернуться к сессиям можно явно:
builder.Services
.AddMcpServer()
.WithHttpTransport(options => options.Stateless = false)
.WithToolsFromAssembly();
MCP9005 и есть список миграции
Запросы, инициируемые сервером, не переживают транспорт без состояния. ElicitAsync, SampleAsync и RequestRootsAsync теперь помечены как устаревшие и выдают диагностику MCP9005. Скомпилируйте проект против 2.0.0, и список предупреждений станет планом миграции: каждое место, где сервер посреди вызова инструмента обращался обратно к клиенту, придётся переписать.
Заменой служит Multi Round-Trip Requests. Вместо того чтобы сервер вызывал клиента, инструмент выбрасывает исключение с нужными ему входными данными, клиент разрешает их локально и затем повторяет вызов с приложенными ответами:
throw new InputRequiredException(
inputRequests: new Dictionary<string, InputRequest>
{
["closeReason"] = InputRequest.ForElicitation(...)
},
requestState: ticketId.ToString());
requestState и есть тот приём, который позволяет обойтись без сессии: это ваш токен корреляции, который возвращает клиент, а не хранит память сервера.
Клиентам достаётся простая половина. McpClient разрешает MRTR прозрачно, если зарегистрирован обработчик:
var client = await McpClient.CreateAsync(
clientTransport,
clientOptions: new()
{
Handlers = new McpClientHandlers
{
ElicitationHandler = (requestParams, ct) =>
ValueTask.FromResult(
new ElicitResult { Action = "accept" })
}
});
Что по-прежнему говорит со старыми узлами
Клиент 2.0.0 предпочитает 2026-07-28 и автоматически откатывается к устаревшему рукопожатию initialize, когда сервер не отвечает на server/discover. Сервер 2.0.0 продолжает принимать initialize от клиентов 1.x. Единственная неработающая комбинация - старый клиент против сервера без состояния, и это как раз тот случай, который нельзя перекрыть мостом, поскольку MRTR против клиента 2025-11-25 требует состояния сессии, чтобы транслироваться в устаревшую elicitation.
Второй острый угол: экспериментальная поддержка Tasks из 1.3.x и 1.4.x исчезла, её заменил переработанный пакет ModelContextProtocol.Extensions.Tasks, согласованный с SEP-2663. Apps и Tasks теперь подключаемые пакеты, а не часть ядра, и включаются через .WithTasks(store) и .WithMcpApps().
По-настоящему приятное дополнение для тех, кто держит серверы за шлюзом: [McpHeader] поднимает параметр инструмента до HTTP-заголовка, так что прокси может маршрутизировать по нему, не разбирая тело JSON-RPC.
public static async Task<string> GetOrderStatus(
[McpHeader("Region")] string region,
string orderId)
Начните с dotnet add package ModelContextProtocol --version 2.0.0, соберите проект и прочитайте список MCP9005, прежде чем трогать что-либо ещё. Примечания к выпуску v2.0.0 перечисляют все 10 несовместимых изменений, включая перенумерацию кодов ошибок JSON-RPC, которая переносит UnsupportedProtocolVersion на -32022.
Comments
Sign in with GitHub to comment. Reactions and replies thread back to the comments repo.