DEV Community

Jyoti Prakash Pradhan
Jyoti Prakash Pradhan

Posted on

Simple MCP tool using NodeJS

Creating an MCP server using Node.js is straightforward. You can integrate various third-party tools—such as JIRA, build tools (TeamCity, Jenkins), and many others—using the code provided below. If you prefer not to rely on external MCP servers, you can follow these steps to create and run your own local MCP server, which can then be used with any AI client.

Folder structure

mcp-server
  - .vscode
    - mcp.json
  - src
    - lib
      - tools.ts
    - index.ts
  - .env
  - .npmrc
  - package.json
  - tsconfig.json
Enter fullscreen mode Exit fullscreen mode

File contents

package.json
Contains script for build, dev and other dependancies information

{
  "name": "groww-mcp-server",
  "version": "1.0.0",
  "description": "",
  "main": "src/index.ts",
  "type": "module",
  "bin": {
    "groww_mcp_server": "./build/index.js"
  },
  "scripts": {
    "build": "tsc && chmod 755 build/index.js",
    "build:watch": "tsc --watch",
    "dev": "tsc --watch",
    "start": "node ./build/index.js",
    "clean": "rm -rf build"
  },
  "files": [
    "build"
  ],
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "@modelcontextprotocol/sdk": "^1.17.4",
    "@types/node-fetch": "^2.6.13",
    "dotenv": "^17.2.1",
    "node-fetch": "^3.3.2",
    "totp-generator": "^1.0.0",
    "zod": "^3.25.76"
  },
  "devDependencies": {
    "@types/node": "^24.3.0",
    "typescript": "^5.9.2"
  }
}
Enter fullscreen mode Exit fullscreen mode

tsconfig.json
Typescript compiler options

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "nodenext",
    "moduleResolution": "nodenext",
    "outDir": "./build",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "sourceMap": true,
    "declaration": false,
    "incremental": true,
    "tsBuildInfoFile": "./build/.tsbuildinfo"
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "build"],
  "watchOptions": {
    "watchFile": "useFsEvents",
    "watchDirectory": "useFsEvents",
    "fallbackPolling": "dynamicPriority",
    "synchronousWatchDirectory": true,
    "excludeDirectories": ["**/node_modules", "_tmp"]
  }
}
Enter fullscreen mode Exit fullscreen mode

.npmrc

registry=https://registry.npmjs.com/
... other project related node settings like freezing node version
Enter fullscreen mode Exit fullscreen mode

.env

# MCP Server configuration
MCP_HOST=127.0.0.1
MCP_PORT=8000
MCP_DEBUG=true

# Docker configuration
DOCKER_PORT=8000
DOCKER_ENV=production

API_KEY=xxxxxx
...other ENV settings...
Enter fullscreen mode Exit fullscreen mode

src/index.ts
This defines all the tools that a MCP server contains. You can add as many tools you can till you are tired.

import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { z } from 'zod';
import dotenv from 'dotenv';
import { Tools, ToolResponse } from './lib/tools.js';

dotenv.config();

// Create server instance
const server = new McpServer({
  name: 'weather',
  version: '1.0.0',
  capabilities: {
    resources: {},
    tools: {},
  },
});

const tools = new Tools();

server.tool(
  'get-user-margin',
  "get available margin for a user",
  {},
  async () => {
    const response: ToolResponse = await Tools.getAvailableMargin();

    return response;
  }
)

server.tool(
  'get-historical-data',
  "get historical data for stocks",
  {
    exchange: z.string(),
    segment: z.string(),
    trading_symbol: z.string(),
    start_time: z.string(),
    end_time: z.string(),
    interval_in_minutes: z.number().min(1).optional()
  },
  async ({ exchange, segment, trading_symbol, start_time, end_time, interval_in_minutes }) => {
    const response: ToolResponse = await Tools.getHistoricalStockData({
      exchange,
      segment,
      trading_symbol,
      start_time,
      end_time,
      interval_in_minutes
    });

    return response;
  }
)


async function main() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
  console.error("Calculator MCP Server running on stdio");
}

main().catch((error) => {
  console.error("Fatal error in main():", error);
  process.exit(1);
});
Enter fullscreen mode Exit fullscreen mode

src/lib/tools.ts

export interface ToolResponse {
  content: {
    type: string;
    text: string;
  }[];
}

export class Tools {
  private api: Api;

  constructor() {
    const Config = {
      apiKey: process.env.API_KEY,
      apiSecret: process.env.API_SECRET,
    };

    this.api = new Api(Config);

    this.api.authenticate();
  }

  async getAvailableMargin(): Promise<ToolResponse> {
    const margin = await this.api.getAvailableMargin();
    return {
      content: [
        {
          type: 'text',
          text: `Your available margin is ₹${margin}`,
        },
      ],
    };
  }

  async getHistoricalStockData(params: HistoricalDataParams): Promise<ToolResponse> {
    const historicalData = await this.api.getHistoricalStockData(params);
    return {
      content: [
        {
          type: 'text',
          text: `Your historical stock data is: ${JSON.stringify(historicalData)}`,
        },
      ],
    };
  }
}
Enter fullscreen mode Exit fullscreen mode

mcp.json
This is how you can use it in VSCode. Settings for other AI tools are different depending on the tools.

{
  "servers": {
    "mcp-server": {
      "command": "node",
      "args": ["./server/build/index.js"],
      "envFile": "${workspaceFolder}/server/.env"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)