Build a Powerful MCP Server with TypeScript in Just a Few Steps
In this article, we're going to be building an MCP server from scratch using TypeScript. The example that we're going to be building is a little bit more real-world than some of the examples that I've seen, in the sense that we're going to be calling real APIs, we're going to be using API keys, and we're going to be building a useful tool. I'm hoping by the end of this article you have a deep understanding of how to build an MCP server so you can go build something useful for your own product or your own application.
What is MCP?
So what is MCP? Let's take a look at the TypeScript documentation for Model Context Protocol, which is what MCP stands for. The overview provides a nice little definition:
Model Context Protocol allows applications to provide context for LLMs in a standardized way, separating the concerns of providing context from the actual LLM interaction. This SDK allows you to build mCP clients and servers and enables two types of transports: one stdio which is something that you might integrate into your terminal with Cloud code or server send events which is more like a traditional HTTP endpoint that uh sends the data back in real time similar to maybe what you've used if you've interacted with other um apis like Claude or chat gbt or maybe you've built your own server.
A good example of something similar would be RAG (Retrieval-Augmented Generation). However, RAG often lacks standardization for how information should be structured and prioritized. MCP is a lot more granular, giving you a ton of control. It's particularly powerful because of two key characteristics: it's very simple to build with, and it's very powerful. You can really supercharge your LLMs using this, and it's just a lot of fun to build with.
In this article, we're going to be building an MCP server that integrates an API. For our example, we'll be calling the igen Explorer API, which brings back a lot of metadata about Igan layer. This will be super helpful for developers who want to get information about IG layer AVSs, or just users that want to get information about IG layer AVSs directly into their workflow for their LLM.
With that being said, we're going to be building this in a very short amount of time, so let's go ahead and get started writing some code.
Setting Up the Project
First, open your terminal and create a new directory for the project.
mkdir igen-layer-mcp
cd igen-layer-mcp
Next, create the main TypeScript file and initialize a new Node.js project.
touch index.ts
npm init -y
The only change we need to make in the package.json
file is to set the type to module
.
{
...
"type": "module",
...
}
Now, let's install the necessary dependencies. We'll need the MCP SDK, Zod for validation, and dotenv
for managing environment variables.
npm install @model-context-protocol/sdk zod dotenv
Finally, create a .env
file in the root of your project. We will populate this with our API keys shortly.
IGEN_EXPLORER_API_KEY=YOUR_API_KEY_HERE
CLAUDE_API_KEY=YOUR_API_KEY_HERE
Implementing the MCP Server
Now we can write the code for our server in index.ts
.
import { MCPeer, StdioPeerTransport } from '@model-context-protocol/sdk';
import 'dotenv/config';
import { z } from 'zod';
// Create a new MCP server instance
const server = new MCPeer({
name: 'igen-layer-avs-data',
version: '0.0.1',
});
// Define a tool for the server
server.tool({
name: 'getAvsStats',
description: 'Gets statistics for an AVS from the Igen Explorer API',
// Define the input schema for the tool
input: z.object({
avsName: z.string().optional().describe('The name of the AVS to get information for'),
fullPrompt: z.string().describe('The full user prompt'),
}),
// The function that executes when the tool is called
execute: async ({ avsName, fullPrompt }) => {
try {
// 1. Fetch data from the Igen Explorer API
const response = await fetch('https://api.igenexplorer.com/avs', {
headers: {
'X-API-KEY': process.env.IGEN_EXPLORER_API_KEY!,
},
});
const avsData = await response.json();
// 2. Call the Claude API with the fetched data
const claudeResponse = await fetch('https://api.anthropic.com/v1/messages', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': process.env.CLAUDE_API_KEY!,
'anthropic-version': '2023-06-01',
},
body: JSON.stringify({
model: 'claude-3-sonnet-20240229',
max_tokens: 1024,
messages: [
{
role: 'user',
content: `
You are an IG Layer AVS data assistant. Your task is to analyze AVS data and respond to user queries.
Here is the AVS data from the IG Explorer API: ${JSON.stringify(avsData)}
User Query: ${fullPrompt}
AVS Name (if provided): ${avsName || 'Not specified'}
Provide a detailed, well-structured response that directly addresses the user's query about the AVS data. Focus on being accurate, informative, and comprehensive.
`,
},
],
}),
});
const claudeJson = await claudeResponse.json();
const claudeText = claudeJson.content[0].text;
// 3. Return the response from Claude
return {
contentType: 'text/plain',
content: claudeText,
};
} catch (error) {
console.error(error);
return {
contentType: 'text/plain',
content: 'An error occurred while processing your request. Please try again.',
};
}
},
});
// Connect the server using standard I/O transport
const transport = new StdioPeerTransport();
await server.connect(transport);
console.log('MCP server connected and ready.');
Testing the Server
With the environment variables set in your .env
file, you can test it out.
First, let's add the server to the Claude CLI so it can be invoked.
claude mcp add
# When prompted for the name, enter: igen-api
# When prompted for the command, enter: npx tsx index.ts
You can verify that the server is configured by listing the available MCP servers.
claude mcp list
You should see igen-api
in the list. Now, you can interact with it directly from the Claude CLI.
claude
Once inside the Claude prompt, you can invoke the tool by asking a question.
User Query:
What is the contract address for lrange abs?
Server Response:
The igen API is invoked...
For the LaGrange Prover Network, the address is: 0x123... For the LaGrange State Committees, the address is: 0x456...
This response comes directly from the igen Explorer API, processed by our MCP server, and delivered into the chat.
That's it! We just created and tested a fully functional MCP server. While this example is relatively basic, it's genuinely useful and demonstrates how you can start building powerful, context-aware AI tools for any application.
Join the 10xdev Community
Subscribe and get 8+ free PDFs that contain detailed roadmaps with recommended learning periods for each programming language or field, along with links to free resources such as books, YouTube tutorials, and courses with certificates.