class McpAdcpSession {
constructor(mcpClient) {
this.mcp = mcpClient;
this.contextId = null;
this.activeTasks = new Map(); // Track async operations
}
async call(tool, params, options = {}) {
// Build request with protocol-level fields
const request = {
tool: tool,
arguments: params
};
// Include context from previous calls
if (this.contextId) {
request.context_id = this.contextId;
}
// Include webhook configuration (protocol-level, A2A-compatible)
if (options.push_notification_config) {
request.push_notification_config = options.push_notification_config;
}
const response = await this.mcp.call(request);
// Save context for next call
this.contextId = response.context_id;
// Track async operations
if (response.task_id) {
this.activeTasks.set(response.task_id, {
tool,
params,
startTime: new Date(),
status: response.status
});
}
return response;
}
reset() {
this.contextId = null;
this.activeTasks.clear();
}
// Poll specific task
async pollTask(taskId, includeResult = false) {
return this.call('tasks/get', {
task_id: taskId,
include_result: includeResult
});
}
// List pending tasks
async listPendingTasks() {
return this.call('tasks/list', {
filters: {
statuses: ["submitted", "working", "input-required"]
}
});
}
// State reconciliation helper
async reconcileState() {
const pending = await this.listPendingTasks();
const serverTasks = new Set(pending.tasks.map(t => t.task_id));
const clientTasks = new Set(this.activeTasks.keys());
return {
missing_from_client: [...serverTasks].filter(id => !clientTasks.has(id)),
missing_from_server: [...clientTasks].filter(id => !serverTasks.has(id)),
total_pending: pending.tasks.length
};
}
}