feat: Implement MCP Hello World Server with basic tools and configuration

This commit is contained in:
Simon Larsen
2025-06-27 12:56:38 +01:00
parent f2de3cc8a8
commit 1e254e32fd
11 changed files with 451 additions and 1 deletions

6
.gitignore vendored
View File

@@ -123,4 +123,8 @@ Terraform/**
TerraformTest/**
terraform-provider-example/**
terraform-provider-example/**
# MCP Hello World Server
mcp-hello-world/build/
mcp-hello-world/.env

12
MCP/.env.example Normal file
View File

@@ -0,0 +1,12 @@
# Environment variables for OneUptime MCP Hello World Server
# Logging
LOG_LEVEL=info
# Server Configuration
NODE_ENV=development
PORT=3002
# OneUptime Configuration
APP_NAME=mcp-hello-world
APP_VERSION=1.0.0

53
MCP/Dockerfile.tpl Normal file
View File

@@ -0,0 +1,53 @@
#
# OneUptime MCP Hello World Dockerfile
#
# Pull base image nodejs image.
FROM public.ecr.aws/docker/library/node:22.3.0
RUN mkdir /tmp/npm && chmod 2777 /tmp/npm && chown 1000:1000 /tmp/npm && npm config set cache /tmp/npm --global
RUN npm config set fetch-retries 5
RUN npm config set fetch-retry-mintimeout 100000
RUN npm config set fetch-retry-maxtimeout 600000
ARG GIT_SHA
ARG APP_VERSION
ENV GIT_SHA=${GIT_SHA}
ENV APP_VERSION=${APP_VERSION}
# IF APP_VERSION is not set, set it to 1.0.0
RUN if [ -z "$APP_VERSION" ]; then export APP_VERSION=1.0.0; fi
# Install bash.
RUN apt-get install bash -y && apt-get install curl -y
# Install python
RUN apt-get update && apt-get install -y .gyp python3 make g++
#Use bash shell by default
SHELL ["/bin/bash", "-c"]
RUN npm install typescript -g
USER root
RUN mkdir /usr/src
WORKDIR /usr/src/Common
COPY ./Common/package*.json /usr/src/Common/
RUN npm install
COPY ./Common /usr/src/Common
WORKDIR /usr/src/app
# Install app dependencies
COPY ./mcp-hello-world/package*.json /usr/src/app/
RUN npm install --only=production
COPY ./mcp-hello-world /usr/src/app
# Expose Port
EXPOSE 3002
#Run the app
RUN npm run compile
CMD [ "npm", "start" ]

190
MCP/Index.ts Normal file
View File

@@ -0,0 +1,190 @@
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
CallToolRequestSchema,
ErrorCode,
ListToolsRequestSchema,
McpError,
} from "@modelcontextprotocol/sdk/types.js";
import logger from "Common/Server/Utils/Logger";
import dotenv from "dotenv";
// Load environment variables
dotenv.config();
const APP_NAME: string = "mcp-hello-world";
logger.info("OneUptime Hello World MCP Server is starting...");
class HelloWorldMCPServer {
private server: Server;
constructor() {
this.server = new Server(
{
name: "oneuptime-mcp",
version: "1.0.0",
},
{
capabilities: {
tools: {},
},
}
);
this.setupHandlers();
}
private setupHandlers(): void {
// List available tools
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: "hello",
description: "Say hello with a personalized greeting",
inputSchema: {
type: "object",
properties: {
name: {
type: "string",
description: "Name of the person to greet",
},
},
required: ["name"],
},
},
{
name: "get_time",
description: "Get the current server time",
inputSchema: {
type: "object",
properties: {},
},
},
{
name: "echo",
description: "Echo back any message",
inputSchema: {
type: "object",
properties: {
message: {
type: "string",
description: "Message to echo back",
},
},
required: ["message"],
},
},
],
};
});
// Handle tool calls
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
try {
switch (name) {
case "hello": {
const personName = args?.name as string;
if (!personName) {
throw new McpError(
ErrorCode.InvalidParams,
"Name parameter is required"
);
}
logger.info(`Saying hello to: ${personName}`);
return {
content: [
{
type: "text",
text: `Hello, ${personName}! Welcome to OneUptime's Hello World MCP Server! 🚀`,
},
],
};
}
case "get_time": {
const currentTime = new Date().toISOString();
logger.info(`Returning current time: ${currentTime}`);
return {
content: [
{
type: "text",
text: `Current server time: ${currentTime}`,
},
],
};
}
case "echo": {
const message = args?.message as string;
if (!message) {
throw new McpError(
ErrorCode.InvalidParams,
"Message parameter is required"
);
}
logger.info(`Echoing message: ${message}`);
return {
content: [
{
type: "text",
text: `Echo: ${message}`,
},
],
};
}
default:
throw new McpError(
ErrorCode.MethodNotFound,
`Unknown tool: ${name}`
);
}
} catch (error) {
logger.error(`Error executing tool ${name}:`, error);
throw error;
}
});
}
async run(): Promise<void> {
const transport = new StdioServerTransport();
await this.server.connect(transport);
logger.info("OneUptime Hello World MCP Server is running!");
logger.info("Available tools: hello, get_time, echo");
}
}
// Start the server
async function main(): Promise<void> {
try {
const mcpServer = new HelloWorldMCPServer();
await mcpServer.run();
} catch (error) {
logger.error("Failed to start MCP server:", error);
process.exit(1);
}
}
// Handle graceful shutdown
process.on("SIGINT", () => {
logger.info("Received SIGINT, shutting down gracefully...");
process.exit(0);
});
process.on("SIGTERM", () => {
logger.info("Received SIGTERM, shutting down gracefully...");
process.exit(0);
});
// Start the server
main().catch((error) => {
logger.error("Unhandled error:", error);
process.exit(1);
});

92
MCP/README.md Normal file
View File

@@ -0,0 +1,92 @@
# OneUptime Hello World MCP Server
A basic Hello World implementation of a Model Context Protocol (MCP) server for OneUptime.
## What is this?
This is a simple MCP server that demonstrates how to create a Model Context Protocol server within the OneUptime ecosystem. It provides basic tools that can be used by AI assistants like Claude to interact with the server.
## Available Tools
1. **hello** - Say hello with a personalized greeting
- Parameters: `name` (string, required)
- Example: Returns "Hello, [name]! Welcome to OneUptime's Hello World MCP Server! 🚀"
2. **get_time** - Get the current server time
- Parameters: None
- Example: Returns current ISO timestamp
3. **echo** - Echo back any message
- Parameters: `message` (string, required)
- Example: Returns "Echo: [your message]"
## Development
### Prerequisites
- Node.js 18+
- npm or yarn
- TypeScript
### Setup
1. Install dependencies:
```bash
npm install
```
2. Start development server:
```bash
npm run dev
```
3. Start production server:
```bash
npm start
```
### Docker
Build and run with Docker:
```bash
# Build the Docker image
docker build -f Dockerfile.tpl -t oneuptime-mcp-hello-world .
# Run the container
docker run -it oneuptime-mcp-hello-world
```
## Usage
This MCP server communicates over stdio and is designed to be used with MCP-compatible clients like Claude Desktop or other AI assistants that support the Model Context Protocol.
### Example Configuration for Claude Desktop
Add this to your Claude Desktop MCP settings:
```json
{
"mcpServers": {
"oneuptime": {
"command": "node",
"args": ["--require", "ts-node/register", "/path/to/mcp-hello-world/Index.ts"]
}
}
}
```
## Architecture
The server is built using:
- **@modelcontextprotocol/sdk**: Official MCP SDK for TypeScript
- **OneUptime Common**: Shared utilities and logging from OneUptime
- **TypeScript**: For type safety and better development experience
## Contributing
This is part of the OneUptime project. Follow the standard OneUptime development practices and coding standards.
## License
Apache-2.0 - see the OneUptime project license for details.

View File

@@ -0,0 +1,16 @@
import { describe, it, expect } from '@jest/globals';
describe('MCP Hello World Server', () => {
it('should have basic structure', () => {
// Basic test to ensure the test setup works
expect(true).toBe(true);
});
it('should export required tools', () => {
// Test for tool definitions
const expectedTools = ['hello', 'get_time', 'echo'];
expect(expectedTools).toContain('hello');
expect(expectedTools).toContain('get_time');
expect(expectedTools).toContain('echo');
});
});

2
MCP/build/.gitkeep Normal file
View File

@@ -0,0 +1,2 @@
# Build directory for compiled TypeScript files
# This directory will contain the compiled JavaScript output

13
MCP/jest.config.json Normal file
View File

@@ -0,0 +1,13 @@
{
"preset": "ts-jest",
"testEnvironment": "node",
"testMatch": ["**/__tests__/**/*.ts", "**/?(*.)+(spec|test).ts"],
"collectCoverageFrom": [
"**/*.ts",
"!**/*.d.ts",
"!**/node_modules/**",
"!**/build/**"
],
"setupFilesAfterEnv": [],
"testTimeout": 30000
}

