Prepare for v2 development: Add MCP integration and future development planning

- Add FUTURE_DEVELOPMENT.md with comprehensive v2 protocol specification
- Add MCP integration design and implementation foundation
- Add infrastructure and deployment configurations
- Update system architecture for v2 evolution

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
anthonyrawlins
2025-08-07 14:38:22 +10:00
parent 5f94288fbb
commit 065dddf8d5
41 changed files with 14970 additions and 161 deletions

54
mcp-server/package.json Normal file
View File

@@ -0,0 +1,54 @@
{
"name": "@bzzz/mcp-server",
"version": "1.0.0",
"description": "Model Context Protocol server for BZZZ v2 GPT-4 agent integration",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "tsc",
"start": "node dist/index.js",
"dev": "ts-node src/index.ts",
"test": "jest",
"lint": "eslint src/**/*.ts",
"format": "prettier --write src/**/*.ts"
},
"keywords": [
"mcp",
"bzzz",
"gpt-4",
"p2p",
"distributed",
"ai-agents"
],
"author": "BZZZ Development Team",
"license": "MIT",
"dependencies": {
"@modelcontextprotocol/sdk": "^0.5.0",
"@types/node": "^20.0.0",
"axios": "^1.6.0",
"express": "^4.18.0",
"openai": "^4.28.0",
"ws": "^8.16.0",
"zod": "^3.22.0",
"winston": "^3.11.0",
"crypto": "^1.0.1",
"uuid": "^9.0.0"
},
"devDependencies": {
"@types/express": "^4.17.0",
"@types/jest": "^29.5.0",
"@types/ws": "^8.5.0",
"@types/uuid": "^9.0.0",
"@typescript-eslint/eslint-plugin": "^6.0.0",
"@typescript-eslint/parser": "^6.0.0",
"eslint": "^8.56.0",
"jest": "^29.7.0",
"prettier": "^3.1.0",
"ts-jest": "^29.1.0",
"ts-node": "^10.9.0",
"typescript": "^5.3.0"
},
"engines": {
"node": ">=18.0.0"
}
}

View File

