Skip to main content
Glama
meerkatsai

Lead Routing MCP Server

by meerkatsai

Lead routing with context, rules and state

tests status: educational prototype data: synthetic

A small, runnable example of AI-assisted lead routing. dbt prepares the business context, plain Python applies the routing policy, a ledger tracks workflow state so retries are safe, and an MCP server gives Claude (or any MCP host) read-only tools to inspect leads and explain decisions.

The model never picks the owner. It reads context, explains the rule that fired, and can suggest a missing value, and every suggestion goes to a human.

Architecture: lead and CRM data flow through a dbt model, a Python routing policy and a workflow ledger; read-only MCP tools let Claude inspect and explain; a human approves before an idempotent CRM write

Status: educational prototype. It runs locally on synthetic data. There is no real CRM connection, no authentication and no multi-worker concurrency. See What this does not do.

The problem

A new lead arrives. The company looks enterprise-sized, but it might already be a customer. There could be an open opportunity with an owner. The country field is blank, and the same person signed up last week with a slightly different email format.

You can ask an LLM "who should own this lead?" and get a plausible answer. What you won't get is the same answer every time, a rule you can point to, protection against assigning the same lead twice, or a record of why. Those come from the system around the model.

This repo splits the job up:

Layer

Tool here

Job

Business context

dbt + DuckDB

Normalize emails, domains, countries and sizes. Join accounts, open opportunities and territories. Flag missing fields and duplicates. One row per lead.

Decision

Python (policy.py)

Ordered, versioned rules. Returns rule_id, reason and evidence for every decision. No I/O, no model calls.

Workflow state

SQLite ledger (workflow.py)

One case per lead, input fingerprint and policy version. Approvals, retries and an audit trail.

Assistance

MCP server (mcp_server.py)

Six read-only tools: list, inspect context, preview, preview with a model-suggested country, inspect a case, explain the policy.

Side effects

Fake CRM (crm_stub.py)

Idempotent owner writes, with simulated outages and lost responses so you can watch retries work.

Related MCP server: Demo CRM MCP Server

Quick start

You need Python 3.11+ and git. No API keys or accounts are required.

git clone https://github.com/meerkatsai/lead-routing-context-demo.git
cd lead-routing-context-demo
python3 -m venv .venv
source .venv/bin/activate          # Windows: .venv\Scripts\activate
pip install -e ".[dev]"

Build the context model. This loads the synthetic CSVs, builds lead_routing_base and runs 16 dbt data tests:

lead-routing build
Done. PASS=26 WARN=0 ERROR=0 SKIP=0 NO-OP=0 REUSED=0 TOTAL=26

Check every lead against the expected outcomes in data/expected_outcomes.csv:

lead-routing eval
lead_id  expected                                  got                                       match
-------  ----------------------------------------  ----------------------------------------  -----
L-001    TERRITORY_OWNER -> own_maya               TERRITORY_OWNER -> own_maya               yes
L-002    EXISTING_ACCOUNT_OWNER -> own_oliver      EXISTING_ACCOUNT_OWNER -> own_oliver      yes
L-003    EXISTING_ACCOUNT_OWNER -> own_maya        EXISTING_ACCOUNT_OWNER -> own_maya        yes
L-004    EXISTING_OWNER_MISSING -> revops_review   EXISTING_OWNER_MISSING -> revops_review   yes
L-005    OWNER_CONFLICT -> revops_review           OWNER_CONFLICT -> revops_review           yes
...
L-015    EXISTING_ACCOUNT_OWNER -> own_priya       EXISTING_ACCOUNT_OWNER -> own_priya       yes

accuracy 15/15   false assignments 0   review rate 33%

Run the test suite (it builds its own copy of the warehouse in a temp folder):

pytest
52 passed

Walk through the workflow

Route every lead and record a case for each:

lead-routing route-all
lead_id  rule_id                 destination       case_status      case_id            ledger
-------  ----------------------  ----------------  ---------------  -----------------  --------
L-001    TERRITORY_OWNER         own_maya          previewed        case_46357e2fb198  new case
L-002    EXISTING_ACCOUNT_OWNER  own_oliver        previewed        case_0b6eb8e9692e  new case
L-004    EXISTING_OWNER_MISSING  revops_review     review_required  case_417e5b342370  new case
L-005    OWNER_CONFLICT          revops_review     review_required  case_4eb2824a5b42  new case
L-012    DUPLICATE_LEAD          L-001             duplicate        case_bb1ddc8fc342  new case
...

