Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions docker/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,21 @@ services:
networks:
- nestjs-todo-network

mcp-server:
build:
context: ..
dockerfile: ./docker/Dockerfile
command: ['npm', 'run', 'mcp:dev']
volumes:
- ../src:/usr/src/app/src
depends_on:
- mongo
- redis-db
env_file:
- ../.env
networks:
- nestjs-todo-network

mongo:
image: mongo
container_name: todo-playground-mongo
Expand Down
100 changes: 88 additions & 12 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"private": true,
"license": "UNLICENSED",
"scripts": {
"mcp:dev": "ts-node -r tsconfig-paths/register src/mcp-server.ts",
"build": "nest build",
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
"start": "nest start",
Expand All @@ -21,6 +22,7 @@
},
"dependencies": {
"@elastic/elasticsearch": "9.0.3",
"@modelcontextprotocol/sdk": "1.18.1",
"@nestjs-modules/ioredis": "2.0.2",
"@nestjs/bullmq": "11.0.3",
"@nestjs/common": "11.1.0",
Expand Down
2 changes: 2 additions & 0 deletions src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { Environment } from './core/interface';
import { TodoModule } from './modules/todo/todo.module';
import { RabbitmqModule } from './modules/utils/rabbitmq/rabbitmq.module';
import { LockModule } from './core/cache/lock/lock.module';
import { McpModule } from './modules/mcp/mcp.module';

@Module({
imports: [
Expand All @@ -37,6 +38,7 @@ import { LockModule } from './core/cache/lock/lock.module';
TodoModule,
RabbitmqModule,
LockModule,
McpModule,
],

controllers: [],
Expand Down
3 changes: 3 additions & 0 deletions src/core/error/error-code.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ export enum ErrorCode {
BAD_INPUT = 400100,
NICKNAME_ALREADY_TAKEN = 400101,
INVALID_CREDENTIALS = 400103,
//MCP
MCP_TOOL_NOT_FOUND = 400200,
MCP_CATEGORY_NOT_SUPPORTED = 400201,

// 401
UNAUTHORIZED = 40100,
Expand Down
2 changes: 2 additions & 0 deletions src/core/error/exception/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,5 @@ export * from './unauthorized.exception';
export * from './invalid-refresh-token.exception';
export * from './todo-not-found.exception';
export * from './todo-deletion-pending.exception';
export * from './mcp-tool-not-found.exception';
export * from './mcp-category-not-supported.exception';
12 changes: 12 additions & 0 deletions src/core/error/exception/mcp-category-not-supported.exception.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { ErrorCode } from '../error-code';
import { BadInputException } from './bad-input.exception';

export class McpCategoryNotSupportedException extends BadInputException {
constructor(category: string) {
super(
`MCP tool category '${category}' is not supported`,
ErrorCode.MCP_CATEGORY_NOT_SUPPORTED,
`Category '${category}' is not available`,
);
}
}
12 changes: 12 additions & 0 deletions src/core/error/exception/mcp-tool-not-found.exception.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { ErrorCode } from '../error-code';
import { NotFoundException } from './not-found.exception';

export class McpToolNotFoundException extends NotFoundException {
constructor(toolName: string) {
super(
`MCP tool '${toolName}' not found`,
ErrorCode.MCP_TOOL_NOT_FOUND,
`Tool '${toolName}' is not available`,
);
}
}
1 change: 1 addition & 0 deletions src/core/interface/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './environment.interface';
export * from './mongo-model';
export * from './bullmq';
export * from './mcp';
1 change: 1 addition & 0 deletions src/core/interface/mcp/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './mcp-tool.const';
38 changes: 38 additions & 0 deletions src/core/interface/mcp/mcp-tool.const.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
export const McpTool = {
AUTH_REGISTER: {
name: 'auth_register',
description: 'Register a new user',
category: 'auth' as const,
},
AUTH_LOGIN: {
name: 'auth_login',
description: 'Login user and get access token',
category: 'auth' as const,
},
TODO_CREATE: {
name: 'todo_create',
description: 'Create a new todo item',
category: 'todo' as const,
},
TODO_LIST: {
name: 'todo_list',
description: 'List user todos with pagination',
category: 'todo' as const,
},
TODO_UPDATE: {
name: 'todo_update',
description: 'Update an existing todo',
category: 'todo' as const,
},
TODO_DELETE: {
name: 'todo_delete',
description: 'Delete a todo item',
category: 'todo' as const,
},
} as const;

// Type utilities
export type McpToolKey = keyof typeof McpTool;
export type McpToolValue = (typeof McpTool)[McpToolKey];
export type McpToolName = McpToolValue['name'];
export type McpToolCategory = McpToolValue['category'];
13 changes: 13 additions & 0 deletions src/mcp-server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { McpServer } from './modules/mcp/server/mcp.server';

async function bootstrap() {
const app = await NestFactory.create(AppModule);

const mcpServer = app.get(McpServer);

await mcpServer.start();
}

bootstrap();
11 changes: 11 additions & 0 deletions src/modules/mcp/mcp.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Module } from '@nestjs/common';
import { McpServer } from './server/mcp.server';
import { AuthModule } from '../auth/auth.module';
import { UserModule } from '../user/user.module';

@Module({
imports: [AuthModule, UserModule],
providers: [McpServer],
exports: [McpServer],
})
export class McpModule {}
Loading