How To Build MCP Server from Scratch with TypeScript and Groq

Three core concepts while building MCP
Resources- Acts as a read-only data source—similar to a local file or static API endpoint—that an LLM can parse for immediate context.Tools- Executable functions that empower the LLM to trigger dynamic actions and interact directly with external environments.Prompts- pre-written template that user can re-use to perform a task
How to build MCP server
1. Local mcp server
1. Setting Up Your Environment
Create and set up our project:
# Create project directory mkdir mcp-local cd mcp-local # Initialize npm project npm init -y # Install dependencies npm install zod @modelcontextprotocol/sdk # Install dev dependencies npm install -D @types/node typescript # Create src dir mkdir src cd src #create index file touch index.tsUpdate
package.json{ "type": "module", "scripts": { "build": "tsc", "start": "node dist/index.js" } }Create a
tsconfig.jsonin the root of your project{ "compilerOptions": { "target": "ES2022", "module": "Node16", "moduleResolution": "Node16", "outDir": "./dist", "rootDir": "./src", "strict": true, "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true }, "include": ["src/**/*"], "exclude": ["node_modules"] }
2. Creating local mcp server
create a src/index.ts file
McpServer instance:
Here we create instance of
McpServerby providing name and version//src/index.ts import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; // Create server instance const server = new McpServer({ name: "Student", version: "1.0.0", });Resources: The "Read-Only" Data:
There is a method called
server.registerResourceit is acts like a file or a URL that the AI can "read" to get background information.The following things we provide to
server.registerResourcemethodname -
"greeting-resource"uriOrTemplate -
"https://example.com/greetings/default"config - resource meta data
title,descriptionandmimeTypecallback - it return object of
uriandtext
//src/index.ts import { ReadResourceResult, } from "@modelcontextprotocol/sdk/types"; server.registerResource( "greeting-resource", "https://example.com/greetings/default", { title: "Default Greeting", // Display name for UI description: "A simple greeting resource", mimeType: "text/plain", }, async (): Promise<ReadResourceResult> => { return { contents: [ { uri: "https://example.com/greetings/default", text: "Hello! I'm, your virtual assistant. I'm here to help you streamline your workflow and answer any questions you might have about. How can I assist you today?", }, ], }; }, );Prompts: The "Templates”
The
server.registerPromptsection provides pre-defined templates that user can reuse to perform a task//src/index.ts import { z } from "zod"; server.registerPrompt( "student_list", { title: "student list", description: "A sample prompt to get list of student", argsSchema: { limit: z.string().describe("no between 1 to 9"), }, }, async ({ limit }): Promise<GetPromptResult> => { return { messages: [ { role: "user", content: { type: "text", text: `give me list of student, give only ${limit} students`, }, }, ], }; }, );Tools: The "Action" Functions
The
server.registerToolsection is the most powerful part. It allows the AI to execute code to get real-time data.//src/index.ts import { z } from "zod"; server.registerTool( "get_student", { description: "Get list of all student with their enrollment no.", inputSchema: { limit: z.number().describe("Constrains the input parameter evaluation to a clean range between 1 and 10 records."), }, }, async ({ limit }) => { const student = [ { id: "STU-001", name: "Elena Rodriguez", age: 20, major: "Marine Biology", gpa: 3.85, email: "elena.r@university.edu", enrolled: true, }, { id: "STU-002", name: "Marcus Chen", age: 22, major: "Cybersecurity", gpa: 3.92, email: "m.chen99@university.edu", enrolled: true, }, { id: "STU-003", name: "Sarah Jenkins", age: 19, major: "Graphic Design", gpa: 3.4, email: "s.jenkins@university.edu", enrolled: true, }, { id: "STU-004", name: "Amara Okafor", age: 21, major: "Mechanical Engineering", gpa: 3.78, email: "a.okafor@university.edu", enrolled: false, } ]; return { content: [ { type: "text", text: JSON.stringify(student.slice(0, limit)), }, ], }; }, );Main Execution and Communication Transport
We create
StdioServerTransportand connect toMcpServerinstance to start listen through stdio transport.//src/index.ts import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; async function main() { const transport = new StdioServerTransport(); await server.connect(transport); console.error("Student MCP Server running on stdio"); } main().catch((error) => { console.error("Fatal error in main():", error); process.exit(1); });
Here is a complete GitHub source code
2. Remote MCP Server
1. Setting Up Your Environment
Create and set up our project:
# Create project directory mkdir mcp-remote cd mcp-remote # Initialize npm project npm init -y # Install dependencies npm install zod @modelcontextprotocol/sdk hono @hono/mcp @hono/node-server # Install dev dependencies npm install -D @types/node typescript # Create src dir mkdir src cd src #create index file touch index.ts touch app.tsUpdate
package.json{ "type": "module", "scripts": { "build": "tsc", "start": "node dist/index.js" } }Create a
tsconfig.jsonin the root of your project{ "compilerOptions": { "target": "ES2022", "module": "Node16", "moduleResolution": "Node16", "outDir": "./dist", "rootDir": "./src", "strict": true, "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true }, "include": ["src/**/*"], "exclude": ["node_modules"] }
2. Creating mcp remote serve
In remote MCP Server the steps for creating Resources, Prompts and Tools are same as local mcp server, only difference in communication part.
Communication Transport
create app.ts file
Setting up the Web Server
//src/app.ts import { StreamableHTTPTransport } from "@hono/mcp"; import { Hono } from "hono"; const app = new Hono(); const transport = new StreamableHTTPTransport();Hono- We leverage Hono to orchestrate our HTTP layer due to its exceptional routing speed and zero-dependency footprint.StreamableHTTPTransport- this is HTTP Transport Layer for remote mcp server and also it leverage SSE for streaming data.
MCP end point
In the
/mcpendpoint where actual transport happens.//src/app.ts import { server } from "."; app.all("/mcp", async (c) => { if (!server.isConnected()) { await server.connect(transport); } return transport.handleRequest(c); });app.all()- This listen all HTTP methodsGET POST PATCH DELETE etcserver.connect- we connect transport to server at 1st time of connection.transport.handleRequest(c)- It intercepts incoming transport protocol payloads and routes them through the execution pipeline.
Listening the server
We listen the remote mcp server on port
8787//src/app.ts import { serve } from "@hono/node-server"; serve({ fetch: app.fetch, port: 8787, });
Here is a complete GitHub source code
How to Debug MCP Inspector
Now we build local/remote mcp servers to test or debug the mcp server there is official library provided by modelcontextprotocol i.e MCP Inspector
This provides interactive developer tool UI which is used for testing and debugging MCP servers very easily.
Here are steps of how to use this tool:
Start the Interactive development UI server
npx @modelcontextprotocol/inspector
Interactive development UI server get started on port http://localhost:6274 it is look like this:
Server connection panel
Left side of UI is the server connection panel and following things are required to connect local/remote server
MCP local server
Transport type -
STDIOCommand -
nodeArguments -
path/to/server/index.js
MCP remote server
Transport type -
Stremable HTTPURL -
http://localhost:8787/mcpConnection Type -
Via Proxy
Resources tab
Lists all available resources
Shows resource metadata (MIME types, descriptions)
Allows resource content inspection
Supports subscription testing
Prompts tab
Displays available prompt templates
Shows prompt arguments and descriptions
Enables prompt testing with custom arguments
Previews generated messages
Tools tab
Lists available tools
Shows tool schemas and descriptions
Enables tool testing with custom inputs
Displays tool execution results
Resources
MCP Official Document - Document
How To Build Local MCP Server Source Code - GitHub
How To Build Remote MCP Server Source Code - GitHub
Read more
- Gen AI Using JS - Github


![Token Based Auth System [state-less]](/_next/image?url=https%3A%2F%2Fcloudmate-test.s3.us-east-1.amazonaws.com%2Fuploads%2Fcovers%2F662e9149ea7b8adaf16495b0%2Ff4e28b41-8d8d-42bd-8b0c-e3b86fbebda5.png&w=3840&q=75)
![Session Based Auth System [state-full]](/_next/image?url=https%3A%2F%2Fcloudmate-test.s3.us-east-1.amazonaws.com%2Fuploads%2Fcovers%2F662e9149ea7b8adaf16495b0%2Fe59a4233-21ac-418e-8af0-9057d2e04cdf.png&w=3840&q=75)