Lead Routing MCP Server
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Lead Routing MCP Serverpreview routing for lead L-004 and explain why it needs review"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Lead routing with context, rules and state
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.

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 ( | Ordered, versioned rules. Returns |
Workflow state | SQLite ledger ( | One case per lead, input fingerprint and policy version. Approvals, retries and an audit trail. |
Assistance | MCP server ( | Six read-only tools: list, inspect context, preview, preview with a model-suggested country, inspect a case, explain the policy. |
Side effects | Fake CRM ( | 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 buildDone. PASS=26 WARN=0 ERROR=0 SKIP=0 NO-OP=0 REUSED=0 TOTAL=26Check every lead against the expected outcomes in data/expected_outcomes.csv:
lead-routing evallead_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):
pytest52 passedWalk through the workflow
Route every lead and record a case for each:
lead-routing route-alllead_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-writesapply 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_7d1153cab4There'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 trailRouting rules

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 |
| Up to 100 leads with a one-line summary each |
| Normalized lead, account, open opportunities, territory, source timestamps, and the lead's notes labelled |
| The policy decision plus whether the ledger already has a case for it |
| A decision using a country the assistant inferred from the notes. Validated against the allowed list, quoted evidence required, always |
| Case status, attempts, errors and audit events |
| 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 testsMore 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 |
|
|
|
|
|
|
|
|
|
|
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.pystands 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 IMMEDIATEserializes 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: runlead-routing buildfirst.Could not set lock on file: another process has the DuckDB file open for writing, usually adbt buildthat'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. UseMCPServeras inmcp_server.py.Claude Desktop doesn't show the tools: check that the path in the config is absolute, that it points at
lead-routing-mcpinside.venv, and that you fully restarted Claude Desktop.
License
Available Tools
6 toolsexplain_routing_policyARead-onlyIdempotent
Return the ordered routing rules, the policy version and the enterprise threshold.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
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.
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.
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.
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.
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.
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_contextBRead-onlyIdempotent
Return the normalized lead plus account, open opportunities, territory and source timestamps. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| lead_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
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.
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.
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.
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.
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.
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_caseARead-onlyIdempotent
Return a workflow case (status, decision, attempts, errors, audit events) by case ID, or all cases for a lead ID.
| Name | Required | Description | Default |
|---|---|---|---|
| case_or_lead_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
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.
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.
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.
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.
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.
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_routingBRead-onlyIdempotent
List up to limit leads (max 100) with a one-line summary each. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
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.
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.
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.
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.
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.
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_routeBRead-onlyIdempotent
Run the deterministic routing policy for one lead and return the decision. Does not write anywhere.
| Name | Required | Description | Default |
|---|---|---|---|
| lead_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
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.
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.
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.
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.
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.
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_hintARead-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.
| Name | Required | Description | Default |
|---|---|---|---|
| lead_id | Yes | ||
| evidence | Yes | ||
| country_code | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
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.
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.
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.
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.
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.
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.
6 tool updates
v0.1.0- First observed
explain_routing_policy - First observed
get_lead_context - First observed
get_routing_case - First observed
list_leads_for_routing - First observed
preview_route - First observed
preview_route_with_country_hint
TDQS
Scored across 6 tools
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.
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.
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.
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
Related MCP Connectors
Read-only finance and operations controls for AI agents with evidence and safe next actions.
Read-only sales CRM for AI clients: leads, pipeline, AI-agent chats, calls, ad attribution.
Read-only AI coding tools for change verification, release readiness, capacity, and guidance.
Read-only checks for proposed orders against evidence and policy; no trading or payment authority.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables 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
- AlicenseAqualityBmaintenanceEnables AI assistants to search, de-duplicate and route leads in a demo CRM, with read-only mode and an audit log for accountability.9MIT

nextQ MCP serverofficial
AlicenseNot gradedqualityCmaintenanceEnables 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- AlicenseNot gradedqualityCmaintenanceExposes 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 npmMIT