Працэўнае з’яеднанне інструментаў MCP у інтэрфейс чату React з вбудованым падтверджэнням ад чалавека
Дазвольце даклэ научыцца, як Протакол контекста модэля падходзіць да додатка на React: чаму бэкенд должен размешчаць MCP, як працюе сервер інструментаў, а таксама як трансляваць і затварджваць вызовы інструментаў у інтэрфейсе.
Функцыі AI ў праектах на React зазвычай развіваюцца паэтапна, праз адну спецыяльную інтеграцыю за раз, пры чым кожная з яных мае свой SDK, систему аутантыкаціі, механізм обробкі адзінакоў і прыладку дадзеных, усе гэта тычуцца адзіна з іншым. Protocol Model Context (MCP) — адкрыты протакол, запрактаваны компаніяй Anthropic і зараз шырока аднароджаны, — заменяе гэты хаос адной стандартной інтарфейсам між прыладамі AI і інструментамі, а таксама дадзеннямі, якія вони выкарыстоўваюць; часта яго порৱняюць з роз’ўтом USB-C для AI. У гэтым артыкуле пояснюецца, як MCP пасляўляецца ў архітектураы React, показана праця маленькага сервера для базы дадзеных і бэкенд-хоста, а пасля стварана тая частка, якая належыць разработчыкам React: інтарфейс чату, який трансляюць запыткі до інструментаў і просіць корыстувальніка ўтвердзіць іх.
Якщо вы хочаце спачатку пазнакоміцца з асэнтамі на рэвэле протакола, якія стосуюцца адкрыцьця і вызывання, пераклікайце статыю пра тое, як MCP дапамагае агентам AI адкрыцьці і вызыванню інструментаў. Увага тут зусім на стороне прыемлень і інтэрфейса.
Што стандартызуе MCP
MCP апісвае, як прыемлень можна сапраўдзіць падачу контэкста і можнасцей да большых мовных модэляў. Ён выдзеляе тры ролі: хостам ёсць ваш прыемленне, кліентам — канектар унутрь хоста, які падтрымвае сесыю з адним серверам, а серверы выклікаюць інструменты і джэрела даных. Хост зазвычай запускае аднаго кліента на кожны сервер, з якім ён падключаецца.
Без MCP спіс залежнасцей React-прыемлення, якое выкарыстоўвае AI, часта выглядае так:
React App
├── OpenAI SDK (for chat)
├── Anthropic SDK (for reasoning)
├── LangChain (for RAG)
├── Custom API Client (for your database)
└── Custom API Client (for your CRM)
Кожны элемент мае свою сыстэму аутантыкаціі, обробку памылак і супараднаванне шэмы; новы источнік дадзейнаоў означае новы канцэнтрабінт плюс новую службу фронтэнду.
За дапамогою MCP інтэграцыя спрыяе стварэнню адного ўніверсальнага патэрану:
React App (Host)
└── MCP Client
├── MCP Server: File System
├── MCP Server: PostgreSQL
├── MCP Server: Slack
├── MCP Server: Your Internal API
└── MCP Server: Any Future Tool
Кожны сервер выкарыстоўвае той самы пратакол. Хосту не трэба разумець PostgreSQL чы формат API Slack; ён ставі два загальныя запитання: «Калікі інструменты є?» і «Застосавіць гэты інструмент з гэтыми аргументамі», а пратакол перадае рэшту інфармацыі. Зверніце увагу, чаго не робіць MCP: ён стандартызуе з’яўленне на інструменты та дадзеныя, але не выбір модэлю. Хост продовжае вялічыцца з тым прадавцам LLM, які вы выкарыстоўвайце.
Тры прымітывы
Ваша аплікацыя на React вялічыцца з трывалякімі можнасцямі сервера, аднойчы безпосередньна, чы, што частае, чераз ваш бэкенд.
Інструменты
Інструменты — это функциі, якія можа выклікаць модэль. Кожны з іх мае назву, апісанне і JSON Schema, які описвае ўсія його параметры. Калі корыстнік запытае, сколькі абліков было створана ўчора, модэль не павінна здагадвалася: яна можа пабачыць інструмент, такі як query_user_signups, який прыме date, выкліканы яго і адпаведзе на падставе рэзультата. Інструменты ўжо тое, што спаявае запыт корыстніка на простай мове з данымі, якія знаходзяцца за вашым дапамогам.
Рэсурсы
Рэсурсы — это фрагменты контексту, якія модэль можа чытаць, такія як файл, запис у базе даных або тэма чату. Кожны з іх пазначаецца URI, напрыклад file:///docs/spec.pdf або db://users/123, і чытанне іх дазволяе модэлі базаваць своия адпаведзі на рэальных даных, а не толькі на матэрыяле, якім яна навучалася.
Запыты
Шаблоны-запросы — это перадаўнае выкарыстоўваныя шаблоны, якія публікуецца серверам. Сервер можа запропанаваць шаблон code_review, які прыймае аргумент file_path; хост запрашвае шаблон, запоўняе аргумент і надае рэзультат модэлю.
Чаму фронтэнд — гэта не проста прадставленне
Фронтэнд з простым перадачай даных
У багацькох дапытках на базе AI кліент React адправляе паведамленне корыстніка на бэкенд на базе Node або FastAPI, який перадае йое прадавцу модэля, чакае на адпаведзь і перадае яго знову. Якщо модэлю патрэбна якая-небудзь інструментальная падтрымка, бэкенд таксама займаецца гэтым. Фронтэнд ёсць пасыўным рэндэраром тексту: ён не мае жадных ведамасцей пра тое, што робіць модэль, і не можа втручацца.
Фронтэнд як панель керування
За дапамою вызоў інструментаў у стыле MCP, інтэрфейс можа паказваць вызоў інструментаў у момент ўжыцця і даваць корыстніку можласць затвердзіць або адхіліць чутлівыя операцыі прытаманне ўжыццю. Незалежна ад таго, чы рэндзер сам падтрымвае з’яўлення MCP-з’язоў, чы, што бывае частае, прымае структураваны стрім з хоста-бэкенду, React стае месцам, дзе арханізацыя ўжыцця інструментаў застаеўся видным і керованым.
Корыстнікі все больш чакаюць такога кантролю: бачыць, што асістэнт збіраецца запытаць іхнія даны, і спачатку затвердзіць гэты запыт. Такой досвяд з’яўляецца завдзяк React.
Дзе павінен знаходзіцца хост MCP
Існуе два працэспрыводныя архітектурных падходы. Выберыце адны з іх на адной з аснова вашых трэбаванняў да безпекі і затрымкі.
MCP, медыяціруемы бэкендам, — стандартны выбар
У гэтым патэрне аплікацыя React связуецца толькі з вашым бэкендам, пры чым бэкенд выступае як хост MCP. Ён падтрымлівае ачытыя з’язкі з серверамі MCP, керуе процэсам аутантыкацыі і перадае інфармацыю пра дзейнасць інструментаў на фронтэнд:
React (Client) <--SSE/WS--> FastAPI/Node (MCP Host) <--stdio/SSE--> MCP Servers
Адрозныя прычыны гэтага падходу є значнымі для большасці продуктам:
- Безпека: даныя аутантыкацыі для сервераў MCP застаюцца на самом сервере і ніколі не прабрачываюцца ў браузер.
- Стан: стойкія сесіі базы дадзенаў і файловай системы застаюцца на сервере, там, дзе ім і месца.
- Магчымасць аудыту: кожны вызов інструмента можа быць задапісаны, обмежаны па колькасці і прызначаны конкрэтнаму корыстніку.
Фронтэнд прымае структураваны струмень з’явоў (фрагменты тексту, запиты на вызов інструментаў, рэзультаты ўжывання інструментаў і заканчоўны адпаведзь) і ўсё гэта адобразвае спецыяльна.
Зьмена пра транспорты: на дыяграме паказаны стандартныя канэкты межа хостам і локальнымі серверамі, а таксама SSE для даляжніх сервераў. Спецыфікацыя MCP з часам развілася ў паводзе своего HTTP-транспорту, таму пераканайцеся, што вы ведаеце апошнюя версію спецыфікацыі і документацыю SDK ў паводзе рэкамендуемага транспорту для даляжніх сервераў.
MCP, які працуе натычна ў браузеры, для спецыяльных случаў
Альтэрнатыва — аплікацыя на React можа безпосередна з’ўязвацца з даляжнімі серверамі MCP через стрімінг на адной заснованай на HTTP. Це працюе, але команды, якія разрабатываюць продакт, рэдка калі выбіраюць гэты варыянт, адколі шар дадзеных і ўсе кантрольныя даны стаюць доступнымі з браузера. Яго краща выкорыстоўваць для локальных інструментаў разработчыка або аплікацый на стороне кліента, якія не обробляюць чутлівых дадзеных.
Сервер інструментаў для базы дадзеных на TypeScript
Стварэнне маленькага сервера — гэта найшырэшы шлях да розумення пратаку. У прыкладзе нижэй показана табліца users у PostgreSQL через два інструмента, выкарыстаныя з офіцыйным SDK TypeScript. Яго можна прачытаць у трох частях. Першая часть стварае басейн з’яўленняў і MCP Server, які аанунсавае можлівасць tools. Другая часть — хэндлер ListToolsRequestSchema — описвае кожны інструмент па імени, апісанню і inputSchema, якое модэль бачыць пад час выбору таго, што запускаць. Трэцяя часть — хэндлер CallToolRequestSchema — направляе запыт па імені інструмента, выкананае параметрызаваная запытка і вяртае рядкі у вастоце тексту, або вяртае isError: true з паведамленнем, калі ўтвараецца проблема. Няўпашцей, сервер падключаецца через stdio, таму хост можа запускаць яго як дзецінскі процэс.
// mcp-servers/database-server.ts
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
CallToolRequestSchema,
ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import { Pool } from "pg";
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
});
const server = new Server(
{
name: "postgres-mcp-server",
version: "1.0.0",
},
{
capabilities: {
tools: {},
},
}
);
// Define available tools
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: "query_users",
description: "Query the users table with filters",
inputSchema: {
type: "object",
properties: {
limit: { type: "number", description: "Max results" },
status: { type: "string", enum: ["active", "inactive"] },
},
required: ["limit"],
},
},
{
name: "get_user_by_email",
description: "Find a user by their email address",
inputSchema: {
type: "object",
properties: {
email: { type: "string" },
},
required: ["email"],
},
},
],
};
});
// Handle tool execution
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
try {
if (name === "query_users") {
const result = await pool.query(
"SELECT id, email, status, created_at FROM users WHERE status = $1 LIMIT $2",
[args.status || "active", args.limit]
);
return {
content: [
{
type: "text",
text: JSON.stringify(result.rows, null, 2),
},
],
};
}
if (name === "get_user_by_email") {
const result = await pool.query(
"SELECT * FROM users WHERE email = $1",
[args.email]
);
return {
content: [
{
type: "text",
text: JSON.stringify(result.rows[0] || null, null, 2),
},
],
};
}
throw new Error(`Unknown tool: ${name}`);
} catch (error) {
return {
content: [
{
type: "text",
text: `Error: ${error.message}`,
},
],
isError: true,
};
}
});
const transport = new StdioServerTransport();
await server.connect(transport);
Зверніце увагу на тое, чаго утримваецца дизайн: модель ніколи не выкарыстоўвае чысты SQL. Яна можа выбіраць толькі межовыя, іменаваныя операцыі, а запиты выкарыстоўваюць месца падставы ($1, $2), таму аргументы не можаюць увести SQL. Верненне памялакоў як кантэнту за дапамогою isError дазволяе модэлі бачыць і поясніць прычыну аберання, замест таго каб уся сесія зламалася.
Перш чым выкорыстоўваць такі элемент у рэальных задачах, трэба выправіць калекцыю момантам. JSON Schema описвае вхідныя даны, але працоўнік все рава должен пераканацца ў правамільнасці самага args (напрыклад, за дапамогою бібліятэкі схем), адтакуль гэты параметр можа быць відсутнім або неправамільны; таксама трэба обмежыць значэнне args.limit. Функцыя get_user_by_email выконвае запит SELECT *, які перадае ў модэль усі столбцы, включаючы чутлівую інфармацыю, такую як хэшы пароў, таму краща выбіраць конкрэтныя столбцы. А ў строгам TypeScript значэнне error у блоке catch ёсць unknown, таму трэба яго пераканацца перш чым чытаць .message.
Хост бэкенду на Python
Аплікацыя React ніколі не выступае ў прымысловы зв’язку з тым серверам; гэта робіць бэкенд. Ёсць мінімальны клас хоста, які выкарыстоўвае Python MCP SDK. Функцыя connect() описвае, як запускаць процес сервера (command, args і сяродавышча, якія перадаюць DATABASE_URL), ачынае кліента stdio, пачынае ClientSession, адбывае рукосткасаванне праймовым протакалам за дапамою initialize(), а пасля вызывае list_tools(), ўбачыць, што пропонуе сервер. Функцыя execute_tool() перадае назву і аргументы інструмента і вяртае першы текстовы элемент з рэзультата, а close() завершае сесію і процес.
# backend/mcp_host.py
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
import asyncio
import json
class MCPHost:
def __init__(self):
self.session = None
self.tools = []
async def connect(self):
server_params = StdioServerParameters(
command="node",
args=["mcp-servers/database-server.ts"],
env={"DATABASE_URL": os.getenv("DATABASE_URL")}
)
self._client = stdio_client(server_params)
self._read, self._write = await self._client.__aenter__()
self.session = await ClientSession(self._read, self._write).__aenter__()
await self.session.initialize()
# Discover available tools
tools_result = await self.session.list_tools()
self.tools = [tool.name for tool in tools_result.tools]
async def execute_tool(self, tool_name: str, arguments: dict):
result = await self.session.call_tool(tool_name, arguments)
return result.content[0].text if result.content else None
async def close(self):
await self.session.__aexit__(None, None, None)
await self._client.__aexit__(None, None, None)
Кадрку трэба часткова пасправіць прытаму, перш чым яна будзе работаць. У ёй викорыстоўваецца os.getenv без імпорту модуля os. У яе запускаецца node на файле з расширэнням .ts, што працюе толькі тады, калі версія Node можа безпасебна выконваць TypeScript; інакш калі трэба, спачатку скомпілюйце сервер у JavaScript або викорыстаўце інструмент, які падтрымвае TypeScript. Ручны вызов функцый __aenter__ і __aexit__ працюе, але варто выкарыстоўваць блакі async with або клас AsyncExitStack, каліколькі гэта безпечней, адтакулькі яны гарантуець вычышэнне ресурсаў у разе апарцэйсоў. Таксама зважайце, што среда, якая перадаецца дзецявім процесу, заменяе среду абоўязковага процеса, таму неабходна уключыць ўсе іншае, што патрэбна серверу, напрыклад, значэнне PATH.
Бок React: стрімінг і апраўленне запытоў да інструментаў
Хточа самэ гэтае месца, дзе разрабоўчыкі React адмахваюць сваю найболей выразную работу. Бэкенд аправляе стрімы з запускамі інструментаў, якія маюць не толькі текст, але і запытанні ўзьвоўвання інструментаў адпаведна да ўсіх рэзультатаў, а інтерфейс ператварае іх у інтэрактыўныя элементы.
Компанента ChatInterface прытрымлівае спіс паведамленняў, кожна з якіх можа мець toolCalls з статусам pending, approved, rejected або completed. Калі корыстнік адправляе паведамленне, яна дадае його запіс, апэнуе EventSource да адресы /api/chat і стварае паведамленне асистента праз прыбутак змян. Змяна типу text дадаецца да зместу, змяна типу tool_call дадае незавершаны запит да інструмента, а змяна типу tool_result фіксуе рэзультат і пазначае вялікі запит як completed. Пасля кожной змяны яна заменяе паведамленне асистента ў стане на новы экземпляр, тады React перарысвае ей. Функцыя approveToolCall адправляе рашэнне на адресу /api/chat/approve-tool і оптымістычна зменяе статус запиту на approved.
// components/ChatInterface.tsx
"use client";
import { useState, useRef, useCallback } from "react";
import { ToolCallCard } from "./ToolCallCard";
interface Message {
id: string;
role: "user" | "assistant";
content: string;
toolCalls?: ToolCall[];
toolResults?: ToolResult[];
}
interface ToolCall {
id: string;
name: string;
arguments: Record<string, any>;
status: "pending" | "approved" | "rejected" | "completed";
}
export function ChatInterface() {
const [messages, setMessages] = useState<Message[]>([]);
const [input, setInput] = useState("");
const eventSourceRef = useRef<EventSource | null>(null);
const sendMessage = useCallback(async (content: string) => {
// Add user message
const userMsg: Message = {
id: `user-${Date.now()}`,
role: "user",
content,
};
setMessages((prev) => [...prev, userMsg]);
// Open SSE connection to backend
const es = new EventSource(
`/api/chat?message=${encodeURIComponent(content)}`
);
eventSourceRef.current = es;
let assistantMsg: Message = {
id: `assistant-${Date.now()}`,
role: "assistant",
content: "",
toolCalls: [],
};
es.onmessage = (event) => {
const chunk = JSON.parse(event.data);
switch (chunk.type) {
case "text":
assistantMsg.content += chunk.text;
setMessages((prev) => {
const filtered = prev.filter((m) => m.id !== assistantMsg.id);
return [...filtered, { ...assistantMsg }];
});
break;
case "tool_call":
// Model wants to call a tool
assistantMsg.toolCalls = [
...(assistantMsg.toolCalls || []),
{
id: chunk.tool_call_id,
name: chunk.name,
arguments: chunk.arguments,
status: "pending",
},
];
setMessages((prev) => {
const filtered = prev.filter((m) => m.id !== assistantMsg.id);
return [...filtered, { ...assistantMsg }];
});
break;
case "tool_result":
// Tool execution completed
assistantMsg.toolResults = [
...(assistantMsg.toolResults || []),
{
toolCallId: chunk.tool_call_id,
result: chunk.result,
},
];
// Update the specific tool call status
assistantMsg.toolCalls = assistantMsg.toolCalls?.map((tc) =>
tc.id === chunk.tool_call_id
? { ...tc, status: "completed" }
: tc
);
setMessages((prev) => {
const filtered = prev.filter((m) => m.id !== assistantMsg.id);
return [...filtered, { ...assistantMsg }];
});
break;
}
};
es.onerror = () => {
es.close();
};
}, []);
const approveToolCall = useCallback(
async (messageId: string, toolCallId: string) => {
// Send approval to backend
await fetch("/api/chat/approve-tool", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ messageId, toolCallId }),
});
// Optimistically update UI
setMessages((prev) =>
prev.map((msg) => {
if (msg.id !== messageId) return msg;
return {
...msg,
toolCalls: msg.toolCalls?.map((tc) =>
tc.id === toolCallId ? { ...tc, status: "approved" } : tc
),
};
})
);
},
[]
);
return (
<div className="flex flex-col h-screen max-w-3xl mx-auto">
<div className="flex-1 overflow-y-auto p-4 space-y-4">
{messages.map((msg) => (
<div
key={msg.id}
className={`flex ${
msg.role === "user" ? "justify-end" : "justify-start"
}`}
>
<div
className={`max-w-[80%] rounded-lg p-4 ${
msg.role === "user"
? "bg-blue-600 text-white"
: "bg-gray-100 text-gray-900"
}`}
>
<p className="whitespace-pre-wrap">{msg.content}</p>
{msg.toolCalls?.map((tool) => (
<ToolCallCard
key={tool.id}
tool={tool}
onApprove={() => approveToolCall(msg.id, tool.id)}
/>
))}
</div>
</div>
))}
</div>
<div className="border-t p-4">
<form
onSubmit={(e) => {
e.preventDefault();
sendMessage(input);
setInput("");
}}
>
<input
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="Ask about your data..."
className="w-full rounded-lg border px-4 py-2"
/>
</form>
</div>
</div>
);
}
Кожны календзінг інструмента адраджваецца за дапамою маленькага компонента для адраджвання, який паказвае назыв інструмента, його статус, аргументы у форматацыі JSON, а таксама, калі календзінг ў стане чакання, кнопкі «Затвердзіць» і «Адхоўначы»:
// components/ToolCallCard.tsx
interface ToolCallCardProps {
tool: {
name: string;
arguments: Record<string, any>;
status: string;
};
onApprove: () => void;
}
export function ToolCallCard({ tool, onApprove }: ToolCallCardProps) {
return (
<div className="mt-3 rounded border border-yellow-300 bg-yellow-50 p-3">
<div className="flex items-center justify-between">
<span className="text-sm font-semibold text-yellow-800">
🔧 Tool Request: {tool.name}
</span>
<span className="text-xs text-yellow-600 uppercase">
{tool.status}
</span>
</div>
<pre className="mt-2 text-xs bg-white p-2 rounded overflow-x-auto">
{JSON.stringify(tool.arguments, null, 2)}
</pre>
{tool.status === "pending" && (
<div className="mt-3 flex gap-2">
<button
onClick={onApprove}
className="px-3 py-1 bg-green-600 text-white text-sm rounded hover:bg-green-700"
>
Approve
</button>
<button className="px-3 py-1 bg-red-600 text-white text-sm rounded hover:bg-red-700">
Reject
</button>
</div>
)}
</div>
);
}
Сюды і прабачаецца абстракцыя. Інтэрфейс не ведае, што query_users выкананы на базе дадзеных PostgreSQL, і яму не патрэбна будзе змена, калі завтра з’явіцца інструмент search_slack. Ён толькі ведае, што календзінг чакае на рашэнне, якія аргументы ён несе і што людзі павінны прыняць рашэнне ўжо.
Праслейкі, якія трэба закрыць перад запускам у прыменне
Прыклад паказвае структуру інтэрфейса, але ёсць калькі праслейкаў, якія варта закрыць:
- Апраўленне павінна быць выканана на сервере. Частка, якая працуе у спіну, должна зберагчы калленг на інструмент пакуль не отрымае апраўленне для самэго ID калленгу, які асоцыяўаны з автентыфікованным пользователям. Змена статусу ў інтерфейсе ёсць толькі фідбэком; як напісана, нічога не заважае
tool_resultпрыйсці, незалежна ад кнопкі. - У кнопкі «Адхіліць» няма працоўніка. Падключыце яе да канцэнтрабу, якая паведаміць хосту аббіцца калленг і дазволіць модэлю продаваць працу без рэзультата.
EventSourceвыканана толькі GET-запыткі, таму паведамленне пользователя праходзіць у строке запытку, дзе яно падлягае лімітам дужоў URL і можа паставіцца ў логі сервера і проксі. POST-запытка, якая чытае тэла адпаведзі ў формате стріму за дапамогоюfetch, ухіляецца ад обох проблем.
onerror корыстніку замест таго, каб закрыць яго без жадных паведамленняў.Спіс пераканальных пунктав для інтэграцыі MCP для команд React
Раскіяйце гэтыя архітектурныя пытанні пры інтэграцыі MCP:
Хто адпавядае за кліент MCP?
У працоўнай супэрфісе — бэкенд. Серверы MCP зазвычай патрабуюць аутантыфікацыйныя данні, стойкія з’язкі і сэсіі з станам. Дзеўер React аплікацыі должен прымаць структураваны стрім супэўтаў, прызначанный для UI, а не чыстыя паведамленні протаколу.
Як апраўдваюцца запытанні да інструментаў?
Ніколы не дазвольце модэлі выканаць разрушальныя інструменты без чыстай санкцыі. Якщо яна прасіць працэўваць з чым-то на кшталт delete_user, інтерфейс павінен паказаць крок падтверджэння. Гэта стосуецца як доверы корыстніка, так і безпекі. Зробіце чат такім, каб стрімінг адстаўался, калі прыходзіць запуск інструмента, і вяртаўся да роботы толькі пасля санкцыі корыстніка, і, як уже згадвалася, прымусова адстаўляйце його на серверы.
Як стрімуюцься частковыя станы?
Іспользуйце SSE або WebSockets. Адна адпаведзь праходзіць через калькі фаз: модэля размышляе, прасіць інструмент, чакае на яго, а потым продовжвае. Інтерфейс павінен чытка адображаць кожную фазу за дапамою показчыка працэсу, карточак запуску інструментаў і рэзультатаў іх работы у вастоўленай форме, а не як неразбірлівы текст.
Як прадстаўляюцься адказы пра аблыкі?
Серверы MCP не працююць: з’являюцца перерывы у з’ўязку з базай маўлявіння, а серверы файловой системы фіксуюць проблемы з правамі. Фронтэнд должен прымаць гэтыя ситуацыі як структураваныя звесткі пра адказы і паказваць іх як проблемы, якія можна выправіць, а не як зламаны экран.
Як виявляюцца інструменты?
Програма должна прыстосавацца да тых інструментоў, якія є у наявнасці. Калі хост падключаецца да новага сервера, ён должен перадаць апошню версію списку інструментоў фронтэнду, які потым можа паказаць корыстнікаў усія доступныя можлівасці, такія як пошук абліков, пошук дакументаў чы выкананне аналітычных запитоў.
Якія змены ў MCP для роботы фронтэнду?
Без спяшанага пратакту кожны источнік дадзейнаў, інтэграцыя модэляў і інструменты патрабуюць сваёй сабе способу з’яеднання, падобна да шухляды заполненай несуміснымі заряднікамі. Стандарт MCP стандартызуе такое з’яеднанне: дадзеныя ператвараюцца ў інструменты, апісаныя схемай, хосты выкарыстоўваюць іх через адну інтарфейсную плошчу, а UI прадстаўляе кожны вызов як інтэрактыўны элемент. У практыцы:
- Новыя можлівасці могу з’явіцца без змян у фронтэндзе. Падключыце новы сервер MCP да хоста, і універсальны UI для вызоў інструментаў можа адразу прадставіць яго інструменты.
- UI ад’еюнаваны ад модэля. Паколькі ён відображае стабільны струмень супэўта, змена прадавцоў модэляў ёсць прыбліжнаю задачай бэкенду; MCP заставляе частку інструментаў стабільной, тады як хост карыстуецца вызамі модэля, прызначаным для конкрэтнага прадавца.
- Компанента чату, якая розумее вызы інструментаў і ўтверджэння, робіць набагато больш, чым тая, якая відображае markdown.
Галоўныя выводы
- Разместіце MCP на бэкендзе, дзе знаходзяцца крантэнцыі, з’язны і логіі аудыту, і перадавайце структураваныя запісы пад React.
- Стварайце серверы інструментаў на аднойчыных, перакананых, параметрызаваных операцыях, якія вяртаюць толькі тое, што патрабуе модэль.
- Забяжайце апраўленне на серверзе; статус UI ёсць фідбэк, а не механізм контролю.
- Моделюйце чат на аднойчыных станах (тэкст, запускаемая вызов, рызультат, адказка) так, каб новыя інструменты не патрабавалі новага коду UI.
Спадневаная літэратура
- Забезпечэнне безпекі Python LangChain Agent за дапамою семи вбудованых мідлвэраў — Дазвольце дазнацца, як мідлвэры LangChain 1.0 дадаюць функцыі стасумаравання, ліміты вызоў, парадзеныя, альтэрнатыўныя модэлі, выдалення персональных даных і апраўленне чалавекам для агента Gemini без змены яго основнай логікі.