@insforge/mcp
Version: 
MCP (Model Context Protocol) server for Insforge backend-as-a-service
1,334 lines (1,316 loc) • 41 kB
JavaScript
#!/usr/bin/env node
// src/index.ts
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z as z12 } from "zod";
import fetch2 from "node-fetch";
import FormData from "form-data";
import { program } from "commander";
import { promises as fs } from "fs";
// src/response-handler.ts
async function handleApiResponse(response) {
  const responseData = await response.json();
  if (!response.ok) {
    const errorData = responseData;
    let fullMessage = errorData.message || errorData.error || "Unknown error";
    if (errorData.nextAction) {
      fullMessage += `. ${errorData.nextAction}`;
    }
    throw new Error(fullMessage);
  }
  return responseData;
}
function formatSuccessMessage(operation, data) {
  if (data && typeof data === "object" && "message" in data) {
    return `${data.message}
${JSON.stringify(data, null, 2)}`;
  }
  return `${operation} completed successfully:
${JSON.stringify(data, null, 2)}`;
}
// src/usage-tracker.ts
import fetch from "node-fetch";
var UsageTracker = class {
  apiBaseUrl;
  apiKey;
  constructor(apiBaseUrl, apiKey) {
    this.apiBaseUrl = apiBaseUrl;
    this.apiKey = apiKey;
  }
  async trackUsage(toolName, success = true) {
    if (!this.apiKey) {
      return;
    }
    try {
      const payload = {
        tool_name: toolName,
        success,
        timestamp: (/* @__PURE__ */ new Date()).toISOString()
      };
      await fetch(`${this.apiBaseUrl}/api/usage/mcp`, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "x-api-key": this.apiKey
        },
        body: JSON.stringify(payload)
      });
    } catch (error) {
      console.error("Failed to track usage:", error);
    }
  }
};
// node_modules/@insforge/shared-schemas/dist/database.schema.js
import { z } from "zod";
var ColumnType;
(function(ColumnType2) {
  ColumnType2["STRING"] = "string";
  ColumnType2["DATE"] = "date";
  ColumnType2["DATETIME"] = "datetime";
  ColumnType2["INTEGER"] = "integer";
  ColumnType2["FLOAT"] = "float";
  ColumnType2["BOOLEAN"] = "boolean";
  ColumnType2["UUID"] = "uuid";
  ColumnType2["JSON"] = "json";
})(ColumnType || (ColumnType = {}));
var onUpdateActionSchema = z.enum(["CASCADE", "RESTRICT", "NO ACTION"]);
var onDeleteActionSchema = z.enum([
  "CASCADE",
  "SET NULL",
  "SET DEFAULT",
  "RESTRICT",
  "NO ACTION"
]);
var columnTypeSchema = z.enum([
  ColumnType.STRING,
  ColumnType.DATE,
  ColumnType.DATETIME,
  ColumnType.INTEGER,
  ColumnType.FLOAT,
  ColumnType.BOOLEAN,
  ColumnType.UUID,
  ColumnType.JSON
]);
var foreignKeySchema = z.object({
  referenceTable: z.string().min(1, "Target table cannot be empty"),
  referenceColumn: z.string().min(1, "Target column cannot be empty"),
  onDelete: onDeleteActionSchema,
  onUpdate: onUpdateActionSchema
});
var columnSchema = z.object({
  columnName: z.string().min(1, "Column name cannot be empty").max(64, "Column name must be less than 64 characters"),
  type: z.union([columnTypeSchema, z.string()]),
  defaultValue: z.string().optional(),
  isPrimaryKey: z.boolean().optional(),
  isNullable: z.boolean(),
  isUnique: z.boolean(),
  foreignKey: foreignKeySchema.optional()
});
var tableSchema = z.object({
  tableName: z.string().min(1, "Table name cannot be empty").max(64, "Table name must be less than 64 characters"),
  columns: z.array(columnSchema).min(1, "At least one column is required"),
  recordCount: z.number().default(0),
  createdAt: z.string().optional(),
  updatedAt: z.string().optional()
});
// node_modules/@insforge/shared-schemas/dist/database-api.schema.js
import { z as z2 } from "zod";
var createTableRequestSchema = tableSchema.pick({
  tableName: true,
  columns: true
}).extend({
  rlsEnabled: z2.boolean().default(true)
});
var createTableResponseSchema = tableSchema.pick({
  tableName: true,
  columns: true
}).extend({
  message: z2.string(),
  autoFields: z2.array(z2.string()),
  nextActions: z2.string()
});
var updateTableSchemaRequestSchema = z2.object({
  addColumns: z2.array(columnSchema.omit({
    foreignKey: true
  })).optional(),
  dropColumns: z2.array(z2.string()).optional(),
  updateColumns: z2.array(z2.object({
    columnName: z2.string(),
    defaultValue: z2.string().optional(),
    newColumnName: z2.string().min(1, "New column name cannot be empty").max(64, "New column name must be less than 64 characters").optional()
  })).optional(),
  addForeignKeys: z2.array(z2.object({
    columnName: z2.string().min(1, "Column name is required for adding foreign key"),
    foreignKey: foreignKeySchema
  })).optional(),
  dropForeignKeys: z2.array(z2.string()).optional(),
  renameTable: z2.object({
    newTableName: z2.string().min(1, "New table name cannot be empty").max(64, "New table name must be less than 64 characters")
  }).optional()
});
var updateTableSchemaResponse = z2.object({
  message: z2.string(),
  tableName: z2.string(),
  operations: z2.array(z2.string())
});
var deleteTableResponse = z2.object({
  message: z2.string(),
  tableName: z2.string(),
  nextActions: z2.string()
});
var rawSQLRequestSchema = z2.object({
  query: z2.string().min(1, "Query is required"),
  params: z2.array(z2.any()).optional()
});
var rawSQLResponseSchema = z2.object({
  rows: z2.array(z2.any()),
  rowCount: z2.number().nullable(),
  fields: z2.array(z2.object({
    name: z2.string(),
    dataTypeID: z2.number()
  })).optional()
});
var exportRequestSchema = z2.object({
  tables: z2.array(z2.string()).optional(),
  format: z2.enum(["sql", "json"]).default("sql"),
  includeData: z2.boolean().default(true),
  includeFunctions: z2.boolean().default(false),
  includeSequences: z2.boolean().default(false),
  includeViews: z2.boolean().default(false),
  rowLimit: z2.number().int().positive().max(1e4).default(1e3)
});
var exportJsonDataSchema = z2.object({
  timestamp: z2.string(),
  tables: z2.record(z2.string(), z2.object({
    schema: z2.array(z2.object({
      columnName: z2.string(),
      dataType: z2.string(),
      characterMaximumLength: z2.number().nullable(),
      isNullable: z2.string(),
      columnDefault: z2.string().nullable()
    })),
    indexes: z2.array(z2.object({
      indexname: z2.string(),
      indexdef: z2.string(),
      isUnique: z2.boolean().nullable(),
      isPrimary: z2.boolean().nullable()
    })),
    foreignKeys: z2.array(z2.object({
      constraintName: z2.string(),
      columnName: z2.string(),
      foreignTableName: z2.string(),
      foreignColumnName: z2.string(),
      deleteRule: z2.string().nullable(),
      updateRule: z2.string().nullable()
    })),
    rlsEnabled: z2.boolean().optional(),
    policies: z2.array(z2.object({
      policyname: z2.string(),
      cmd: z2.string(),
      roles: z2.array(z2.string()),
      qual: z2.string().nullable(),
      withCheck: z2.string().nullable()
    })),
    triggers: z2.array(z2.object({
      triggerName: z2.string(),
      actionTiming: z2.string(),
      eventManipulation: z2.string(),
      actionOrientation: z2.string(),
      actionCondition: z2.string().nullable(),
      actionStatement: z2.string(),
      newTable: z2.string().nullable(),
      oldTable: z2.string().nullable()
    })),
    rows: z2.array(z2.any()).optional()
  })),
  functions: z2.array(z2.object({
    functionName: z2.string(),
    functionDef: z2.string(),
    kind: z2.string()
  })),
  sequences: z2.array(z2.object({
    sequenceName: z2.string(),
    startValue: z2.string(),
    increment: z2.string(),
    minValue: z2.string().nullable(),
    maxValue: z2.string().nullable(),
    cycle: z2.string()
  })),
  views: z2.array(z2.object({
    viewName: z2.string(),
    definition: z2.string()
  }))
});
var exportResponseSchema = z2.object({
  format: z2.enum(["sql", "json"]),
  data: z2.union([z2.string(), exportJsonDataSchema]),
  timestamp: z2.string()
});
var importRequestSchema = z2.object({
  truncate: z2.union([
    z2.boolean(),
    z2.string().transform((val) => {
      if (val === "true")
        return true;
      if (val === "false")
        return false;
      throw new Error("Invalid boolean string");
    })
  ]).default(false)
});
var importResponseSchema = z2.object({
  success: z2.boolean(),
  message: z2.string(),
  filename: z2.string(),
  tables: z2.array(z2.string()),
  rowsImported: z2.number(),
  fileSize: z2.number()
});
var bulkUpsertRequestSchema = z2.object({
  table: z2.string().min(1, "Table name is required"),
  upsertKey: z2.string().optional()
  // Note: File handling is done at the API layer via multipart/form-data
});
var bulkUpsertResponseSchema = z2.object({
  success: z2.boolean(),
  message: z2.string(),
  table: z2.string(),
  rowsAffected: z2.number(),
  totalRecords: z2.number(),
  filename: z2.string()
});
// node_modules/@insforge/shared-schemas/dist/storage.schema.js
import { z as z3 } from "zod";
var storageFileSchema = z3.object({
  key: z3.string(),
  bucket: z3.string(),
  size: z3.number(),
  mimeType: z3.string().optional(),
  uploadedAt: z3.string(),
  url: z3.string()
});
var storageBucketSchema = z3.object({
  name: z3.string(),
  public: z3.boolean(),
  createdAt: z3.string()
});
// node_modules/@insforge/shared-schemas/dist/storage-api.schema.js
import { z as z4 } from "zod";
var createBucketRequestSchema = z4.object({
  bucketName: z4.string().min(1, "Bucket name cannot be empty"),
  isPublic: z4.boolean().default(true)
});
var updateBucketRequestSchema = z4.object({
  isPublic: z4.boolean()
});
var listObjectsResponseSchema = z4.object({
  objects: z4.array(storageFileSchema),
  pagination: z4.object({
    offset: z4.number(),
    limit: z4.number(),
    total: z4.number()
  })
});
var uploadStrategyRequestSchema = z4.object({
  filename: z4.string().min(1, "Filename cannot be empty"),
  contentType: z4.string().optional(),
  size: z4.number().optional()
});
var uploadStrategyResponseSchema = z4.object({
  method: z4.enum(["presigned", "direct"]),
  uploadUrl: z4.string(),
  fields: z4.record(z4.string()).optional(),
  key: z4.string(),
  confirmRequired: z4.boolean(),
  confirmUrl: z4.string().optional(),
  expiresAt: z4.date().optional()
});
var downloadStrategyRequestSchema = z4.object({
  expiresIn: z4.number().optional().default(3600)
});
var downloadStrategyResponseSchema = z4.object({
  method: z4.enum(["presigned", "direct"]),
  url: z4.string(),
  expiresAt: z4.date().optional(),
  headers: z4.record(z4.string()).optional()
});
var confirmUploadRequestSchema = z4.object({
  size: z4.number(),
  contentType: z4.string().optional(),
  etag: z4.string().optional()
});
// node_modules/@insforge/shared-schemas/dist/auth.schema.js
import { z as z5 } from "zod";
var userIdSchema = z5.string().uuid("Invalid user ID format");
var emailSchema = z5.string().email("Invalid email format").toLowerCase().trim();
var passwordSchema = z5.string().min(6, "Password must be at least 6 characters").max(32, "Password must be less than 32 characters");
var nameSchema = z5.string().min(1, "Name is required").max(100, "Name must be less than 100 characters").trim();
var roleSchema = z5.enum(["authenticated", "project_admin"]);
var userSchema = z5.object({
  id: userIdSchema,
  email: emailSchema,
  name: nameSchema,
  emailVerified: z5.boolean(),
  identities: z5.array(z5.object({
    provider: z5.string()
  })).optional(),
  providerType: z5.string().optional(),
  createdAt: z5.string(),
  // PostgreSQL timestamp
  updatedAt: z5.string()
  // PostgreSQL timestamp
});
var oAuthProvidersSchema = z5.enum(["google", "github"]);
var oAuthStateSchema = z5.object({
  provider: oAuthProvidersSchema,
  redirectUri: z5.string().url().optional()
});
var oAuthConfigSchema = z5.object({
  provider: z5.string(),
  clientId: z5.string().optional(),
  scopes: z5.array(z5.string()).optional(),
  redirectUri: z5.string().optional(),
  useSharedKey: z5.boolean()
});
var tokenPayloadSchema = z5.object({
  sub: userIdSchema,
  // Subject (user ID)
  email: emailSchema,
  role: roleSchema,
  iat: z5.number().optional(),
  // Issued at
  exp: z5.number().optional()
  // Expiration
});
// node_modules/@insforge/shared-schemas/dist/auth-api.schema.js
import { z as z6 } from "zod";
var paginationSchema = z6.object({
  limit: z6.string().optional(),
  offset: z6.string().optional()
});
var createUserRequestSchema = z6.object({
  email: emailSchema,
  password: passwordSchema,
  name: nameSchema.optional()
});
var createSessionRequestSchema = z6.object({
  email: emailSchema,
  password: passwordSchema
});
var exchangeAdminSessionRequestSchema = z6.object({
  code: z6.string()
});
var listUsersRequestSchema = paginationSchema.extend({
  search: z6.string().optional()
}).optional();
var deleteUsersRequestSchema = z6.object({
  userIds: z6.array(userIdSchema).min(1, "At least one user ID is required")
});
var createUserResponseSchema = z6.object({
  user: userSchema,
  accessToken: z6.string()
});
var getCurrentSessionResponseSchema = z6.object({
  user: z6.object({
    id: userIdSchema,
    email: emailSchema,
    role: roleSchema
  })
});
var listUsersResponseSchema = z6.object({
  data: z6.array(userSchema),
  pagination: z6.object({
    offset: z6.number(),
    limit: z6.number(),
    total: z6.number()
  })
});
var deleteUsersResponseSchema = z6.object({
  message: z6.string(),
  deletedCount: z6.number().int().nonnegative()
});
var getOauthUrlResponseSchema = z6.object({
  authUrl: z6.string().url()
});
var createOAuthConfigRequestSchema = oAuthConfigSchema.extend({
  clientSecret: z6.string().optional()
});
var updateOAuthConfigRequestSchema = oAuthConfigSchema.extend({
  clientSecret: z6.string().optional()
}).omit({
  provider: true
});
var listOAuthConfigsResponseSchema = z6.object({
  data: z6.array(oAuthConfigSchema),
  count: z6.number()
});
var authErrorResponseSchema = z6.object({
  error: z6.string(),
  message: z6.string(),
  statusCode: z6.number().int(),
  nextActions: z6.string().optional()
});
// node_modules/@insforge/shared-schemas/dist/metadata.schema.js
import { z as z7 } from "zod";
var authMetadataSchema = z7.object({
  oauths: z7.array(oAuthConfigSchema)
});
var databaseMetadataSchema = z7.object({
  tables: z7.array(tableSchema),
  totalSize: z7.number()
});
var bucketMetadataSchema = storageBucketSchema.extend({
  objectCount: z7.number().optional()
});
var storageMetadataSchema = z7.object({
  buckets: z7.array(bucketMetadataSchema),
  totalSize: z7.number()
});
var edgeFunctionMetadataSchema = z7.object({
  slug: z7.string(),
  name: z7.string(),
  description: z7.string().nullable(),
  status: z7.string()
});
var aiMetadataSchema = z7.object({
  models: z7.array(z7.object({
    inputModality: z7.array(z7.string()),
    outputModality: z7.array(z7.string()),
    modelId: z7.string()
  }))
});
var appMetaDataSchema = z7.object({
  auth: authMetadataSchema,
  database: databaseMetadataSchema,
  storage: storageMetadataSchema,
  aiIntegration: aiMetadataSchema.optional(),
  functions: z7.array(edgeFunctionMetadataSchema),
  version: z7.string().optional()
});
// node_modules/@insforge/shared-schemas/dist/ai.schema.js
import { z as z8 } from "zod";
var modalitySchema = z8.enum(["text", "image"]);
var aiConfigurationSchema = z8.object({
  id: z8.string().uuid(),
  inputModality: z8.array(modalitySchema).min(1),
  outputModality: z8.array(modalitySchema).min(1),
  provider: z8.string(),
  modelId: z8.string(),
  systemPrompt: z8.string().optional()
});
var aiConfigurationWithUsageSchema = aiConfigurationSchema.extend({
  usageStats: z8.object({
    totalInputTokens: z8.number(),
    totalOutputTokens: z8.number(),
    totalTokens: z8.number(),
    totalImageCount: z8.number(),
    totalRequests: z8.number()
  }).optional()
});
var aiUsageDataSchema = z8.object({
  configId: z8.string().uuid(),
  inputTokens: z8.number().int().optional(),
  outputTokens: z8.number().int().optional(),
  imageCount: z8.number().int().optional(),
  imageResolution: z8.string().optional()
});
var aiUsageRecordSchema = aiUsageDataSchema.extend({
  id: z8.string().uuid(),
  createdAt: z8.date()
});
var aiUsageSummarySchema = z8.object({
  totalInputTokens: z8.number(),
  totalOutputTokens: z8.number(),
  totalTokens: z8.number(),
  totalImageCount: z8.number(),
  totalRequests: z8.number()
});
// node_modules/@insforge/shared-schemas/dist/ai-api.schema.js
import { z as z9 } from "zod";
var chatMessageSchema = z9.object({
  role: z9.enum(["user", "assistant", "system"]),
  content: z9.string(),
  images: z9.array(z9.object({
    url: z9.string()
  })).optional()
});
var chatCompletionRequestSchema = z9.object({
  model: z9.string(),
  messages: z9.array(chatMessageSchema),
  temperature: z9.number().min(0).max(2).optional(),
  maxTokens: z9.number().positive().optional(),
  topP: z9.number().min(0).max(1).optional(),
  stream: z9.boolean().optional()
});
var chatCompletionResponseSchema = z9.object({
  text: z9.string(),
  metadata: z9.object({
    model: z9.string(),
    usage: z9.object({
      promptTokens: z9.number().optional(),
      completionTokens: z9.number().optional(),
      totalTokens: z9.number().optional()
    }).optional()
  }).optional()
});
var imageGenerationRequestSchema = z9.object({
  model: z9.string(),
  prompt: z9.string(),
  images: z9.array(z9.object({
    url: z9.string()
  })).optional()
});
var imageGenerationResponseSchema = z9.object({
  text: z9.string().optional(),
  images: z9.array(z9.object({
    type: z9.literal("imageUrl"),
    imageUrl: z9.string()
  })),
  metadata: z9.object({
    model: z9.string(),
    usage: z9.object({
      promptTokens: z9.number().optional(),
      completionTokens: z9.number().optional(),
      totalTokens: z9.number().optional()
    }).optional()
  }).optional()
});
var openRouterModelSchema = z9.object({
  id: z9.string(),
  name: z9.string(),
  created: z9.number(),
  description: z9.string().optional(),
  architecture: z9.object({
    inputModalities: z9.array(z9.string()),
    outputModalities: z9.array(z9.string()),
    tokenizer: z9.string(),
    instructType: z9.string()
  }).optional(),
  topProvider: z9.object({
    isModerated: z9.boolean(),
    contextLength: z9.number(),
    maxCompletionTokens: z9.number()
  }).optional(),
  pricing: z9.object({
    prompt: z9.string(),
    completion: z9.string(),
    image: z9.string().optional(),
    request: z9.string().optional(),
    webSearch: z9.string().optional(),
    internalReasoning: z9.string().optional(),
    inputCacheRead: z9.string().optional(),
    inputCacheWrite: z9.string().optional()
  })
});
var listModelsResponseSchema = z9.object({
  text: z9.array(z9.object({
    provider: z9.string(),
    configured: z9.boolean(),
    models: z9.array(openRouterModelSchema)
  })),
  image: z9.array(z9.object({
    provider: z9.string(),
    configured: z9.boolean(),
    models: z9.array(openRouterModelSchema)
  }))
});
var createAIConfigurationRequestSchema = aiConfigurationSchema.omit({
  id: true
});
var updateAIConfigurationRequestSchema = z9.object({
  systemPrompt: z9.string().nullable()
});
var listAIUsageResponseSchema = z9.object({
  records: z9.array(aiUsageRecordSchema),
  total: z9.number()
});
var getAIUsageRequestSchema = z9.object({
  startDate: z9.string().datetime().optional(),
  endDate: z9.string().datetime().optional(),
  limit: z9.string().regex(/^\d+$/).default("50"),
  offset: z9.string().regex(/^\d+$/).default("0")
});
var getAIUsageSummaryRequestSchema = z9.object({
  configId: z9.string().uuid().optional(),
  startDate: z9.string().datetime().optional(),
  endDate: z9.string().datetime().optional()
});
// node_modules/@insforge/shared-schemas/dist/logs.schema.js
import { z as z10 } from "zod";
var auditLogSchema = z10.object({
  id: z10.string(),
  actor: z10.string(),
  action: z10.string(),
  module: z10.string(),
  details: z10.record(z10.unknown()).nullable(),
  ipAddress: z10.string().nullable(),
  createdAt: z10.string(),
  updatedAt: z10.string()
});
// node_modules/@insforge/shared-schemas/dist/logs-api.schema.js
import { z as z11 } from "zod";
var getAuditLogsRequestSchema = z11.object({
  limit: z11.number().default(100),
  offset: z11.number().default(0),
  actor: z11.string().optional(),
  action: z11.string().optional(),
  module: z11.string().optional(),
  startDate: z11.string().optional(),
  endDate: z11.string().optional()
});
var getAuditLogsResponseSchema = z11.object({
  data: z11.array(auditLogSchema),
  pagination: z11.object({
    limit: z11.number(),
    offset: z11.number(),
    total: z11.number()
  })
});
var getAuditLogStatsRequestSchema = z11.object({
  days: z11.number().default(7)
});
var getAuditLogStatsResponseSchema = z11.object({
  totalLogs: z11.number(),
  uniqueActors: z11.number(),
  uniqueModules: z11.number(),
  actionsByModule: z11.record(z11.number()),
  recentActivity: z11.array(auditLogSchema)
});
var clearAuditLogsRequestSchema = z11.object({
  daysToKeep: z11.number().default(90)
});
var clearAuditLogsResponseSchema = z11.object({
  message: z11.string(),
  deleted: z11.number()
});
// src/index.ts
program.option("--api_key <value>", "API Key");
program.parse(process.argv);
var options = program.opts();
var { api_key } = options;
var GLOBAL_API_KEY = api_key || process.env.API_KEY || "";
var server = new McpServer({
  name: "insforge-mcp",
  version: "1.0.0"
});
var API_BASE_URL = process.env.API_BASE_URL || "http://localhost:7130";
var usageTracker = new UsageTracker(API_BASE_URL, GLOBAL_API_KEY);
async function trackToolUsage(toolName, success = true) {
  if (GLOBAL_API_KEY) {
    await usageTracker.trackUsage(toolName, success);
  }
}
function withUsageTracking(toolName, handler) {
  return async (...args) => {
    try {
      const result = await handler(...args);
      await trackToolUsage(toolName, true);
      return result;
    } catch (error) {
      await trackToolUsage(toolName, false);
      throw error;
    }
  };
}
var getApiKey = (toolApiKey) => {
  if (GLOBAL_API_KEY) {
    return GLOBAL_API_KEY;
  }
  if (toolApiKey) {
    return toolApiKey;
  }
  throw new Error(
    "API key is required. Either pass --api_key as command line argument or provide api_key in tool calls."
  );
};
var fetchDocumentation = async (docType) => {
  try {
    const response = await fetch2(`${API_BASE_URL}/api/docs/${docType}`, {
      method: "GET",
      headers: {
        "Content-Type": "application/json"
      }
    });
    const result = await handleApiResponse(response);
    if (result && typeof result === "object" && "content" in result) {
      let content = result.content;
      content = content.replace(/http:\/\/localhost:7130/g, API_BASE_URL);
      return content;
    }
    throw new Error("Invalid response format from documentation endpoint");
  } catch (error) {
    const errMsg = error instanceof Error ? error.message : "Unknown error occurred";
    throw new Error(`Unable to retrieve ${docType} documentation: ${errMsg}`);
  }
};
var fetchInsforgeInstructionsContext = async () => {
  try {
    return await fetchDocumentation("instructions");
  } catch (error) {
    console.error("Failed to fetch insforge-instructions.md:", error);
    return null;
  }
};
var addBackgroundContext = async (response) => {
  const context = await fetchInsforgeInstructionsContext();
  if (context && response.content && Array.isArray(response.content)) {
    response.content.push({
      type: "text",
      text: `
---
\u{1F527} INSFORGE DEVELOPMENT RULES (Auto-loaded):
${context}`
    });
  }
  return response;
};
server.tool(
  "get-instructions",
  "Instruction Essential backend setup tool. <critical>MANDATORY: You MUST use this tool FIRST before attempting any backend operations. Contains required API endpoints, authentication details, and setup instructions.</critical>",
  {},
  withUsageTracking("get-instructions", async () => {
    try {
      const content = await fetchDocumentation("instructions");
      const response = {
        content: [
          {
            type: "text",
            text: content
          }
        ]
      };
      return await addBackgroundContext(response);
    } catch (error) {
      const errMsg = error instanceof Error ? error.message : "Unknown error occurred";
      const errorResponse = {
        content: [{ type: "text", text: `Error: ${errMsg}` }]
      };
      return await addBackgroundContext(errorResponse);
    }
  })
);
server.tool(
  "get-api-key",
  "Retrieves the API key for the Insforge OSS backend. This is used to authenticate all requests to the backend.",
  {},
  async () => {
    try {
      return await addBackgroundContext({
        content: [{ type: "text", text: `API key: ${getApiKey()}` }]
      });
    } catch (error) {
      const errMsg = error instanceof Error ? error.message : "Unknown error occurred";
      return await addBackgroundContext({
        content: [{ type: "text", text: `Error: ${errMsg}` }]
      });
    }
  }
);
server.tool(
  "get-table-schema",
  "Returns the schema of a specific table",
  {
    apiKey: z12.string().optional().describe("API key for authentication (optional if provided via --api_key)"),
    tableName: z12.string().describe("Name of the table")
  },
  withUsageTracking("get-table-schema", async ({ apiKey, tableName }) => {
    try {
      const actualApiKey = getApiKey(apiKey);
      const response = await fetch2(`${API_BASE_URL}/api/metadata/${tableName}`, {
        method: "GET",
        headers: {
          "x-api-key": actualApiKey
        }
      });
      const result = await handleApiResponse(response);
      return await addBackgroundContext({
        content: [
          {
            type: "text",
            text: formatSuccessMessage("Schema retrieved", result)
          }
        ]
      });
    } catch (error) {
      const errMsg = error instanceof Error ? error.message : "Unknown error occurred";
      return await addBackgroundContext({
        content: [
          {
            type: "text",
            text: `Error getting table schema: ${errMsg}`
          }
        ],
        isError: true
      });
    }
  })
);
server.tool(
  "get-backend-metadata",
  "Index all backend metadata",
  {
    apiKey: z12.string().optional().describe("API key for authentication (optional if provided via --api_key)")
  },
  withUsageTracking("get-backend-metadata", async ({ apiKey }) => {
    try {
      const actualApiKey = getApiKey(apiKey);
      const response = await fetch2(`${API_BASE_URL}/api/metadata?mcp=true`, {
        method: "GET",
        headers: {
          "x-api-key": actualApiKey
        }
      });
      const metadata = await handleApiResponse(response);
      return await addBackgroundContext({
        content: [
          {
            type: "text",
            text: `Backend metadata:
${JSON.stringify(metadata, null, 2)}`
          }
        ]
      });
    } catch (error) {
      const errMsg = error instanceof Error ? error.message : "Unknown error occurred";
      return await addBackgroundContext({
        content: [
          {
            type: "text",
            text: `Error retrieving backend metadata: ${errMsg}`
          }
        ],
        isError: true
      });
    }
  })
);
server.tool(
  "run-raw-sql",
  "Execute raw SQL query with optional parameters. Admin access required. Use with caution as it can modify data directly.",
  {
    apiKey: z12.string().optional().describe("API key for authentication (optional if provided via --api_key)"),
    ...rawSQLRequestSchema.shape
  },
  withUsageTracking("run-raw-sql", async ({ apiKey, query, params }) => {
    try {
      const actualApiKey = getApiKey(apiKey);
      const requestBody = {
        query,
        params: params || []
      };
      const response = await fetch2(`${API_BASE_URL}/api/database/advance/rawsql`, {
        method: "POST",
        headers: {
          "x-api-key": actualApiKey,
          "Content-Type": "application/json"
        },
        body: JSON.stringify(requestBody)
      });
      const result = await handleApiResponse(response);
      return await addBackgroundContext({
        content: [
          {
            type: "text",
            text: formatSuccessMessage("SQL query executed", result)
          }
        ]
      });
    } catch (error) {
      const errMsg = error instanceof Error ? error.message : "Unknown error occurred";
      return await addBackgroundContext({
        content: [
          {
            type: "text",
            text: `Error executing SQL query: ${errMsg}`
          }
        ],
        isError: true
      });
    }
  })
);
server.tool(
  "bulk-upsert",
  "Bulk insert or update data from CSV or JSON file. Supports upsert operations with a unique key.",
  {
    apiKey: z12.string().optional().describe("API key for authentication (optional if provided via --api_key)"),
    ...bulkUpsertRequestSchema.shape,
    filePath: z12.string().describe("Path to CSV or JSON file containing data to import")
  },
  withUsageTracking("bulk-upsert", async ({ apiKey, table, filePath, upsertKey }) => {
    try {
      const actualApiKey = getApiKey(apiKey);
      const fileBuffer = await fs.readFile(filePath);
      const fileName = filePath.split("/").pop() || "data.csv";
      const formData = new FormData();
      formData.append("file", fileBuffer, fileName);
      formData.append("table", table);
      if (upsertKey) {
        formData.append("upsertKey", upsertKey);
      }
      const response = await fetch2(`${API_BASE_URL}/api/database/advance/bulk-upsert`, {
        method: "POST",
        headers: {
          "x-api-key": actualApiKey,
          ...formData.getHeaders()
        },
        body: formData
      });
      const result = await handleApiResponse(response);
      const message = result.success ? `Successfully processed ${result.rowsAffected} of ${result.totalRecords} records into table "${result.table}"` : result.message || "Bulk upsert operation completed";
      return await addBackgroundContext({
        content: [
          {
            type: "text",
            text: formatSuccessMessage("Bulk upsert completed", {
              message,
              table: result.table,
              rowsAffected: result.rowsAffected,
              totalRecords: result.totalRecords,
              errors: result.errors
            })
          }
        ]
      });
    } catch (error) {
      const errMsg = error instanceof Error ? error.message : "Unknown error occurred";
      return await addBackgroundContext({
        content: [
          {
            type: "text",
            text: `Error performing bulk upsert: ${errMsg}`
          }
        ],
        isError: true
      });
    }
  })
);
server.tool(
  "create-bucket",
  "Create new storage bucket",
  {
    apiKey: z12.string().optional().describe("API key for authentication (optional if provided via --api_key)"),
    ...createBucketRequestSchema.shape
  },
  withUsageTracking("create-bucket", async ({ apiKey, bucketName, isPublic }) => {
    try {
      const actualApiKey = getApiKey(apiKey);
      const response = await fetch2(`${API_BASE_URL}/api/storage/buckets`, {
        method: "POST",
        headers: {
          "x-api-key": actualApiKey,
          "Content-Type": "application/json"
        },
        body: JSON.stringify({ bucketName, isPublic })
      });
      const result = await handleApiResponse(response);
      return await addBackgroundContext({
        content: [
          {
            type: "text",
            text: formatSuccessMessage("Bucket created", result)
          }
        ]
      });
    } catch (error) {
      const errMsg = error instanceof Error ? error.message : "Unknown error occurred";
      return await addBackgroundContext({
        content: [
          {
            type: "text",
            text: `Error creating bucket: ${errMsg}`
          }
        ],
        isError: true
      });
    }
  })
);
server.tool(
  "list-buckets",
  "Lists all storage buckets",
  {},
  withUsageTracking("list-buckets", async () => {
    try {
      const response = await fetch2(`${API_BASE_URL}/api/storage/buckets`, {
        method: "GET",
        headers: {
          "x-api-key": getApiKey()
          // Still need API key for protected endpoint
        }
      });
      const result = await handleApiResponse(response);
      return await addBackgroundContext({
        content: [
          {
            type: "text",
            text: formatSuccessMessage("Buckets retrieved", result)
          }
        ]
      });
    } catch (error) {
      const errMsg = error instanceof Error ? error.message : "Unknown error occurred";
      return await addBackgroundContext({
        content: [
          {
            type: "text",
            text: `Error listing buckets: ${errMsg}`
          }
        ],
        isError: true
      });
    }
  })
);
server.tool(
  "delete-bucket",
  "Deletes a storage bucket",
  {
    apiKey: z12.string().optional().describe("API key for authentication (optional if provided via --api_key)"),
    bucketName: z12.string().describe("Name of the bucket to delete")
  },
  withUsageTracking("delete-bucket", async ({ apiKey, bucketName }) => {
    try {
      const actualApiKey = getApiKey(apiKey);
      const response = await fetch2(`${API_BASE_URL}/api/storage/buckets/${bucketName}`, {
        method: "DELETE",
        headers: {
          "x-api-key": actualApiKey
        }
      });
      const result = await handleApiResponse(response);
      return await addBackgroundContext({
        content: [
          {
            type: "text",
            text: formatSuccessMessage("Bucket deleted", result)
          }
        ]
      });
    } catch (error) {
      const errMsg = error instanceof Error ? error.message : "Unknown error occurred";
      return await addBackgroundContext({
        content: [
          {
            type: "text",
            text: `Error deleting bucket: ${errMsg}`
          }
        ],
        isError: true
      });
    }
  })
);
server.tool(
  "create-function",
  "Create a new edge function that runs in Deno runtime. The code must be written to a file first for version control",
  {
    slug: z12.string().regex(/^[a-zA-Z0-9_-]+$/, "Slug must be alphanumeric with hyphens or underscores only").describe(
      'URL-friendly identifier (alphanumeric, hyphens, underscores only). Example: "my-calculator"'
    ),
    name: z12.string().describe('Function display name. Example: "Calculator Function"'),
    codeFile: z12.string().describe(
      "Path to JavaScript file containing the function code. Must export: module.exports = async function(request) { return new Response(...) }"
    ),
    description: z12.string().optional().describe("Description of what the function does"),
    active: z12.boolean().optional().describe("Set to true to deploy immediately, false for draft mode")
  },
  withUsageTracking("create-function", async (args) => {
    try {
      let code;
      try {
        code = await fs.readFile(args.codeFile, "utf-8");
      } catch (fileError) {
        throw new Error(
          `Failed to read code file '${args.codeFile}': ${fileError instanceof Error ? fileError.message : "Unknown error"}`
        );
      }
      const response = await fetch2(`${API_BASE_URL}/api/functions`, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "x-api-key": getApiKey()
        },
        body: JSON.stringify({
          slug: args.slug,
          name: args.name,
          code,
          description: args.description || "",
          status: args.active ? "active" : "draft"
        })
      });
      const result = await handleApiResponse(response);
      return await addBackgroundContext({
        content: [
          {
            type: "text",
            text: formatSuccessMessage(
              `Edge function '${args.slug}' created successfully from ${args.codeFile}`,
              result
            )
          }
        ]
      });
    } catch (error) {
      const errMsg = error instanceof Error ? error.message : "Unknown error occurred";
      return await addBackgroundContext({
        content: [
          {
            type: "text",
            text: `Error creating function: ${errMsg}`
          }
        ],
        isError: true
      });
    }
  })
);
server.tool(
  "get-function",
  "Get details of a specific edge function including its code",
  {
    slug: z12.string().describe("The slug identifier of the function")
  },
  withUsageTracking("get-function", async (args) => {
    try {
      const response = await fetch2(`${API_BASE_URL}/api/functions/${args.slug}`, {
        method: "GET",
        headers: {
          "x-api-key": getApiKey()
        }
      });
      const result = await handleApiResponse(response);
      return await addBackgroundContext({
        content: [
          {
            type: "text",
            text: formatSuccessMessage(`Edge function '${args.slug}' details`, result)
          }
        ]
      });
    } catch (error) {
      const errMsg = error instanceof Error ? error.message : "Unknown error occurred";
      return await addBackgroundContext({
        content: [
          {
            type: "text",
            text: `Error getting function: ${errMsg}`
          }
        ],
        isError: true
      });
    }
  })
);
server.tool(
  "update-function",
  "Update an existing edge function code or metadata",
  {
    slug: z12.string().describe("The slug identifier of the function to update"),
    name: z12.string().optional().describe("New display name"),
    codeFile: z12.string().optional().describe(
      "Path to JavaScript file containing the new function code. Must export: module.exports = async function(request) { return new Response(...) }"
    ),
    description: z12.string().optional().describe("New description"),
    status: z12.string().optional().describe('Function status: "draft" (not deployed), "active" (deployed), or "error"')
  },
  withUsageTracking("update-function", async (args) => {
    try {
      const updateData = {};
      if (args.name) {
        updateData.name = args.name;
      }
      if (args.codeFile) {
        try {
          updateData.code = await fs.readFile(args.codeFile, "utf-8");
        } catch (fileError) {
          throw new Error(
            `Failed to read code file '${args.codeFile}': ${fileError instanceof Error ? fileError.message : "Unknown error"}`
          );
        }
      }
      if (args.description !== void 0) {
        updateData.description = args.description;
      }
      if (args.status) {
        updateData.status = args.status;
      }
      const response = await fetch2(`${API_BASE_URL}/api/functions/${args.slug}`, {
        method: "PUT",
        headers: {
          "Content-Type": "application/json",
          "x-api-key": getApiKey()
        },
        body: JSON.stringify(updateData)
      });
      const result = await handleApiResponse(response);
      const fileInfo = args.codeFile ? ` from ${args.codeFile}` : "";
      return await addBackgroundContext({
        content: [
          {
            type: "text",
            text: formatSuccessMessage(
              `Edge function '${args.slug}' updated successfully${fileInfo}`,
              result
            )
          }
        ]
      });
    } catch (error) {
      const errMsg = error instanceof Error ? error.message : "Unknown error occurred";
      return await addBackgroundContext({
        content: [
          {
            type: "text",
            text: `Error updating function: ${errMsg}`
          }
        ],
        isError: true
      });
    }
  })
);
server.tool(
  "delete-function",
  "Delete an edge function permanently",
  {
    slug: z12.string().describe("The slug identifier of the function to delete")
  },
  withUsageTracking("delete-function", async (args) => {
    try {
      const response = await fetch2(`${API_BASE_URL}/api/functions/${args.slug}`, {
        method: "DELETE",
        headers: {
          "x-api-key": getApiKey()
        }
      });
      const result = await handleApiResponse(response);
      return await addBackgroundContext({
        content: [
          {
            type: "text",
            text: formatSuccessMessage(`Edge function '${args.slug}' deleted successfully`, result)
          }
        ]
      });
    } catch (error) {
      const errMsg = error instanceof Error ? error.message : "Unknown error occurred";
      return await addBackgroundContext({
        content: [
          {
            type: "text",
            text: `Error deleting function: ${errMsg}`
          }
        ],
        isError: true
      });
    }
  })
);
async function main() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
  console.error("Insforge MCP server started");
}
main().catch(console.error);