UNPKG

systemprompt-mcp-reddit

Version:

A specialized Model Context Protocol (MCP) server that enables you to search, read, and interact with Reddit content, leveraging an AI Agent to help with each operation.

144 lines 5.28 kB
import { sendJsonResultNotification } from "../handlers/notifications.js"; export class SystemPromptService { constructor() { this.baseUrl = "https://api.systemprompt.io/v1"; } static initialize() { if (!SystemPromptService.instance) { SystemPromptService.instance = new SystemPromptService(); } } static getInstance() { if (!SystemPromptService.instance) { throw new Error("SystemPromptService must be initialized first"); } return SystemPromptService.instance; } static cleanup() { SystemPromptService.instance = null; } async request(method, path, body, headers) { try { const url = `${this.baseUrl}${path}`; const response = await fetch(url, { method, headers: { "Content-Type": "application/json", "api-key": process.env.SYSTEMPROMPT_API_KEY, ...headers, }, body: body ? JSON.stringify(body) : undefined, }); const text = await response.text(); let data; try { data = text ? JSON.parse(text) : undefined; } catch (error) { throw new Error("Failed to parse API response"); } if (!response.ok) { switch (response.status) { case 403: throw new Error("Invalid API key"); case 404: throw new Error("Resource not found - it may have been deleted"); default: throw new Error(data?.message || "API request failed"); } } return data; } catch (error) { if (error instanceof Error) { throw error; } throw new Error("Failed to make API request"); } } async getAllPrompts() { return this.request("GET", "/prompts"); } async listBlocks(options = {}) { const params = new URLSearchParams(); if (options.tags?.length) { params.set("tag", options.tags.join(",")); } else { params.set("tag", "mcp_systemprompt_reddit"); } const queryString = params.toString(); const url = `/block${queryString ? `?${queryString}` : ""}`; // Add notification to log the full URL const fullUrl = `${this.baseUrl}${url}`; await sendJsonResultNotification(`Requesting SystemPrompt URL: ${fullUrl}`); // Add cache-busting headers to the request return this.request("GET", url, undefined, { "Cache-Control": "no-cache, no-store, must-revalidate", Pragma: "no-cache", Expires: "0", }); } async getBlock(blockId) { const response = await this.request("GET", `/block/${blockId}?t=${Date.now()}`); return response; } async fetchUserStatus() { return this.request("GET", "/user/me"); } async deletePrompt(id) { await this.request("DELETE", `/prompts/${id}`); } async getUser() { return this.request("GET", "/user/me"); } async createBlock(block) { return this.request("POST", "/block", block); } async updateBlock(id, block) { return this.request("PATCH", `/block/${id}`, block); } async upsertBlock(block) { try { // First try to find existing blocks with matching prefix and tag const existingBlocks = await this.listBlocks({ tags: block.metadata.tag, }); // Find the most recent block with matching prefix only const existingBlock = existingBlocks .filter((b) => b.prefix === block.prefix) .sort((a, b) => { const dateA = new Date(a.metadata.updated || a.metadata.created || ""); const dateB = new Date(b.metadata.updated || b.metadata.created || ""); return dateB.getTime() - dateA.getTime(); })[0]; if (existingBlock) { // Update existing block with new content but preserve the ID const updatedBlock = { ...block, id: existingBlock.id, metadata: { ...block.metadata, }, }; return await this.request("PATCH", `/block/${existingBlock.id}`, updatedBlock); } // If no existing block found, create new one const newBlock = { ...block, metadata: { ...block.metadata, }, }; return await this.request("POST", "/block", newBlock); } catch (error) { throw new Error(`Failed to upsert block: ${error instanceof Error ? error.message : "Unknown error"}`); } } async deleteBlock(id) { await this.request("DELETE", `/block/${id}`); } } SystemPromptService.instance = null; //# sourceMappingURL=systemprompt-service.js.map