Skip to main content
Glama
stampchain-io

Stampchain MCP Server

Official

analyze_stamp_code

Evaluate recursive stamp code structure, dependencies, and patterns, including JavaScript parsing, security checks, and performance analysis, with configurable depth and content inclusion.

Instructions

Analyze the code structure and dependencies of a recursive stamp, including JavaScript parsing, dependency resolution, and pattern detection

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
include_dependenciesNoWhether to analyze referenced stamps
include_performance_analysisNoWhether to include performance analysis
include_raw_contentNoWhether to include raw stamp content in response
include_security_analysisNoWhether to include security analysis
max_depthNoMaximum depth for dependency analysis
stamp_idYesThe ID or CPID of the stamp to analyze

Implementation Reference

  • AnalyzeStampCodeTool class: the primary handler class extending BaseTool with name 'analyze_stamp_code'. Contains the execute() method (lines 100-134) that orchestrates stamp resolution, analysis, and response formatting. Includes private methods for stamp resolution (139-196), analysis (201-301), dependency resolution (306-348), and response formatting (353-466).
    export class AnalyzeStampCodeTool extends BaseTool< z.input<typeof AnalyzeStampCodeParamsSchema>, AnalyzeStampCodeParams > { public readonly name = 'analyze_stamp_code'; public readonly description = 'Analyze the code structure and dependencies of a recursive stamp, including JavaScript parsing, dependency resolution, and pattern detection'; public readonly inputSchema: MCPTool['inputSchema'] = { type: 'object', properties: { stamp_id: { type: ['number', 'string'], description: 'The ID or CPID of the stamp to analyze', }, include_dependencies: { type: 'boolean', description: 'Whether to analyze referenced stamps', default: true, }, max_depth: { type: 'number', description: 'Maximum depth for dependency analysis', default: 3, minimum: 1, maximum: 10, }, include_raw_content: { type: 'boolean', description: 'Whether to include raw stamp content in response', default: false, }, include_security_analysis: { type: 'boolean', description: 'Whether to include security analysis', default: true, }, include_performance_analysis: { type: 'boolean', description: 'Whether to include performance analysis', default: true, }, }, required: ['stamp_id'], }; public readonly schema = AnalyzeStampCodeParamsSchema; public readonly metadata = { version: '1.0.0', tags: ['stamps', 'analysis', 'recursive', 'dependencies'], requiresNetwork: true, apiDependencies: ['stampchain'], }; private apiClient: StampchainClient; private parser: RecursiveStampParser; constructor(apiClient?: StampchainClient) { super(); this.apiClient = apiClient || new StampchainClient(); this.parser = new RecursiveStampParser(); } public async execute( params: AnalyzeStampCodeParams, context?: ToolContext ): Promise<ToolResponse> { try { context?.logger?.info('Executing analyze_stamp_code tool', { params }); // Validate parameters const validatedParams = this.validateParams(params); // Resolve stamp ID from CPID if needed const stamp = await this.resolveStamp(validatedParams.stamp_id, context); // Analyze the stamp const analysis = await this.analyzeStamp(stamp, validatedParams, context); // Format response const formattedResponse = this.formatAnalysisResponse(analysis, validatedParams); return multiResponse( { type: 'text', text: formattedResponse }, { type: 'text', text: `\nDetailed Analysis:\n${JSON.stringify(analysis, null, 2)}` } ); } catch (error) { // Handle Zod validation errors with new standardized pattern if (error instanceof z.ZodError) { const result = handleValidationError(error, this.name, params, context); return result.response; } // Handle all other errors with standardized pattern const result = handleMCPError(error, this.name, 'stamp_analysis', params, context); return result.response; } } /** * Resolve stamp by ID or CPID */ private async resolveStamp(stampId: string | number, context?: ToolContext): Promise<Stamp> { try { // If it's a number, use it directly if (typeof stampId === 'number') { return await this.apiClient.getStamp(stampId); } // If it's a string, determine if it's a numeric ID or CPID try { const identifier = isStampIdentifier(stampId); if (identifier.type === 'id') { // It's a numeric ID return await this.apiClient.getStamp(identifier.value as number); } else { // It's a CPID, search for it first to get the stamp ID context?.logger?.debug('Searching for stamp by CPID', { cpid: identifier.value }); const searchResults = await this.apiClient.searchStamps({ cpid: identifier.value as string, }); if (searchResults.length === 0) { throw new ToolExecutionError( `No stamp found with CPID: ${identifier.value}`, this.name ); } // Now get the full stamp data with base64 content using the stamp ID const stampId = searchResults[0].stamp; if (!stampId) { throw new ToolExecutionError( `Invalid stamp ID for CPID: ${identifier.value}`, this.name ); } context?.logger?.debug('Getting full stamp data', { stampId }); return await this.apiClient.getStamp(stampId); } } catch (validationError) { throw new ToolExecutionError( `Invalid stamp identifier: ${validationError instanceof Error ? validationError.message : String(validationError)}`, this.name, validationError ); } } catch (error) { if (error instanceof ToolExecutionError) { throw error; } throw new ToolExecutionError( `Failed to resolve stamp: ${error instanceof Error ? error.message : String(error)}`, this.name, error ); } } /** * Analyze a stamp for recursive patterns and dependencies */ private async analyzeStamp( stamp: Stamp, params: AnalyzeStampCodeParams, context?: ToolContext ): Promise<StampAnalysisResult> { context?.logger?.debug('Analyzing stamp', { stampId: stamp.stamp, cpid: stamp.cpid }); // Get the stamp content if (!stamp.stamp_base64) { throw new ToolExecutionError( `Stamp ${stamp.stamp} does not have base64 content available`, this.name ); } // Decode the content const rawContent = Buffer.from(stamp.stamp_base64, 'base64').toString('utf8'); context?.logger?.debug('Decoded stamp content', { contentLength: rawContent.length }); // Parse the JavaScript code const parsedJs = this.parser.parseJavaScript(rawContent); // Analyze code structure const codeStructure = this.parser.analyzeCodeStructure(rawContent); // Resolve dependencies if requested let resolvedDependencies: StampDependency[] = parsedJs.dependencies; if (params.include_dependencies) { resolvedDependencies = await this.resolveDependencies( parsedJs.dependencies, params.max_depth, context ); } // Perform security analysis if requested let security; if (params.include_security_analysis) { security = this.parser.analyzeCodeSecurity(rawContent); } else { security = { riskLevel: 'low' as const, risks: [], hasDangerousPatterns: false, isCodeSafe: true, }; } // Perform performance analysis if requested let performance; if (params.include_performance_analysis) { performance = this.parser.analyzeCodePerformance(rawContent, resolvedDependencies); } else { performance = { complexityScore: 0, dependencyCount: resolvedDependencies.length, maxDependencyDepth: 0, }; } // Process HTML data if present let decodedContent: string | undefined; for (const dep of resolvedDependencies) { if (dep.type === 'html' && dep.cpid) { try { decodedContent = await this.parser.decompressHtmlData(dep.cpid); break; // Only process the first HTML dependency for now } catch (error) { context?.logger?.warn('Failed to decompress HTML data', { error }); } } } const result: StampAnalysisResult = { stamp: { id: stamp.stamp || 0, cpid: stamp.cpid, creator: stamp.creator, mimetype: stamp.stamp_mimetype, blockIndex: stamp.block_index, txHash: stamp.tx_hash, }, codeStructure, dependencies: resolvedDependencies, patterns: parsedJs.patterns, security, performance, rawContent: params.include_raw_content ? rawContent : undefined, decodedContent, analysisTimestamp: Date.now(), }; context?.logger?.info('Stamp analysis completed', { stampId: stamp.stamp, dependencyCount: resolvedDependencies.length, patternCount: parsedJs.patterns.length, isRecursive: codeStructure.isRecursive, }); return result; } /** * Resolve stamp dependencies by looking up their metadata */ private async resolveDependencies( dependencies: StampDependency[], maxDepth: number, context?: ToolContext, currentDepth: number = 0 ): Promise<StampDependency[]> { if (currentDepth >= maxDepth) { return dependencies; } const resolved: StampDependency[] = []; for (const dep of dependencies) { const resolvedDep = { ...dep }; // Only try to resolve CPID dependencies (not HTML data) if (dep.type !== 'html' && dep.cpid && dep.cpid.match(/^A[0-9]+$/)) { try { context?.logger?.debug('Resolving dependency', { cpid: dep.cpid }); const searchResults = await this.apiClient.searchStamps({ cpid: dep.cpid }); if (searchResults.length > 0) { resolvedDep.isResolved = true; resolvedDep.stampId = searchResults[0].stamp || undefined; resolvedDep.metadata = searchResults[0]; context?.logger?.debug('Resolved dependency', { cpid: dep.cpid, stampId: searchResults[0].stamp, }); } else { context?.logger?.warn('Could not resolve dependency', { cpid: dep.cpid }); } } catch (error) { context?.logger?.warn('Error resolving dependency', { cpid: dep.cpid, error }); } } resolved.push(resolvedDep); } return resolved; } /** * Format the analysis response for display */ private formatAnalysisResponse( analysis: StampAnalysisResult, params: AnalyzeStampCodeParams ): string { const lines: string[] = []; lines.push(`πŸ” Recursive Stamp Analysis Report`); lines.push(`=====================================`); lines.push(''); // Basic stamp info lines.push(`πŸ“„ Stamp Information:`); lines.push(` ID: ${analysis.stamp.id}`); lines.push(` CPID: ${analysis.stamp.cpid}`); lines.push(` Creator: ${analysis.stamp.creator}`); lines.push(` MIME Type: ${analysis.stamp.mimetype}`); lines.push(` Block: ${analysis.stamp.blockIndex}`); lines.push(''); // Code structure lines.push(`πŸ—οΈ Code Structure:`); lines.push(` Has JavaScript: ${analysis.codeStructure.hasJavaScript ? 'βœ…' : '❌'}`); lines.push(` Has HTML: ${analysis.codeStructure.hasHTML ? 'βœ…' : '❌'}`); lines.push( ` Uses Append Framework: ${analysis.codeStructure.usesAppendFramework ? 'βœ…' : '❌'}` ); lines.push(` Is Recursive: ${analysis.codeStructure.isRecursive ? 'βœ…' : '❌'}`); lines.push(` Has Async Loading: ${analysis.codeStructure.hasAsyncLoading ? 'βœ…' : '❌'}`); lines.push(` Has Error Handling: ${analysis.codeStructure.hasErrorHandling ? 'βœ…' : '❌'}`); lines.push(''); // Dependencies if (analysis.dependencies.length > 0) { lines.push(`πŸ”— Dependencies (${analysis.dependencies.length}):`); analysis.dependencies.forEach((dep, index) => { const status = dep.isResolved ? 'βœ…' : '❌'; const stampInfo = dep.stampId ? ` (Stamp #${dep.stampId})` : ''; lines.push( ` ${index + 1}. ${status} ${dep.cpid} [${dep.type}/${dep.loadMethod}]${stampInfo}` ); }); lines.push(''); } // Patterns if (analysis.patterns.length > 0) { lines.push(`🎯 Detected Patterns (${analysis.patterns.length}):`); analysis.patterns.forEach((pattern, index) => { const confidence = Math.round(pattern.confidence * 100); lines.push(` ${index + 1}. ${pattern.name} (${confidence}% confidence)`); lines.push(` Category: ${pattern.category}`); lines.push(` Description: ${pattern.description}`); }); lines.push(''); } // Security analysis if (params.include_security_analysis) { const riskIcon = analysis.security.riskLevel === 'low' ? '🟒' : analysis.security.riskLevel === 'medium' ? '🟑' : 'πŸ”΄'; lines.push(`πŸ”’ Security Analysis:`); lines.push(` Risk Level: ${riskIcon} ${analysis.security.riskLevel.toUpperCase()}`); lines.push( ` Code Safety: ${analysis.security.isCodeSafe ? 'βœ… Safe' : '⚠️ Potentially Unsafe'}` ); if (analysis.security.risks.length > 0) { lines.push(` Risks Found:`); analysis.security.risks.forEach((risk, index) => { lines.push(` ${index + 1}. ${risk}`); }); } lines.push(''); } // Performance analysis if (params.include_performance_analysis) { const complexityIcon = analysis.performance.complexityScore <= 3 ? '🟒' : analysis.performance.complexityScore <= 6 ? '🟑' : 'πŸ”΄'; lines.push(`⚑ Performance Analysis:`); lines.push( ` Complexity Score: ${complexityIcon} ${analysis.performance.complexityScore.toFixed(1)}/10` ); lines.push(` Dependency Count: ${analysis.performance.dependencyCount}`); lines.push(` Max Dependency Depth: ${analysis.performance.maxDependencyDepth}`); if (analysis.performance.estimatedLoadTime) { lines.push( ` Estimated Load Time: ${analysis.performance.estimatedLoadTime.toFixed(0)}ms` ); } lines.push(''); } // Decoded HTML content if (analysis.decodedContent) { lines.push(`πŸ“ Decoded HTML Content:`); lines.push(` Length: ${analysis.decodedContent.length} characters`); lines.push( ` Preview: ${analysis.decodedContent.substring(0, 200)}${analysis.decodedContent.length > 200 ? '...' : ''}` ); lines.push(''); } lines.push(`πŸ“Š Analysis completed at ${new Date(analysis.analysisTimestamp).toISOString()}`); return lines.join('\n'); } }
  • Zod schema for input parameters validation of the analyze_stamp_code tool.
    export const AnalyzeStampCodeParamsSchema = z.object({ stamp_id: z.union([z.number(), z.string()]), include_dependencies: z.boolean().default(true), max_depth: z.number().min(1).max(10).default(3), include_raw_content: z.boolean().default(false), include_security_analysis: z.boolean().default(true), include_performance_analysis: z.boolean().default(true), });
  • Export of stampAnalysisTools object registering AnalyzeStampCodeTool under 'analyze_stamp_code' key.
    export const stampAnalysisTools = { analyze_stamp_code: AnalyzeStampCodeTool, get_stamp_dependencies: GetStampDependenciesTool, analyze_stamp_patterns: AnalyzeStampPatternsTool, };
  • Factory function createStampAnalysisTools that instantiates and registers the analyze_stamp_code tool.
    export function createStampAnalysisTools(apiClient?: StampchainClient) { return { analyze_stamp_code: new AnalyzeStampCodeTool(apiClient), get_stamp_dependencies: new GetStampDependenciesTool(apiClient), analyze_stamp_patterns: new AnalyzeStampPatternsTool(apiClient), }; }
  • Central createAllTools function that includes stamp analysis tools (including analyze_stamp_code) in the full tool registry.
    export function createAllTools(apiClient?: StampchainClient): Record<string, ITool> { const client = apiClient || new StampchainClient(); const stamps = createStampTools(client); const collections = createCollectionTools(client); const tokens = createTokenTools(client); const analysis = createStampAnalysisTools(client); return { ...stamps, ...collections, ...tokens, ...analysis, }; }

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/stampchain-io/stampchain-mcp'

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