Skip to main content

When to use it

  • Short user inputs need to be mapped to a handful of flows before you invest in full orchestration.
  • You want to gate automation on a confidence score (only auto-run when the intent is clear, otherwise escalate).
  • You need structured metadata—like extracted entities or a human-readable reason—to feed into downstream logic.
  • You want deterministic categorisation (embeddings) or richer explanations (LLM) without building a bespoke classifier.

Defining intents

Every classifier consumes a list of Intent objects:
from mcp_agent.workflows.intent_classifier.intent_classifier_base import Intent  INTENTS = [  Intent(  name="fetch_file",  description="Retrieve the contents of a file from the filesystem MCP server.",  examples=[  "show me README.md",  "open src/app.py",  "cat /var/log/system.log",  ],  metadata={"priority": "high", "team": "infra"},  ),  Intent(  name="general_question",  description="Answer an informational question without tool use.",  examples=["what is MCP?", "explain the router pattern"],  ), ] 
  • description gives the classifier context and is surfaced in tracing metadata.
  • examples dramatically improve accuracy—provide several phrasing variants.
  • metadata is propagated to the result so you can attach business logic (e.g. SLA, handoff target).

Choosing a classifier

VariantFactory helperBest forOutput extras
LLM-basedcreate_intent_classifier_llm(...)Highest quality natural language understanding, explanations, entity extractionconfidence (low/medium/high), p_score, reasoning, extracted_entities
Embedding-basedcreate_intent_classifier_embedding(...)Deterministic scoring, lower latency, custom embedding providersp_score (0–1 similarity)
LLM classification enforces a strict JSON schema (StructuredIntentResponse), ensuring stable output even under temperature.

Quick start

from mcp_agent.app import MCPApp from mcp_agent.workflows.factory import (  create_intent_classifier_embedding,  create_intent_classifier_llm, ) from mcp_agent.workflows.intent_classifier.intent_classifier_base import Intent  app = MCPApp(name="intent_demo") INTENTS = [...] # see definition above  async def main():  async with app.run() as running_app:  llm_classifier = await create_intent_classifier_llm(  intents=INTENTS,  provider="openai",  classification_instruction="Return at most one intent unless the user explicitly asks for multiple.",  context=running_app.context,  )   embedding_classifier = await create_intent_classifier_embedding(  intents=INTENTS,  provider="openai", # or "cohere"  context=running_app.context,  )   request = "Could you open README.md for me?"  llm_result = (await llm_classifier.classify(request, top_k=2))[0]  emb_result = (await embedding_classifier.classify(request, top_k=2))[0]   return {  "llm_intent": llm_result.intent,  "llm_confidence": llm_result.confidence,  "llm_reasoning": llm_result.reasoning,  "embedding_intent": emb_result.intent,  "embedding_score": emb_result.p_score,  } 

Working with results

  • LLM classifier returns LLMIntentClassificationResult with:
    • intent: matched intent name.
    • confidence: "low", "medium", "high" (auto-quantised from raw scores).
    • p_score: continuous probability (0–1).
    • reasoning: short explanation.
    • extracted_entities: optional name/value pairs surfaced by the LLM.
  • Embedding classifier returns IntentClassificationResult with intent and p_score. Sort or threshold the score to decide automation boundaries.
Both variants support top_k, letting you offer alternatives to a human or feed multiple candidates into a downstream router.

Integrating with the router

Intent classifiers and routers pair naturally: classify first, then route using a richer skill set.
intent = (await llm_classifier.classify(request, top_k=1))[0] if intent.confidence != "high":  return "Escalating to human – intent unclear."  decisions = await router.route(  f"[intent={intent.intent}] {request}",  top_k=3, ) 
The intent name/metadata can be prepended to the router prompt (as above) or used to select different router instances entirely.

Tuning and operations

  • Override classification_instruction to bias LLM behaviour (hierarchical intents, abstain thresholds, multilingual hints).
  • Pass request_params=RequestParams(strict=True, temperature=0) to disable sampling variance for high-stakes automation.
  • Pre-compute embeddings for cold start by calling await classifier.initialize() at app startup.
  • Record tracing output (otel.enabled: true) to inspect intent descriptions, examples, and resulting confidence scores per request.

Example projects