6
MCP/nodemon.json Normal file
View File

@@ -0,0 +1,6 @@
{
"watch": ["Index.ts"],
"ext": "ts",
"ignore": ["build/*"],
"exec": "npm start"
}

32
MCP/package.json Normal file
View File

@@ -0,0 +1,32 @@
{
"name": "@oneuptime/mcp-hello-world",
"version": "1.0.0",
"description": "OneUptime Hello World MCP Server",
"main": "Index.ts",
"type": "module",
"scripts": {
"start": "export NODE_OPTIONS='--max-old-space-size=8096' && node --require ts-node/register Index.ts",
"compile": "tsc",
"clear-modules": "rm -rf node_modules && rm package-lock.json && npm install",
"dev": "npx nodemon",
"audit": "npm audit --audit-level=low",
"dep-check": "npm install -g depcheck && depcheck ./ --skip-missing=true",
"test": "jest --passWithNoTests"
},
"author": "OneUptime <hello@oneuptime.com> (https://oneuptime.com/)",
"license": "Apache-2.0",
"dependencies": {
"Common": "file:./Common",
"@modelcontextprotocol/sdk": "^0.6.0",
"ts-node": "^10.9.1",
"dotenv": "^16.4.5"
},
"devDependencies": {
"@types/jest": "^27.5.0",
"@types/node": "^17.0.31",
"jest": "^28.1.0",
"nodemon": "^2.0.20",
"ts-jest": "^28.0.2",
"typescript": "^5.8.3"
}
}

30
MCP/tsconfig.json Normal file
View File

@@ -0,0 +1,30 @@
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"lib": ["es6"],
"allowJs": true,
"outDir": "./build",
"rootDir": "./",
"strict": true,
"moduleResolution": "node",
"baseUrl": "./",
"paths": {
"Common/*": ["./Common/*"]
},
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true
},
"include": [
"**/*.ts"
],
"exclude": [
"node_modules",
"build"
]
}