#
tokens: 3662/50000 6/6 files
lines: on (toggle) GitHub
raw markdown copy reset
# Directory Structure

```
├── fetch.py
├── mcp.json
├── package-lock.json
├── package.json
├── README.md
├── src
│   └── index.ts
└── tsconfig.json
```

# Files

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
 1 | # MCP Stock Analysis Server by Akshay Bavkar
 2 | 
 3 | This is an MCP server that provides access to real-time and historical Indian stock data using the Yahoo Finance API. It allows stock data retrieval to be used as context by local LLMs via Claude Desktop, Cursor, and other MCP-compatible agents.
 4 | 
 5 | ## Available Features
 6 | 
 7 | - **getStockQuote**: Get the current quote for an Indian stock.
 8 | - **getHistoricalData**: Get historical data for an Indian stock with custom intervals and periods.
 9 | ---
10 | 
11 | ## Setup
12 | 
13 | ```bash
14 | npm install mcp-stock-analysis
15 | ```
16 | 
17 | ## Usage in Host
18 | Configure your MCP client (e.g., Claude Desktop) to connect to the server:
19 | 
20 | ```JSON
21 | {
22 |   "mcpServers": {
23 |     "mcp-stock-analysis": {
24 |       "command": "npx",
25 |       "args": ["-y", "mcp-stock-analysis"],
26 |     }
27 |   }
28 | }
29 | ```
30 | 
31 | ## Tools
32 | ### `getStockQuote`
33 | Get the current quote for a stock.
34 | 
35 | Input:
36 | 
37 | `symbol`: The stock symbol (e.g., RELIANCE.NS)
38 | 
39 | Output:
40 | ```JSON
41 | {
42 |   "symbol": "RELIANCE.NS",
43 |   "price": 2748.15,
44 |   "name": "Reliance Industries Ltd"
45 | }
46 | ```
47 | 
48 | ### `getHistoricalData`
49 | Get historical data for a stock.
50 | 
51 | Input:
52 | 
53 | - `symbol`: the stock symbol (e.g., RELIANCE.NS)
54 | - `interval`: the time interval for the data (`daily`, `weekly`, or `monthly`) (optional, default: `daily`)
55 | 
56 | Output:
57 | ```JSON
58 | {
59 |     "date": "2025-03-21T00:00:00+05:30",
60 |     "open": 2735,
61 |     "high": 2750,
62 |     "low": 2725,
63 |     "close": 2748.15,
64 |     "volume": 21780769
65 | }
66 | ```
67 | 
68 | JSON object containing the historical data. The structure of the output depends on the interval parameter.
69 | 
70 | ## Contributing
71 | Contributions are welcome! Please open an issue or pull request.
72 | 
73 | 
74 | ### License
75 | MIT
76 | 
```

--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "compilerOptions": {
 3 |     "target": "ES2022",
 4 |     "module": "Node16",
 5 |     "moduleResolution": "Node16",
 6 |     "strict": true,
 7 |     "esModuleInterop": true,
 8 |     "skipLibCheck": true,
 9 |     "forceConsistentCasingInFileNames": true,
10 |     "resolveJsonModule": true,
11 |     "outDir": "./dist",
12 |     "rootDir": "./src"
13 |   },
14 |   "include": ["src/**/*.ts"],
15 |   "exclude": ["node_modules"]
16 | }
```

--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "name": "mcp-stock-analysis",
 3 |   "version": "1.0.0",
 4 |   "description": "MCP server for Indian stock market using yfinance",
 5 |   "type": "module",
 6 |   "main": "src/index.ts",
 7 |   "bin": {
 8 |     "mcp-stock-analysis": "dist/index.js"
 9 |   },
10 |   "scripts": {
11 |     "build": "tsc && chmod +x dist/index.js",
12 |     "prepare": "npm run build",
13 |     "start": "node dist/index.js"
14 |   },
15 |   "files": [
16 |     "dist",
17 |     "fetch.py"
18 |   ],
19 |   "dependencies": {
20 |     "@modelcontextprotocol/sdk": "^0.0.8"
21 |   },
22 |   "devDependencies": {
23 |     "typescript": "^5.3.3"
24 |   }
25 | }
```

--------------------------------------------------------------------------------
/fetch.py:
--------------------------------------------------------------------------------

```python
 1 | import sys
 2 | import yfinance as yf
 3 | import json
 4 | 
 5 | mode = sys.argv[1]
 6 | symbol = sys.argv[2]
 7 | 
 8 | if mode == "quote":
 9 |     stock = yf.Ticker(symbol)
