mCP 2.0
MCP без состояния, приложение с состоянием
Минимальный JavaScript-проект, демонстрирующий основные паттерны запросов/ответов MCP 2026-07-28 с MCP TypeScript SDK v2.
Демо охватывает:
HTTP-запросы без сохранения состояния без
Mcp-Session-Id.Состояние, управляемое приложением, адресуемое явными дескрипторами.
Многоэтапные запросы для подтверждения пользователем.
Обновления прогресса, ограниченные отдельной операцией.
Кэшируемое обнаружение инструментов с TTL и областью совместного использования.
Запуск
Требуется Node.js 20 или новее.
npm install
npm run demoКоманда запускает сервер на доступном локальном порту, выполняет все сценарии, выводит результаты и завершает работу сервера. Пример удаления использует виртуальный набор файлов в памяти и никогда не затрагивает файлы на диске.
Запустите интеграционные тесты с помощью:
npm testЧтобы оставить сервер запущенным для другого MCP-клиента:
npm run serverКонечная точка — http://127.0.0.1:3000/mcp. Установите PORT, чтобы переопределить порт.
Related MCP server: MCP RC Long-Running Task Prototype
1. Запросы без сохранения состояния
MCP 2026-07-28 удаляет HTTP-сессии на уровне протокола. Этот проект создаёт новый McpServer для каждого запроса, поэтому любой запрос может достичь любого экземпляра сервера:
const mcpHandler = createMcpHandler(
() => createStateServer(demoFiles),
{
legacy: "reject",
onerror: (error) => console.error("MCP error:", error),
},
);Клиент явно выбирает современную ревизию протокола:
const client = new Client(
{ name: "state-demo-client", version: "0.1.0" },
{
capabilities: { elicitation: { form: {} } },
versionNegotiation: {
mode: { pin: "2026-07-28" },
},
},
);Состояние, хранящееся внутри одного экземпляра McpServer, исчезает после этого запроса. Двойной вызов эфемерного счётчика демо даёт 1 от двух разных экземпляров сервера.
2. Данные приложения с сохранением состояния
MCP без состояния не требует приложения без состояния. Долговременное состояние находится вне MCP-сервера, создаваемого на каждый запрос, и выбирается с помощью явного дескриптора:
const countersById = new Map();
server.registerTool(
"create-counter",
{
outputSchema: z.object({ counterId: z.uuid(), value: z.number() }),
},
async () => {
const counterId = randomUUID();
countersById.set(counterId, 0);
const structuredContent = { counterId, value: 0 };
return {
content: [{ type: "text", text: JSON.stringify(structuredContent) }],
structuredContent,
};
},
);Клиент передаёт дескриптор между вызовами, которые в остальном независимы:
const created = await client.callTool({ name: "create-counter" });
const { counterId } = created.structuredContent;
await client.callTool({
name: "increment-counter",
arguments: { counterId },
});Map в памяти — лишь временная замена. Продакшн-сервер должен использовать базу данных или общее хранилище, привязывать дескрипторы к аутентифицированному субъекту и обеспечивать соблюдение авторизации и срока действия при каждом поиске.
3. Многоэтапное подтверждение
Инструмент, которому нужны дополнительные данные, возвращает input_required. Клиент получает ответ и повторяет исходный запрос с inputResponses, поэтому сервер не инициирует второй JSON-RPC-запрос в потоке операций.
server.registerTool(
"delete-files",
{
inputSchema: z.object({ files: z.array(z.string()).min(1) }),
annotations: { destructiveHint: true },
},
async ({ files }, ctx) => {
const confirmation = acceptedContent(
ctx.mcpReq.inputResponses,
"confirm",
confirmationSchema,
);
if (confirmation === undefined) {
return inputRequired({
inputRequests: {
confirm: inputRequired.elicit({
message: `Delete ${files.length} virtual files?`,
requestedSchema: confirmationSchema,
}),
},
});
}
if (!confirmation.confirm) {
return {
content: [{ type: "text", text: "Cancelled" }],
structuredContent: { status: "cancelled", deleted: [] },
};
}
const deleted = files.filter((file) => demoFiles.delete(file));
return {
content: [{ type: "text", text: `Deleted: ${deleted.join(", ")}` }],
structuredContent: { status: "deleted", deleted },
};
},
);SDK может выполнить запрос и автоматически повторить его с помощью обычного обработчика запроса дополнительных данных:
client.setRequestHandler("elicitation/create", async (request) => {
const confirm = await askUser(request.params.message);
return {
action: "accept",
content: { confirm },
};
});Подтверждение — это пользовательский опыт, а не авторизация. Сервер по-прежнему должен аутентифицировать вызывающего и независимо обеспечивать разрешение на удаление файлов.
4. Прогресс, ограниченный запросом
Прогресс остаётся привязанным к запросу, который начал работу. Параллельные операции получают только свои обновления, а не общий глобальный поток событий.
server.registerTool(
"run-work",
{ inputSchema: z.object({ job: z.string() }) },
async ({ job }, ctx) => {
const progressToken = ctx.mcpReq._meta?.progressToken;
for (const progress of [10, 30, 70]) {
if (progressToken !== undefined) {
await ctx.mcpReq.notify({
method: "notifications/progress",
params: {
progressToken,
progress,
total: 100,
message: `${job}: ${progress}%`,
},
});
}
}
return {
content: [{ type: "text", text: `${job}: complete` }],
structuredContent: { job, status: "complete" },
};
},
);Каждый вызов клиента предоставляет собственный обратный вызов прогресса:
await Promise.all([
client.callTool(
{ name: "run-work", arguments: { job: "alpha" } },
{ onprogress: (update) => alphaProgress.push(update) },
),
client.callTool(
{ name: "run-work", arguments: { job: "beta" } },
{ onprogress: (update) => betaProgress.push(update) },
),
]);5. Кэшируемость
Кэшируемые ответы включают срок свежести и политику совместного использования. Это снижает повторный трафик обнаружения, когда один агент подключается ко многим MCP-серверам.
Этот сервер помечает свой каталог инструментов как пригодный для повторного использования в течение пяти минут:
const server = new McpServer(
{ name: "mcp-state-demo", version: "0.1.0" },
{
cacheHints: {
"tools/list": {
ttlMs: 300_000,
cacheScope: "public",
},
},
},
);Клиент автоматически использует свежие записи:
await client.listTools(); // network request; stores the result
await client.listTools(); // cache hit; no network request
await client.listTools(undefined, {
cacheMode: "refresh",
}); // forces a network request and updates the cacheПоля применяются к результатам tools/list, prompts/list, resources/list, resources/templates/list и resources/read.
publicпозволяет клиентам и общим посредникам повторно использовать результат для разных пользователей.privateограничивает повторное использование контекстом авторизации запроса. Если хранилище кэша является общим, установитеcachePartitionклиента в стабильный идентификатор субъекта.
TTL — это оценка свежести. Уведомления об изменении списков могут аннулировать кэшированные каталоги до истечения их TTL.
Структура проекта
src/server.js MCP server and tool implementations
src/demo.js Client exercising all five scenarios
test/state.test.js Integration tests for every scenarioПакеты MCP закреплены на версии 2.0.0, включая inputRequired, acceptedContent, кэширование и API прогресса, ограниченного запросом, используемые здесь.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceA reference implementation demonstrating proper MCP server patterns with HTTP transport, featuring session management, progress notifications, and example tools for testing server functionality. Serves as a clean template for building MCP servers with streamable responses and comprehensive error handling.7
- FlicenseNot gradedqualityCmaintenanceDemonstrates MCP 2026-07-28 behavior for long-running tool calls, task lifecycle (get, update, cancel), and elicitation clarification during async tasks.
- AlicenseNot gradedqualityCmaintenanceEducational MCP server demonstrating the 2026-07-28 stateless protocol with raw Starlette, no SDK, featuring tools, request state handles, MRTR elicitation, and subscriptions.MIT
- AlicenseNot gradedqualityBmaintenanceDemo MCP server for ACEL, a runtime verification middleware that blocks a rule-violating tool call before it executes. 5 tools (authenticate, read/validate/delete records, send payment) showing ACEL enforcing call ordering and state preconditions live via the official MCP SDK's middleware hook.MIT
Related MCP Connectors
AI Reasoning Cache & Consensus Layer with 11 MCP tools via Streamable HTTP.
Hash-chained HMAC-signed audit log MCP for A2A (agent-to-agent) calls. Every tool-call, agent-ha...
Workflow diagnostics, capability routing, and x402 settlement for MCP-compatible agents.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/weijianzhg/mcp-2-0'
If you have feedback or need assistance with the MCP directory API, please join our Discord server