mcp-server

mcp-server

0

The MCP Server is a comprehensive server implementation of the Model Context Protocol designed for real-time communication with AI models. It features a clean architecture, extensive tooling, and multiple transport options. Built for developers, it offers logging, error handling, and is highly extensible.

MCP Server

License: MIT Node.js: β‰₯18

A robust server implementation of the Model Context Protocol (MCP) that supports multiple transport methods (SSE and STDIO) for real-time communication with AI models.

πŸš€ Features

  • Full MCP Implementation: Complete and standard-compliant implementation of the Model Context Protocol
  • Multiple Transports: Seamless communication via SSE (Server-Sent Events) and STDIO
  • Robust Architecture: Built on Clean Architecture and SOLID principles for maintainability and extensibility
  • Powerful Tooling: Easily extensible tools, resources, and prompts
  • Developer-Friendly: Comprehensive logging, error handling, and testing support

πŸ—οΈ Architecture

The project follows a clean, layered architecture adhering to SOLID principles:

LayerResponsibilityComponents
DomainCore business logicInterfaces, Models, Entities
ApplicationUse cases, application flowServices, Use Cases, DTOs
InfrastructureTechnical concernsImplementations, Adapters, External services
PresentationUser interfaceAPI Controllers, HTTP endpoints

Architectural Diagram

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Presentation       β”‚      β”‚  Application        β”‚
β”‚  Layer              β”‚      β”‚  Layer              β”‚
β”‚  - Express API      │─────▢│  - Use Cases        β”‚
β”‚  - Controllers      β”‚      β”‚  - Services         β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                        β”‚
                                        β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Infrastructure     β”‚      β”‚  Domain             β”‚
β”‚  Layer              │◀─────│  Layer              β”‚
β”‚  - Implementations  β”‚      β”‚  - Interfaces       β”‚
β”‚  - Adapters         β”‚      β”‚  - Models           β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ’» Requirements

  • Node.js 18 or higher
  • Yarn or npm package manager

πŸ“¦ Installation

# Clone the repository
git clone https://github.com/your-username/mcp-server.git
cd mcp-server

# Install dependencies
yarn install

# Build the project
yarn build

πŸš€ Running the Server

# Start the server
yarn start

# Build and start in one command (for development)
yarn rebuild

By default, the server runs on port 3001. You can configure this using the PORT environment variable.

πŸ”Œ Transport Options

The MCP server supports two transport methods:

TransportDescriptionUse Case
SSEServer-Sent Events over HTTPWeb applications, browser clients
STDIOStandard input/output streamsCLI tools, local applications

πŸ›£οΈ API Endpoints

  • SSE: /sse - Establish SSE connections for real-time communication
  • Messages: /messages - Send JSON-RPC messages to the server

πŸ§ͺ Testing

Use the official MCP Inspector tool to test your server implementation:

  1. Build and start your MCP Server
yarn build
yarn rebuild  # if using SSE transport (builds & starts)
# OR
yarn start    # manual start
  1. Run the inspector against your server
npx @modelcontextprotocol/inspector node build/index.js
  1. Access to Inspecto UI http://127.0.0.1:6274 πŸš€

🧩 Extending Functionality

Adding a New Tool

// tools/custom/my-tool.ts
import { z } from "zod";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { ITool } from "../core/domain/interfaces/tool.interface.js";
import { ILogger } from "../core/domain/interfaces/logger.interface.js";

export class MyTool implements ITool {
    private readonly logger: ILogger;

    constructor(logger: ILogger) {
        this.logger = logger;
    }

    public register(server: McpServer): void {
        server.tool(
            "my-tool",
            "Description of my tool",
            {
                param1: z.string().describe("Parameter description"),
            },
            async ({ param1 }) => {
                this.logger.info(`MyTool called with param1: ${param1}`);
                
                return {
                    content: [
                        {
                            type: "text",
                            text: `Result: ${param1}`,
                        },
                    ],
                };
            },
        );

        this.logger.info("MyTool registered");
    }
}

Adding a New Resource

// resources/custom/my-resource.ts
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { IResource } from "../core/domain/interfaces/resource.interface.js";
import { ILogger } from "../core/domain/interfaces/logger.interface.js";

export class MyResource implements IResource {
    private readonly logger: ILogger;

    constructor(logger: ILogger) {
        this.logger = logger;
    }

    public register(server: McpServer): void {
        server.resource('my-resource', 'my-data.json', async () => {
            this.logger.info('My resource accessed');

            return {
                contents: [
                    {
                        uri: 'my-data.json',
                        text: JSON.stringify({ key: "value" }, null, 2),
                        mimeType: 'application/json',
                    },
                ],
            };
        });

        this.logger.info('My resource registered');
    }
}

Adding a New Prompt

// prompts/custom/my-prompt.ts
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { IPrompt } from "../core/domain/interfaces/prompt.interface.js";
import { ILogger } from "../core/domain/interfaces/logger.interface.js";

export class MyPrompt implements IPrompt {
    private readonly logger: ILogger;

    constructor(logger: ILogger) {
        this.logger = logger;
    }

    public register(server: McpServer): void {
        server.prompt(
            'my-prompt',
            'Description of my prompt',
            () => {
                this.logger.info('My prompt accessed');

                return {
                    messages: [
                        {
                            role: 'user',
                            content: {
                                type: 'text',
                                text: 'Initial user message',
                            },
                        },
                        {
                            role: 'assistant',
                            content: {
                                type: 'text',
                                text: 'Initial assistant response',
                            },
                        },
                    ],
                };
            },
        );

        this.logger.info('My prompt registered');
    }
}

πŸ“ SOLID Principles Applied

PrincipleImplementation
Single ResponsibilityEach class has one clear responsibility
Open/ClosedSystem can be extended without modifying existing code
Liskov SubstitutionDerived types can be substituted for their base types
Interface SegregationSpecific interfaces for specific clients
Dependency InversionHigh-level modules depend on abstractions

πŸ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.