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
JavaScript
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