Zum Hauptinhalt springen
tsecurity.de LIVE
Echtzeit-Radar & Feeds
Alle RSS Feeds
👥 Community & Social
Windows Tipps & SecurityGetting Repeated No Caller ID Calls? Here’s What’s Really Going On(22.09.2026 um 22:31 Uhr)
Windows Tipps & SecurityHöllenmaschine: Gaming-Peripherie für gut 1.800 Euro für die HMX 6(23.09.2026 um 10:20 Uhr)
Windows Tipps & SecurityDas nächste große Ding: KI-Agenten(23.09.2026 um 10:30 Uhr)
Sichere ProgrammierungHow AI Is Making Restaurant Menus Easier to Navigate(23.09.2026 um 10:55 Uhr)
Windows Tipps & SecurityGetting Repeated No Caller ID Calls? Here’s What’s Really Going On(22.09.2026 um 22:31 Uhr)
Windows Tipps & SecurityHöllenmaschine: Gaming-Peripherie für gut 1.800 Euro für die HMX 6(23.09.2026 um 10:20 Uhr)
Windows Tipps & SecurityDas nächste große Ding: KI-Agenten(23.09.2026 um 10:30 Uhr)
Sichere ProgrammierungHow AI Is Making Restaurant Menus Easier to Navigate(23.09.2026 um 10:55 Uhr)
Intelligence View
⚡ tsecurity.de Intelligence

Building an MCP server with Node.js

The Model Context Protocol (MCP) is an open standard for connecting AI hosts (Claude, ChatGPT, Cursor, VS Code, and others) to external context and actions through a structured protocol instead of ad-hoc plugins. The host runs an MCP…

0
↗ Quelle (dev.to)
Reagiere als Erste:r — dein Feedback zählt!

The Model Context Protocol (MCP) is an open standard for connecting AI hosts (Claude, ChatGPT, Cursor, VS Code, and others) to external context and actions through a structured protocol instead of ad-hoc plugins.



The host runs an MCP client. Your application is the MCP server, exposing tools (actions the model can invoke), resources (read-only data), and optionally prompts (reusable message templates). Communication uses JSON-RPC over a transport such as stdio or HTTP.



This post shows how to build a small todo MCP server with Node.js using the official @modelcontextprotocol/sdk package and Zod schemas.






Architecture at a glance






sequenceDiagram
participant User
participant Host as AI Host (Claude / ChatGPT)
participant Client as MCP Client
participant Transport as Transport (stdio or HTTP)
participant Server as MCP Server (Node.js)
participant Store as App data / APIs

User->>Host: Natural language request
Host->>Client: Decide to call tool / read resource
Client->>Transport: JSON-RPC (initialize, tools/list, tools/call)
Transport->>Server: Deliver message
Server->>Store: Read or mutate data
Store-->>Server: Result
Server-->>Transport: Tool result / resource contents
Transport-->>Client: Response
Client-->>Host: Structured result
Host-->>User: Answer grounded in tool output






After the client connects, the server completes an initialization handshake (initializeinitialized). The host discovers capabilities via tools/list, resources/list, and prompts/list, then calls tools or reads resources at runtime.






Prerequisites




  • Node.js version 26

  • npm i @modelcontextprotocol/sdk zod

  • Optional for client testing: Claude Desktop and/or ChatGPT (Connectors / Apps)



The stable v1 SDK is @modelcontextprotocol/sdk. A v2 split (@modelcontextprotocol/server, @modelcontextprotocol/client) is in pre-release - this post uses v1, which matches current production tooling.






MCP capabilities - tools, resources, prompts




























Capability Purpose Demo example
Tools Model-invoked actions with typed inputs
add_todo, list_todos, mark_todo_done
Resources Read-only context the host can fetch
todo://all JSON snapshot

Prompts (optional)
Named templates with arguments summarize-open-todos


Tools are the main integration surface - the model calls them via tools/call. Resources are fetched with resources/read and should stay read-only. Prompts return pre-built messages via prompts/get.



Tool inputs need a schema so clients know parameters. With the TypeScript SDK, pass Zod fields in inputSchema:




import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { z } from 'zod';

const server = new McpServer({ name: 'todo-mcp-server', version: '1.0.0' });