Run it again, or rebuild dbt and run it again. Every row now says existing case, because the input fingerprint and policy version haven't changed. Your case IDs will differ from the ones shown here.

Look at one decision:

lead-routing preview L-003
{
  "lead_id": "L-003",
  "status": "assigned",
  "queue_or_owner": "own_maya",
  "rule_id": "EXISTING_ACCOUNT_OWNER",
  "reason": "Kept the owner of the existing account/opportunity",
  "needs_review": false,
  "policy_version": "v1",
  "evidence": {
    "account_id": "A-102",
    "is_existing_customer": false,
    "account_owner_id": "own_maya",
    "open_opportunity_ids": ["O-500"],
    "open_opportunity_owner_ids": ["own_maya"]
  },
  "data_quality_flags": []
}

L-003 has no country, so a territory rule can't run. The open opportunity already has an owner, and that rule comes first, so the owner is kept.

Approve a case and write it, simulating a CRM timeout where the write lands but the response is lost:

lead-routing apply case_46357e2fb198              # refused: case is previewed, not approved
lead-routing approve case_46357e2fb198 --by maya.chen
lead-routing apply case_46357e2fb198 --simulate-timeout
lead-routing apply case_46357e2fb198              # retry
lead-routing crm-writes
apply failed and was recorded on the case: TimeoutError('CRM write may have succeeded, but the response was lost'). Run apply again to retry.
case_46357e2fb198: applied -> own_maya (crm action crm_7d1153cab4)

lead_id  owner_or_queue  action_id
-------  --------------  --------------
L-001    own_maya        crm_7d1153cab4

There's one write. The retry reused the case's idempotency key, so the CRM returned the first write instead of making a second one.

Settle a review case. A human picks the destination and has to leave a note:

lead-routing resolve case_4eb2824a5b42 --owner own_maya --by rev.ops \
  --note "Negotiation-stage opportunity owner keeps the account"
lead-routing apply case_4eb2824a5b42
lead-routing case case_4eb2824a5b42                # full audit trail

Routing rules

Six routing rules in order: duplicate lead, existing account owner, missing required data, enterprise threshold, territory owner, no safe match

The first rule that matches wins. The order is part of the policy. For example, rule 2 sitting above rule 4 is why an existing customer with 900 employees keeps its account owner instead of going to the enterprise queue. Every pair of rules that can match the same lead has a test in tests/test_policy.py.

The rules and the 200-employee threshold are illustrative. Replace them with your company's ownership rules, change LEAD_ROUTING_POLICY_VERSION when you do, and the ledger will supersede open cases with a reason (policy v1 -> v2).

Connect Claude

The MCP server exposes six tools, all annotated readOnlyHint: true:

Tool

What it returns

list_leads_for_routing(limit)

Up to 100 leads with a one-line summary each

get_lead_context(lead_id)

Normalized lead, account, open opportunities, territory, source timestamps, and the lead's notes labelled notes_untrusted

preview_route(lead_id)

The policy decision plus whether the ledger already has a case for it

preview_route_with_country_hint(lead_id, country_code, evidence)

A decision using a country the assistant inferred from the notes. Validated against the allowed list, quoted evidence required, always needs_review: true

get_routing_case(case_or_lead_id)

Case status, attempts, errors and audit events

explain_routing_policy()

The ordered rules, version and threshold

Claude Desktop: add this to claude_desktop_config.json (Settings → Developer → Edit Config), using the absolute path to your clone, then restart Claude Desktop:

{
  "mcpServers": {
    "lead-routing-demo": {
      "command": "/ABSOLUTE/PATH/TO/lead-routing-context-demo/.venv/bin/lead-routing-mcp"
    }
  }
}

On Windows the command is ...\\.venv\\Scripts\\lead-routing-mcp.exe. A copy is in examples/claude_desktop_config.json.

Claude Code:

claude mcp add lead-routing-demo -- "$(pwd)/.venv/bin/lead-routing-mcp"

Then try:

  • "Why did L-005 go to review? Show me the evidence."

  • "L-006 has no country. Read its notes and preview a route with your best guess."

  • "List every lead that needs a human and explain why, one line each."

For the second one, Claude should call preview_route_with_country_hint with IN and quote "based in Pune". The tool runs the normal policy on it and returns own_priya marked for review. Claude never writes anything.

How the pieces fit

dbt_project/
  seeds/                 synthetic leads, accounts, opportunities, territories, country aliases
  models/staging/        per-source cleanup
  models/lead_routing_base.sql   the routing contract: one row per lead
  models/schema.yml      data tests (unique keys, accepted values, relationships)
  tests/                 singular test: no lead dropped or duplicated by joins
