@kya-os/mcp-i
Version:
COMING SOON:Production-ready MCP Identity with automatic registration, key rotation, and optimized performance
220 lines • 8.64 kB
JavaScript
/**
* 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': `-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': `-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