agent-orchestration-mcp-server
Version:
MCP server that converts natural language queries to orchestration cards for GAFF
188 lines • 7.06 kB
JavaScript
/**
* Memory MCP Server Client
*
* Connects to the memory MCP server to store and retrieve orchestration cards.
* This enables the agent-orchestration server to persist state that can be
* passed to intent-graph-generator via memory key.
*
* Author: Sean Poyner <sean.poyner@pm.me>
*/
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
export class MemoryClient {
constructor() {
this.client = null;
this.transport = null;
this.isConnected = false;
}
/**
* Connect to the memory MCP server
*/
async connect() {
if (this.isConnected) {
return;
}
try {
// Determine the memory server command based on environment
const memoryCommand = process.env.MEMORY_MCP_COMMAND || 'npx';
const memoryArgs = process.env.MEMORY_MCP_ARGS
? process.env.MEMORY_MCP_ARGS.split(',')
: ['-y', '@modelcontextprotocol/server-memory'];
console.error('[MemoryClient] Connecting to memory server...');
console.error('[MemoryClient] Command:', memoryCommand);
console.error('[MemoryClient] Args:', memoryArgs);
this.transport = new StdioClientTransport({
command: memoryCommand,
args: memoryArgs,
});
this.client = new Client({
name: 'agent-orchestration-memory-client',
version: '1.0.0',
}, {
capabilities: {},
});
await this.client.connect(this.transport);
this.isConnected = true;
console.error('[MemoryClient] Successfully connected to memory server');
}
catch (error) {
console.error('[MemoryClient] Failed to connect to memory server:', error);
throw new Error(`Failed to connect to memory server: ${error}`);
}
}
/**
* Store an orchestration card in memory
*/
async storeCard(card, key) {
try {
if (!this.isConnected || !this.client) {
await this.connect();
}
// Serialize the card data
const cardData = JSON.stringify(card);
const metadata = JSON.stringify({
agent_count: card.available_agents?.length || 0,
domain: card.user_request?.domain || 'unknown',
created_at: new Date().toISOString(),
memory_key: key,
});
console.error('[MemoryClient] Storing orchestration card with key:', key);
console.error('[MemoryClient] Card size:', cardData.length, 'chars');
// Call memory:create_entities
const result = await this.client.callTool({
name: 'create_entities',
arguments: {
entities: [
{
name: key,
entityType: 'orchestration_card',
observations: [
`card_data: ${cardData}`,
`metadata: ${metadata}`,
],
},
],
},
});
console.error('[MemoryClient] Storage result:', JSON.stringify(result).substring(0, 200));
return {
success: true,
memory_key: key,
};
}
catch (error) {
console.error('[MemoryClient] Failed to store card:', error);
return {
success: false,
memory_key: key,
error: error instanceof Error ? error.message : String(error),
};
}
}
/**
* Retrieve an orchestration card from memory
*/
async retrieveCard(key) {
try {
if (!this.isConnected || !this.client) {
await this.connect();
}
console.error('[MemoryClient] Retrieving card with key:', key);
// Call memory:open_nodes
const result = await this.client.callTool({
name: 'open_nodes',
arguments: {
names: [key],
},
});
console.error('[MemoryClient] Retrieval result:', JSON.stringify(result).substring(0, 200));
// Parse the result to extract the card data
if (result.content && Array.isArray(result.content) && result.content.length > 0) {
const content = result.content[0];
if (content.type === 'text' && typeof content.text === 'string') {
const parsed = JSON.parse(content.text);
if (parsed.entities && Array.isArray(parsed.entities) && parsed.entities.length > 0) {
const entity = parsed.entities[0];
if (entity.observations && Array.isArray(entity.observations)) {
// Find the card_data observation
const cardDataObs = entity.observations.find((obs) => obs.startsWith('card_data:'));
if (cardDataObs) {
const cardDataJson = cardDataObs.substring('card_data:'.length).trim();
return JSON.parse(cardDataJson);
}
}
}
}
}
console.error('[MemoryClient] No card data found for key:', key);
return null;
}
catch (error) {
console.error('[MemoryClient] Failed to retrieve card:', error);
return null;
}
}
/**
* Disconnect from the memory server
*/
async disconnect() {
if (this.client && this.isConnected) {
try {
await this.client.close();
this.isConnected = false;
this.client = null;
this.transport = null;
console.error('[MemoryClient] Disconnected from memory server');
}
catch (error) {
console.error('[MemoryClient] Error during disconnect:', error);
}
}
}
}
// Singleton instance
let memoryClient = null;
/**
* Get or create the memory client singleton
*/
export function getMemoryClient() {
if (!memoryClient) {
memoryClient = new MemoryClient();
}
return memoryClient;
}
/**
* Store a card in memory (convenience function)
*/
export async function storeCardInMemory(card, key) {
const client = getMemoryClient();
return client.storeCard(card, key);
}
/**
* Retrieve a card from memory (convenience function)
*/
export async function retrieveCardFromMemory(key) {
const client = getMemoryClient();
return client.retrieveCard(key);
}
//# sourceMappingURL=memory-client.js.map