server.registerTool(
'add_todo',
{
description: 'Add a new todo item',
inputSchema: { title: z.string().min(1) },
},
async ({ title }) => ({
content: [{ type: 'text', text: JSON.stringify({ title, done: false }) }],
})
);






Register a resource at a fixed URI:




server.registerResource(
'all-todos',
'todo://all',
{
title: 'All todos',
mimeType: 'application/json',
},
async (uri) => ({
contents: [
{
uri: uri.href,
mimeType: 'application/json',
text: JSON.stringify([{ id: 1, title: 'Learn MCP', done: false }]),
},
],
})
);






Register an optional prompt:




server.registerPrompt(
'summarize-open-todos',
{
title: 'Summarize open todos',
description: 'Ask the model to summarize open todos',
},
() => ({
messages: [
{
role: 'user',
content: {
type: 'text',
text: 'Summarize my open todos and suggest a priority order.',
},
},
],
})
);









Building the server



Use a factory so the same server definition works with multiple transports:




import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { z } from 'zod';

const todos = [
{ id: 1, title: 'Learn MCP basics', done: false },
{ id: 2, title: 'Ship demo server', done: false },
];
let nextId = 3;

export function createMcpServer() {
const server = new McpServer({ name: 'todo-mcp-server', version: '1.0.0' });

server.registerTool(
'add_todo',
{
description: 'Add a new todo item',
inputSchema: { title: z.string().min(1) },
},
async ({ title }) => {
const todo = { id: nextId++, title, done: false };
todos.push(todo);
return { content: [{ type: 'text', text: JSON.stringify(todo, null, 2) }] };
}
);

server.registerTool('list_todos', { description: 'List all todo items' }, async () => ({
content: [{ type: 'text', text: JSON.stringify(todos, null, 2) }],
}));

server.registerTool(
'mark_todo_done',
{
description: 'Mark a todo item as done by id',
inputSchema: { id: z.number().int().positive() },
},
async ({ id }) => {
const todo = todos.find((item) => item.id === id);
if (!todo) {
return { content: [{ type: 'text', text: `Todo ${id} not found` }], isError: true };
}
todo.done = true;
return { content: [{ type: 'text', text: JSON.stringify(todo, null, 2) }] };
}
);

// register resource and prompt here (see snippets above)

return server;
}






Tool handlers return { content: [...] }. Set isError: true when a tool fails so the host can surface the error. Resource handlers return { contents: [...] }. Prompt handlers return { messages: [...] }.



The demo uses an in-memory store so you can run it without API keys or a database.






Transports - stdio vs SSE / Streamable HTTP



MCP separates protocol (JSON-RPC messages) from transport (how bytes move between client and server).



Stdio (StdioServerTransport)



The client spawns your server as a child process. JSON-RPC goes over stdin/stdout.





  • Use when: Claude Desktop, Cursor, VS Code, Claude Code, local CLI agents


  • Pros: simplest setup, no ports or firewall rules, no OAuth


  • Cons: one client per process; cloud hosts cannot spawn your local binary




import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { createMcpServer } from './create-server.js';

const server = createMcpServer();
await server.connect(new StdioServerTransport());






Write logs to stderr only - stdout is the protocol channel.



Remote HTTP - SSE (legacy) vs Streamable HTTP (current)



Early MCP remote servers used HTTP + SSE: POST for client→server requests, Server-Sent Events for server→client streaming. That transport is deprecated.



New servers should use Streamable HTTP (StreamableHTTPServerTransport). It supports POST request/response, optional SSE for notifications, and session management. The v2 SDK removes server-side SSE entirely; client-side SSE remains for legacy servers.




























Scenario Transport
Claude Desktop, local dev stdio
Cursor / VS Code project MCP stdio
ChatGPT Apps / Connectors Streamable HTTP over public HTTPS
Legacy SSE-only clients SSE client transport still exists; prefer Streamable HTTP for new servers


Streamable HTTP entry (stateless):




import { createMcpExpressApp } from '@modelcontextprotocol/sdk/server/express.js';
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
import { createMcpServer } from './create-server.js';

const app = createMcpExpressApp();
const PORT = Number(process.env.PORT) || 3000;

app.post('/mcp', async (req, res) => {
const server = createMcpServer();
const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined });

