Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion apps/mcp-server/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,12 @@ import { ToolRegistry } from "./registry/ToolRegistry.js";
import { LighthouseService } from "./services/LighthouseService.js";
import { ILighthouseService } from "./services/ILighthouseService.js";
import { MockDatasetService } from "./services/MockDatasetService.js";
import { LighthouseUploadFileTool, LighthouseFetchFileTool } from "./tools/index.js";
import {
LighthouseUploadFileTool,
LighthouseFetchFileTool,
LighthouseGenerateKeyTool,
LighthouseSetupAccessControlTool,
} from "./tools/index.js";
import {
ListToolsHandler,
CallToolHandler,
Expand Down Expand Up @@ -120,6 +125,11 @@ export class LighthouseMCPServer {
// Create tool instances with service dependencies
const uploadFileTool = new LighthouseUploadFileTool(this.lighthouseService, this.logger);
const fetchFileTool = new LighthouseFetchFileTool(this.lighthouseService, this.logger);
const generateKeyTool = new LighthouseGenerateKeyTool(this.lighthouseService, this.logger);
const setupAccessControlTool = new LighthouseSetupAccessControlTool(
this.lighthouseService,
this.logger,
);

// Register lighthouse_upload_file tool
this.registry.register(
Expand All @@ -133,6 +143,18 @@ export class LighthouseMCPServer {
async (args) => await fetchFileTool.execute(args),
);

// Register lighthouse_generate_key tool
this.registry.register(
LighthouseGenerateKeyTool.getDefinition(),
async (args) => await generateKeyTool.execute(args),
);

// Register lighthouse_setup_access_control tool
this.registry.register(
LighthouseSetupAccessControlTool.getDefinition(),
async (args) => await setupAccessControlTool.execute(args),
);

// Register lighthouse_create_dataset tool (keeping existing implementation)
const datasetTool = LIGHTHOUSE_MCP_TOOLS.find((t) => t.name === "lighthouse_create_dataset");
if (datasetTool) {
Expand Down
31 changes: 31 additions & 0 deletions apps/mcp-server/src/services/ILighthouseService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
*/

import { UploadResult, DownloadResult, AccessCondition } from "@lighthouse-tooling/types";
import { EnhancedAccessCondition } from "@lighthouse-tooling/sdk-wrapper";

export interface StoredFile {
cid: string;
Expand Down Expand Up @@ -75,4 +76,34 @@ export interface ILighthouseService {
* Clear cache (for testing)
*/
clear(): void;

/**
* Generate encryption key with threshold cryptography
*/
generateEncryptionKey?(
threshold?: number,
keyCount?: number,
): Promise<{
success: boolean;
data?: { masterKey: string; keyShards: Array<{ key: string; index: string }> };
error?: string;
}>;

/**
* Setup access control for encrypted files
*/
setupAccessControl?(
config: {
address: string;
cid: string;
conditions: EnhancedAccessCondition[];
aggregator?: string;
chainType?: "evm" | "solana";
keyShards?: Array<{ key: string; index: string }>;
},
authToken: string,
): Promise<{
success: boolean;
error?: string;
}>;
}
132 changes: 131 additions & 1 deletion apps/mcp-server/src/services/LighthouseService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Real Lighthouse Service - Uses the unified SDK wrapper for actual Lighthouse operations
*/

import { LighthouseAISDK } from "@lighthouse-tooling/sdk-wrapper";
import { LighthouseAISDK, EnhancedAccessCondition } from "@lighthouse-tooling/sdk-wrapper";
import { UploadResult, DownloadResult, AccessCondition } from "@lighthouse-tooling/types";
import { Logger } from "@lighthouse-tooling/shared";
import { ILighthouseService, StoredFile } from "./ILighthouseService.js";
Expand Down Expand Up @@ -355,6 +355,136 @@ export class LighthouseService implements ILighthouseService {
};
}

/**
* Generate encryption key with threshold cryptography
*/
async generateEncryptionKey(
threshold: number = 3,
keyCount: number = 5,
): Promise<{
success: boolean;
data?: { masterKey: string; keyShards: Array<{ key: string; index: string }> };
error?: string;
}> {
try {
this.logger.info("Generating encryption key", { threshold, keyCount });

// Check if encryption is available
if (!this.sdk.isEncryptionAvailable()) {
const error = "Encryption features not available - Kavach SDK not found";
this.logger.warn(error);
return {
success: false,
error,
};
}

const result = await this.sdk.generateEncryptionKey(threshold, keyCount);

this.logger.info("Encryption key generated successfully", {
keyShardCount: result.keyShards.length,
});

return {
success: true,
data: {
masterKey: result.masterKey || "",
keyShards: result.keyShards,
},
};
} catch (error) {
const errorMessage = error instanceof Error ? error.message : "Unknown error";
this.logger.error("Failed to generate encryption key", error as Error, {
threshold,
keyCount,
});

return {
success: false,
error: errorMessage,
};
}
}

/**
* Setup access control for encrypted files
*/
async setupAccessControl(
config: {
address: string;
cid: string;
conditions: EnhancedAccessCondition[];
aggregator?: string;
chainType?: "evm" | "solana";
keyShards?: Array<{ key: string; index: string }>;
},
authToken: string,
): Promise<{
success: boolean;
error?: string;
}> {
try {
this.logger.info("Setting up access control", {
address: config.address,
cid: config.cid,
conditionCount: config.conditions.length,
});

// Check if encryption is available
if (!this.sdk.isEncryptionAvailable()) {
const error = "Encryption features not available - Kavach SDK not found";
this.logger.warn(error);
return {
success: false,
error,
};
}

const result = await this.sdk.setupAccessControl(
{
address: config.address,
cid: config.cid,
conditions: config.conditions,
aggregator: config.aggregator,
chainType: config.chainType || "evm",
keyShards: config.keyShards,
},
authToken,
);

if (!result.isSuccess) {
this.logger.error(
"Access control setup failed",
new Error(result.error || "Unknown error"),
);
return {
success: false,
error: result.error || "Unknown error",
};
}

this.logger.info("Access control set up successfully", {
address: config.address,
cid: config.cid,
});

return {
success: true,
};
} catch (error) {
const errorMessage = error instanceof Error ? error.message : "Unknown error";
this.logger.error("Failed to setup access control", error as Error, {
address: config.address,
cid: config.cid,
});

return {
success: false,
error: errorMessage,
};
}
}

/**
* Clear cache (for testing)
*/
Expand Down
107 changes: 107 additions & 0 deletions apps/mcp-server/src/services/MockLighthouseService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
*/

import { UploadResult, DownloadResult, AccessCondition } from "@lighthouse-tooling/types";
import { EnhancedAccessCondition } from "@lighthouse-tooling/sdk-wrapper";
import { Logger, FileUtils } from "@lighthouse-tooling/shared";
import { CIDGenerator } from "../utils/cid-generator.js";
import { ILighthouseService, StoredFile } from "./ILighthouseService.js";
Expand Down Expand Up @@ -260,6 +261,112 @@ export class MockLighthouseService implements ILighthouseService {
};
}

/**
* Mock encryption key generation
*/
async generateEncryptionKey(
threshold: number = 3,
keyCount: number = 5,
): Promise<{
success: boolean;
data?: { masterKey: string; keyShards: Array<{ key: string; index: string }> };
error?: string;
}> {
try {
this.logger.info("Generating mock encryption key", { threshold, keyCount });

// Simulate key generation delay
await this.simulateDelay(100, 200);

// Generate mock key shards
const keyShards = Array.from({ length: keyCount }, (_, i) => ({
key: `mock-shard-${i + 1}-${Math.random().toString(36).slice(2, 10)}`,
index: `index-${i + 1}-${Math.random().toString(36).slice(2, 8)}`,
}));

const masterKey = `mock-master-key-${Math.random().toString(36).slice(2, 12)}`;

this.logger.info("Mock encryption key generated", { keyShardCount: keyShards.length });

return {
success: true,
data: {
masterKey,
keyShards,
},
};
} catch (error) {
this.logger.error("Mock key generation failed", error as Error);
return {
success: false,
error: error instanceof Error ? error.message : "Unknown error",
};
}
}

/**
* Mock access control setup
*/
async setupAccessControl(
config: {
address: string;
cid: string;
conditions: EnhancedAccessCondition[];
aggregator?: string;
chainType?: "evm" | "solana";
keyShards?: Array<{ key: string; index: string }>;
},
authToken: string,
): Promise<{
success: boolean;
error?: string;
}> {
try {
this.logger.info("Setting up mock access control", {
address: config.address,
cid: config.cid,
conditionCount: config.conditions.length,
});

// Simulate access control setup delay
await this.simulateDelay(150, 300);

// Check if file exists
const storedFile = this.fileStore.get(config.cid);
if (!storedFile) {
return {
success: false,
error: `File not found: ${config.cid}`,
};
}

// Update file with access conditions
// Convert enhanced conditions to basic AccessCondition format for storage
storedFile.accessConditions = config.conditions.map((condition: any) => ({
type: "smart_contract" as any,
condition: condition.method || "unknown",
value: condition.returnValueTest?.value?.toString() || "0",
parameters: { ...condition },
}));
storedFile.encrypted = true;

this.logger.info("Mock access control set up successfully", {
address: config.address,
cid: config.cid,
});

return {
success: true,
};
} catch (error) {
this.logger.error("Mock access control setup failed", error as Error);
return {
success: false,
error: error instanceof Error ? error.message : "Unknown error",
};
}
}

/**
* Clear all stored files (for testing)
*/
Expand Down
Loading
Loading