src/lead_routing/
  policy.py              ordered rules, pure function
  context.py             read-only DuckDB access, input fingerprint
  workflow.py            ledger: cases, transitions, audit events, idempotent apply
  crm_stub.py            fake CRM with idempotency keys and failure simulation
  assist.py              validation for model-suggested values
  mcp_server.py          read-only MCP tools
  cli.py                 lead-routing command
data/expected_outcomes.csv   the eval set: expected rule and destination per lead
tests/                   policy, data model, ledger and MCP tests

More detail on each design choice, including why the duplicate check runs first and why unknown company size gets flagged instead of treated as zero, is in docs/architecture.md.

Configuration

Everything has a default, and every setting can be overridden with an environment variable:

Variable

Default

LEAD_ROUTING_DUCKDB

warehouse/lead_routing.duckdb

LEAD_ROUTING_LEDGER

warehouse/ledger.sqlite

LEAD_ROUTING_FAKE_CRM

warehouse/fake_crm.sqlite

LEAD_ROUTING_POLICY_VERSION

v1

LEAD_ROUTING_ENTERPRISE_THRESHOLD

200

To start over, delete the warehouse/ folder and run lead-routing build.

Tested versions

Tested on macOS with Python 3.12.12, dbt-core 1.12.6, dbt-duckdb 1.11.1, duckdb 2.0.0, mcp 2.3.0 and pytest 9.1.1. CI runs the build, eval and tests on Python 3.11, 3.12 and 3.13 on Ubuntu.

The MCP code targets the 2.x Python SDK, where FastMCP was renamed MCPServer (from mcp.server import MCPServer). Older tutorials that import mcp.server.fastmcp fail on 2.x.

What this does not do

  • No real CRM. crm_stub.py stands in for one. Many CRM APIs don't accept idempotency keys. If yours doesn't, read the current owner before writing, and reconcile timeouts before retrying.

  • Single machine only. SQLite with BEGIN IMMEDIATE serializes transitions on one machine. Several workers need a server database with row locks, or a durable workflow engine.

  • No auth, tenancy or secrets handling. The MCP server runs locally over stdio, for one user.

  • Synthetic policy. The rules, the order and the threshold are examples.

  • Exact-match dedupe. Duplicates are matched on normalized email only, with no fuzzy matching on names or companies.

  • No observability stack. Decisions and transitions are logged to the ledger. A production setup would also emit traces (OpenTelemetry, for example) and alert on failed or stuck cases.

A sensible path to production: run read-only on synthetic data (this repo), then shadow mode on live leads where you compare against human decisions, then human approval before every write, then automatic writes for one low-risk route, and expand from there.

Troubleshooting

  • warehouse/lead_routing.duckdb not found: run lead-routing build first.

  • Could not set lock on file: another process has the DuckDB file open for writing, usually a dbt build that's still running. The app opens the file read-only and closes it straight away, so retry once dbt finishes.

  • No module named 'mcp.server.fastmcp': you're running v1 example code against the v2 SDK. Use MCPServer as in mcp_server.py.

  • Claude Desktop doesn't show the tools: check that the path in the config is absolute, that it points at lead-routing-mcp inside .venv, and that you fully restarted Claude Desktop.

License

MIT. See LICENSE. Built by Meerkats.

Available Tools

6 tools
explain_routing_policyA
Read-onlyIdempotent

Return the ordered routing rules, the policy version and the enterprise threshold.

NameRequiredDescriptionDefault

No parameters

Output Schema

NameRequiredDescription

No output parameters

TDQS

A3.7/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly, idempotent, non-destructive, and closed-world, so the safety profile is fully covered. The description adds one useful behavioral detail – that rules are returned in order – and enumerates the returned components. Beyond that it adds little behavioral context, which is acceptable given the annotation coverage.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single tight sentence that front-loads the verb and packs the three returned artifacts without filler. Nothing to trim.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no inputs, full annotation coverage, and an output schema documenting the return shape, the description only needs to say what the tool is for, which it does. Minor gap: it doesn't say whose policy (enterprise scope) is returned, though the mention of 'enterprise threshold' implies it.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters, so there is nothing for the description to disambiguate. Baseline of 4 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb ('Return') and names the exact resources returned: ordered routing rules, policy version, and enterprise threshold. This clearly separates it from siblings like preview_route and get_routing_case. It stops short of explicitly contrasting itself with those siblings, which keeps it at 4 rather than 5.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no explicit 'use this when' guidance and no named alternatives, but the wording ('policy', 'threshold', 'version') implies this is a policy-introspection call rather than a route evaluation. The distinction from preview_route is left to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_lead_contextB
Read-onlyIdempotent

