server.jsā¢9.44 kB
#!/usr/bin/env node
/**
* MCP Server Implementation
*
* This server provides various tools and resources that AI models can use
* through the Model Context Protocol (MCP).
*/
const { Server } = require('@modelcontextprotocol/sdk/server/index.js');
const { StdioServerTransport } = require('@modelcontextprotocol/sdk/server/stdio.js');
const { CallToolRequestSchema, ListToolsRequestSchema } = require('@modelcontextprotocol/sdk/types.js');
const express = require('express');
const cors = require('cors');
const fs = require('fs').promises;
const path = require('path');
const os = require('os');
require('dotenv').config();
class MCPServer {
constructor() {
this.server = new Server(
{
name: 'custom-mcp-server',
version: '1.0.0',
},
{
capabilities: {
tools: {},
resources: {},
},
}
);
this.setupTools();
this.setupResources();
this.setupHttpServer();
}
setupTools() {
// File System Tools
this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [
{
name: 'read_file',
description: 'Read the contents of a file',
inputSchema: {
type: 'object',
properties: {
path: {
type: 'string',
description: 'The path to the file to read',
},
},
required: ['path'],
},
},
{
name: 'write_file',
description: 'Write content to a file',
inputSchema: {
type: 'object',
properties: {
path: {
type: 'string',
description: 'The path to the file to write',
},
content: {
type: 'string',
description: 'The content to write to the file',
},
},
required: ['path', 'content'],
},
},
{
name: 'list_directory',
description: 'List the contents of a directory',
inputSchema: {
type: 'object',
properties: {
path: {
type: 'string',
description: 'The path to the directory to list',
},
},
required: ['path'],
},
},
{
name: 'get_system_info',
description: 'Get system information',
inputSchema: {
type: 'object',
properties: {},
},
},
{
name: 'execute_command',
description: 'Execute a system command (use with caution)',
inputSchema: {
type: 'object',
properties: {
command: {
type: 'string',
description: 'The command to execute',
},
cwd: {
type: 'string',
description: 'Working directory for the command',
},
},
required: ['command'],
},
},
{
name: 'fetch_url',
description: 'Fetch content from a URL',
inputSchema: {
type: 'object',
properties: {
url: {
type: 'string',
description: 'The URL to fetch',
},
method: {
type: 'string',
description: 'HTTP method (GET, POST, etc.)',
default: 'GET',
},
headers: {
type: 'object',
description: 'HTTP headers to include',
},
},
required: ['url'],
},
},
],
}));
// Tool execution handler
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
try {
switch (name) {
case 'read_file':
return await this.readFile(args.path);
case 'write_file':
return await this.writeFile(args.path, args.content);
case 'list_directory':
return await this.listDirectory(args.path);
case 'get_system_info':
return await this.getSystemInfo();
case 'execute_command':
return await this.executeCommand(args.command, args.cwd);
case 'fetch_url':
return await this.fetchUrl(args.url, args.method, args.headers);
default:
throw new Error(`Unknown tool: ${name}`);
}
} catch (error) {
return {
content: [
{
type: 'text',
text: `Error: ${error.message}`,
},
],
};
}
});
}
setupResources() {
// Resources are static content that can be referenced
// This could include documentation, templates, etc.
}
setupHttpServer() {
this.app = express();
this.app.use(cors());
this.app.use(express.json());
// Health check endpoint
this.app.get('/health', (req, res) => {
res.json({ status: 'healthy', timestamp: new Date().toISOString() });
});
// MCP endpoint for HTTP transport
this.app.post('/mcp', async (req, res) => {
try {
// Handle MCP requests over HTTP
// This would require implementing HTTP transport
res.json({ message: 'MCP HTTP transport not yet implemented' });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
const port = process.env.PORT || 3000;
this.app.listen(port, () => {
console.log(`MCP Server HTTP interface listening on port ${port}`);
console.log(`Health check: http://localhost:${port}/health`);
});
}
// Tool implementations
async readFile(filePath) {
try {
const content = await fs.readFile(filePath, 'utf-8');
return {
content: [
{
type: 'text',
text: content,
},
],
};
} catch (error) {
throw new Error(`Failed to read file: ${error.message}`);
}
}
async writeFile(filePath, content) {
try {
await fs.writeFile(filePath, content, 'utf-8');
return {
content: [
{
type: 'text',
text: `Successfully wrote to ${filePath}`,
},
],
};
} catch (error) {
throw new Error(`Failed to write file: ${error.message}`);
}
}
async listDirectory(dirPath) {
try {
const items = await fs.readdir(dirPath, { withFileTypes: true });
const listing = items.map(item => ({
name: item.name,
type: item.isDirectory() ? 'directory' : 'file',
path: path.join(dirPath, item.name),
}));
return {
content: [
{
type: 'text',
text: JSON.stringify(listing, null, 2),
},
],
};
} catch (error) {
throw new Error(`Failed to list directory: ${error.message}`);
}
}
async getSystemInfo() {
const info = {
platform: os.platform(),
arch: os.arch(),
hostname: os.hostname(),
cpus: os.cpus().length,
totalMemory: Math.round(os.totalmem() / 1024 / 1024 / 1024) + ' GB',
freeMemory: Math.round(os.freemem() / 1024 / 1024 / 1024) + ' GB',
uptime: Math.round(os.uptime() / 3600) + ' hours',
nodeVersion: process.version,
currentDirectory: process.cwd(),
};
return {
content: [
{
type: 'text',
text: JSON.stringify(info, null, 2),
},
],
};
}
async executeCommand(command, cwd = process.cwd()) {
const { exec } = require('child_process');
const { promisify } = require('util');
const execAsync = promisify(exec);
try {
const { stdout, stderr } = await execAsync(command, { cwd });
return {
content: [
{
type: 'text',
text: `Command: ${command}\nOutput:\n${stdout}${stderr ? `\nErrors:\n${stderr}` : ''}`,
},
],
};
} catch (error) {
throw new Error(`Command execution failed: ${error.message}`);
}
}
async fetchUrl(url, method = 'GET', headers = {}) {
const fetch = require('node-fetch');
try {
const response = await fetch(url, {
method,
headers,
});
const content = await response.text();
const responseInfo = {
status: response.status,
statusText: response.statusText,
headers: Object.fromEntries(response.headers),
content,
};
return {
content: [
{
type: 'text',
text: JSON.stringify(responseInfo, null, 2),
},
],
};
} catch (error) {
throw new Error(`Failed to fetch URL: ${error.message}`);
}
}
async start() {
const transport = new StdioServerTransport();
await this.server.connect(transport);
console.log('MCP Server started with stdio transport');
}
}
// Start the server
if (require.main === module) {
const server = new MCPServer();
server.start().catch((error) => {
console.error('Failed to start MCP server:', error);
process.exit(1);
});
}
module.exports = MCPServer;