10 |     info = stock.info
11 |     result = {
12 |         "symbol": symbol,
13 |         "price": float(info.get("currentPrice") or info.get("regularMarketPrice")),
14 |         "name": info.get("shortName")
15 |     }
16 |     print(json.dumps(result))
17 | 
18 | elif mode == "history":
19 |     period = sys.argv[3]
20 |     interval = sys.argv[4]
21 |     stock = yf.Ticker(symbol)
22 |     hist = stock.history(period=period, interval=interval).reset_index()
23 |     result = []
24 |     for _, row in hist.iterrows():
25 |         result.append({
26 |             "date": row["Date"].isoformat(),
27 |             "open": float(row["Open"]),
28 |             "high": float(row["High"]),
29 |             "low": float(row["Low"]),
30 |             "close": float(row["Close"]),
31 |             "volume": int(row["Volume"])
32 |         })
33 |     print(json.dumps(result))
```

--------------------------------------------------------------------------------
/mcp.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "name": "mcp-stock-analysis",
 3 |   "version": "0.1.0",
 4 |   "description": "A stock analysis tool that provides real-time and historical stock data",
 5 |   "author": "Your Name",
 6 |   "tools": [
 7 |     {
 8 |       "id": "getStockQuote",
 9 |       "description": "Get the current price of an Indian stock",
10 |       "parameters": {
11 |         "symbol": {
12 |           "type": "string",
13 |           "description": "The stock symbol (e.g., RELIANCE.NS for Reliance Industries)"
14 |         }
15 |       }
16 |     },
17 |     {
18 |       "id": "getHistoricalData",
19 |       "description": "Fetch historical stock prices",
20 |       "parameters": {
21 |         "symbol": {
22 |           "type": "string",
23 |           "description": "The stock symbol (e.g., RELIANCE.NS for Reliance Industries)"
24 |         },
25 |         "period": {
26 |           "type": "string",
27 |           "description": "Time period (e.g., 1d, 5d, 1mo, 3mo, 6mo, 1y, 2y, 5y, 10y, ytd, max)",
28 |           "default": "1mo"
29 |         },
30 |         "interval": {
31 |           "type": "string",
32 |           "description": "Data interval (e.g., 1m, 2m, 5m, 15m, 30m, 60m, 90m, 1h, 1d, 5d, 1wk, 1mo, 3mo)",
33 |           "default": "1d"
34 |         }
35 |       }
36 |     }
37 |   ],
38 |   "command": "npx tsx index.ts",
39 |   "cwd": "."
40 | } 
```

--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------