Return the normalized lead plus account, open opportunities, territory and source timestamps. Read-only.

NameRequiredDescriptionDefault
lead_idYes

Output Schema

NameRequiredDescription

No output parameters

TDQS

B3.3/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, destructiveHint=false and openWorldHint=false, so the trailing "Read-only" is largely redundant. The description does add scope value by enumerating the joined entities returned (account, open opportunities, territory, timestamps), which signals this performs several lookups, but it says nothing about behavior when a lead is missing or the result is partial.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences, zero waste, with the payload contents front-loaded and the safety note last. Nothing to cut.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Output schema exists, so return values need no prose. For a single-param read tool this is close to adequate, but it leaves open the lead_id format and the when-to-use boundary against five routing siblings — decisions an agent still has to guess at.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description carries the burden for lead_id and adds nothing — no format, no source-system hint. The parameter is self-evident by name and required, which keeps this at minimum-viable rather than failing.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

Specific verb+resource: returns a normalized lead plus its account, open opportunities, territory and source timestamps — an agent knows exactly what data it gets back. It does not, however, distinguish itself from routing siblings like get_routing_case or list_leads_for_routing, so the boundary must be inferred.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no guidance on when to call this versus the routing siblings, nor on prerequisites (does the lead need to be in a routing case first?). "Read-only" hints at safety but is not a usage condition.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_routing_caseA
Read-onlyIdempotent

Return a workflow case (status, decision, attempts, errors, audit events) by case ID, or all cases for a lead ID.

NameRequiredDescriptionDefault
case_or_lead_idYes

Output Schema

NameRequiredDescription

No output parameters

TDQS

A3.6/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, and destructiveHint=false, so safety is covered by structured data. The description adds the returned content categories, but nothing about missing-ID behavior, result caps when querying by lead ID, or ordering of audit events — meaningful gaps for a lookup tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single well-formed sentence that front-loads the verb and the dual-mode behavior, with the field list as a compact parenthetical. Nothing is wasted; it is perhaps slightly terse given the parameter ambiguity it resolves.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need not be spelled out, and the important dual-mode semantics are captured. The only shortfall is edge-case behavior (unknown ID, empty lead result) and result volume when querying by lead ID.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0% and the single parameter has an opaque name (case_or_lead_id); the description is what disambiguates it, explaining that a case ID yields one case while a lead ID yields all cases. That is real value beyond the schema, though no format examples are given.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb ("Return") plus a concrete resource (workflow case) and enumerates the payload fields (status, decision, attempts, errors, audit events). It does not explicitly contrast itself with siblings like explain_routing_policy or get_lead_context, but the retrieval purpose is unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It implies two usage modes (single case by case ID, all cases by lead ID), which is useful routing information. However, it never says when to prefer this over alternatives such as explain_routing_policy or get_lead_context, and no exclusions or prerequisites are stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_leads_for_routingB
Read-onlyIdempotent

List up to limit leads (max 100) with a one-line summary each. Read-only.

NameRequiredDescriptionDefault
limitNo

Output Schema

NameRequiredDescription

No output parameters

TDQS

B3.2/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare read-only, idempotent, and non-destructive behavior. The description adds useful behavioral context with the max 100 cap and one-line summary output shape, but it omits ordering, pagination, and what leads are included. It does not contradict the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is only two sentences and is front-loaded with the key list operation and cap. 'Read-only' is slightly redundant with the annotations, but the rest is efficient.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The output schema exists, so return values do not need explanation, and the annotations cover safety behavior. However, with five sibling tools in the routing workflow, the description does not explain when this list operation is the right choice versus get_lead_context or preview_route.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate for the single limit parameter. It states the max of 100, which is useful, but it does not mention the default value of 20 or what happens when limit is omitted, leaving partial coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: list leads, with a one-line summary each. It is clear what the tool does, but it does not distinguish itself from routing siblings like get_lead_context or preview_route.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The only usage-like statement is 'Read-only,' which restates the annotation rather than explaining when to use this tool. It gives no guidance on choosing between this and get_lead_context, preview_route, or the other routing tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

preview_routeB
Read-onlyIdempotent

Run the deterministic routing policy for one lead and return the decision. Does not write anywhere.

NameRequiredDescriptionDefault
lead_idYes

Output Schema

NameRequiredDescription

No output parameters

TDQS

