Build Your Own MCP Server
Create and publish an MCP server step-by-step
Building your own MCP server means you can connect Claude, Cursor, or any MCP-compatible AI to literally any system — your company's internal database, a government API, a custom business tool, or anything else you can write code for.
This tutorial walks you through building a complete MCP server from scratch. We will build a practical example: an MCP server that lets AI query Indian stock market data and BSE/NSE prices.
What You'll Learn
- What you need before starting (prerequisites)
- How to set up the MCP SDK
- Building a simple MCP server with one tool
- Testing your server with Claude Desktop
- Adding more tools and resources
- Publishing your MCP server for others to use
Prerequisites
Before building an MCP server, you should be comfortable with:
- Basic Python or TypeScript/JavaScript
- Running commands in a terminal
- Understanding of APIs and JSON
You need:
- Python 3.10+ or Node.js 18+
- Claude Desktop installed (for testing)
- A text editor or IDE
🇮🇳 India Note: The MCP Python SDK works well on Indian internet connections. All dependencies are available from PyPI without VPN. If you are using pip in India and seeing slow speeds, add this to your pip command:
pip install mcp --index-url https://pypi.org/simple/
Understanding MCP Server Structure
An MCP server exposes three types of capabilities:
Tools: Functions the AI can call. Example: get_stock_price(ticker: str) -> float
Resources: Data the AI can read. Example: A company's financial report as a text resource
Prompts: Pre-written prompt templates the AI can use
For most use cases, you only need to implement tools.
Building Your First MCP Server (Python)
Step 1: Install the MCP SDK
pip install mcp
Step 2: Create the Server File
Create a file called stock_server.py:
from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp import types
import httpx
import asyncio
# Initialize the MCP server
server = Server("india-stocks")
@server.list_tools()
async def list_tools() -> list[types.Tool]:
"""Tell Claude what tools this server provides."""
return [
types.Tool(
name="get_stock_price",
description="Get current stock price for an Indian company listed on NSE or BSE",
inputSchema={
"type": "object",
"properties": {
"ticker": {
"type": "string",
"description": "NSE ticker symbol (e.g., RELIANCE, TCS, INFY)"
}
},
"required": ["ticker"]
}
),
types.Tool(
name="get_market_summary",
description="Get current NIFTY 50 and SENSEX index values",
inputSchema={
"type": "object",
"properties": {}
}
)
]
@server.call_tool()
async def call_tool(name: str, arguments: dict) -> list[types.TextContent]:
"""Handle tool calls from Claude."""
if name == "get_stock_price":
ticker = arguments["ticker"].upper()
# Using Yahoo Finance API (free, no key needed)
async with httpx.AsyncClient() as client:
response = await client.get(
f"https://query1.finance.yahoo.com/v8/finance/chart/{ticker}.NS",
headers={"User-Agent": "Mozilla/5.0"}
)
data = response.json()
try:
price = data["chart"]["result"][0]["meta"]["regularMarketPrice"]
company = data["chart"]["result"][0]["meta"]["shortName"]
return [types.TextContent(
type="text",
text=f"{company} ({ticker}): ₹{price:,.2f}"
)]
except:
return [types.TextContent(
type="text",
text=f"Could not fetch price for {ticker}. Check the ticker symbol."
)]
elif name == "get_market_summary":
async with httpx.AsyncClient() as client:
nifty = await client.get(
"https://query1.finance.yahoo.com/v8/finance/chart/%5ENSEI",
headers={"User-Agent": "Mozilla/5.0"}
)
sensex = await client.get(
"https://query1.finance.yahoo.com/v8/finance/chart/%5EBSESN",
headers={"User-Agent": "Mozilla/5.0"}
)
nifty_price = nifty.json()["chart"]["result"][0]["meta"]["regularMarketPrice"]
sensex_price = sensex.json()["chart"]["result"][0]["meta"]["regularMarketPrice"]
return [types.TextContent(
type="text",
text=f"NIFTY 50: {nifty_price:,.2f}\nSENSEX: {sensex_price:,.2f}"
)]
async def main():
async with stdio_server() as (read_stream, write_stream):
await server.run(
read_stream,
write_stream,
server.create_initialization_options()
)
if __name__ == "__main__":
asyncio.run(main())
Step 3: Install Dependencies
pip install mcp httpx
Step 4: Test Locally
Run your server to make sure it starts without errors:
python stock_server.py
You should see no errors. Press Ctrl+C to stop it.
Connecting to Claude Desktop
Step 1: Find Your Config File
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
Step 2: Add Your Server
Edit the config file and add your server:
{
"mcpServers": {
"india-stocks": {
"command": "python",
"args": ["/path/to/your/stock_server.py"]
}
}
}
Replace /path/to/your/stock_server.py with the actual path to your file.
Step 3: Restart Claude Desktop
Close and reopen Claude Desktop. You should see a hammer icon (tools) in the chat interface, indicating MCP tools are available.
Step 4: Test with Claude
Type in Claude Desktop:
"What is the current price of TCS and RELIANCE? Also show me the NIFTY and SENSEX values."
Claude will automatically call your MCP tools to get the live data.
Adding Resources to Your Server
Beyond tools, you can expose data resources — static or dynamic data that Claude can read:
@server.list_resources()
async def list_resources() -> list[types.Resource]:
return [
types.Resource(
uri="stocks://watchlist",
name="My Stock Watchlist",
description="Personal watchlist of Indian stocks to track"
)
]
@server.read_resource()
async def read_resource(uri: str) -> str:
if uri == "stocks://watchlist":
return "RELIANCE, TCS, INFY, HDFC, ICICIBANK, WIPRO, LT, AXISBANK"
Publishing Your MCP Server
Once your server works locally, share it with the community:
Option 1 — PyPI (Python):
# Add setup.py or pyproject.toml
pip publish
Then others can install it with pip install your-server-name.
Option 2 — npm (TypeScript/JavaScript):
npm publish
Option 3 — Submit to the MCP Registry: Go to modelcontextprotocol.io/servers and follow the submission process to list your server in the official community registry.
TypeScript Alternative
The MCP SDK is also available for TypeScript, which many Node.js developers prefer:
npm install @modelcontextprotocol/sdk
The structure is identical — implement server.setRequestHandler for ListToolsRequestSchema and CallToolRequestSchema. See the official docs for TypeScript examples.
Official Resources
- MCP Python SDK — Official Python SDK with examples
- MCP TypeScript SDK — Official TypeScript SDK
- MCP Documentation — Complete protocol documentation
- MCP Server Examples — Anthropic's official example servers
- MCP Community Discord — Help and community for MCP builders
Community Questions
0No questions yet. Be the first to ask!