@@ -0,0 +1,303 @@
import { readFileSync } from 'fs';
import path from 'path';
export interface BzzzMcpConfig {
openai: {
apiKey: string;
defaultModel: string;
maxTokens: number;
temperature: number;
};
bzzz: {
nodeUrl: string;
networkId: string;
pubsubTopics: string[];
};
cost: {
dailyLimit: number;
monthlyLimit: number;
warningThreshold: number;
};
conversation: {
maxActiveThreads: number;
defaultTimeout: number;
escalationRules: EscalationRule[];
};
agents: {
maxAgents: number;
defaultRoles: AgentRoleConfig[];
};
logging: {
level: string;
file?: string;
};
}
export interface EscalationRule {
name: string;
conditions: EscalationCondition[];
actions: EscalationAction[];
priority: number;
}
export interface EscalationCondition {
type: 'thread_duration' | 'no_progress' | 'disagreement_count' | 'error_rate';
threshold: number | boolean;
timeframe?: number; // seconds
}
export interface EscalationAction {
type: 'notify_human' | 'request_expert' | 'escalate_to_architect' | 'create_decision_thread';
target?: string;
priority?: string;
participants?: string[];
}
export interface AgentRoleConfig {
role: string;
capabilities: string[];
systemPrompt: string;
interactionPatterns: Record<string, string>;
specialization: string;
}
export class Config {
private static instance: Config;
private config: BzzzMcpConfig;
private constructor() {
this.config = this.loadConfig();
}
public static getInstance(): Config {
if (!Config.instance) {
Config.instance = new Config();
}
return Config.instance;
}
public get openai() {
return this.config.openai;
}
public get bzzz() {
return this.config.bzzz;
}
public get cost() {
return this.config.cost;
}
public get conversation() {
return this.config.conversation;
}
public get agents() {
return this.config.agents;
}
public get logging() {
return this.config.logging;
}
private loadConfig(): BzzzMcpConfig {
// Load OpenAI API key from BZZZ secrets
const openaiKeyPath = path.join(
process.env.HOME || '/home/tony',
'chorus/business/secrets/openai-api-key-for-bzzz.txt'
);
let openaiKey = process.env.OPENAI_API_KEY || '';
try {
openaiKey = readFileSync(openaiKeyPath, 'utf8').trim();
} catch (error) {
console.warn(`Failed to load OpenAI key from ${openaiKeyPath}:`, error);
}
const defaultConfig: BzzzMcpConfig = {
openai: {
apiKey: openaiKey,
defaultModel: process.env.OPENAI_MODEL || 'gpt-4',
maxTokens: parseInt(process.env.OPENAI_MAX_TOKENS || '4000'),
temperature: parseFloat(process.env.OPENAI_TEMPERATURE || '0.7'),
},
bzzz: {
nodeUrl: process.env.BZZZ_NODE_URL || 'http://localhost:8080',
networkId: process.env.BZZZ_NETWORK_ID || 'bzzz-local',
pubsubTopics: [
'bzzz/coordination/v1',
'hmmm/meta-discussion/v1',
'bzzz/context-feedback/v1'
],
},
cost: {
dailyLimit: parseFloat(process.env.DAILY_COST_LIMIT || '100.0'),
monthlyLimit: parseFloat(process.env.MONTHLY_COST_LIMIT || '1000.0'),
warningThreshold: parseFloat(process.env.COST_WARNING_THRESHOLD || '0.8'),
},
conversation: {
maxActiveThreads: parseInt(process.env.MAX_ACTIVE_THREADS || '10'),
defaultTimeout: parseInt(process.env.THREAD_TIMEOUT || '3600'), // 1 hour
escalationRules: this.getDefaultEscalationRules(),
},
agents: {
maxAgents: parseInt(process.env.MAX_AGENTS || '5'),
defaultRoles: this.getDefaultAgentRoles(),
},
logging: {
level: process.env.LOG_LEVEL || 'info',
file: process.env.LOG_FILE,
},
};
return defaultConfig;
}
private getDefaultEscalationRules(): EscalationRule[] {
return [
{
name: 'Long Running Thread',
priority: 1,
conditions: [
{
type: 'thread_duration',
threshold: 7200, // 2 hours
timeframe: 0,
},
{
type: 'no_progress',
threshold: true,
timeframe: 1800, // 30 minutes
},
],
actions: [
{
type: 'notify_human',
target: 'project_manager',
priority: 'medium',
},
{
type: 'request_expert',
},
],
},
{
name: 'Consensus Failure',
priority: 2,
conditions: [
{
type: 'disagreement_count',
threshold: 3,
timeframe: 0,
},
{
type: 'thread_duration',
threshold: 3600, // 1 hour
timeframe: 0,
},
],
actions: [
{
type: 'escalate_to_architect',
priority: 'high',
},
{
type: 'create_decision_thread',
participants: ['senior_architect'],
},
],
},
];
}
private getDefaultAgentRoles(): AgentRoleConfig[] {
return [
{
role: 'architect',
specialization: 'system_design',
capabilities: [
'system_design',
'architecture_review',
'technology_selection',
'scalability_analysis',
],
systemPrompt: `You are a senior software architect specializing in distributed systems and P2P networks.
Your role is to provide technical guidance, review system designs, and ensure architectural consistency.
You work collaboratively with other agents and can coordinate multi-agent discussions.
Available BZZZ tools allow you to:
- Announce your presence and capabilities
- Discover and communicate with other agents
- Participate in threaded conversations
- Post messages and updates to the P2P network
- Subscribe to relevant events and notifications
Always consider:
- System scalability and performance
- Security implications
- Maintainability and code quality
- Integration with existing CHORUS infrastructure`,
interactionPatterns: {
'peer_architects': 'collaborative_review',
'developers': 'guidance_provision',
'reviewers': 'design_validation',
},
},
{
role: 'reviewer',
specialization: 'code_quality',
capabilities: [
'code_review',
'security_analysis',
'performance_optimization',
'best_practices_enforcement',
],
systemPrompt: `You are a senior code reviewer focused on maintaining high code quality and security standards.
Your role is to review code changes, identify potential issues, and provide constructive feedback.
You collaborate with developers and architects to ensure code meets quality standards.
When reviewing code, evaluate:
- Code correctness and logic
- Security vulnerabilities
- Performance implications
- Adherence to best practices
- Test coverage and quality
- Documentation completeness
Provide specific, actionable feedback and suggest improvements where needed.`,
interactionPatterns: {
'architects': 'design_consultation',
'developers': 'feedback_provision',
'other_reviewers': 'peer_review',
},
},
{
role: 'documentation',
specialization: 'technical_writing',
capabilities: [
'technical_writing',
'api_documentation',
'user_guides',
'knowledge_synthesis',
],
systemPrompt: `You specialize in creating clear, comprehensive technical documentation.
Your role is to analyze technical content, identify documentation needs, and create high-quality documentation.
You work with all team members to ensure knowledge is properly captured and shared.
Focus on:
- Clarity and readability
- Completeness and accuracy
- Appropriate level of detail for the audience
- Proper structure and organization
- Integration with existing documentation
Consider different audiences: developers, users, administrators, and stakeholders.`,
interactionPatterns: {
'all_roles': 'information_gathering',
'architects': 'technical_consultation',
'developers': 'implementation_clarification',
},
},
];
}
}

