Skip to main content
Glama
server-todo.ts6.96 kB
import fastify from "fastify"; import type { FastifyInstance, FastifyPluginAsync } from "fastify"; import swagger from "@fastify/swagger"; import swaggerUI from "@fastify/swagger-ui"; import mcpPlugin from "@mcp-it/fastify"; // Todo interface interface Todo { id: number; title: string; completed: boolean; createdAt: string; } // In-memory database let todos: Todo[] = []; let idCounter = 1; // Todo plugin const todoPlugin: FastifyPluginAsync = async (fastify: FastifyInstance) => { // Get all todos fastify.get( "/", { schema: { tags: ["todos"], summary: "Get all todos", description: "Retrieves a list of all todo items", response: { 200: { type: "array", items: { type: "object", properties: { id: { type: "number" }, title: { type: "string" }, completed: { type: "boolean" }, createdAt: { type: "string", format: "date-time" }, }, }, }, }, }, }, async () => { return todos; } ); // Get a specific todo fastify.get( "/:id", { schema: { operationId: "getTodoById", tags: ["todos"], summary: "Get a specific todo", description: "Retrieves a single todo item by id", params: { type: "object", required: ["id"], properties: { id: { type: "number" }, }, }, response: { 200: { type: "object", properties: { id: { type: "number" }, title: { type: "string" }, completed: { type: "boolean" }, createdAt: { type: "string", format: "date-time" }, }, }, 404: { type: "object", properties: { message: { type: "string" }, }, }, }, }, }, async (request, reply) => { const { id } = request.params as { id: number }; const todo = todos.find((t) => t.id === Number(id)); if (!todo) { reply.code(404); return { message: "Todo not found" }; } return todo; } ); // Create a new todo fastify.post( "/", { schema: { tags: ["todos"], summary: "Create a new todo", description: "Creates a new todo item", body: { type: "object", required: ["title"], properties: { title: { type: "string" }, completed: { type: "boolean" }, }, }, response: { 201: { type: "object", properties: { id: { type: "number" }, title: { type: "string" }, completed: { type: "boolean" }, createdAt: { type: "string", format: "date-time" }, }, }, }, }, }, async (request, reply) => { const { title, completed = false } = request.body as { title: string; completed?: boolean; }; const newTodo: Todo = { id: idCounter++, title, completed, createdAt: new Date().toISOString(), }; todos.push(newTodo); reply.code(201); return newTodo; } ); // Update a todo fastify.put( "/:id", { schema: { tags: ["todos"], summary: "Update a todo", description: "Updates a specific todo item by id", params: { type: "object", required: ["id"], properties: { id: { type: "number" }, }, }, body: { type: "object", properties: { title: { type: "string" }, completed: { type: "boolean" }, }, }, response: { 200: { type: "object", properties: { id: { type: "number" }, title: { type: "string" }, completed: { type: "boolean" }, createdAt: { type: "string", format: "date-time" }, }, }, 404: { type: "object", properties: { message: { type: "string" }, }, }, }, }, }, async (request, reply) => { const { id } = request.params as { id: number }; const { title, completed } = request.body as { title?: string; completed?: boolean; }; const todo = todos.find((t) => t.id === Number(id)); if (!todo) { reply.code(404); return { message: "Todo not found" }; } if (title !== undefined) { todo.title = title; } if (completed !== undefined) { todo.completed = completed; } return todo; } ); // Delete a todo fastify.delete( "/:id", { schema: { tags: ["todos"], summary: "Delete a todo", description: "Deletes a specific todo item by id", params: { type: "object", required: ["id"], properties: { id: { type: "number" }, }, }, response: { 200: { type: "object", properties: { message: { type: "string" }, }, }, 404: { type: "object", properties: { message: { type: "string" }, }, }, }, }, }, async (request, reply) => { const { id } = request.params as { id: number }; const todoIndex = todos.findIndex((t) => t.id === Number(id)); if (todoIndex === -1) { reply.code(404); return { message: "Todo not found" }; } todos.splice(todoIndex, 1); return { message: "Todo deleted successfully" }; } ); }; // Create server const server = fastify({ logger: true, }); // Enable CORS await server.register(import("@fastify/cors")); // Register swagger server.register(swagger, { swagger: { info: { title: "Todo API", description: "A simple Todo API with CRUD operations", version: "1.0.0", }, tags: [{ name: "todos", description: "Todo related endpoints" }], }, }); server.register(swaggerUI, { routePrefix: "/documentation", uiConfig: { docExpansion: "list", deepLinking: false, }, }); await server.register(mcpPlugin, { mountPath: "/mcp", addDebugEndpoint: true, }); // Register routes server.register(todoPlugin, { prefix: "/api/todos" }); // Add hook to generate swagger documentation when the server starts server.ready(() => { server.swagger(); }); // Start server const start = async () => { try { await server.listen({ port: 3000 }); } catch (err) { server.log.error(err); process.exit(1); } }; start();

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/AdirAmsalem/mcp-it'

If you have feedback or need assistance with the MCP directory API, please join our Discord server