लोकल MCP सर्वर कैसे बनाएँ और Claude से जोड़ें (काम करने वाले कोड के साथ)
खाली फ़ोल्डर से लोकल MCP सर्वर बनाएँ: TypeScript SDK इंस्टॉल करें, दो काम करने वाले टूल रजिस्टर करें, MCP Inspector में उनकी जाँच करें, फिर सर्वर को Claude Desktop और Claude Code से जोड़ें। इसमें कॉन्फ़िग फ़ाइलें, Windows पाथ के सुधार और उन आम विफलताओं की चेकलिस्ट शामिल है जो ज़्यादातर सेटअप तोड़ देती हैं।
ज़्यादातर MCP ट्यूटोरियल "hello world" पर रुक जाते हैं और आपको लाल Disconnected बैज के सामने छोड़ देते हैं। यह ट्यूटोरियल आपकी अपनी मशीन पर चलते सर्वर पर खत्म होता है, जहाँ Claude उसके टूल कॉल करता है। साथ ही उन विफलताओं की छोटी चेकलिस्ट भी है जो ज़्यादातर लोगों को परेशान करती हैं। आप लगभग 70 लाइन का TypeScript लिखेंगे, उसे ब्राउज़र-आधारित इंस्पेक्टर में जाँचेंगे और नतीजे को Claude Desktop और Claude Code दोनों से जोड़ेंगे।
यह सर्वर एक छोटा नोट्स टूल है: Claude आपकी डिस्क पर एक JSON फ़ाइल में नोट सेव कर सकता है और बाद में उसमें खोज सकता है। इसे जानबूझकर सादा रखा गया है, क्योंकि कनेक्शन का ढांचा वही रहता है, चाहे आपके टूल नोट्स फ़ाइल पढ़ें, डेटाबेस क्वेरी करें या इमेज मॉडल को कॉल करें। मैंने नीचे दी गई सर्वर फ़ाइल TypeScript SDK के वर्ज़न 1.32 के साथ कंपाइल और चलाकर देखी है, इसलिए कोड ठीक वैसे ही बनता है जैसे दिखाया गया है।
आप असल में क्या बना रहे हैं
दो पैराग्राफ़ में MCP
Model Context Protocol (MCP) एक ओपन स्टैंडर्ड है, जिसे Anthropic ने नवंबर 2024 में पेश किया था। यह किसी AI ऐप को बाहरी टूल से एक ही सुसंगत तरीके से बात करने देता है। हर ऐप अपना अलग प्लगइन फ़ॉर्मेट बनाने के बजाय, एक MCP सर्वर अपनी क्षमताएँ दिखाता है, और Claude Desktop या Claude Code जैसा MCP क्लाइंट उन्हें खोजकर कॉल करता है। संदेश सादे JSON-RPC 2.0 में होते हैं, इसलिए सर्वर किसी भी भाषा में लिखा जा सकता है।
एक सर्वर तीन तरह की चीज़ें दे सकता है:
Tools: ऐसे फ़ंक्शन जिन्हें मॉडल कॉल कर सकता है, जैसे "नोट सेव करो" या "क्वेरी चलाओ"।
Resources: केवल-पढ़ने वाला डेटा जिसे ऐप संदर्भ के रूप में लोड कर सकता है, जैसे कोई फ़ाइल या डेटाबेस रिकॉर्ड।
Prompts: दोहराए जा सकने वाले प्रॉम्प्ट टेम्पलेट, जिन्हें यूज़र जानबूझकर चालू करता है।
यह ट्यूटोरियल सिर्फ़ टूल पर केंद्रित है, क्योंकि उन्हें जाँचना सबसे आसान है और पहले ही दिन सबसे काम के हैं।
लोकल क्यों चलाएँ
लोकल सर्वर क्लाइंट के चाइल्ड प्रोसेस के रूप में चलता है, आपकी मशीन पर, आपकी फ़ाइलों और आपकी अनुमतियों के साथ। कुछ भी इंटरनेट पर उजागर नहीं होता, होस्टिंग का कोई बिल नहीं आता, और सुधार तेज़ी से होता है: फ़ाइल बदलें, फिर से बिल्ड करें, फिर रीस्टार्ट करें। यह stdio ट्रांसपोर्ट इस्तेमाल करता है: क्लाइंट आपका प्रोग्राम लॉन्च करता है और स्टैंडर्ड इनपुट व आउटपुट के ज़रिए उससे बात करता है।
stdio (लोकल)
Streamable HTTP (रिमोट)
कहाँ चलता है
आपके कंप्यूटर पर चाइल्ड प्रोसेस
एक वेब सर्वर जिसे आप या कोई और होस्ट करता है
कौन पहुँच सकता है
केवल वह ऐप जिसने उसे लॉन्च किया
URL और क्रेडेंशियल वाला कोई भी व्यक्ति
ऑथेंटिकेशन
कोई नहीं, यह आपके यूज़र अकाउंट को इनहेरिट करता है
ज़रूरी (OAuth या टोकन)
सबसे अच्छा किसके लिए
पर्सनल टूल, फ़ाइल एक्सेस, डेवलपमेंट
साझा टीम टूल, SaaS इंटीग्रेशन
💡 जानना अच्छा है: Streamable HTTP ने 2025-03-26 स्पेक रिविज़न में पुराने HTTP+SSE ट्रांसपोर्ट की जगह ली। और चूँकि ब्राउज़र आपके कंप्यूटर पर कोई प्रोसेस लॉन्च नहीं कर सकता, इसलिए stdio सर्वर को ब्राउज़र में claude.ai में नहीं जोड़ा जा सकता। वहाँ केवल रिमोट सर्वर काम करते हैं।
प्रोजेक्ट सेट अप करें
क्या इंस्टॉल होना चाहिए
टूल
वर्ज़न
जाँच कैसे करें
Node.js
20 LTS या नया
node --version
npm
Node के साथ आता है
npm --version
Claude Desktop
नवीनतम, macOS या Windows
Settings, फिर Developer
Claude Code (वैकल्पिक)
नवीनतम
claude --version
Claude Desktop macOS और Windows के लिए आता है। Linux पर नीचे दिए कनेक्शन सेक्शन में Claude Code वाला रास्ता अपनाएँ; सर्वर खुद बिल्कुल वैसा ही है।
⚠️ सावधान: TypeScript 7, जो आज npm इंस्टॉल करता है, अब अपने आप @types पैकेज लोड नहीं करता। "types": ["node"] लाइन के बिना हर Node import पर आपको Cannot find name 'process' और इसी तरह की एरर मिलेंगी।
अपने पहले दो टूल लिखें
पूरी सर्वर फ़ाइल
इसे src/index.ts के नाम से सेव करें। यह save_note और search_notes दिखाती है, और सब कुछ एक JSON फ़ाइल में रखती है।
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
import { promises as fs } from "node:fs";
import os from "node:os";
import path from "node:path";
const NOTES_DIR = process.env.NOTES_DIR ?? path.join(os.homedir(), "mcp-notes");
const NOTES_FILE = path.join(NOTES_DIR, "notes.json");
type Note = { id: number; title: string; body: string; createdAt: string };
async function readNotes(): Promise<Note[]> {
try {
return JSON.parse(await fs.readFile(NOTES_FILE, "utf8"));
} catch {
return [];
}
}
const server = new McpServer({ name: "local-notes", version: "1.0.0" });
server.registerTool(
"save_note",
{
title: "Save note",
description: "Save a short note with a title and a body to the local notes file.",
inputSchema: {
title: z.string().min(1).max(120).describe("Short title for the note"),
body: z.string().min(1).describe("The text of the note"),
},
},
async ({ title, body }) => {
const notes = await readNotes();
const note: Note = {
id: notes.length + 1,
title,
body,
createdAt: new Date().toISOString(),
};
await fs.mkdir(NOTES_DIR, { recursive: true });
await fs.writeFile(NOTES_FILE, JSON.stringify([...notes, note], null, 2));
return { content: [{ type: "text", text: `Saved note #${note.id}: ${title}` }] };
}
);
server.registerTool(
"search_notes",
{
title: "Search notes",
description: "Find saved notes whose title or body contains a word or phrase.",
inputSchema: {
query: z.string().min(1).describe("Word or phrase to look for"),
},
},
async ({ query }) => {
const q = query.toLowerCase();
const hits = (await readNotes()).filter((n) =>
`${n.title} ${n.body}`.toLowerCase().includes(q)
);
if (hits.length === 0) {
return { content: [{ type: "text", text: `No notes match "${query}".` }] };
}
const text = hits.map((n) => `#${n.id} ${n.title}\n${n.body}`).join("\n\n");
return { content: [{ type: "text", text }] };
}
);
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("local-notes MCP server running on stdio");
हर हिस्सा क्या करता है
McpServer हाई-लेवल क्लास है। आप जो name और version देते हैं, वे क्लाइंट की सर्वर सूची और लॉग में दिखते हैं।
registerTool एक टूल नाम, एक कॉन्फ़िग ऑब्जेक्ट (title, description, inputSchema) और एक async हैंडलर लेता है।
Zod schema आपका हैंडलर चलने से पहले वैलिडेट होता है, फिर Claude के पढ़ने के लिए JSON Schema में बदला जाता है। हर .describe() स्ट्रिंग मॉडल तक पहुँचती है।
रिटर्न वैल्यू हमेशा { content: [...] } होती है। सादा टेक्स्ट सबसे सरल कंटेंट टाइप है; इमेज और रिसोर्स लिंक भी समर्थित हैं।
StdioServerTransport stdin से अनुरोध पढ़ता है और stdout पर जवाब लिखता है।
💡 टिप: विवरण मॉडल के लिए लिखें, इंसानों के लिए नहीं। "ऐसे सेव किए गए नोट खोजें जिनके शीर्षक या बॉडी में कोई शब्द या वाक्यांश हो" Claude को बताता है कि टूल कब कॉल करना है। "Search" नहीं बताता। Claude टूल ज़्यादातर उनके नाम और विवरण से चुनता है।
चूँकि search_notes कभी कुछ नहीं बदलता, इसलिए इसकी कॉन्फ़िग में यह बात चिह्नित करें: annotations: { readOnlyHint: true }। ये hints केवल सलाह हैं, और क्लाइंट खुद तय करते हैं कि उन पर कितना भरोसा करें। फिर भी ये अच्छे व्यवहार वाले क्लाइंट को केवल-पढ़ने वाले टूल के साथ नरमी से पेश आने देते हैं।
stdout पर कभी प्रिंट न करें
stdio में stdout ही प्रोटोकॉल चैनल है। एक भटका हुआ console.log("started") स्ट्रीम में गैर-JSON लाइन भेज देता है, और ज़्यादातर क्लाइंट या तो कनेक्शन तोड़ देंगे या सर्वर को failed दिखाएँगे। यह नियम याद रखें, तो पहले दिन की सबसे आम विफलता से बच जाएँगे:
करें:console.error("message"), जो stderr पर लिखता है, जहाँ क्लाइंट लॉग इकट्ठा करते हैं।
न करें: आपके सर्वर में कहीं भी console.log(...) या process.stdout.write(...), जिसमें वे लाइब्रेरी भी शामिल हैं जो आप इम्पोर्ट करते हैं।
Claude से पहले खुद जाँचें
MCP Inspector चलाएँ
MCP Inspector आधिकारिक डीबगिंग टूल है। यह आपके सर्वर को ठीक उसी तरह लॉन्च करता है जैसे क्लाइंट करेगा, और कमांड-लाइन के निर्देशों की जगह आपको बटन देता है।
npm run build
npx @modelcontextprotocol/inspector node build/index.js
आपके ब्राउज़र में एक पेज खुलता है। Connect पर क्लिक करें, Tools टैब खोलें और List Tools दबाएँ। आपको save_note और search_notes उनके schemas के साथ दिखने चाहिए। एक शीर्षक और बॉडी के साथ save_note चलाएँ, फिर उस बॉडी के किसी शब्द के साथ search_notes चलाएँ। पहली कॉल Saved note #1: Standup लौटाती है, और नोट्स फ़ाइल आपके होम डायरेक्टरी के अंदर mcp-notes फ़ोल्डर में दिखती है (या अगर आपने सेट किया हो तो NOTES_DIR में)।
कच्चे JSON-RPC संदेश भेजें
अगर आप खुद प्रोटोकॉल देखना चाहते हैं, तो stdio में हर संदेश एक JSON के रूप में एक लाइन में होता है। ये तीन लाइनें requests.jsonl में रखें:
दूसरा जवाब दोनों टूल उनके JSON Schemas के साथ सूचीबद्ध करता है। यही आदान-प्रदान वह सब है जो Claude कनेक्ट होते समय करता है: हैंडशेक, टूल की सूची, टूल कॉल।
इसे Claude से जोड़ें
Claude Desktop कॉन्फ़िग संपादित करें
Claude Desktop में Settings, फिर Developer, फिर Edit Config खोलें। इससे claude_desktop_config.json दिखेगी:
अपना सर्वर mcpServers के अंतर्गत जोड़ें। एब्सोल्यूट पाथ इस्तेमाल करें, क्योंकि Claude Desktop आपका प्रोसेस अपनी वर्किंग डायरेक्टरी से लॉन्च करता है, आपके प्रोजेक्ट फ़ोल्डर से नहीं।
macOS पर पाथ /Users/you/projects/local-notes-mcp/build/index.js जैसा दिखता है। फ़ाइल सेव करें, फिर Claude Desktop को पूरी तरह बंद करें (Windows पर सिस्टम ट्रे से, सिर्फ़ विंडो का क्लोज़ बटन दबाकर नहीं) और फिर खोलें। आपके टूल चैट इनपुट के टूल मेनू में दिखेंगे, और किसी टूल को चलाने से पहले Claude आपकी अनुमति माँगता है।
Claude Code में जोड़ें
Claude Code में फ़ाइल संपादित करने की ज़रूरत नहीं है। एक कमांड सर्वर रजिस्टर कर देती है:
डबल डैश के बाद की हर चीज़ वह कमांड है जो आपका सर्वर लॉन्च करती है। इसे claude mcp list से जाँचें, या किसी सेशन के अंदर /mcp टाइप करके इसकी स्थिति देखें। एक scope फ़्लैग तय करता है कि सर्वर किसे मिलेगा:
Scope
कहाँ सेव होता है
कौन देखता है
local (डिफ़ॉल्ट)
इस प्रोजेक्ट के लिए आपकी निजी सेटिंग्स
केवल आप, इसी प्रोजेक्ट में
project (--scope project)
रिपो में .mcp.json
हर वह व्यक्ति जो इसे क्लोन करे, मंज़ूरी देने के बाद
user (--scope user)
आपकी यूज़र कॉन्फ़िग
केवल आप, हर प्रोजेक्ट में
एक असली प्रॉम्प्ट आज़माएँ
Claude से कुछ ऐसा पूछें जिसके लिए टूल कॉल ज़रूरी हो:
"Standup" शीर्षक वाला एक नोट सेव करें जिसमें लिखा हो "Ship the MCP post on Friday"। फिर मेरे नोट्स में "Friday" खोजें।
Claude save_note कॉल करता है, फिर search_notes, और नतीजा वापस उद्धृत करता है। पुष्टि के लिए notes.json खोलें कि डेटा आपकी डिस्क पर पहुँचा या नहीं। अगर पहुँचा है, तो आपके पास एक काम करता लोकल MCP सर्वर है।
विफलताएँ ठीक करें और सुरक्षित करें
आम विफलताएँ ठीक करें
लक्षण
संभावित कारण
सुधार
सर्वर failed या disconnected दिखता है
stdout पर आउटपुट, या स्टार्टअप पर क्रैश
node build/index.js हाथ से चलाएँ और stderr पढ़ें; हर console.log हटाएँ
कॉन्फ़िग बदलने के बाद कोई टूल नहीं
क्लाइंट अब भी चल रहा है, या JSON गलत है
पूरी तरह बंद करें; ट्रेलिंग कॉमा देखें
spawn node ENOENT
ऐप अपने PATH पर node नहीं ढूँढ पाता
node बाइनरी का एब्सोल्यूट पाथ command के रूप में इस्तेमाल करें
Inspector में चलता है, Claude में विफल
रिलेटिव पाथ या गायब environment variables
एब्सोल्यूट पाथ, और variables को env में रखें
कोड बदलने का कोई असर नहीं
आपने रीबिल्ड या रीस्टार्ट नहीं किया
npm run build चलाएँ, फिर क्लाइंट रीस्टार्ट करें
बाकी परेशानी का आधा हिस्सा दो Windows विवरणों से आता है। JSON स्ट्रिंग के अंदर बैकस्लैश को दोगुना करना पड़ता है (C:\\Users\\you\\...), या आप ऊपर के उदाहरण की तरह सीधे फ़ॉरवर्ड स्लैश इस्तेमाल कर सकते हैं। और नेटिव Windows पर npx से लॉन्च होने वाले सर्वर को आम तौर पर command में एक cmd /c रैपर चाहिए; सादा node कमांड काम नहीं करती।
जब कुछ फिर भी विफल हो, तो लॉग पढ़ें। Claude Desktop हर सर्वर के लिए एक लॉग लिखता है: macOS पर ~/Library/Logs/Claude में और Windows पर %APPDATA%\Claude\logs में। आपकी अपनी console.error लाइनें वहीं पहुँचती हैं।
सुरक्षित डिफ़ॉल्ट जो रखने लायक हैं
stdio सर्वर आपकी अनुमतियाँ इनहेरिट करता है, इसलिए हर टूल को ऐसे कोड की तरह मानें जो आपकी ओर से काम कर सकता है।
नुकसान का दायरा सीमित करें। फ़ाइल एक्सेस एक ही फ़ोल्डर तक रखें। अगर कोई टूल पाथ स्वीकार करता है, तो उसे resolve करें और अनुमत डायरेक्टरी के बाहर का कुछ भी अस्वीकार करें।
हर इनपुट वैलिडेट करें। Zod के min, max और enum नियमों की कोई कीमत नहीं लगती, और ये आपके हैंडलर चलने से पहले ख़राब कॉल रोक देते हैं।
सीक्रेट्स कोड से बाहर रखें। टोकन अपनी कॉन्फ़िग के env ब्लॉक में रखें, और वह फ़ाइल version control से बाहर रखें।
इंस्टॉल करने से पहले पढ़ें। केवल वही तीसरे-पक्ष के सर्वर जोड़ें जिनका सोर्स आपने देखा है। वे आपके अकाउंट की अनुमतियों के साथ चलते हैं।
टूल के आउटपुट को अविश्वसनीय मानें। आपका टूल वेब पेज या ईमेल से जो टेक्स्ट लाता है, उसमें मॉडल के लिए निर्देश हो सकते हैं। उसे डेटा की तरह लौटाएँ, और लिखने वाले एक्शन को पुष्टि के पीछे रखें।
stdio से HTTP पर जाना
जब टीम के साथी वही टूल चाहें, तो ट्रांसपोर्ट बदलें। SDK StreamableHTTPServerTransport देता है, जो उसी McpServer को आपकी अपनी ऑथेंटिकेशन के पीछे HTTP पर चलाता है। आपकी registerTool कॉल नहीं बदलतीं। बदलते हैं केवल ट्रांसपोर्ट और क्लाइंट रजिस्ट्रेशन, जैसे claude mcp add --transport http notes https://your-host/mcp।
यह पैटर्न असल दुनिया में पहले से दिख रहा है। claude.ai में PicassoIA कनेक्टर एक रिमोट MCP सर्वर है, जो इमेज जनरेशन, इमेज एडिटिंग और वीडियो जनरेशन को टूल के रूप में दिखाता है, और Claude इन्हें बिना किसी लोकल प्रोसेस के कॉल करता है।
PicassoIA पर टूल स्पेक्स का ड्राफ़्ट बनाएँ
अच्छे टूल अच्छे नामों और विवरणों से शुरू होते हैं, और कोड लिखने से पहले उनका ड्राफ़्ट बनाने का एक तेज़ तरीका लैंग्वेज मॉडल है। PicassoIA अपनी Large Language Models कैटेगरी में 75 टेक्स्ट मॉडल होस्ट करता है, जिनमें Claude Sonnet 5 भी है, जो कोडिंग कार्यों के लिए बना है। टूल डिज़ाइन के लिए इसे इस्तेमाल करने का तरीका यह है।
टूल को सादी भाषा में बताएँ: वह क्या करता है, क्या लेता है, क्या लौटाता है, और क्या कुछ बदलता है या नहीं।
एक तय आउटपुट फ़ॉर्मैट माँगें: एक snake_case टूल नाम, मॉडल के लिए लिखा दो वाक्यों से ज़्यादा का विवरण नहीं, हर फ़ील्ड पर .describe() वाला Zod schema, और तीन एज केस जिन्हें वैलिडेशन में फ़ेल होना चाहिए।
नतीजा registerTool कॉल में डालें, रीबिल्ड करें, और Inspector में जाँचें।
जब Claude गलत टूल चुने, तो schema नहीं, विवरण बदलें। आम तौर पर समस्या शब्दों की होती है।
एक प्रॉम्प्ट जो अच्छा काम करता है:
मैं list_overdue_tasks नाम का एक MCP टूल बना रहा हूँ। यह tasks.json पढ़ता है, वे टास्क लौटाता है जिनकी dueDate आज से पहले है, और कुछ नहीं बदलता। टूल का नाम, AI मॉडल के लिए दो वाक्यों का विवरण, हर फ़ील्ड पर describe() वाला Zod इनपुट schema, और तीन अमान्य इनपुट लिखें जिन्हें उसे अस्वीकार करना चाहिए।
बड़े रीफ़ैक्टर के लिए, जैसे 600 लाइन के सर्वर को मॉड्यूल में बाँटना, Claude Fable 5 या Claude Opus 4.7 को अपनी पूरी फ़ाइल पेस्ट करके आज़माएँ।
PicassoIA पर अपनी पहली इमेज बनाएँ
आपका नोट्स सर्वर एक टेम्पलेट है। JSON फ़ाइल की जगह किसी इमेज मॉडल की कॉल लगा दें, और Claude माँगने पर तस्वीरें रेंडर कर सकता है। नतीजा देखने के लिए आपको पहले वह बनाने की ज़रूरत नहीं है। इस लेख की हर फ़ोटो P-Image से बनाई गई है, जो Picasso IA के टेक्स्ट-टू-इमेज मॉडल में से एक है।
Picasso IA खोलें, एक दृश्य का वर्णन करने वाला एक वाक्य लिखें, और जनरेट करें। फिर तीन प्रयोग करें:
लेंस बदलें। वही प्रॉम्प्ट पहले "35mm" और फिर "85mm" के साथ लिखें, और फ़्रेमिंग की तुलना करें।
रोशनी बदलें। "सुबह की खिड़की की रोशनी" की जगह "गर्म डेस्क लैंप" रखें और मूड बदलते देखें।
एंगल बदलें। वही सब्जेक्ट एक बार ओवरहेड शॉट में और फिर लो-एंगल शॉट में माँगें।
एक ऐसा टूल बनाएँ जो आपको लगता है कि Claude में होना चाहिए, उसे ऊपर दिए चरणों से जोड़ें, और फिर अपने प्रोजेक्ट के विज़ुअल बनाने में Picasso IA पर दस मिनट लगाएँ। सर्वर बनाने में एक दोपहर लगती है। इमेज सेकंडों में बन जाती हैं।