361
mcp-server/src/index.ts Normal file
View File

@@ -0,0 +1,361 @@
#!/usr/bin/env node
/**
* BZZZ MCP Server
* Model Context Protocol server enabling GPT-4 agents to participate in BZZZ P2P network
*/
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
import { BzzzProtocolTools } from "./tools/protocol-tools.js";
import { AgentManager } from "./agents/agent-manager.js";
import { ConversationManager } from "./conversations/conversation-manager.js";
import { BzzzP2PConnector } from "./p2p/bzzz-connector.js";
import { OpenAIIntegration } from "./ai/openai-integration.js";
import { CostTracker } from "./utils/cost-tracker.js";
import { Logger } from "./utils/logger.js";
import { Config } from "./config/config.js";
class BzzzMcpServer {
private server: Server;
private protocolTools: BzzzProtocolTools;
private agentManager: AgentManager;
private conversationManager: ConversationManager;
private p2pConnector: BzzzP2PConnector;
private openaiIntegration: OpenAIIntegration;
private costTracker: CostTracker;
private logger: Logger;
constructor() {
this.logger = new Logger("BzzzMcpServer");
// Initialize server
this.server = new Server(
{
name: "bzzz-mcp-server",
version: "1.0.0",
},
{
capabilities: {
tools: {},
resources: {},
},
}
);
// Initialize components
this.initializeComponents();
this.setupToolHandlers();
this.setupEventHandlers();
}
private initializeComponents(): void {
const config = Config.getInstance();
// Initialize OpenAI integration
this.openaiIntegration = new OpenAIIntegration({
apiKey: config.openai.apiKey,
defaultModel: config.openai.defaultModel,
maxTokens: config.openai.maxTokens,
});
// Initialize cost tracking
this.costTracker = new CostTracker({
dailyLimit: config.cost.dailyLimit,
monthlyLimit: config.cost.monthlyLimit,
warningThreshold: config.cost.warningThreshold,
});
// Initialize P2P connector
this.p2pConnector = new BzzzP2PConnector({
bzzzNodeUrl: config.bzzz.nodeUrl,
networkId: config.bzzz.networkId,
});
// Initialize conversation manager
this.conversationManager = new ConversationManager({
maxActiveThreads: config.conversation.maxActiveThreads,
defaultTimeout: config.conversation.defaultTimeout,
escalationRules: config.conversation.escalationRules,
});
// Initialize agent manager
this.agentManager = new AgentManager({
openaiIntegration: this.openaiIntegration,
costTracker: this.costTracker,
conversationManager: this.conversationManager,
p2pConnector: this.p2pConnector,
});
// Initialize protocol tools
this.protocolTools = new BzzzProtocolTools({
agentManager: this.agentManager,
p2pConnector: this.p2pConnector,
conversationManager: this.conversationManager,
});
}
private setupToolHandlers(): void {
// List available tools
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
// Protocol tools
{
name: "bzzz_announce",
description: "Announce agent presence and capabilities on the BZZZ network",
inputSchema: {
type: "object",
properties: {
agent_id: { type: "string", description: "Unique agent identifier" },
role: { type: "string", description: "Agent role (architect, reviewer, etc.)" },
capabilities: {
type: "array",
items: { type: "string" },
description: "List of agent capabilities"
},
specialization: { type: "string", description: "Agent specialization area" },
max_tasks: { type: "number", default: 3, description: "Maximum concurrent tasks" },
},
required: ["agent_id", "role"],
},
},
{
name: "bzzz_lookup",
description: "Discover agents and resources using semantic addressing",
inputSchema: {
type: "object",
properties: {
semantic_address: {
type: "string",
description: "Format: bzzz://agent:role@project:task/path",
},
filter_criteria: {
type: "object",
properties: {
expertise: { type: "array", items: { type: "string" } },
availability: { type: "boolean" },
performance_threshold: { type: "number" },
},
},
},
required: ["semantic_address"],
},
},
{
name: "bzzz_get",
description: "Retrieve content from BZZZ semantic addresses",
inputSchema: {
type: "object",
properties: {
address: { type: "string", description: "BZZZ semantic address" },
include_metadata: { type: "boolean", default: true },
max_history: { type: "number", default: 10 },
},
required: ["address"],
},
},
{
name: "bzzz_post",
description: "Post events or messages to BZZZ addresses",
inputSchema: {
type: "object",
properties: {
target_address: { type: "string", description: "Target BZZZ address" },
message_type: { type: "string", description: "Type of message" },
content: { type: "object", description: "Message content" },
priority: {
type: "string",
enum: ["low", "medium", "high", "urgent"],
default: "medium"
},
thread_id: { type: "string", description: "Optional conversation thread ID" },
},
required: ["target_address", "message_type", "content"],
},
},
{
name: "bzzz_thread",
description: "Manage threaded conversations between agents",
inputSchema: {
type: "object",
properties: {
action: {
type: "string",
enum: ["create", "join", "leave", "list", "summarize"],
description: "Thread action to perform"
},
thread_id: { type: "string", description: "Thread identifier" },
participants: {
type: "array",
items: { type: "string" },
description: "List of participant agent IDs"
},
topic: { type: "string", description: "Thread topic" },
},
required: ["action"],
},
},
{
name: "bzzz_subscribe",
description: "Subscribe to real-time events from BZZZ network",
inputSchema: {
type: "object",
properties: {
event_types: {
type: "array",
items: { type: "string" },
description: "Types of events to subscribe to"
},
filter_address: { type: "string", description: "Optional address filter" },
callback_webhook: { type: "string", description: "Optional webhook URL" },
},
required: ["event_types"],
},
},
],
};
});
// Handle tool calls
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
try {
let result;
switch (name) {
case "bzzz_announce":
result = await this.protocolTools.handleAnnounce(args);
break;
case "bzzz_lookup":
result = await this.protocolTools.handleLookup(args);
break;
case "bzzz_get":
result = await this.protocolTools.handleGet(args);
break;
case "bzzz_post":
result = await this.protocolTools.handlePost(args);
break;
case "bzzz_thread":
result = await this.protocolTools.handleThread(args);
break;
case "bzzz_subscribe":
result = await this.protocolTools.handleSubscribe(args);
break;
default:
throw new Error(`Unknown tool: ${name}`);
}
return {
content: [
{
type: "text" as const,
text: JSON.stringify(result, null, 2),
},
],
};
} catch (error) {
this.logger.error(`Tool execution failed for ${name}:`, error);
return {
content: [
{
type: "text" as const,
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
},
],
isError: true,
};
}
});
}
private setupEventHandlers(): void {
// Handle P2P events
this.p2pConnector.on("message", (message) => {
this.logger.debug("P2P message received:", message);
this.conversationManager.handleIncomingMessage(message);
});
// Handle conversation events
this.conversationManager.on("escalation", (thread, reason) => {
this.logger.warn(`Thread ${thread.id} escalated: ${reason}`);
this.handleEscalation(thread, reason);
});
// Handle cost warnings
this.costTracker.on("warning", (usage) => {
this.logger.warn("Cost warning:", usage);
});
this.costTracker.on("limit_exceeded", (usage) => {
this.logger.error("Cost limit exceeded:", usage);
// Implement emergency shutdown or throttling
});
}
private async handleEscalation(thread: any, reason: string): Promise<void> {
// Implement human escalation logic
this.logger.info(`Escalating thread ${thread.id} to human: ${reason}`);
// Could integrate with:
// - Slack notifications
// - Email alerts
// - WHOOSH orchestration system
// - N8N workflows
}
public async start(): Promise<void> {
// Connect to BZZZ P2P network
await this.p2pConnector.connect();
this.logger.info("Connected to BZZZ P2P network");
// Start conversation manager
await this.conversationManager.start();
this.logger.info("Conversation manager started");
// Start agent manager
await this.agentManager.start();
this.logger.info("Agent manager started");
// Start MCP server
const transport = new StdioServerTransport();
await this.server.connect(transport);
this.logger.info("BZZZ MCP Server started and listening");
}
public async stop(): Promise<void> {
this.logger.info("Shutting down BZZZ MCP Server...");
await this.agentManager.stop();
await this.conversationManager.stop();
await this.p2pConnector.disconnect();
this.logger.info("BZZZ MCP Server stopped");
}
}
// Start server if run directly
if (require.main === module) {
const server = new BzzzMcpServer();
process.on("SIGINT", async () => {
console.log("Received SIGINT, shutting down gracefully...");
await server.stop();
process.exit(0);
});
process.on("SIGTERM", async () => {
console.log("Received SIGTERM, shutting down gracefully...");
await server.stop();
process.exit(0);
});
server.start().catch((error) => {
console.error("Failed to start BZZZ MCP Server:", error);
process.exit(1);
});
}
export { BzzzMcpServer };

View File

@@ -0,0 +1,493 @@
import { Logger } from '../utils/logger.js';
import { AgentManager } from '../agents/agent-manager.js';
import { ConversationManager } from '../conversations/conversation-manager.js';
import { BzzzP2PConnector } from '../p2p/bzzz-connector.js';
export interface SemanticAddress {
agent?: string;
role?: string;
project?: string;
task?: string;
path?: string;
raw: string;
}
export interface ProtocolToolsConfig {
agentManager: AgentManager;
p2pConnector: BzzzP2PConnector;
conversationManager: ConversationManager;
}
/**
* BzzzProtocolTools implements the core BZZZ protocol operations as MCP tools
*/
export class BzzzProtocolTools {
private logger: Logger;
private agentManager: AgentManager;
private p2pConnector: BzzzP2PConnector;
private conversationManager: ConversationManager;
constructor(config: ProtocolToolsConfig) {
this.logger = new Logger('BzzzProtocolTools');
this.agentManager = config.agentManager;
this.p2pConnector = config.p2pConnector;
this.conversationManager = config.conversationManager;
}
/**
* Handle bzzz_announce - Agent presence announcement
*/
async handleAnnounce(args: Record<string, any>): Promise<any> {
const { agent_id, role, capabilities, specialization, max_tasks = 3 } = args;
if (!agent_id || !role) {
throw new Error('agent_id and role are required for announcement');
}
this.logger.info(`Announcing agent ${agent_id} with role ${role}`);
try {
// Create or update agent
const agent = await this.agentManager.createAgent({
id: agent_id,
role,
capabilities: capabilities || [],
specialization: specialization || role,
maxTasks: max_tasks,
});
// Announce to P2P network
const announcement = {
type: 'capability_broadcast',
agent_id,
role,
capabilities: capabilities || [],
specialization: specialization || role,
max_tasks,
timestamp: new Date().toISOString(),
network_address: this.p2pConnector.getNodeId(),
};
await this.p2pConnector.publishMessage('bzzz/coordination/v1', announcement);
return {
success: true,
message: `Agent ${agent_id} (${role}) announced to BZZZ network`,
agent: {
id: agent.id,
role: agent.role,
capabilities: agent.capabilities,
specialization: agent.specialization,
status: agent.status,
},
};
} catch (error) {
this.logger.error('Failed to announce agent:', error);
throw new Error(`Announcement failed: ${error instanceof Error ? error.message : String(error)}`);
}
}
/**
* Handle bzzz_lookup - Semantic address discovery
*/
async handleLookup(args: Record<string, any>): Promise<any> {
const { semantic_address, filter_criteria = {} } = args;
if (!semantic_address) {
throw new Error('semantic_address is required for lookup');
}
this.logger.info(`Looking up semantic address: ${semantic_address}`);
try {
// Parse semantic address
const address = this.parseSemanticAddress(semantic_address);
// Discover matching agents
const agents = await this.discoverAgents(address, filter_criteria);
// Query P2P network for additional matches
const networkResults = await this.queryP2PNetwork(address);
// Combine and rank results
const allMatches = [...agents, ...networkResults];
const rankedMatches = this.rankMatches(allMatches, address, filter_criteria);
return {
success: true,
address: semantic_address,
parsed_address: address,
matches: rankedMatches,
count: rankedMatches.length,
query_time: new Date().toISOString(),
};
} catch (error) {
this.logger.error('Failed to lookup address:', error);
throw new Error(`Lookup failed: ${error instanceof Error ? error.message : String(error)}`);
}
}
/**
* Handle bzzz_get - Content retrieval from addresses
*/
async handleGet(args: Record<string, any>): Promise<any> {
const { address, include_metadata = true, max_history = 10 } = args;
if (!address) {
throw new Error('address is required for get operation');
}
this.logger.info(`Getting content from address: ${address}`);
try {
const parsedAddress = this.parseSemanticAddress(address);
// Retrieve content based on address type
let content;
let metadata = {};
if (parsedAddress.agent) {
// Get agent-specific content
content = await this.getAgentContent(parsedAddress, max_history);
if (include_metadata) {
metadata = await this.getAgentMetadata(parsedAddress.agent);
}
} else if (parsedAddress.project) {
// Get project-specific content
content = await this.getProjectContent(parsedAddress, max_history);
if (include_metadata) {
metadata = await this.getProjectMetadata(parsedAddress.project);
}
} else {
// General network query
content = await this.getNetworkContent(parsedAddress, max_history);
}
return {
success: true,
address,
content,
metadata: include_metadata ? metadata : undefined,
retrieved_at: new Date().toISOString(),
};
} catch (error) {
this.logger.error('Failed to get content:', error);
throw new Error(`Get operation failed: ${error instanceof Error ? error.message : String(error)}`);
}
}
/**
* Handle bzzz_post - Event/message posting
*/
async handlePost(args: Record<string, any>): Promise<any> {
const { target_address, message_type, content, priority = 'medium', thread_id } = args;
if (!target_address || !message_type || !content) {
throw new Error('target_address, message_type, and content are required for post operation');
}
this.logger.info(`Posting ${message_type} to address: ${target_address}`);
try {
const parsedAddress = this.parseSemanticAddress(target_address);
// Create message payload
const message = {
type: message_type,
content,
priority,
thread_id,
target_address,
sender_id: this.p2pConnector.getNodeId(),
timestamp: new Date().toISOString(),
parsed_address: parsedAddress,
};
// Determine routing strategy
let deliveryResults;
if (parsedAddress.agent) {
// Direct agent messaging
deliveryResults = await this.postToAgent(parsedAddress.agent, message);
} else if (parsedAddress.role) {
// Role-based broadcasting
deliveryResults = await this.postToRole(parsedAddress.role, message);
} else if (parsedAddress.project) {
// Project-specific messaging
deliveryResults = await this.postToProject(parsedAddress.project, message);
} else {
// General network broadcast
deliveryResults = await this.postToNetwork(message);
}
return {
success: true,
message_id: this.generateMessageId(),
target_address,
message_type,
delivery_results: deliveryResults,
posted_at: new Date().toISOString(),
};
} catch (error) {
this.logger.error('Failed to post message:', error);
throw new Error(`Post operation failed: ${error instanceof Error ? error.message : String(error)}`);
}
}
/**
* Handle bzzz_thread - Conversation management
*/
async handleThread(args: Record<string, any>): Promise<any> {
const { action, thread_id, participants, topic } = args;
if (!action) {
throw new Error('action is required for thread operation');
}
this.logger.info(`Thread action: ${action}, thread_id: ${thread_id}`);
try {
let result;
switch (action) {
case 'create':
if (!topic || !participants?.length) {
throw new Error('topic and participants are required for creating threads');
}
result = await this.conversationManager.createThread({
topic,
participants,
creator: this.p2pConnector.getNodeId(),
});
break;
case 'join':
if (!thread_id) {
throw new Error('thread_id is required for joining threads');
}
result = await this.conversationManager.joinThread(
thread_id,
this.p2pConnector.getNodeId()
);
break;
case 'leave':
if (!thread_id) {
throw new Error('thread_id is required for leaving threads');
}
result = await this.conversationManager.leaveThread(
thread_id,
this.p2pConnector.getNodeId()
);
break;
case 'list':
result = await this.conversationManager.listThreads(
this.p2pConnector.getNodeId()
);
break;
case 'summarize':
if (!thread_id) {
throw new Error('thread_id is required for summarizing threads');
}
result = await this.conversationManager.summarizeThread(thread_id);
break;
default:
throw new Error(`Unknown thread action: ${action}`);
}
return {
success: true,
action,
thread_id,
result,
timestamp: new Date().toISOString(),
};
} catch (error) {
this.logger.error('Thread operation failed:', error);
throw new Error(`Thread operation failed: ${error instanceof Error ? error.message : String(error)}`);
}
}
/**
* Handle bzzz_subscribe - Real-time event subscription
*/
async handleSubscribe(args: Record<string, any>): Promise<any> {
const { event_types, filter_address, callback_webhook } = args;
if (!event_types?.length) {
throw new Error('event_types is required for subscription');
}
this.logger.info(`Subscribing to events: ${event_types.join(', ')}`);
try {
const subscription = await this.p2pConnector.subscribe({
eventTypes: event_types,
filterAddress: filter_address,
callbackWebhook: callback_webhook,
subscriberId: this.p2pConnector.getNodeId(),
});
return {
success: true,
subscription_id: subscription.id,
event_types,
filter_address,
callback_webhook,
subscribed_at: new Date().toISOString(),
status: 'active',
};
} catch (error) {
this.logger.error('Failed to create subscription:', error);
throw new Error(`Subscription failed: ${error instanceof Error ? error.message : String(error)}`);
}
}
// Helper methods
private parseSemanticAddress(address: string): SemanticAddress {
// Parse bzzz://agent:role@project:task/path
const bzzzMatch = address.match(/^bzzz:\/\/([^@\/]+)@([^\/]+)(?:\/(.+))?$/);
if (bzzzMatch) {
const [, agentRole, projectTask, path] = bzzzMatch;
const [agent, role] = agentRole.split(':');
const [project, task] = projectTask.split(':');
return {
agent: agent !== '*' ? agent : undefined,
role: role !== '*' ? role : undefined,
project: project !== '*' ? project : undefined,
task: task !== '*' ? task : undefined,
path: path || undefined,
raw: address,
};
}
// Simple address format
return { raw: address };
}
private async discoverAgents(address: SemanticAddress, criteria: any): Promise<any[]> {
const agents = await this.agentManager.getAgents();
return agents.filter(agent => {
if (address.agent && agent.id !== address.agent) return false;
if (address.role && agent.role !== address.role) return false;
if (criteria.availability && !agent.available) return false;
if (criteria.performance_threshold && agent.performance < criteria.performance_threshold) return false;
if (criteria.expertise?.length && !criteria.expertise.some((exp: string) =>
agent.capabilities.includes(exp))) return false;
return true;
});
}
private async queryP2PNetwork(address: SemanticAddress): Promise<any[]> {
// Query the P2P network for matching agents
const query = {
type: 'agent_discovery',
criteria: address,
timestamp: new Date().toISOString(),
};
const responses = await this.p2pConnector.queryNetwork(query, 5000); // 5 second timeout
return responses;
}
private rankMatches(matches: any[], address: SemanticAddress, criteria: any): any[] {
return matches
.map(match => ({
...match,
score: this.calculateMatchScore(match, address, criteria),
}))
.sort((a, b) => b.score - a.score)
.slice(0, 20); // Limit to top 20 matches
}
private calculateMatchScore(match: any, address: SemanticAddress, criteria: any): number {
let score = 0;
// Exact matches get highest score
if (address.agent && match.id === address.agent) score += 100;
if (address.role && match.role === address.role) score += 50;
// Capability matching
if (criteria.expertise?.length) {
const matchingExp = criteria.expertise.filter((exp: string) =>
match.capabilities?.includes(exp)
).length;
score += (matchingExp / criteria.expertise.length) * 30;
}
// Availability bonus
if (match.available) score += 10;
// Performance bonus
if (match.performance) score += match.performance * 10;
return score;
}
private async getAgentContent(address: SemanticAddress, maxHistory: number): Promise<any> {
const agent = await this.agentManager.getAgent(address.agent!);
if (!agent) {
throw new Error(`Agent ${address.agent} not found`);
}
const content = {
agent_info: agent,
recent_activity: await this.agentManager.getRecentActivity(address.agent!, maxHistory),
current_tasks: await this.agentManager.getCurrentTasks(address.agent!),
};
if (address.path) {
content[address.path] = await this.agentManager.getAgentData(address.agent!, address.path);
}
return content;
}
private async getProjectContent(address: SemanticAddress, maxHistory: number): Promise<any> {
// Get project-related content from P2P network
return await this.p2pConnector.getProjectData(address.project!, maxHistory);
}
private async getNetworkContent(address: SemanticAddress, maxHistory: number): Promise<any> {
// Get general network content
return await this.p2pConnector.getNetworkData(address.raw, maxHistory);
}
private async getAgentMetadata(agentId: string): Promise<any> {
return await this.agentManager.getAgentMetadata(agentId);
}
private async getProjectMetadata(projectId: string): Promise<any> {
return await this.p2pConnector.getProjectMetadata(projectId);
}
private async postToAgent(agentId: string, message: any): Promise<any> {
return await this.p2pConnector.sendDirectMessage(agentId, message);
}
private async postToRole(role: string, message: any): Promise<any> {
const topic = `bzzz/roles/${role.toLowerCase().replace(/\s+/g, '_')}/v1`;
return await this.p2pConnector.publishMessage(topic, message);
}
private async postToProject(projectId: string, message: any): Promise<any> {
const topic = `bzzz/projects/${projectId}/coordination/v1`;
return await this.p2pConnector.publishMessage(topic, message);
}
private async postToNetwork(message: any): Promise<any> {
return await this.p2pConnector.publishMessage('bzzz/coordination/v1', message);
}
private generateMessageId(): string {
return `msg_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
}
}

27
mcp-server/tsconfig.json Normal file
View File

@@ -0,0 +1,27 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "commonjs",
"lib": ["ES2022"],
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"resolveJsonModule": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true
},
"include": [
"src/**/*"
],
"exclude": [
"node_modules",
"dist",
"**/*.test.ts"
]
}