await server.connect(transport);
await transport.handleRequest(req, res, req.body);

res.on('close', () => {
transport.close();
server.close();
});
});

app.listen(PORT, () => {
console.error(`MCP server listening on http://127.0.0.1:${PORT}/mcp`);
});






createMcpExpressApp() enables DNS rebinding protection when binding to localhost - recommended for local HTTP servers.



Deploy Streamable HTTP behind HTTPS before exposing it to cloud clients. ChatGPT Connectors also require OAuth 2.1 for production use.






Connecting MCP clients



Claude Desktop (stdio - primary demo path)



Config file on Windows: %APPDATA%\Claude\claude_desktop_config.json. Open it via Settings → Developer → Edit Config.




{
"mcpServers": {
"todo-mcp": {
"command": "node",
"args": ["C:/path/to/demos/mcp-server-nodejs-demo/src/stdio.js"]
}
}
}






Restart Claude Desktop after saving. Claude shows a tool approval UI before executing write operations.



Claude Desktop (remote HTTP)



claude_desktop_config.json validates stdio servers only - do not put a bare url field there expecting it to work. For a public HTTPS MCP server, use Settings → Connectors → Add custom connector. For local HTTP during development, bridge with mcp-remote as a stdio-launched proxy.



ChatGPT (Connectors / Apps)



ChatGPT has no local MCP config file. Register servers in Settings → Apps (or Connectors) with a name, description, and MCP server URL.



Requirements:





  • Public HTTPS endpoint (Streamable HTTP)


  • OAuth 2.1 for production connectors

  • Stdio-only servers need an HTTP wrapper or tunnel before ChatGPT can reach them



ChatGPT shows confirmation modals before write/modify tool calls.



Cursor



Cursor uses .cursor/mcp.json with the same stdio shape as Claude Desktop (command + args).






What else matters





  • Security - validate tool inputs, scope tools narrowly, and never expose secrets in resources.


  • Logging - stderr only for stdio servers; avoid console.log on stdout.


  • Testing - use @modelcontextprotocol/sdk client helpers with StdioClientTransport for smoke tests.


  • Spec evolution - prefer Streamable HTTP over legacy SSE; watch the v2 SDK split when upgrading.






Demo



Runnable scripts for this post live in the mcp-server-nodejs-demo folder in the private demos repository. Get access via code demos.

Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten Building an MCP server with Node.js

Thematisch verwandte Begriffe: Building, server, with, Nodejs · 6 Treffer

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Zum Aktualisieren ziehen
ZERO-DAY CVE-2026-96258 | A vulnerability has been found in onSite internet GmbH Auktion NG Auktio…
Advisory →
TTS Reader • tsecurity.de Voice
tsecurity.de Icon
tsecurity.de App
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag
Themen-Radar & Intelligence Matrix
Echtzeit-Taxonomie nach Angriffsvektoren & Plattformen

tsecurity.de Live Threat Radar

🔴 LIVE RADAR
MONITORING
AKTIV
CVE-DATENBANK
LIVE
🔍
Community Radar & Live Chat
Sentinel Bot online • Live-Stream
Dein Cluster: Security Explorer
Match:
lädt…
Verbindung zum Community-Stream wird aufgebaut...
Bearbeitungsmodus — Senden überschreibt deine Nachricht
Community-Puls — was gerade passiert
lädt…
Aktivitäten deiner Analysten
lädt…
Neues Thema oder Eilmeldung einreichen

Reiche interessante Links, Zero-Days oder Debatten ein. Die Community entscheidet per Upvote über die Veröffentlichung.

Heiß diskutierte Einreichungen
🔖 Gespeicherte Artikel
📂 Keine gespeicherten Artikel vorhanden.
Zurück Ziehen Vor
Links: vorheriger Artikel Rechts: nächster Artikel unten: schließen
News NIS-2 Frühwarnung Tier-1 Intel ⏱️ 3 Min vor 10 Min
Artikeldaten werden geladen...

Zurück: vorheriger Vor: nächster
↗ Original-Quelle
Social Reaktionen Deine Reaktion zählt
Einstufung & Relevanz-Poll 0 Stimmen
In sozialen Netzwerken teilen 1-Klick