B3.4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, and the description's 'does not write anywhere' plus 'deterministic' largely restate those hints rather than extending them. It is consistent, not contradictory, but adds little beyond what structured fields already say — no mention of state dependencies, expected cost, or what 'decision' contains.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences, zero filler, with the core action front-loaded and the non-writing constraint immediately after. Nothing to trim.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values needn't be explained, and with a single obvious parameter the description covers the essentials. The one remaining gap is the relationship to preview_route_with_country_hint, which an agent would need to pick correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0% for the single parameter, so the description must compensate. 'For one lead' loosely ties lead_id to a single lead, but it never explains the identifier format, whether it must exist first, or what happens when it doesn't. For a trivial one-parameter tool this is adequate but thin.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: run the deterministic routing policy for one lead and return the decision. It is clear what the tool does, but it never distinguishes itself from the near-identical sibling preview_route_with_country_hint, leaving the agent to infer the difference from the name alone.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no explicit when-to-use, when-not-to-use, or alternative named. The most important routing decision an agent faces here — choosing between preview_route and preview_route_with_country_hint — is left entirely unaddressed. Only a weak implied signal ('preview', 'does not write anywhere') suggests this is the plain dry-run variant.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

preview_route_with_country_hintA
Read-onlyIdempotent

Preview a route for a lead whose country is missing, using a country you inferred from its notes.

country_code must be a two-letter code; evidence must quote the text that supports it. The hint is validated, the normal policy runs on it, and the result is always marked for human review. Does not write anywhere.

NameRequiredDescriptionDefault
lead_idYes
evidenceYes
country_codeYes

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly/idempotent/non-destructive, so the bar is lower; the description adds real value by disclosing that the hint is validated, normal policy runs on it, and results are always marked for human review. The 'does not write anywhere' line is redundant with annotations but harmless.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the purpose, then gives the two constraint sentences, then the safety note. No wasted sentences; every line adds information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists so return values needn't be explained, and the description covers usage scope, param constraints, and validation/review behavior. Only lead_id's role is left implicit, a minor gap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 0% schema description coverage, the description must carry the burden, and it does for the two non-obvious params: country_code must be a two-letter code and evidence must quote the supporting text. lead_id is left implied as the target lead, kept from a 5.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (preview), resource (route), and the discriminating condition (a lead whose country is missing, using an inferred country hint). This clearly separates it from the sibling preview_route, which presumably assumes a known country.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly scopes usage to leads with a missing country, implying preview_route handles the normal case. It does not name the alternative tool outright or state when-not to use it, so it stops short of a full routing directive.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 6 tool updatesv0.1.0
    • First observedexplain_routing_policy
    • First observedget_lead_context
    • First observedget_routing_case
    • First observedlist_leads_for_routing
    • First observedpreview_route
    • First observedpreview_route_with_country_hint

TDQS

A3.7/5.0

Scored across 6 tools

Disambiguation4/5

The two preview tools overlap in purpose, but the country-hint variant is clearly scoped to missing-country leads with validation and human review. The remaining tools target distinct read operations: cases, policy, lead lists, and lead context.

Naming Consistency5/5

All tool names use consistent snake_case with predictable verb-led phrasing such as preview_route, get_routing_case, explain_routing_policy, and list_leads_for_routing. The one longer variant, preview_route_with_country_hint, still follows the same convention.

Tool Count5/5

Six tools is well-scoped for a focused lead-routing server. Each tool supports a distinct part of the read/preview/explain workflow without excessive surface area.

Completeness3/5

The server covers previewing decisions, inspecting cases, explaining policy, listing leads, and fetching lead context. However, it lacks any write or execution operation for actually routing a lead or creating/updating workflow cases, which is a notable gap for a routing system.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables agent clients to perform read-only regulatory retrieval through tools for searching the corpus, retrieving source text, tracing citations, listing authorities, and inspecting recent filings. It is designed to keep regulated actions and workspace changes behind human review gates.
    Apache 2.0
  • A
    license
    A
    quality
    B
    maintenance
    Enables AI assistants to search, de-duplicate and route leads in a demo CRM, with read-only mode and an audit log for accountability.
    9
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables Claude to answer seller questions from previously saved research using read-only tools for accounts, initiatives, intent signals, key people, knowledge retrieval, and guarded dataset queries. It supports multi-tenant, authenticated access with tenant isolation and enforced read-only security.
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Exposes lead-funnel tools with input/output schemas and structured content, so agents can triage inbound sales messages and pick a safe next action. Read-only hints and prompt-injection screening keep the tools constrained and untrusted text handled safely.
    7 npm
    MIT