Skip to main content
Glama
server.js3.59 kB
#!/usr/bin/env node import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { McpError, ErrorCode } from '@modelcontextprotocol/sdk/types.js'; import axios from 'axios'; import crypto from 'crypto'; /** * Core GhostServer class that handles initialization and API communication */ export class GhostServer { /** * Initialize the Ghost MCP server */ constructor() { // Initialize MCP server this.server = new Server({ name: 'ghost-server', version: '1.0.0', }, { capabilities: { tools: {}, }, }); // Set up error handler this.server.onerror = (error) => console.error('[MCP Error]', error); // Initialize API configuration this.baseUrl = process.env.GHOST_URL || 'https://blog.emmanuelu.com'; this.keyId = process.env.GHOST_KEY_ID; this.keySecret = process.env.GHOST_KEY_SECRET; if (!this.keyId || !this.keySecret) { console.warn('Warning: GHOST_KEY_ID or GHOST_KEY_SECRET environment variables not set'); } // Initialize axios instance for API requests this.api = axios.create({ baseURL: `${this.baseUrl}/ghost/api/admin`, headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', }, }); } /** * Create a JWT token for Ghost Admin API authentication * @returns {string} JWT token */ createGhostToken() { const header = { alg: "HS256", typ: "JWT", kid: this.keyId }; const iat = Math.floor(Date.now() / 1000); const payload = { iat: iat, exp: iat + 300, // Token expires in 5 minutes aud: "/admin/" }; // Base64 encode function const b64encode = (obj) => { return Buffer.from(JSON.stringify(obj)) .toString('base64') .replace(/=+$/, '') .replace(/\+/g, '-') .replace(/\//g, '_'); }; const headerEncoded = b64encode(header); const payloadEncoded = b64encode(payload); const message = `${headerEncoded}.${payloadEncoded}`; const key = Buffer.from(this.keySecret, 'hex'); const signature = crypto.createHmac('sha256', key) .update(message) .digest('base64') .replace(/=+$/, '') .replace(/\+/g, '-') .replace(/\//g, '_'); return `${headerEncoded}.${payloadEncoded}.${signature}`; } /** * Get API headers with authentication * @returns {Object} Headers object */ getApiHeaders() { return { 'Authorization': `Ghost ${this.createGhostToken()}`, 'Content-Type': 'application/json', 'Accept': 'application/json', }; } /** * Create a standard error response * @param {Error} error - The error object * @returns {Object} Formatted error response */ createErrorResponse(error) { console.error('Error in tool handler:', error); return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: error.message, details: error.response?.data || error, }, null, 2), }], isError: true, }; } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/oculairmedia/Ghost-MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server