Skip to main content
Glama
api.ts11 kB
import { getApiKey, getBaseUrl } from "./config.js"; export class NexusAPIError extends Error { constructor( public status: number, message: string ) { super(message); this.name = "NexusAPIError"; } } export interface ApiResponse<T> { data?: T; error?: string; } async function request<T>( endpoint: string, options: RequestInit = {} ): Promise<T> { const apiKey = getApiKey(); if (!apiKey) { throw new NexusAPIError(401, "Not authenticated. Run: nexus-mcp login"); } const baseUrl = getBaseUrl(); const url = `${baseUrl}/api/mcp${endpoint}`; const response = await fetch(url, { ...options, headers: { "Content-Type": "application/json", Authorization: `Bearer ${apiKey}`, ...options.headers, }, }); if (!response.ok) { const error = await response.text(); throw new NexusAPIError(response.status, error || response.statusText); } return response.json(); } // ============================================================================ // Projects // ============================================================================ export interface Project { id: string; name: string; slug: string; description: string; url?: string; status: string; featureCompletion: number; productionReadiness: number; previewImage?: string; testCredentials?: Record<string, unknown>; createdAt: string; updatedAt: string; } export async function listProjects(params?: { status?: string; assignedTo?: string; limit?: number; }): Promise<Project[]> { const query = new URLSearchParams(); if (params?.status) query.set("status", params.status); if (params?.assignedTo) query.set("assignedTo", params.assignedTo); if (params?.limit) query.set("limit", params.limit.toString()); return request<Project[]>(`/projects?${query}`); } export async function getProject(idOrSlug: string): Promise<Project> { return request<Project>(`/projects/${idOrSlug}`); } export async function createProject(data: { name: string; description?: string; url?: string; templateId?: string; deadline?: string; screenshotBase64?: string; screenshotUrl?: string; status?: string; }): Promise<Project> { return request<Project>("/projects", { method: "POST", body: JSON.stringify(data), }); } export async function updateProject( idOrSlug: string, data: Partial<{ name: string; description: string; url: string; status: string; testCredentials: Record<string, unknown>; setupData: Record<string, unknown>; featureCompletion: number; productionReadiness: number; previewImage: string; }> ): Promise<Project> { return request<Project>(`/projects/${idOrSlug}`, { method: "PATCH", body: JSON.stringify(data), }); } export async function updateProjectStatus( idOrSlug: string, status: string ): Promise<Project> { return request<Project>(`/projects/${idOrSlug}/status`, { method: "POST", body: JSON.stringify({ status }), }); } // ============================================================================ // Bugs / Cards // ============================================================================ export interface Card { id: string; projectId: string; title: string; description?: string; type: "Task" | "Bug" | "Review" | "Doc"; status: string; priority?: string; labels: string[]; assigneeId?: string; createdById: string; createdAt: string; updatedAt: string; bug?: Bug; } export interface Bug { id: string; severity: string; steps: string; expected: string; actual: string; env?: string; screenshotUrl?: string; } export async function listBugs( projectIdOrSlug: string, params?: { status?: string; severity?: string; assignedToAI?: boolean; limit?: number; } ): Promise<Card[]> { const query = new URLSearchParams(); if (params?.status) query.set("status", params.status); if (params?.severity) query.set("severity", params.severity); if (params?.assignedToAI !== undefined) query.set("assignedToAI", params.assignedToAI.toString()); if (params?.limit) query.set("limit", params.limit.toString()); return request<Card[]>(`/projects/${projectIdOrSlug}/bugs?${query}`); } export async function createBug( projectIdOrSlug: string, data: { title: string; description: string; severity: "LOW" | "MEDIUM" | "HIGH" | "CRITICAL"; steps?: string; expected?: string; actual?: string; environment?: string; screenshotUrl?: string; priority?: "LOW" | "MEDIUM" | "HIGH" | "URGENT"; labels?: string[]; assigneeId?: string; } ): Promise<Card> { return request<Card>(`/projects/${projectIdOrSlug}/bugs`, { method: "POST", body: JSON.stringify(data), }); } export async function updateCard( cardId: string, data: Partial<{ title: string; description: string; status: string; priority: string; labels: string[]; assigneeId: string; }> ): Promise<Card> { return request<Card>(`/cards/${cardId}`, { method: "PATCH", body: JSON.stringify(data), }); } export async function addComment( cardId: string, data: { content: string; mentions?: string[]; } ): Promise<{ id: string; content: string; createdAt: string }> { return request(`/cards/${cardId}/comments`, { method: "POST", body: JSON.stringify(data), }); } // ============================================================================ // Templates // ============================================================================ export interface Template { id: string; name: string; slug: string; description?: string; kind: "UI" | "API" | "FULLSTACK"; githubRepo?: string; previewImage?: string; tags: string[]; } export async function listTemplates(params?: { kind?: string; tags?: string[]; }): Promise<Template[]> { const query = new URLSearchParams(); if (params?.kind) query.set("kind", params.kind); if (params?.tags) query.set("tags", params.tags.join(",")); return request<Template[]>(`/templates?${query}`); } export async function createTemplate(data: { name: string; slug: string; description?: string; kind: "UI" | "API" | "FULLSTACK"; githubRepoUrl?: string; previewImage?: string; tags?: string[]; promptsJson?: Record<string, unknown>; }): Promise<Template> { return request<Template>("/templates", { method: "POST", body: JSON.stringify(data), }); } // ============================================================================ // Milestones // ============================================================================ export interface MilestoneTask { id: string; title: string; completed: boolean; order: number; } export interface Milestone { id: string; title: string; description?: string; type: "GENERAL" | "ONBOARDING" | "LAUNCH" | "REVIEW" | "DEADLINE"; priority: "HIGH" | "MEDIUM" | "LOW"; date: string; completed: boolean; color?: string; tasks: MilestoneTask[]; projects: { id: string; name: string }[]; } export async function listMilestones(params?: { startDate?: string; endDate?: string; type?: string; completed?: boolean; }): Promise<Milestone[]> { const query = new URLSearchParams(); if (params?.startDate) query.set("startDate", params.startDate); if (params?.endDate) query.set("endDate", params.endDate); if (params?.type) query.set("type", params.type); if (params?.completed !== undefined) query.set("completed", params.completed.toString()); return request<Milestone[]>(`/milestones?${query}`); } export async function createMilestone(data: { title: string; date: string; description?: string; type?: string; priority?: string; color?: string; projectIds?: string[]; tasks?: { title: string; order?: number }[]; businessEntity?: string; paymentProvider?: string; }): Promise<Milestone> { return request<Milestone>("/milestones", { method: "POST", body: JSON.stringify(data), }); } export async function updateMilestone( id: string, data: Partial<{ title: string; description: string; date: string; completed: boolean; addProjects: string[]; removeProjects: string[]; }> ): Promise<Milestone> { return request<Milestone>(`/milestones/${id}`, { method: "PATCH", body: JSON.stringify(data), }); } export async function updateMilestoneTask( milestoneId: string, taskId: string, data: Partial<{ title: string; completed: boolean; }> ): Promise<MilestoneTask> { return request<MilestoneTask>(`/milestones/${milestoneId}/tasks/${taskId}`, { method: "PATCH", body: JSON.stringify(data), }); } // ============================================================================ // Concepts // ============================================================================ export interface Concept { id: string; name: string; slug: string; description: string; status: string; problemStatement?: string; solution?: string; businessModel?: string; targetAudience?: string; prdJson?: Record<string, unknown>; templateId?: string; projectId?: string; createdAt: string; } export async function listConcepts(params?: { status?: string; templateId?: string; }): Promise<Concept[]> { const query = new URLSearchParams(); if (params?.status) query.set("status", params.status); if (params?.templateId) query.set("templateId", params.templateId); return request<Concept[]>(`/concepts?${query}`); } export async function getConcept(idOrSlug: string): Promise<Concept> { return request<Concept>(`/concepts/${idOrSlug}`); } export async function createConcept(data: { name: string; description: string; problemStatement?: string; solution?: string; businessModel?: string; targetAudience?: string; templateId?: string; }): Promise<Concept> { return request<Concept>("/concepts", { method: "POST", body: JSON.stringify(data), }); } export async function updateConcept( id: string, data: Partial<{ name: string; description: string; status: string; problemStatement: string; solution: string; prdJson: Record<string, unknown>; }> ): Promise<Concept> { return request<Concept>(`/concepts/${id}`, { method: "PATCH", body: JSON.stringify(data), }); } export async function promoteConcept( id: string, data?: { projectName?: string } ): Promise<{ project: Project }> { return request(`/concepts/${id}/promote`, { method: "POST", body: JSON.stringify(data || {}), }); } // ============================================================================ // Auth // ============================================================================ export async function verifyApiKey(): Promise<{ valid: boolean; user?: { id: string; email: string; name: string }; org?: { id: string; name: string }; }> { return request("/auth/verify"); }

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/iamserge/nexus-mcp'

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