```typescript
  1 | // src/index.ts — MCP Server for Stock Analysis using yfinance (built for dist/ publishing)
  2 | 
  3 | import { spawn } from "child_process";
  4 | import { Server } from "@modelcontextprotocol/sdk/server/index.js";
  5 | import {
  6 |   ListToolsRequestSchema,
  7 |   CallToolRequestSchema,
  8 |   CallToolRequest,
  9 |   CallToolResult,
 10 |   Tool
 11 | } from "@modelcontextprotocol/sdk/types.js";
 12 | import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
 13 | 
 14 | function runPythonScript(args: string[]): Promise<any> {
 15 |   return new Promise((resolve, reject) => {
 16 |     const proc = spawn("python3", ["fetch.py", ...args]);
 17 |     let output = "";
 18 |     let error = "";
 19 | 
 20 |     proc.stdout.on("data", (data) => (output += data));
 21 |     proc.stderr.on("data", (data) => (error += data));
 22 | 
 23 |     proc.on("close", (code) => {
 24 |       if (code === 0) {
 25 |         try {
 26 |           resolve(JSON.parse(output));
 27 |         } catch (err) {
 28 |           reject(`JSON parse error: ${err}`);
 29 |         }
 30 |       } else {
 31 |         reject(`Python error: ${error}`);
 32 |       }
 33 |     });
 34 |   });
 35 | }
 36 | 
 37 | const getStockQuoteTool: Tool = {
 38 |   name: "getStockQuote",
 39 |   description: "Get the current price of an Indian stock",
 40 |   inputSchema: {
 41 |     type: "object",
 42 |     properties: {
 43 |       symbol: { type: "string" }
 44 |     },
 45 |     required: ["symbol"]
 46 |   },
 47 |   outputSchema: {
 48 |     type: "object",
 49 |     properties: {
 50 |       symbol: { type: "string" },
 51 |       price: { type: "number" },
 52 |       name: { type: "string" }
 53 |     },
 54 |     required: ["symbol", "price", "name"]
 55 |   }
 56 | };
 57 | 
 58 | const getHistoricalDataTool: Tool = {
 59 |   name: "getHistoricalData",
 60 |   description: "Fetch historical stock prices",
 61 |   inputSchema: {
 62 |     type: "object",
 63 |     properties: {
 64 |       symbol: { type: "string" },
 65 |       period: { type: "string", default: "1mo" },
 66 |       interval: { type: "string", default: "1d" }
 67 |     },
 68 |     required: ["symbol"]
 69 |   },
 70 |   outputSchema: {
 71 |     type: "array",
 72 |     items: {
 73 |       type: "object",
 74 |       properties: {
 75 |         date: { type: "string" },
 76 |         open: { type: "number" },
 77 |         high: { type: "number" },
 78 |         low: { type: "number" },
 79 |         close: { type: "number" },
 80 |         volume: { type: "number" }
 81 |       },
 82 |       required: ["date", "open", "high", "low", "close", "volume"]
 83 |     }
 84 |   }
 85 | };
 86 | 
 87 | const server = new Server(
 88 |   {
 89 |     name: "mcp-stock-analysis",
 90 |     version: "0.1.0",
 91 |     description: "A stock analysis tool that provides real-time and historical stock data",
 92 |     author: "Gipti Labs",
 93 |     capabilities: {
 94 |       tools: {
 95 |         getStockQuote: {
 96 |           description: "Get the current price of an Indian stock",
 97 |           parameters: {
 98 |             symbol: {
 99 |               type: "string",
100 |               description: "The stock symbol (e.g., RELIANCE.NS for Reliance Industries)"
101 |             }
102 |           }
103 |         },
104 |         getHistoricalData: {
105 |           description: "Fetch historical stock prices",
106 |           parameters: {
107 |             symbol: {
108 |               type: "string",
109 |               description: "The stock symbol (e.g., RELIANCE.NS for Reliance Industries)"
110 |             },
111 |             period: {
112 |               type: "string",
113 |               description: "Time period (e.g., 1d, 5d, 1mo, 3mo, 6mo, 1y, 2y, 5y, 10y, ytd, max)",
114 |               default: "1mo"
115 |             },
116 |             interval: {
117 |               type: "string",
118 |               description: "Data interval (e.g., 1m, 2m, 5m, 15m, 30m, 60m, 90m, 1h, 1d, 5d, 1wk, 1mo, 3mo)",
119 |               default: "1d"
120 |             }
121 |           }
122 |         }
123 |       }
124 |     }
125 |   },
126 |   {
127 |     capabilities: {
128 |       tools: {},
129 |     },
130 |   }
131 | );
132 | 
133 | server.setRequestHandler(ListToolsRequestSchema, async () => ({
134 |   tools: [getStockQuoteTool, getHistoricalDataTool],
135 | }));
136 | 
137 | server.setRequestHandler(CallToolRequestSchema, async (request: CallToolRequest): Promise<CallToolResult> => {
138 |   const { name, arguments: args } = request.params;
139 | 
140 |   if (name === "getStockQuote") {
141 |     try {
142 |       const input = args as { symbol: string };
143 |       const result = await runPythonScript(["quote", input.symbol]);
144 |       return {
145 |         content: [{ type: "text", text: JSON.stringify(result) }]
146 |       };
147 |     } catch (error) {
148 |       return {
149 |         content: [{ type: "text", text: `Error: ${error}` }],
150 |         isError: true
151 |       };
152 |     }
153 |   } else if (name === "getHistoricalData") {
154 |     try {
155 |       const input = args as { symbol: string; period?: string; interval?: string };
156 |       const period = input.period || "1mo";
157 |       const interval = input.interval || "1d";
158 |       const result = await runPythonScript(["history", input.symbol, period, interval]);
159 |       return {
160 |         content: [{ type: "text", text: JSON.stringify(result) }]
161 |       };
162 |     } catch (error) {
163 |       return {
164 |         content: [{ type: "text", text: `Error: ${error}` }],
165 |         isError: true
166 |       };
167 |     }
168 |   } else {
169 |     return {
170 |       content: [{ type: "text", text: "Unknown tool" }],
171 |       isError: true
172 |     };
173 |   }
174 | });
175 | 
176 | const transport = new StdioServerTransport();
177 | await server.connect(transport);
178 | console.error("✅ MCP Server started and ready for requests...");
179 | 
```