Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Tento článek vysvětluje, jak vytvořit server MCP (Model Context Protocol) pomocí Node.js a TypeScriptu. Server spouští nástroje a služby v bezserverovém prostředí. Tuto strukturu použijte jako výchozí bod k vytvoření vlastních serverů MCP.
Přejděte ke kódu
Prozkoumejte ukázku serveru MCP (Remote Model Context Protocol) TypeScriptu . Ukazuje, jak pomocí Node.js a TypeScriptu sestavit vzdálený server MCP a nasadit ho do Azure Container Apps.
Přejděte do části s návodem kódu, abyste pochopili, jak tato ukázka funguje.
Přehled architektury
Následující diagram znázorňuje jednoduchou architekturu ukázkové aplikace:
Server MCP běží jako kontejnerizovaná aplikace v Azure Container Apps (ACA). Používá back-end Node.js/TypeScript k poskytování nástrojů klientovi MCP prostřednictvím protokolu kontextu modelu. Všechny nástroje pracují s back-endovou databází SQLite.
Náklady
Pokud chcete zachovat nízké náklady, tato ukázka používá u většiny prostředků základní nebo spotřební cenové úrovně. Podle potřeby upravte úroveň a odstraňte prostředky, abyste se vyhnuli poplatkům.
Požadavky
- Visual Studio Code – nejnovější verze pro podporu vývoje serveru MCP.
- GitHub Copilot Rozšíření editoru Visual Studio Code
- GitHub Copilot Chat Rozšíření editoru Visual Studio Code
- Azure Developer CLI (azd)
Vývojový kontejner obsahuje všechny závislosti, které potřebujete pro tento článek. Můžete ho spustit v GitHub Codespaces (v prohlížeči) nebo místně pomocí editoru Visual Studio Code.
Pokud chcete postupovat podle tohoto článku, ujistěte se, že splňujete tyto požadavky:
- Předplatné Azure – Vytvořte si ho zdarma
- Oprávnění účtu Azure – Váš účet Azure musí mít
Microsoft.Authorization/roleAssignments/writeoprávnění, jako je správce řízení přístupu na základě role, správce uživatelských přístupů nebo vlastník. Pokud nemáte oprávnění na úrovni předplatného, musíte mít oprávnění RBAC pro existující skupinu prostředků a nasadit ji do této skupiny.- Váš účet Azure také potřebuje
Microsoft.Resources/deployments/writeoprávnění na úrovni předplatného.
- Váš účet Azure také potřebuje
- Účet GitHub
Otevřené vývojové prostředí
Podle těchto kroků nastavte předem nakonfigurované vývojové prostředí se všemi požadovanými závislostmi.
GitHub Codespaces spouští vývojový kontejner spravovaný GitHubem pomocí editoru Visual Studio Code pro web jako rozhraní. K nejjednoduššímu nastavení použijte GitHub Codespaces, protože obsahuje potřebné nástroje a závislosti předinstalované pro tento článek.
Důležité
Všechny účty GitHubu můžou každý měsíc používat Codespaces až 60 hodin zdarma se dvěma základními instancemi. Podrobnější informace najdete v GitHub Codespaces o měsíčně zahrnutém úložišti a hodinách jádra.
Pomocí následujícího postupu vytvořte nový GitHub Codespace ve main větvi Azure-Samples/mcp-container-ts úložiště GitHub.
Klikněte pravým tlačítkem myši na následující tlačítko a vyberte Otevřít odkaz v novém okně. Tato akce umožňuje mít vývojové prostředí a otevřenou dokumentaci vedle sebe.
Na stránce Create codespace (Vytvořit kódový prostor ) zkontrolujte a pak vyberte Create new codespace (Vytvořit nový prostor kódu).
Počkejte, až se codespace spustí. Může to trvat několik minut.
Přihlaste se k Azure pomocí Azure Developer CLI v terminálu v dolní části obrazovky.
azd auth loginZkopírujte kód z terminálu a vložte ho do prohlížeče. Postupujte podle pokynů k ověření pomocí účtu Azure.
Proveďte zbývající úlohy v tomto vývojovém kontejneru.
Poznámka:
Místní spuštění serveru MCP:
- Nastavte prostředí podle popisu v části Nastavení místního prostředí v ukázkovém úložišti.
- Podle pokynů v části Konfigurace serveru MCP v nástroji Visual Studio Code v ukázkovém úložišti nakonfigurujte server MCP tak, aby používal místní prostředí.
- Pokračujte v části Použití nástrojů serveru TODO MCP v režimu agenta .
Nasazení a spuštění
Ukázkové úložiště obsahuje veškerý kód a konfigurační soubory pro nasazení Azure serveru MCP. Následující kroky vás provedou ukázkovým procesem nasazení Azure serveru MCP.
Nasazení do Azure
Důležité
Prostředky Azure v této části začnou okamžitě účtovat peníze, a to i když zastavíte příkaz před jeho dokončením.
Spusťte následující příkaz Azure Developer CLI pro zřizování prostředků Azure a nasazení zdrojového kódu:
azd upPomocí následující tabulky odpovězte na výzvy:
Podnět Odpověď Název prostředí Udržte to krátké a pište malými písmeny. Přidejte svoje jméno nebo alias. Například: my-mcp-server. Používá se jako součást názvu skupiny prostředků.Předplatné Vyberte předplatné, ve kterém chcete prostředky vytvořit. Umístění (pro hostování) V seznamu vyberte umístění blízko vás. Umístění modelu Azure OpenAI V seznamu vyberte umístění blízko vás. Pokud je stejné umístění dostupné jako vaše první umístění, vyberte ho. Počkejte, až se aplikace nasadí. Dokončení nasazení obvykle trvá 5 až 10 minut.
Po dokončení nasazení můžete k serveru MCP přistupovat pomocí adresy URL zadané ve výstupu. Adresa URL vypadá takto:
https://<env-name>.<container-id>.<region>.azurecontainerapps.io
- Zkopírujte adresu URL do schránky. Budete ho potřebovat v další části.
Konfigurace serveru MCP v editoru Visual Studio Code
Nakonfigurujte server MCP v místním prostředí VS Code přidáním adresy URL do mcp.json souboru ve .vscode složce.
Otevřete soubor
mcp.jsonve složce.vscode.Vyhledejte sekci
mcp-server-sse-remotev souboru. Měl by vypadat takto:"mcp-server-sse-remote": { "type": "sse", "url": "https://<container-id>.<location>.azurecontainerapps.io/sse" }Nahraďte existující
urlhodnotu adresou URL, kterou jste zkopírovali v předchozím kroku.mcp.jsonUložte soubor do.vscodesložky.
Použití nástrojů serveru TODO MCP v režimu agenta
Po úpravě serveru MCP můžete použít nástroje, které poskytuje v režimu agenta. Použití nástrojů MCP v režimu agenta:
Otevřete zobrazení chatu (
Ctrl+Alt+I) a v rozevíracím seznamu vyberte režim agenta.Výběrem tlačítka Nástroje zobrazíte seznam dostupných nástrojů. Volitelně můžete vybrat nebo zrušit výběr nástrojů, které chcete použít. Nástroje můžete hledat zadáním do vyhledávacího pole.
Do pole pro vstup chatu zadejte výzvu, například "Potřebuji poslat e-mail vedoucímu ve středu" a všimněte si, jak jsou nástroje automaticky aktivovány podle potřeby, jak je znázorněno na následujícím snímku obrazovky.
Poznámka:
Ve výchozím nastavení je při vyvolání nástroje nutné před spuštěním nástroje akci potvrdit. Jinak se nástroje můžou spouštět místně na vašem počítači a můžou provádět akce, které upravují soubory nebo data.
Pomocí rozevíracího seznamu Tlačítka Pokračovat můžete automaticky potvrdit konkrétní nástroj pro aktuální relaci, pracovní prostor nebo všechna budoucí vyvolání.
Prozkoumání ukázkového kódu
Tato část obsahuje přehled klíčových souborů a struktury kódu v ukázce serveru MCP. Kód je uspořádaný do několika hlavních komponent:
-
index.ts: Hlavní vstupní bod pro server MCP, který nastaví HTTP server Express.js a směrování. -
server.ts: Přenosová vrstva, která spravuje připojení Server-Sent Events (SSE) a zpracování protokolů MCP. -
tools.ts: Obsahuje obchodní logiku a funkce nástroje pro server MCP. -
types.ts: Definuje typy a rozhraní TypeScript používané na celém serveru MCP.
index.ts - Jak se server spouští a přijímá připojení HTTP
Soubor index.ts je hlavním vstupním bodem serveru MCP. Inicializuje server, nastaví Express.js server HTTP a definuje směrování pro koncové body Server-Sent Events (SSE).
Vytvoření instance serveru MCP
Následující fragment kódu inicializuje server MCP pomocí StreamableHTTPServer třídy, což je obálka kolem základní třídy MCP Server . Tato třída zpracovává transportní vrstvu pro Server-Sent Events (SSE) a spravuje připojení klientů.
const server = new StreamableHTTPServer(
new Server(
{
name: 'todo-http-server',
version: '1.0.0',
},
{
capabilities: {
tools: {},
},
}
)
);
Koncepty:
-
Vzor složení:
SSEPServerobaluje třídu nízké úrovněServer - Deklarace schopností: Server oznámí, že podporuje nástroje (ale ne prostředky nebo výzvy)
- Zásady vytváření názvů: Název serveru se stane součástí identifikace MCP.
Nastavení expressových tras
Následující fragment kódu nastaví Express.js server pro zpracování příchozích požadavků HTTP pro připojení SSE a zpracování zpráv:
router.post('/messages', async (req: Request, res: Response) => {
await server.handlePostRequest(req, res);
});
router.get('/sse', async (req: Request, res: Response) => {
await server.handleGetRequest(req, res);
});
Koncepty:
- Model dvou koncových bodů: GET pro navázání připojení SSE, POST pro odesílání zpráv
-
Model delegování: Expresní trasy okamžitě delegovat na
SSEPServer
Správa životního cyklu procesů
Následující fragment kódu zpracovává životní cyklus serveru, včetně spuštění serveru a jeho řádné vypnutí na signálech ukončení:
process.on('SIGINT', async () => {
log.error('Shutting down server...');
await server.close();
process.exit(0);
});
Koncepty:
- Plynulé vypnutí: Korektní ukončení na Ctrl+C
- Asynchronní vyčištění: Operace uzavření serveru je asynchronní
- Správa prostředků: Důležité pro připojení SSE
Přenosová vrstva: server.ts
Tento server.ts soubor implementuje transportní vrstvu pro MCP server, konkrétně zpracovává připojení Server-Sent Events (SSE) a směrování zpráv protokolu MCP.
Nastavení připojení klienta SSE a vytvoření přenosu
Třída SSEPServer je hlavní přenosová vrstva pro zpracování Server-Sent Events (SSE) na serveru MCP. Používá třídu SSEServerTransport ke správě jednotlivých klientských připojení. Spravuje více transportních systémů a jejich životní cyklus.
export class SSEPServer {
server: Server;
transport: SSEServerTransport | null = null;
transports: Record<string, SSEServerTransport> = {};
constructor(server: Server) {
this.server = server;
this.setupServerRequestHandlers();
}
}
Koncepty:
- Správa stavu: Sleduje aktuální přepravu i všechny přepravy.
- Mapování relací: objekt mapuje ID relací na přenosové instance.
- Delegování konstruktoru: Okamžitě nastaví obslužné rutiny pro zpracování požadavků.
Zřízení připojení SSE (handleGetRequest)
Metoda handleGetRequest je zodpovědná za vytvoření nového připojení SSE, když klient odešle do koncového /sse bodu požadavek GET.
async handleGetRequest(req: Request, res: Response) {
log.info(`GET ${req.originalUrl} (${req.ip})`);
try {
log.info("Connecting transport to server...");
this.transport = new SSEServerTransport("/messages", res);
TransportsCache.set(this.transport.sessionId, this.transport);
res.on("close", () => {
if (this.transport) {
TransportsCache.delete(this.transport.sessionId);
}
});
await this.server.connect(this.transport);
log.success("Transport connected. Handling request...");
} catch (error) {
// Error handling...
}
}
Koncepty:
-
Vytvoření přenosu: Nové
SSEServerTransportpro každý požadavek GET - Správa relací: Automaticky vygenerované ID relace uložené v mezipaměti
- Obslužné rutiny událostí: Vyčištění při zavření připojení
-
Připojení MCP:
server.connect()navazuje spojení protokolu - Asynchronní tok: Nastavení připojení je asynchronní s hranicemi chyb
Zpracování zpráv (handlePostRequest)
Metoda handlePostRequest zpracovává příchozí požadavky POST za účelem zpracování zpráv MCP odeslaných klientem. K vyhledání správné instance přenosu používá ID relace z parametrů dotazu.
async handlePostRequest(req: Request, res: Response) {
log.info(`POST ${req.originalUrl} (${req.ip}) - payload:`, req.body);
const sessionId = req.query.sessionId as string;
const transport = TransportsCache.get(sessionId);
if (transport) {
await transport.handlePostMessage(req, res, req.body);
} else {
log.error("Transport not initialized. Cannot handle POST request.");
res.status(400).json(/* error response */);
}
}
Koncepty:
-
Vyhledávání relace: Používá
sessionIdparametr dotazu k vyhledání přenosu. - Ověření relace: Nejprve ověří připojení SSE.
- Delegování zpráv: Transportní vrstva zpracovává skutečné zpracování zpráv.
- Chybové odpovědi: Správné kódy chyb HTTP pro chybějící relace
Nastavení obslužné rutiny protokolu MCP (setupServerRequestHandlers)
Metoda setupServerRequestHandlers zaregistruje následující obslužné rutiny pro požadavky protokolu MCP:
- Obslužný program pro
ListToolsRequestSchemavracející seznam dostupných TODO nástrojů. - Obslužná rutina,
CallToolRequestSchemakterá vyhledá a spustí požadovaný nástroj se zadanými argumenty.
Tato metoda používá schémata Zod k definování očekávaných formátů požadavků a odpovědí.
private setupServerRequestHandlers() {
this.server.setRequestHandler(ListToolsRequestSchema, async (_request) => {
return {
tools: TodoTools,
};
});
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
const tool = TodoTools.find((tool) => tool.name === name);
if (!tool) {
return this.createJSONErrorResponse(`Tool "${name}" not found.`);
}
const response = await tool.execute(args as any);
return { content: [{ type: "text", text: response }] };
});
}
Koncepty:
- Schema-Based Routing: Používá schémata Zod pro zpracování typově bezpečných požadavků.
-
Zjišťování nástrojů:
ListToolsRequestSchemaVrátí statické pole TodoTools. -
Provádění nástrojů:
CallToolRequestSchemanajde a spustí nástroje. - Zpracování chyb: Řádné zpracování neznámých nástrojů
- Formát odpovědi: Struktura odpovědí kompatibilní s MCP
- Zabezpečení typů: Typy TypeScript zajišťují správné předávání argumentů.
Obchodní logika: tools.ts
Soubor tools.ts definuje skutečnou funkčnost dostupnou klientům MCP:
- Metadata nástrojů (název, popis, schémata)
- Schémata ověřování vstupu
- Logika spouštění nástrojů
- Integrace s databázovou vrstvou
Tento MCP Server definuje čtyři nástroje pro správu úkolů:
-
add_todo: Vytvoří novou položku TODO. -
complete_todo: Označí položku úkol jako dokončenou. -
delete_todo: Odstraní položku TODO. -
list_todos: Zobrazí seznam všech položek seznamu úkolů. -
update_todo_text: Aktualizuje text existující položky TODO.
Vzor definice nástroje
Nástroje jsou definovány jako pole objektů, z nichž každá představuje konkrétní operaci TODO. V následujícím fragmentu addTodo kódu je nástroj definován:
{
name: "addTodo",
description: "Add a new TODO item to the list...",
inputSchema: {
type: "object",
properties: {
text: { type: "string" },
},
required: ["text"],
},
outputSchema: { type: "string" },
async execute({ text }: { text: string }) {
const info = await addTodo(text);
return `Added TODO: ${text} (id: ${info.lastInsertRowid})`;
},
}
Každá definice nástroje má:
-
name: Jedinečný identifikátor nástroje -
description: Stručný popis účelu nástroje -
inputSchema: Schéma Zod definující očekávaný vstupní formát -
outputSchema: Schéma Zod definující očekávaný výstupní formát -
execute: Funkce implementuje logiku nástroje.
Tyto definice nástrojů se importují ve server.ts a jsou zpřístupněny skrze handler ListToolsRequestSchema.
Koncepty:
- Modulární návrh nástrojů: Každý nástroj je samostatný objekt.
-
Ověřování schématu JSON: definuje očekávané parametry.
inputSchema - Zabezpečení typů: Typy TypeScriptu odpovídají definicům schématu.
- Asynchronní spuštění: Všechna spuštění nástrojů jsou asynchronní
- Integrace databáze: Volání importovaných databázových funkcí
- Human-Readable Odpovědi: Vrátí formátované řetězce, ne nezpracovaná data.
Export pole nástrojů
Nástroje se exportují jako statické pole, což usnadňuje import a použití na serveru. Každý nástroj je objekt s jeho metadaty a logikou spouštění. Tato struktura umožňuje serveru MCP dynamicky zjišťovat a spouštět nástroje na základě požadavků klientů.
export const TodoTools = [
{ /* addTodo */ },
{ /* listTodos */ },
{ /* completeTodo */ },
{ /* deleteTodo */ },
{ /* updateTodoText */ },
];
Koncepty:
- Statická registrace: Nástroje definované v době načítání modulu
- Struktura pole: Jednoduché pole usnadňuje iteraci nástrojů
- Import/export: Vyčištění oddělení od logiky serveru
Zpracování chyb při provádění nástrojů
Funkce jednotlivých nástrojů execute zpracovává chyby hladce a vrací jasné zprávy místo vyvolání výjimek. Tento přístup zajišťuje, že server MCP poskytuje bezproblémové uživatelské prostředí.
Nástroje zpracovávají různé chybové scénáře:
async execute({ id }: { id: number }) {
const info = await completeTodo(id);
if (info.changes === 0) {
return `TODO with id ${id} not found.`;
}
return `Marked TODO ${id} as completed.`;
}
Koncepty:
-
Kontrola odezvy databáze: Používá
info.changesse k detekci selhání. - Plynulé zhoršení: Vrátí popisné chybové zprávy místo vyvolání výjimek.
- chybyUser-Friendly: Zprávy vhodné pro interpretaci AI
Datová vrstva: db.ts
Tento db.ts soubor spravuje připojení k databázi SQLite a zpracovává operace CRUD pro aplikaci TODO. Používá knihovnu better-sqlite3 pro synchronní přístup k databázi.
Inicializace databáze
Databáze se inicializuje připojením k SQLite a vytvořením tabulek, pokud neexistují. Následující fragment kódu ukazuje proces inicializace:
const db = new Database(":memory:", {
verbose: log.info,
});
try {
db.pragma("journal_mode = WAL");
db.prepare(
`CREATE TABLE IF NOT EXISTS ${DB_NAME} (
id INTEGER PRIMARY KEY AUTOINCREMENT,
text TEXT NOT NULL,
completed INTEGER NOT NULL DEFAULT 0
)`
).run();
log.success(`Database "${DB_NAME}" initialized.`);
} catch (error) {
log.error(`Error initializing database "${DB_NAME}":`, { error });
}
Koncepty:
-
In-Memory Databáze:
:memory:znamená ztrátu dat při restartování (pouze demo/testování) - Režim WAL: logování Write-Ahead pro lepší výkon
- Definice schématu: Jednoduchá tabulka TODO s ID automatického přírůstku
- Zpracování chyb: Řádné zpracování inicializačních selhání
- Protokolování integrace: Operace databáze jsou zaznamenány pro účely ladění.
Vzory operací CRUD
Soubor db.ts poskytuje čtyři hlavní operace CRUD pro správu položek úkolů:
Operace vytvoření:
export async function addTodo(text: string) {
log.info(`Adding TODO: ${text}`);
const stmt = db.prepare(`INSERT INTO todos (text, completed) VALUES (?, 0)`);
return stmt.run(text);
}
Operace čtení:
export async function listTodos() {
log.info("Listing all TODOs...");
const todos = db.prepare(`SELECT id, text, completed FROM todos`).all() as Array<{
id: number;
text: string;
completed: number;
}>;
return todos.map(todo => ({
...todo,
completed: Boolean(todo.completed),
}));
}
Operace aktualizace:
export async function completeTodo(id: number) {
log.info(`Completing TODO with ID: ${id}`);
const stmt = db.prepare(`UPDATE todos SET completed = 1 WHERE id = ?`);
return stmt.run(id);
}
Operace odstranění:
export async function deleteTodo(id: number) {
log.info(`Deleting TODO with ID: ${id}`);
const row = db.prepare(`SELECT text FROM todos WHERE id = ?`).get(id) as
| { text: string }
| undefined;
if (!row) {
log.error(`TODO with ID ${id} not found`);
return null;
}
db.prepare(`DELETE FROM todos WHERE id = ?`).run(id);
log.success(`TODO with ID ${id} deleted`);
return row;
}
Koncepty:
- Připravené příkazy: Ochrana proti injektáži SQL
- Přetypování typů: Explicitní typy TypeScriptu pro výsledky dotazu
- Transformace dat: Převod celých čísel SQLite na logické hodnoty
- Atomické operace: Každá funkce je jedna databázová transakce.
- Konzistence návratových hodnot: Metadata operace vrácení funkcí
- Obranné programování: Vzor kontroly před odstraněním
Návrh schématu
Schéma databáze je definováno v db.ts souboru pomocí jednoduchého příkazu SQL. Tabulka todos obsahuje tři pole:
CREATE TABLE todos (
id INTEGER PRIMARY KEY AUTOINCREMENT, -- Unique identifier
text TEXT NOT NULL, -- TODO description
completed INTEGER NOT NULL DEFAULT 0 -- Boolean as integer
);
Pomocné nástroje: helpers/ adresář
Adresář helpers/ poskytuje pro server funkce a třídy nástrojů.
Strukturované logování pro ladění a monitorování: helpers/logs.ts
Soubor helpers/logs.ts poskytuje nástroj pro strukturované protokolování pro server MCP. Používá knihovnu debug pro protokolování a chalk pro barevný výstup v konzole.
export const logger = (namespace: string) => {
const dbg = debug('mcp:' + namespace);
const log = (colorize: ChalkInstance, ...args: any[]) => {
const timestamp = new Date().toISOString();
const formattedArgs = [timestamp, ...args].map((arg) => {
if (typeof arg === 'object') {
return JSON.stringify(arg, null, 2);
}
return arg;
});
dbg(colorize(formattedArgs.join(' ')));
};
return {
info(...args: any[]) { log(chalk.cyan, ...args); },
success(...args: any[]) { log(chalk.green, ...args); },
warn(...args: any[]) { log(chalk.yellow, ...args); },
error(...args: any[]) { log(chalk.red, ...args); },
};
};
Správa relací pro přenosy SSE: helpers/cache.ts
Soubor helpers/cache.ts používá Map k ukládání přenosů SSE podle ID relace. Tento přístup umožňuje serveru rychle najít a spravovat aktivní připojení.
import type { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse";
export const TransportsCache = new Map<string, SSEServerTransport>();
Poznámka:
TransportsCache je jednoduchá mezipaměť v paměti. V produkčním prostředí zvažte použití robustnějšího řešení, jako je Redis nebo databáze pro správu relací.
Souhrn toku provádění
Následující diagram znázorňuje úplnou cestu požadavku od klienta k serveru MCP a zpět, včetně provádění nástrojů a databázových operací:
Vyčištění služby GitHub Codespaces
Odstraňte prostředí Codespaces na GitHubu pro maximální využití vašich bezplatných hodin pro jednotlivé jádro.
Důležité
Další informace o bezplatném úložišti a hodinách procesoru vašeho účtu GitHub najdete v tématu GitHub Codespaces měsíčně zahrnuté úložiště a hodiny procesoru.
Vyhledejte aktivní Codespaces vytvořené z
Azure-Samples//mcp-container-tsúložiště na GitHubu.Otevřete kontextovou nabídku pro codespace a vyberte Odstranit.
Získání pomoci
Zapište svůj problém do problémů úložiště.