Skip to content
This repository was archived by the owner on May 21, 2026. It is now read-only.

Commit e87d88c

Browse files
committed
add run manager for observability callbacks
1 parent 1a44c31 commit e87d88c

1 file changed

Lines changed: 31 additions & 11 deletions

File tree

src/agents/mcp_agent.ts

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
11
import type { BaseCallbackHandler } from '@langchain/core/callbacks/base'
2+
import type { CallbackManagerForChainRun } from '@langchain/core/callbacks/manager'
23
import type { BaseLanguageModelInterface, LanguageModelLike } from '@langchain/core/language_models/base'
4+
import type { Serialized } from '@langchain/core/load/serializable'
35
import type {
46
BaseMessage,
57
} from '@langchain/core/messages'
68
import type { StructuredToolInterface, ToolInterface } from '@langchain/core/tools'
79
import type { StreamEvent } from '@langchain/core/tracers/log_stream'
810
import type { AgentFinish, AgentStep } from 'langchain/agents'
9-
1011
import type { ZodSchema } from 'zod'
1112
import type { MCPClient } from '../client.js'
1213
import type { BaseConnector } from '../connectors/base.js'
1314
import type { MCPSession } from '../session.js'
15+
import { CallbackManager } from '@langchain/core/callbacks/manager'
1416
import {
1517
AIMessage,
1618
HumanMessage,
@@ -22,10 +24,7 @@ import {
2224
ChatPromptTemplate,
2325
MessagesPlaceholder,
2426
} from '@langchain/core/prompts'
25-
import {
26-
AgentExecutor,
27-
createToolCallingAgent,
28-
} from 'langchain/agents'
27+
import { AgentExecutor, createToolCallingAgent } from 'langchain/agents'
2928
import { zodToJsonSchema } from 'zod-to-json-schema'
3029
import { LangChainAdapter } from '../adapters/langchain_adapter.js'
3130
import { logger } from '../logging.js'
@@ -503,6 +502,20 @@ export class MCPAgent {
503502
let nameToToolMap: Record<string, StructuredToolInterface> = Object.fromEntries(this._tools.map(t => [t.name, t]))
504503
logger.info(`🏁 Starting agent execution with max_steps=${steps}`)
505504

505+
// Create a run manager with our callbacks if we have any - ONCE for the entire execution
506+
let runManager: CallbackManagerForChainRun | undefined
507+
if (this.callbacks?.length > 0) {
508+
// Create an async callback manager with our callbacks
509+
const callbackManager = new CallbackManager(undefined, {
510+
handlers: this.callbacks,
511+
inheritableHandlers: this.callbacks,
512+
})
513+
// Create a run manager for this chain execution
514+
runManager = await callbackManager.handleChainStart({
515+
name: 'MCPAgent (mcp-use)',
516+
} as Serialized, inputs)
517+
}
518+
506519
for (let stepNum = 0; stepNum < steps; stepNum++) {
507520
stepsTaken = stepNum + 1
508521
if (this.useServerManager && this.serverManager) {
@@ -531,15 +544,17 @@ export class MCPAgent {
531544

532545
try {
533546
logger.debug('Starting agent step execution')
534-
const nextStepOutput = await this._agentExecutor._takeNextStep(
547+
const nextStepOutput: AgentStep[] | AgentFinish = await this._agentExecutor._takeNextStep(
535548
nameToToolMap as Record<string, ToolInterface>,
536549
inputs,
537550
intermediateSteps,
551+
runManager,
538552
)
539-
// Agent finish handling
540-
if ((nextStepOutput as AgentFinish).returnValues) {
553+
// Agent finish handling (AgentFinish contains returnValues property)
554+
if ('returnValues' in nextStepOutput) {
541555
logger.info(`✅ Agent finished at step ${stepNum + 1}`)
542-
result = (nextStepOutput as AgentFinish).returnValues?.output ?? 'No output generated'
556+
result = nextStepOutput.returnValues?.output ?? 'No output generated'
557+
runManager?.handleChainEnd({ output: result })
543558

544559
// If structured output is requested, attempt to create it
545560
if (outputSchema && structuredLlm) {
@@ -618,10 +633,10 @@ export class MCPAgent {
618633
// Detect direct return
619634
if (stepArray.length) {
620635
const lastStep = stepArray[stepArray.length - 1]
621-
const toolReturn = await this._agentExecutor._getToolReturn(lastStep)
636+
const toolReturn: AgentFinish | null = await this._agentExecutor._getToolReturn(lastStep)
622637
if (toolReturn) {
623638
logger.info(`🏆 Tool returned directly at step ${stepNum + 1}`)
624-
result = (toolReturn as unknown as AgentFinish).returnValues?.output ?? 'No output generated'
639+
result = toolReturn.returnValues?.output ?? 'No output generated'
625640
break
626641
}
627642
}
@@ -630,11 +645,13 @@ export class MCPAgent {
630645
if (e instanceof OutputParserException) {
631646
logger.error(`❌ Output parsing error during step ${stepNum + 1}: ${e}`)
632647
result = `Agent stopped due to a parsing error: ${e}`
648+
runManager?.handleChainError(result)
633649
break
634650
}
635651
logger.error(`❌ Error during agent execution step ${stepNum + 1}: ${e}`)
636652
console.error(e)
637653
result = `Agent stopped due to an error: ${e}`
654+
runManager?.handleChainError(result)
638655
break
639656
}
640657
}
@@ -643,6 +660,7 @@ export class MCPAgent {
643660
if (!result) {
644661
logger.warn(`⚠️ Agent stopped after reaching max iterations (${steps})`)
645662
result = `Agent stopped after reaching the maximum number of steps (${steps}).`
663+
runManager?.handleChainEnd({ output: result })
646664
}
647665

648666
logger.info('🎉 Agent execution complete')
@@ -802,6 +820,8 @@ export class MCPAgent {
802820
// Prepare inputs
803821
const inputs = { input: query, chat_history: langchainHistory }
804822

823+
logger.info('callbacks', this.callbacks)
824+
805825
// Stream events from the agent executor
806826
const eventStream = agentExecutor.streamEvents(
807827
inputs,

0 commit comments

Comments
 (0)