Skip to content

Instantly share code, notes, and snippets.

@ynonp
Created October 30, 2025 09:41
Show Gist options
  • Save ynonp/421ab41a0c313e8cf04f9ddf4ee99813 to your computer and use it in GitHub Desktop.
Save ynonp/421ab41a0c313e8cf04f9ddf4ee99813 to your computer and use it in GitHub Desktop.
mc-from-scratch

Writing MCP Server from scratch

  1. Why write our own MCP Server

    • connect AI to our own code
  2. Tech stack

    • TypeScript
    • Deno
    • Deno Deploy
  3. Project setup

  4. Code and test a local MCP server

  5. Change to Streamable HTTP MCP Server

  6. Deploy

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
import dadJokes from '@mikemcbride/dad-jokes'
import express from 'express';
import { z } from "zod";
// Create server instance
const server = new McpServer({
name: "dadjokes",
version: "1.0.0",
capabilities: {
resources: {},
tools: {},
},
});
server.registerTool(
"tell-me-a-joke",
{
inputSchema: {
id: z.number().min(0).max(dadJokes.all.length - 1).describe('joke id')
},
title: 'Joke Teller',
description: `Tells a joke according to its index. Valid ids 0-${dadJokes.all.length - 1}`,
},
async ({id}) => {
const joke = { joke: dadJokes.all[id] };
return ({
content: [
{
type: "text",
text: JSON.stringify(joke),
}
],
structuredContent: {joke},
})
}
)
server.registerTool(
"tell-me-a-random-joke",
{
title: 'Random Joke Teller',
description: 'Tells a random joke',
},
async () => {
const joke = {joke: dadJokes.random()};
return ({
content: [
{
type: "text",
text: JSON.stringify(joke),
}
],
structuredContent: joke
})
}
);
// Streamable HTTP Server
const app = express();
app.use(express.json());
app.post('/mcp', async (req: any, res: any) => {
// Create a new transport for each request to prevent request ID collisions
const transport = new StreamableHTTPServerTransport({
sessionIdGenerator: undefined,
enableJsonResponse: true
});
res.on('close', () => {
transport.close();
});
await server.connect(transport);
await transport.handleRequest(req, res, req.body);
});
const port = parseInt(process.env.PORT || '3000');
app.listen(port, () => {
console.log(`Demo MCP Server running on http://localhost:${port}/mcp`);
}).on('error', error => {
console.error('Server error:', error);
process.exit(1);
});
// STDIO Server
// const transport = new StdioServerTransport();
// await server.connect(transport);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment