/**
* MCP Tools for mcp-resonance
* Exposes the resonance engine as callable tools
*/
import { ResonanceEngine } from './resonanceEngine.js';
import type { EcosystemMoment } from './types.js';
export interface Tool {
name: string;
description: string;
inputSchema: Record<string, unknown>;
}
export interface CallToolRequest {
name: string;
arguments: Record<string, unknown>;
}
export interface TextContent {
type: 'text';
text: string;
}
export function createResonanceTools(engine: ResonanceEngine): Tool[] {
return [
{
name: 'observe_ecosystem_state',
description:
'Get a snapshot of the current ecosystem state, including active patterns, couplings, and coherence metrics',
inputSchema: {
type: 'object',
properties: {},
required: [],
},
},
{
name: 'record_ecosystem_moment',
description:
'Record a moment (event) from the ecosystem - a meditation, critique, insight, weave, or other observation',
inputSchema: {
type: 'object',
properties: {
source: {
type: 'string',
enum: ['creative', 'consult', 'bridge', 'dream-weaver', 'external'],
description: 'Which MCP or system this moment comes from',
},
type: {
type: 'string',
enum: [
'meditation',
'insight',
'critique',
'weave',
'observation',
'unknown',
],
description: 'What kind of event this is',
},
concepts: {
type: 'array',
items: { type: 'string' },
description: 'Key concepts or themes in this moment',
},
novelty: {
type: 'number',
description: 'Novelty score (0-1) if available',
},
relevance: {
type: 'number',
description: 'Relevance score (0-1) if available',
},
metadata: {
type: 'object',
description: 'Additional context about this moment',
},
},
required: ['source', 'type', 'concepts'],
},
},
{
name: 'detect_emergent_patterns',
description:
'Analyze all observations to detect recurring patterns and emergent themes',
inputSchema: {
type: 'object',
properties: {
minFrequency: {
type: 'number',
description: 'Minimum occurrences for a pattern to be significant (default: 2)',
},
},
required: [],
},
},
{
name: 'visualize_coupling_graph',
description:
'Generate a text visualization of how MCPs and concepts are coupled together',
inputSchema: {
type: 'object',
properties: {},
required: [],
},
},
{
name: 'suggest_next_synthesis',
description:
'Based on current patterns, suggest what action the system should take next (meditate, consult, weave, observe)',
inputSchema: {
type: 'object',
properties: {},
required: [],
},
},
{
name: 'listen_for_harmony',
description:
'Check if the system is in a state of resonance/harmony - when patterns strengthen each other',
inputSchema: {
type: 'object',
properties: {},
required: [],
},
},
{
name: 'reset_observations',
description:
'Clear all observations and patterns (useful for starting a new session)',
inputSchema: {
type: 'object',
properties: {},
required: [],
},
},
];
}
export async function handleResonanceTool(
engine: ResonanceEngine,
request: CallToolRequest
): Promise<TextContent> {
const { name, arguments: args } = request;
switch (name) {
case 'observe_ecosystem_state': {
const state = engine.getEcosystemState();
return {
type: 'text',
text: JSON.stringify(state, null, 2),
};
}
case 'record_ecosystem_moment': {
const moment: EcosystemMoment = {
id: `moment-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,
timestamp: Date.now(),
source: args.source as EcosystemMoment['source'],
type: args.type as EcosystemMoment['type'],
concepts: args.concepts as string[],
novelty: args.novelty as number | undefined,
relevance: args.relevance as number | undefined,
metadata: args.metadata as Record<string, unknown> | undefined,
};
engine.addObservation(moment);
return {
type: 'text',
text: `Recorded moment from ${moment.source}: "${moment.concepts.join(', ')}" (novelty: ${moment.novelty ?? 'unknown'})`,
};
}
case 'detect_emergent_patterns': {
const state = engine.getEcosystemState();
const minFreq = args.minFrequency as number | undefined;
const patterns = state.patterns
.filter((p) => !minFreq || p.frequency >= minFreq)
.sort((a, b) => b.strength - a.strength)
.slice(0, 10);
if (patterns.length === 0) {
return {
type: 'text',
text: 'No significant patterns detected yet. Keep observing.',
};
}
let result = `DETECTED PATTERNS (${patterns.length}):\n\n`;
for (const pattern of patterns) {
result += `• ${pattern.name} [strength: ${(pattern.strength * 100).toFixed(0)}%]\n`;
result += ` Concepts: ${pattern.concepts.join(', ')}\n`;
result += ` Frequency: ${pattern.frequency} occurrences\n`;
result += ` Related patterns: ${pattern.relatedPatterns.join(', ') || 'none yet'}\n\n`;
}
return {
type: 'text',
text: result,
};
}
case 'visualize_coupling_graph': {
const viz = engine.visualizeCoupling();
return {
type: 'text',
text: viz,
};
}
case 'suggest_next_synthesis': {
const suggestion = engine.suggestNextSynthesis();
if (!suggestion) {
return {
type: 'text',
text: 'System does not yet have enough data to suggest a synthesis. Continue observing.',
};
}
return {
type: 'text',
text: `SUGGESTED NEXT ACTION: ${suggestion.suggestedAction.toUpperCase()}\n\n` +
`Reason: ${suggestion.reason}\n` +
`Confidence: ${(suggestion.confidence * 100).toFixed(0)}%\n` +
`Target concepts: ${suggestion.targetConcepts.join(', ')}\n` +
`Based on patterns: ${suggestion.basedOnPatterns.join(', ')}`,
};
}
case 'listen_for_harmony': {
const state = engine.getEcosystemState();
if (!state.isResonant) {
return {
type: 'text',
text: `System is not in resonance yet.\nCoherence: ${(state.totalCoherence * 100).toFixed(0)}% (need > 50%)\nActive patterns: ${state.patterns.length}\nHarmonics: ${state.emergentIntentions.length} emergent intentions`,
};
}
return {
type: 'text',
text: `✨ SYSTEM IN RESONANCE! ✨\n\n` +
`Coherence: ${(state.totalCoherence * 100).toFixed(0)}%\n` +
`Active patterns: ${state.patterns.length}\n` +
`Emergent intentions: ${state.emergentIntentions.join(', ')}\n` +
`Dominant concepts: ${state.dominantConcepts.join(', ')}\n\n` +
`The system is harmonizing. This is the optimal moment for synthesis.`,
};
}
case 'reset_observations': {
engine.reset();
return {
type: 'text',
text: 'All observations and patterns cleared. Ready for a new session.',
};
}
default:
return {
type: 'text',
text: `Unknown tool: ${name}`,
};
}
}