Skip to main content

MCP

This document explains how MCP works internally in ConvEngine, based strictly on the real implementation of:

com.github.salilvnair.convengine.engine.steps.McpToolStep

MCP is used when:

  • An intent requires external data
  • That data must be fetched safely
  • The engine must reason in multiple steps
  • SQL or tools must be DB-driven, not hardcoded

Example conversation​

What is the status of my move for connection USPSC003BA100SA277CON1388

πŸ‘€

πŸ€–

The status of your move for connection USPSC003BA100SA277CON1388 is MOVED.


MCP execution timeline​

MCP step starts

McpToolStep runs after intent resolution and before rules / response.

Enabled tools loaded

McpToolRegistry loads enabled tools from ce_mcp_tool. If no tools exist, MCP exits early.

MCP context cleared

Any stale context_json.mcp.finalAnswer or observations are removed.

If this step is skipped, previous answers WILL leak into new requests.

Planner loop begins (max 5 iterations)

Planner decides whether to CALL_TOOL or ANSWER.

Planner calls DB tool

Tool code + arguments are returned by the planner and audited.

DB tool executed safely

SQL template from ce_mcp_db_tool is executed via McpDbExecutor.

Observation recorded

Tool result is appended to context_json.mcp.observations.

Planner returns ANSWER

Final answer is written to context_json.mcp.finalAnswer.


Core MCP loop (real code)​

🧩 McpToolStep.execute(...)

MCP context structure​

After execution, MCP writes into ce_conversation.context_json:

{
"mcp": {
"observations": [
{
"toolCode": "postgres.move_status",
"json": "[{ \"status\": \"MOVED\" }]"
}
],
"finalAnswer": "The status of your move is MOVED."
}
}


MCP does NOT return the API response directly.

It prepares data for rules and response resolution.


How McpPlanner decides which tool to call​

McpPlanner is the only component that decides:

  • Whether MCP should continue
  • Whether to CALL_TOOL or ANSWER
  • Which tool to call
  • Which arguments to pass

McpToolStep never chooses a tool.
It blindly executes whatever McpPlanner returns.

Why postgres.move_status is chosen​

Given:

  • Intent = MOVE_CONNECTIONS
  • Question contains a connection id
  • No existing answer in context
  • Tool metadata describing move-status lookup

The planner emits a CALL_TOOL plan.


Core MCP loop (real code)​

🧩 McpToolStep.execute(...)

What happens after MCP?​

β€’ RulesStep may short-circuit if $.mcp.finalAnswer exists

β€’ Or state may be updated via ce_rule

β€’ ResponseResolutionStep selects ce_response

β€’ Response may be EXACT or DERIVED


Why MCP is safe by design​

No dynamic SQL from LLM

All tools are DB-configured

Param schema validated

Max rows enforced

Failures degrade gracefully

Every step is audited


Final takeaway​

MCP is controlled, deterministic, DB-driven, and safe.

Debugging tip​

If you ever see:

Second request returns previous answer

Check these in order:

  1. MCP_CONTEXT_CLEARED audit exists
  2. SQL tool params extracted correctly
  3. derivation_hint does not blindly reuse old finalAnswer

Final takeaway​

MCP in ConvEngine is not β€œagents doing magic”.

It is:
β€’ Controlled
β€’ Deterministic
β€’ Auditable
β€’ DB-driven
β€’ Safe