UNPKG

@kya-os/mcp-i

Version:

COMING SOON:Production-ready MCP Identity with automatic registration, key rotation, and optimized performance

220 lines 8.64 kB
/** * KnowThat.ai Registry Adapter * Primary registry that can host DIDs */ import { TransportFactory } from '../transport.js'; import { pollRegistrationStatus, isAsyncRegistrationResponse } from '../polling.js'; import { getLogger } from '../logger.js'; import { generateClientInfo } from '../platform-info.js'; export class KnowThatRegistry { name = 'knowthat'; type = 'primary'; endpoint; transport; options; constructor(endpoint = 'https://knowthat.ai', transport, options) { this.endpoint = endpoint; this.transport = transport || TransportFactory.create(); this.options = options; } /** * Use the fast CLI registration endpoint */ async publishViaCLI(data) { const logger = getLogger(); try { logger.debug('Using fast CLI registration endpoint'); // Submit registration request with flat structure const response = await this.transport.post(`${this.endpoint}/api/agents/cli-register`, { name: data.name, description: data.description, repository: data.repository, publicKey: data.publicKey }, { timeout: 5000, // 5 second timeout for CLI endpoint headers: { 'Content-Type': 'application/json', 'User-Agent': `@kya-os/mcp-i/${generateClientInfo().sdkVersion}` } }); logger.debug(`CLI registration completed in ${response.data.responseTime}ms`); // Handle key generation if the server generated keys if (response.data.keys && !data.publicKey) { logger.warn(response.data.keys.warning || 'Server generated keys - store them securely!'); } return { success: true, registryAgentId: response.data.agent.id, profileUrl: response.data.agent.url, claimUrl: response.data.claimUrl, claimToken: response.data.claimToken, generatedKeys: response.data.keys }; } catch (error) { logger.debug(`CLI registration failed: ${error.message}`); throw error; // Re-throw for fallback handling } } /** * Determine which endpoint to use based on configuration and context */ shouldUseCLIEndpoint() { // Explicit configuration takes precedence if (this.options?.registryEndpoint === 'cli') return true; if (this.options?.registryEndpoint === 'auto-register') return false; // Auto mode: use CLI endpoint if we're in a context that suggests CLI usage if (this.options?.registryEndpoint === 'auto' || !this.options?.registryEndpoint) { // Check if we have a progress callback (indicates CLI usage) if (this.options?.onProgress) return true; // Check if processingMode is explicitly set to sync (CLI preference) if (this.options?.processingMode === 'sync') return true; // Check if we're in a TTY environment (interactive terminal) if (process.stdout?.isTTY) return true; } return false; } /** * Primary registration - creates DID and hosts DID document * Now supports both CLI (fast) and auto-register (async) endpoints */ async publish(data) { const logger = getLogger(); // Determine which endpoint to use const useCLI = this.shouldUseCLIEndpoint(); if (useCLI) { try { return await this.publishViaCLI(data); } catch (error) { logger.debug('CLI endpoint failed, falling back to auto-register'); // Fall through to auto-register } } // Use auto-register endpoint (existing implementation) return await this.publishViaAutoRegister(data); } /** * Original auto-register implementation */ async publishViaAutoRegister(data) { const logger = getLogger(); try { // Generate dynamic client info based on runtime environment const clientInfo = generateClientInfo({ // Convert 'auto' to undefined to let platform detection decide processingMode: this.options?.processingMode === 'auto' ? undefined : this.options?.processingMode || 'sync', customMetadata: { source: 'mcp-i-sdk' } }); logger.debug(`Generated client info: ${JSON.stringify(clientInfo)}`); // Submit registration request const response = await this.transport.post(`${this.endpoint}/api/agents/auto-register`, { metadata: { name: data.name, description: data.description, repository: data.repository, version: '1.0.0' }, clientInfo, // If we already have a public key, send it publicKey: data.publicKey || undefined }, { timeout: 30000, headers: { 'Content-Type': 'application/json', 'User-Agent': `@kya-os/mcp-i/${clientInfo.sdkVersion}` } }); logger.debug(`Registration response status: ${response.status}`); logger.debug(`Registration response data: ${JSON.stringify(response.data, null, 2)}`); // Check if we got an async response (v2.0 API) if (response.status === 202 && isAsyncRegistrationResponse(response.data)) { logger.debug('Got async registration response, polling for completion...'); // Poll for completion using simple 2-second intervals const result = await pollRegistrationStatus(response.data.status, // Status URL this.transport, { pollInterval: 2000, // Fixed 2-second intervals maxPollingTime: 60000, // 60 seconds max logger, onProgress: (message) => { logger.debug(message); } }); // Return the same structure as sync response return { success: true, registryAgentId: result.agent.id, profileUrl: result.agent.url }; } // Handle sync response (backward compatibility) const syncResponse = response.data; return { success: true, registryAgentId: syncResponse.agent.id, profileUrl: syncResponse.agent.url }; } catch (error) { // The transport layer now provides clearer error messages return { success: false, error: error.message || 'Failed to register with KnowThat.ai' }; } } /** * Verify agent exists and is valid */ async verify(did) { try { const agentSlug = this.extractAgentSlug(did); const response = await this.transport.get(`${this.endpoint}/api/agents/${agentSlug}/verify`, { timeout: 5000 }); return response.data.valid === true; } catch { return false; } } /** * Get agent status in KnowThat registry */ async getStatus(did) { try { const agentSlug = this.extractAgentSlug(did); const response = await this.transport.get(`${this.endpoint}/api/agents/${agentSlug}/status`, { timeout: 5000 }); return { name: this.name, status: response.data.verified ? 'active' : 'pending', registeredAt: response.data.registeredAt, type: 'primary' }; } catch (error) { return { name: this.name, status: 'failed', type: 'primary', error: 'Failed to get status' }; } } /** * Extract agent slug from DID */ extractAgentSlug(did) { // did:web:knowthat.ai:agents:my-agent -> my-agent const parts = did.split(':'); return parts[parts.length - 1]; } } //# sourceMappingURL=knowthat.js.map