Skip to main content
Glama

Stampchain MCP Server

Official
test-helpers.ts8.52 kB
/** * Test utility functions and helpers */ import { vi, expect } from 'vitest'; import { StampchainClient } from '../../api/stampchain-client.js'; import { createLogger } from '../../utils/index.js'; import type { Stamp, StampListResponse, CollectionResponse, TokenResponse, } from '../../api/types.js'; import type { ServerConfig } from '../../config/index.js'; /** * Create a mock logger for testing */ export function createMockLogger() { return createLogger('test', { level: 'error' }); } /** * Create a mock API client for testing */ export function createMockApiClient() { return { getStamp: vi.fn(), searchStamps: vi.fn(), getRecentStamps: vi.fn(), getCollection: vi.fn(), searchCollections: vi.fn(), getToken: vi.fn(), searchTokens: vi.fn(), getBlock: vi.fn(), getBalance: vi.fn(), customRequest: vi.fn(), // v2.3 methods getRecentSales: vi.fn(), getMarketData: vi.fn(), getStampMarketData: vi.fn(), getAvailableVersions: vi.fn(), testVersionCompatibility: vi.fn(), getApiVersion: vi.fn(), setApiVersion: vi.fn(), getFeatureAvailability: vi.fn(), initializeWithVersionNegotiation: vi.fn(), }; } /** * Create a test configuration */ export function createTestConfig(): ServerConfig { return { name: 'stampchain-mcp-test', version: '0.1.0-test', logging: { level: 'error', enableTimestamps: false, enableColors: false, }, api: { baseUrl: 'https://test.stampchain.io/api', timeout: 5000, retries: 1, retryDelay: 100, }, registry: { maxTools: 100, validateOnRegister: true, allowDuplicateNames: false, }, performance: { requestTimeout: 30000, maxConcurrentRequests: 5, }, development: { enableDebugLogs: false, enableStackTraces: false, }, }; } /** * Creates a mock stamp object with all required fields for testing */ export function createMockStamp(overrides: Partial<Stamp> = {}): Stamp { return { stamp: 12345, block_index: 800000, cpid: 'A123456789012345678901234567890123456789', creator: 'bc1qtest123456789012345678901234567890', creator_name: 'Mike in Space', divisible: 0, keyburn: null, locked: 1, stamp_url: 'https://stampchain.io/stamps/test.png', stamp_mimetype: 'image/png', supply: 1, block_time: '2024-01-01T00:00:00.000Z', tx_hash: 'eb3da8146e626b5783f4359fb1510729f4aad923dfac45b6f1f3a2063907147c', tx_index: 1, ident: 'STAMP' as const, stamp_hash: 'GNGxz7X4LYQoG61sLdvE', file_hash: 'b60ab2708daec7685f3d412a5e05191a', stamp_base64: 'iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==', // Legacy fields (required for v2.3 compatibility) floorPrice: null, floorPriceUSD: null, marketCapUSD: null, // v2.3 fields (optional) marketData: { cpid: 'A123456789012345678901234567890123456789', floorPriceBTC: null, recentSalePriceBTC: null, openDispensersCount: 0, closedDispensersCount: 0, totalDispensersCount: 0, holderCount: 1, uniqueHolderCount: 1, topHolderPercentage: 100, holderDistributionScore: 0, volume24hBTC: 0, volume7dBTC: 0, volume30dBTC: 0, totalVolumeBTC: 0, priceSource: 'counterparty', volumeSources: { counterparty: 1 }, dataQualityScore: 5, confidenceLevel: 3, lastUpdated: '2025-01-08T12:00:00.000Z', lastPriceUpdate: null, updateFrequencyMinutes: 30, lastSaleTxHash: null, lastSaleBuyerAddress: null, lastSaleDispenserAddress: null, lastSaleBtcAmount: null, lastSaleDispenserTxHash: null, lastSaleBlockIndex: null, activityLevel: 'COLD' as const, lastActivityTime: null, floorPriceUSD: null, recentSalePriceUSD: null, volume24hUSD: null, volume7dUSD: null, volume30dUSD: null, }, cacheStatus: 'fresh' as const, dispenserInfo: { openCount: 0, closedCount: 0, totalCount: 0, }, ...overrides, }; } /** * Creates a mock stamp list response for testing */ export function createMockStampListResponse(stamps: Stamp[] = []): StampListResponse { return { data: stamps.length > 0 ? stamps : [createMockStamp()], last_block: 800000, metadata: { btcPrice: 50000, cacheStatus: 'fresh' as const, source: 'coingecko', }, page: 1, limit: 20, totalPages: 1, total: stamps.length > 0 ? stamps.length : 1, }; } /** * Create mock recent sale data for testing (v2.3) */ export function createMockRecentSale(overrides: Partial<any> = {}): any { return { tx_hash: '1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef', block_index: 844755, stamp_id: 12345, price_btc: 0.001, price_usd: 50.0, timestamp: 1704067200, buyer_address: 'bc1qbuyer123456789012345678901234567890', dispenser_address: null, time_ago: '2h ago', btc_amount_satoshis: 100000, dispenser_tx_hash: null, btcPriceUSD: 50000, ...overrides, }; } /** * Create mock recent sales response for testing (v2.3) */ export function createMockRecentSalesResponse(overrides: Partial<any> = {}): any { return { data: [createMockRecentSale()], metadata: { dayRange: 30, lastUpdated: 1704067200000, total: 1, }, last_block: 844755, ...overrides, }; } /** * Create mock stamp market data for testing (v2.3) */ export function createMockStampMarketData(overrides: Partial<any> = {}): any { return { floorPrice: 0.001, floorPriceUSD: 50.0, marketCapUSD: 1000000, activityLevel: 'HOT' as const, lastActivityTime: 1704067200, lastSaleTxHash: 'abcd1234567890abcdef1234567890abcdef1234567890abcdef1234567890', lastSaleBuyerAddress: 'bc1qbuyer123456789012345678901234567890', lastSaleDispenserAddress: null, lastSaleBtcAmount: 0.001, lastSaleDispenserTxHash: null, lastSaleBlockIndex: 844755, volume24h: 0.5, volume7d: 2.1, volume30d: 10.5, ...overrides, }; } /** * Create mock collection data for testing */ export function createMockCollection( overrides: Partial<CollectionResponse> = {} ): CollectionResponse { return { collection_id: 'test-collection', collection_name: 'Test Collection', collection_description: 'A test collection for unit tests', creators: ['bc1qtest123456789012345678901234567890'], stamp_count: 100, total_editions: 100, stamps: [1, 2, 3, 4, 5], ...overrides, }; } /** * Create mock SRC-20 token data for testing */ export function createMockToken(overrides: Partial<TokenResponse> = {}): TokenResponse { return { tx_hash: '1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef', block_index: 800000, p: 'src-20', op: 'deploy', tick: 'TEST', creator: 'bc1qtest123456789012345678901234567890', amt: 1000, deci: 8, lim: '1000', max: '21000000', destination: 'bc1qtest123456789012345678901234567890', block_time: '2024-01-01T00:00:00Z', creator_name: null, destination_name: null, ...overrides, }; } /** * Create mock MCP tool execution context */ export function createMockToolContext() { return { logger: createMockLogger(), apiClient: createMockApiClient(), config: createTestConfig(), }; } /** * Mock axios response for testing */ export function createMockAxiosResponse<T>(data: T, status = 200) { return { data, status, statusText: 'OK', headers: {}, config: {}, }; } /** * Create a promise that resolves after a delay */ export function delay(ms: number): Promise<void> { return new Promise((resolve) => setTimeout(resolve, ms)); } /** * Assert that a function throws with a specific message */ export async function expectToThrow( fn: () => Promise<unknown> | unknown, expectedMessage?: string | RegExp ): Promise<Error> { try { await fn(); throw new Error('Expected function to throw, but it did not'); } catch (error) { if (error instanceof Error) { if (expectedMessage) { if (typeof expectedMessage === 'string') { expect(error.message).toContain(expectedMessage); } else { expect(error.message).toMatch(expectedMessage); } } return error; } throw error; } }

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