mirror of
https://github.com/OneUptime/oneuptime.git
synced 2026-04-06 00:32:12 +02:00
feat: Implement MCP Hello World Server with basic tools and configuration
This commit is contained in:
6
.gitignore
vendored
6
.gitignore
vendored
@@ -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
12
MCP/.env.example
Normal 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
53
MCP/Dockerfile.tpl
Normal 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
190
MCP/Index.ts
Normal 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
92
MCP/README.md
Normal 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.
|
||||
16
MCP/__tests__/server.test.ts
Normal file
16
MCP/__tests__/server.test.ts
Normal 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
2
MCP/build/.gitkeep
Normal 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
13
MCP/jest.config.json
Normal 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
6
MCP/nodemon.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"watch": ["Index.ts"],
|
||||
"ext": "ts",
|
||||
"ignore": ["build/*"],
|
||||
"exec": "npm start"
|
||||
}
|
||||
32
MCP/package.json
Normal file
32
MCP/package.json
Normal 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
30
MCP/tsconfig.json
Normal 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"
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user