Skip to main content
Glama
sinhasulabh

Meridian Commercial Intelligence MCP Server

by sinhasulabh

Meridian Commercial Intelligence

A trustworthy agentic system that answers natural-language questions about Q1 2026 sales pipeline data. Autonomy — planning, language understanding, dialogue — lives in a Google ADK orchestrator powered by Anthropic Claude. Every number it reports comes from a governed, deterministic MCP tool server over DuckDB, returned with the query and rows that produced it. A thin, executive-grade React client renders the answer with its confidence stamp and full source trace.

Built against REQUIREMENTS-v2.md in this repo — that document is the full spec; this README is the map and the honest account of what shipped.

Table of contents

Related MCP server: StratoForce MCP Server

The trust thesis

A prior version of this tool lost executive confidence because a language model produced numbers, and it produced wrong ones in public. Going agentic does not relax that — it relocates the trust boundary to the tool contract and the orchestrator's system prompt, and it holds two tiers apart:

┌────────────────────────────────────────────────────────────────┐
│  AUTONOMOUS TIER (may be wrong, must be honest)                 │
│  ADK orchestrator on Claude — NL understanding, planning,       │
│  dialogue. Contains an LLM. Bound by system-prompt invariants.  │
└────────────────────────────────────────────────────────────────┘
                       │ MCP tool calls (typed, validated)
                       ▼
┌────────────────────────────────────────────────────────────────┐
│  GOVERNED TIER (cannot be wrong, has NO LLM)                    │
│  governed/ = semantic layer + gates + DuckDB engine.             │
│  Pure deterministic compute. Returns value + stamp + receipt.   │
└────────────────────────────────────────────────────────────────┘

The trusted tier contains no model at all. governed/ never imports agent/, never calls an LLM, and is fully unit-testable on its own — that's tests/test_engine.py and tests/test_gates.py, and neither needs a network connection or an API key.

Ten invariants (REQUIREMENTS-v2.md §1.1) hold this together. The two that matter most for reading this codebase:

  • No model-authored numbers. Every figure in an answer must appear verbatim in a tool result. The agent's system prompt (agent/prompts.py) makes this the first rule, and Tier B evals check the model actually followed it.

  • Abstention is terminal. When data can't support an answer, a tool returns cannot_verify and that's the end of it — not a retry trigger, not a chance for the model to fill the gap.

The Ironbridge case

The canonical regression test, at every layer: "Why did we lose Ironbridge?" OPP-008 is Closed Lost, Enterprise, $195,000 — and loss_reason is empty in the source data. The correct answer is "the record exists, it was lost, and no reason was recorded." Nothing else.

  • Tool layer (governed/engine.py::get_deal_reason): detects the empty field and returns stamp: cannot_verify, never a fabricated cause. Pinned by test_ironbridge_refuses_without_inventing_a_reason (Tier A).

  • Agent layer (agent/prompts.py): the system prompt names this case explicitly and instructs the model to relay the refusal, never to supply a cause of its own. Pinned by test_ironbridge_final_answer_invents_no_cause (Tier B).

  • UI layer (ui/src/components/ConfidenceBadge.tsx): renders the brick cannot_verify badge, and the source trace shows the actual row with its empty loss_reason field.

Why this design

Why ADK + MCP, on Claude, instead of one model doing everything? Because the failure mode this system exists to prevent — a model inventing a number — has to be structurally impossible, not prompt-engineered away. Putting the governed tools behind MCP means the model never sees a code path where it could compute a figure itself; it can only call a tool and relay what comes back. The inner NL→spec translator from the prior version is deleted, not relocated — ADK's native Claude function-calling is the translation layer now, and the translation step never touches the numbers.

Why DuckDB, given the data is 85 rows? At this scale the engine choice is irrelevant to performance, so it's made on the trust axis instead. DuckDB's receipt is an executable, portable SELECT — an analyst can copy the string out of the source trace and run it against the source CSVs to reconcile a figure by hand (INV-7: the SQL in the receipt is the literal string that ran, never a reconstruction). The same SQL dialect scales to a real warehouse, so the prototype and the production data layer are the same choice, not a migration waiting to happen.

How INV-8/INV-9 defend the boundary. A governed tool being correct doesn't help if the model is dishonest about what it returned — that's exactly the shape of the original failure, and it can re-enter through the agent's mouth even with perfect tools underneath. Two mechanisms close that gap:

  • INV-8 (stamp/figure fidelity): the system prompt forbids upgrading assumption or cannot_verify into confident prose, and forbids introducing any number a tool didn't return.

  • INV-9 (receipt propagation): every tool result's receipt travels with the agent's answer, through agent/server.py's /run response, into the UI's source-trace panel. A figure three hops deep is still traceable back to the exact query that produced it.

Architecture

Code boundaries vs. deployment boundaries

The code is factored into three tiers regardless of how it's deployed — that's what makes MCP a real seam rather than decoration:

meridian-agentic/
├── governed/       # GOVERNED TIER — no LLM, no ADK, no UI imports
│   ├── semantic.py     # metric definitions, defined exactly once
│   ├── engine.py       # DuckDB load + the 5 governed executors
│   ├── gates.py        # arg validation, access-scope resolution, invariant post-checks
│   └── models.py       # Pydantic ToolResult / Receipt (the envelope every tool returns)
├── mcp_server/      # wraps governed/ as MCP tools (FastMCP-equivalent MCPServer)
├── agent/           # ADK LlmAgent on Claude — the only LLM in the system
│   ├── agent.py         # tool wrappers (viewer injected via ToolContext, never LLM-visible)
│   ├── prompts.py       # the trust guardrail system prompt
│   └── server.py        # to_a2a() + the UI's /run endpoint, one ASGI app
├── ui/              # thin React (Vite) exec client — no business logic, no LLM key
├── data/            # deals.csv, reps.csv — the only source of truth
└── tests/           # Tier A (hard gate) + Tier B (faithfulness) evals

Demo topology — 2 deployables

  Executives ──►  Thin React UI (nginx-on-Cloud-Run)         [deployable #1]
                       │ HTTPS → agent /run (CORS-locked)
                       ▼
  A2A peers ──►  ADK Agent service (LlmAgent on Claude)      [deployable #2]
                       │ governed tools attached IN-PROCESS as ADK FunctionTools
                       ▼  (in-process call — no network hop)
                 governed/ tier — no LLM
                       ▼
                 DuckDB (in-memory) over data/*.csv

The governed tools run in the agent process for the demo (agent/agent.py registers the governed/engine.py functions directly as ADK FunctionTools — the spec's "simplest" option). mcp_server/server.py still exists as fully separate, independently-runnable code with no import from agent/ — it's just not the wiring the demo agent uses.

Why co-located isn't a corner cut: the governed functions underneath are identical either way. Promoting to the production topology means changing agent/agent.py's tool list from the direct-FunctionTool wrappers to an MCPToolset pointed at a deployed mcp_server/, and nothing in governed/ changes. That's a wiring change, not a rewrite — which is the entire point of having drawn the tier boundary before touching the deploy story.

Production topology — 3 services

  UI (static) ──►  ADK Agent service ──MCP (Streamable HTTP, authed)──►  MCP Server service

mcp_server/server.py deploys as its own Cloud Run service (mcp_server/Dockerfile), reachable over Streamable HTTP, independently callable by any MCP client — not just this agent. See Deployment.

Running it locally

Governed tier + Tier A evals (no API key, no network)

uv sync
uv run pytest tests/test_engine.py tests/test_gates.py tests/test_tool_determinism.py -v

This is the hard gate. If it's not green, nothing downstream is trustworthy enough to run.

The agent, locally

export ANTHROPIC_API_KEY=sk-ant-...
export UI_ORIGIN=http://localhost:5173
uv run uvicorn agent.server:app --reload --port 8080

agent/server.py is one ASGI app exposing:

  • POST /run{question, viewer, session_id?}{answer, stamp, receipts[], session_id}, the contract the React UI speaks.

  • GET /.well-known/agent-card.json — the auto-generated A2A agent card (from to_a2a()).

  • GET /livez — liveness check. Named /livez rather than the more common /healthz because on Cloud Run's *.run.app domains, GFE (the edge in front of the container) reserves /healthz for its own internal convention and never forwards it to the app.

Without a key, the agent process will fail to make model calls — there is deliberately no LLM fallback for figures (spec §13.5): if the model is unreachable, the intent is an honest refusal, never a guessed number. To exercise the governed tools without any model, call mcp_server/server.py directly (see below) or hit governed/engine.py's functions from a Python shell — both paths are model-free by construction.

Dev/debug alternative: uv run adk web agent gives ADK's own tool-call-chain visualizer. It is not the executive-facing surface and isn't part of the demo — the React UI is.

The MCP server, standalone

uv run python -m mcp_server.server                 # stdio (demo transport)
MCP_TRANSPORT=streamable-http uv run python -m mcp_server.server   # production transport

Any MCP client can call the five tools directly this way, with no agent in the loop. Every tool requires viewer as an explicit argument here ("LEADERSHIP" or a rep_id like "REP-02") — unlike the agent's LLM-facing schema, this is the self-sufficient governed surface, so it has to take the real argument (see Access control for why the agent's version doesn't).

The UI, in dev

cd ui
npm install
npm run dev   # http://localhost:5173, expects the agent at http://localhost:8080

Set VITE_AGENT_URL (ui/.env or the shell) to point at a different agent instance. The UI never holds the Anthropic key and never calls the MCP server directly (spec §11A) — it only knows the agent's /run endpoint.

The eval suite (what gates a deploy)

Two tiers, mirrored in .github/workflows/deploy.yml:

Tier A — governed-tool determinism (hard deploy gate; no LLM, no network). tests/test_engine.py, tests/test_gates.py, tests/test_tool_determinism.py. Calls the actual MCP tool surface (not just the raw functions) against tests/golden_tool_evals.yaml, and asserts:

Tool call

Stamp

Figure

get_segment_attainment("Enterprise")

assumption

58.6% ($2,050,000 / $3,500,000)

get_segment_attainment("Mid-Market")

assumption

56.4% ($1,100,000 / $1,950,000)

get_segment_attainment("SMB")

assumption

58.5% ($275,000 / $470,000)

get_reps_at_risk()

assumption

7 of 10 below 70%

get_pipeline_value(close_before="2026-03-31")

assumption

$1,301,000

get_pipeline_value()

verified

$4,311,000

get_deal_reason("Ironbridge")

cannot_verify

refuses — loss_reason empty

get_deal_reason("Fulcrum Enterprises")

verified

"Competitor - Salesforce"

Plus the access-scoping cases: a scoped rep (viewer="REP-02") gets only their own contribution (never the org-level figure, by any phrasing — the filter lives in query construction), an unknown/blank viewer fails closed, and LEADERSHIP is unrestricted. Also asserted: calling any tool twice with identical arguments returns byte-identical results (INV-6), and every receipt's sql field is non-empty.

Gate rule: this suite green, or no deploy. It runs in ~1 second and needs nothing but uv.

Tier B — orchestrator faithfulness (needs a live Claude call). tests/test_agent_faithfulness.py, skipped locally unless ANTHROPIC_API_KEY is set, and run as its own CI job against anthropic/claude-haiku-4-5-20251001 to keep cost down. Asserts the final agent answer — not just the tool result — honors the invariants: no fabricated Ironbridge cause, forecast questions refused as out-of-scope, a segment-attainment answer's figure matches the tool's exactly, a compound comparison calls both tools and self-computes nothing, and access forwarding holds (a scoped rep's final answer never contains the org-level figure). A Tier B failure blocks the agent-service deploy.

Access control

Model: authenticate high, authorize low. Identity is claimed at the UI's login screen (no password — a stubbed claim, spec §11B); authorization is enforced in the governed tier as a mandatory SQL predicate. The LLM is never in the access path.

Mechanically, in agent/agent.py: every tool wrapper takes tool_context: ToolContext instead of viewer: str. ADK detects the ToolContext-typed parameter and (a) excludes it from the JSON schema the model sees — confirmed by inspecting the generated function declarations, none of which contain viewer — and (b) injects the real session object at call time. The wrapper reads tool_context.state["viewer"], populated by agent/server.py from the authenticated login identity on every /run call, and forwards it unchanged into governed/engine.py. The model cannot see it, set it, or be prompt-injected into changing it, because there is no parameter for it to act on.

Enforcement, in governed/gates.py::resolve_viewer + scope_predicate: "LEADERSHIP" gets no filter; a known rep_id gets AND rep_id = ? injected into every query the engine builds, applied to both sides of a ratio (a scoped rep's segment attainment is their own won ÷ their own quota, not their contribution to the segment total); anything else — unknown identity, blank, a segment they don't belong to being asked about — fails closed: an empty cannot_verify result, never full data. The applied scope is written into receipt.assumptions (e.g. "Scoped to your deals (REP-02); org-level figures are restricted to leadership"), so the access boundary is itself part of the auditable receipt.

The honest stub: the login screen's identity is unauthenticated and therefore spoofable — anyone can type REP-02 or LEADERSHIP. That is the deliberate simplification for this demo. Swapping it for a real IdP that sets a verified rep_id claim changes only where viewer originates (an auth middleware in front of agent/server.py's /run endpoint instead of a login form); it does not touch resolve_viewer, scope_predicate, or anything in governed/engine.py — the same promote-without-rewrite pattern as the MCP seam.

A2A and calling the MCP tools directly

agent/server.py builds its ASGI app from google.adk.a2a.utils.agent_to_a2a.to_a2a(root_agent), which auto-generates the agent card at /.well-known/agent-card.json and the A2A JSON-RPC endpoint. Any A2A-aware peer (another ADK agent, Gemini Enterprise, a different framework entirely) can discover the card and delegate pipeline questions without going through the React UI at all.

To call the governed tools with no agent in the loop, run mcp_server/server.py (stdio or Streamable HTTP per above) and connect any MCP client to it — list_supported_questions is a reasonable first call to confirm the connection and see the capability set.

Personalizing the UI

Everything client-specific lives in ui/config.ts: BRANDING (client name, title line, context line, tagline), the stubbed REP_ROSTER login identities, and SUGGESTED_QUESTIONS (the chips, including the dashed Ironbridge trap). VITE_AGENT_URL points the build at a specific agent deployment. Re-skinning for a new engagement is editing this one file and rebuilding — no component code changes.

Deployment

CI (.github/workflows/deploy.yml) on push to main: ruffTier A → (in parallel) build the UI bundle and run Tier B → build + push both container images → deploy. No deploy if Tier A fails; a Tier B failure blocks the agent-service deploy specifically. Auth to GCP is keyless (Workload Identity Federation) — no JSON key ever lives in this public repo.

  • Agent service: agent/Dockerfile, non-root, uv-managed, runs uvicorn agent.server:app. ANTHROPIC_API_KEY is injected from Secret Manager at deploy time — it is never baked into the image and never present anywhere but this one service.

  • UI: ui/Dockerfile, multi-stage (npm run build → static nginx), VITE_AGENT_URL passed as a build arg pointing at the deployed agent URL.

  • MCP server (production only): mcp_server/Dockerfile, not deployed in the demo topology. Splitting it out is documented above under Architecture and is a config change to agent/agent.py's tool wiring, not a rewrite.

Enterprise alternative: deploy the agent to Vertex AI Agent Engine instead of raw Cloud Run for managed scaling/registry.

Scope cuts

Deliberate, not oversights (spec §5.2):

  • Read-only. No write-back to any system of record.

  • No auth/user management beyond Cloud Run IAM, MCP-server auth (production only), and the UI↔agent CORS lock — the login screen's identity is a stub, documented as one above.

  • No forecasting, and no "why" beyond a stored loss_reason — the Ironbridge case is the canonical example of exactly the boundary this draws.

  • Data ships as CSVs; no live warehouse connector.

  • Exactly five governed metrics. Anything else is a navigational refusal via list_supported_questions, not an approximation.

  • The UI is intentionally thin: ask, answer, verify. No dashboards, saved views, or exports.

What this proves, and what it doesn't

Proves: that an LLM can sit in the planning/dialogue loop of a numbers-reporting tool without ever being the source of a number — the governed tier is fully independent, unit-tested without any model, and every figure the agent relays is traceable through a receipt back to an executable SQL statement. That access control can be enforced without putting the model anywhere near the enforcement path. That the trust properties survive an extra hop (agent → A2A → external caller, or agent → UI) because the receipt is carried as data, not re-derived at each hop.

Doesn't prove: that Claude's tool-selection is perfect on arbitrary phrasing — Tier B checks specific canonical and adversarial-ish questions, not exhaustive phrasing coverage. That the login screen is a real authentication system — it isn't, by design, and the README says so rather than letting the UI imply otherwise. That this scales past a demo dataset — DuckDB and an in-memory 85-row load are the right choice for this exercise specifically, with an explicit note about what changes (warehouse connection string, nothing else in the SQL) if it didn't.

Versions

Pin exact versions at build time; re-verify against current docs before a real deployment. Installed in this repo's uv.lock at the time of writing: google-adk==2.5.0, mcp==2.0.0 (its FastMCP is now mcp.server.MCPServer — same tool-decorator shape, see mcp_server/server.py's module docstring), litellm==1.94.0, a2a-sdk per pyproject.toml, Python 3.12, React 18 + Vite 5. Default model: anthropic/claude-haiku-4-5-20251001 (MODEL_ID env var; set to anthropic/claude-sonnet-5 for an exec demo). References:

Available Tools

5 tools
get_deal_reasonA

The stored loss_reason for one account, verbatim. Refuses if empty.

Args:
    account_name: The account to look up.
    viewer: "LEADERSHIP" or a rep_id. Required.
ParametersJSON Schema
NameRequiredDescriptionDefault
viewerYes
account_nameYes

Output Schema

ParametersJSON 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?

No annotations are provided, so the description carries the behavioral disclosure burden. It does disclose that the tool 'refuses if empty' and returns the reason 'verbatim', which are useful behavioral details. However, it does not explicitly state read-only status, permission requirements, or error handling for invalid account_name/viewer, leaving gaps.

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?

The description is extremely concise—two short sentences plus an Args list—and front-loads the core purpose. Every sentence earns its place, with no redundancy or fluff. The structure is clean and immediately scannable.

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?

The tool is simple with only two parameters and an output schema, so the description does not need to detail return values. It covers the main behavior, parameter meanings, and an important edge case (empty refusal). It lacks broader usage context or explicit safety statement, but for a simple read tool, it is largely complete.

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 Args section adds meaning beyond the bare schema: account_name is described as 'The account to look up' and viewer as 'LEADERSHIP or a rep_id. Required.' This compensates for the schema's 0% description coverage and clarifies the expected format for viewer. The descriptions are concise but valuable.

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 clearly identifies the resource (stored loss_reason) and scope (one account), and the tool name includes 'get'. It differs from sibling tools by focusing on a specific deal/account reason rather than segment attainment, reps at risk, pipeline value, or supported questions. It lacks an explicit verb, but the intent 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?

The description implies usage via 'for one account' and 'Refuses if empty', but it does not explicitly state when to use this tool versus alternatives, nor does it mention any exclusions or alternative tools. It offers only implied context, so it meets the 'implied usage' level.

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

get_pipeline_valueA

Sum of open-stage deal_value, optionally filtered.

Args:
    viewer: "LEADERSHIP" or a rep_id. Required.
    segment: Optional segment filter.
    close_before: Optional ISO date; keeps deals with close_date <= this.
ParametersJSON Schema
NameRequiredDescriptionDefault
viewerYes
segmentNo
close_beforeNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

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

With no annotations provided, the description carries the full burden of behavioral disclosure. It clearly explains the calculation logic, the meaning of 'open-stage', and the exact filter semantics (e.g., close_before keeps deals with close_date <= the given date). This makes the tool's behavior transparent.

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?

The description is concise and well-structured: a one-line summary followed by a bulleted Args list. Every sentence provides essential information, with no redundancy or filler.

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

Completeness5/5

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

Given the tool's simplicity, the description covers the computation, all parameters, and filter semantics. The presence of an output schema means return-value details need not be in the description. This is fully adequate for an agent to invoke the tool correctly.

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

Parameters5/5

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

Schema coverage is 0%, but the description fully compensates by explaining each parameter: viewer must be 'LEADERSHIP' or a rep_id and is required; segment is an optional filter; close_before is an optional ISO date with an exact comparison rule. This adds substantial meaning beyond the raw schema.

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?

The description clearly states the tool computes a sum of open-stage deal_value with optional filters. It uses a specific verb ('Sum') and resource ('deal_value'), distinguishing it from sibling tools like get_segment_attainment or get_reps_at_risk.

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?

The description provides clear context for when to use the tool (computing pipeline value) and explains optional filters, but it does not explicitly name alternatives or when-not-to-use conditions. The context is unambiguous, so it earns a 4 rather than a 5.

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

get_reps_at_riskA

Reps whose Q1 2026 closed-won attainment is below threshold.

Args:
    viewer: "LEADERSHIP" or a rep_id. Required.
    threshold: Attainment cutoff in [0.0, 1.0]. Defaults to 0.70.
ParametersJSON Schema
NameRequiredDescriptionDefault
viewerYes
thresholdNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A3.7/5.0
Behavior2/5

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

With no annotations, the description carries the full burden of behavioral disclosure. It explains the core filtering logic and parameter roles, but omits important behavioral traits such as how the viewer parameter affects data scope (e.g., whether a rep_id returns only that rep's data vs a leadership view of all reps), access permissions, auth requirements, or error behavior.

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?

The description is concise and well-structured: two sentences for the main purpose, followed by a clear Args section. Every sentence provides necessary information, with no redundancy or filler.

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?

Given the tool's modest complexity and the presence of an output schema, the description covers the essential function and parameters. However, it lacks details on viewer role semantics (e.g., what data a rep_id viewer can access) and potential edge cases, leaving some contextual ambiguity for an agent deciding when and how to invoke the tool.

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 description coverage is 0%, so the description must compensate. It does so effectively by defining viewer as 'LEADERSHIP' or a rep_id and threshold as a numeric cutoff in [0.0, 1.0] with a default of 0.70, adding meaning beyond the raw schema types.

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?

The description clearly states the tool returns reps whose Q1 2026 closed-won attainment is below a threshold, using a specific verb and resource. It distinguishes itself from sibling tools like get_segment_attainment and get_pipeline_value by focusing on rep-level at-risk status based on attainment.

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?

The description implies usage context through the threshold and viewer parameters, but does not explicitly state when to use this tool versus alternatives. It provides no exclusions or references to sibling tools, leaving the agent to infer applicability from the functional definition.

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

get_segment_attainmentA

Q1 2026 closed-won attainment vs. quota for one segment.

Args:
    segment: One of "Enterprise", "Mid-Market", "SMB".
    viewer: "LEADERSHIP" or a rep_id (e.g. "REP-02"). Required.
ParametersJSON Schema
NameRequiredDescriptionDefault
viewerYes
segmentYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.3/5.0
Behavior3/5

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

No annotations are provided, so the description carries the transparency burden. It provides useful behavioral details such as allowed values for segment and viewer, and marks viewer as 'Required.' However, it does not disclose error handling, authorization implications of the viewer parameter, or explicitly state that this is a read-only operation, leaving some ambiguity.

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?

The description is extremely concise and well-structured. The main purpose is front-loaded in a single line, followed by a clean arguments block. Every sentence adds value, with no redundant or wasted words.

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?

The tool has an output schema, so return values are covered elsewhere. The description provides the time period, allowed segment values, and viewer types, which covers the essential context for a simple two-parameter tool. However, it leaves the purpose of the viewer parameter slightly ambiguous (e.g., whether it is for permission filtering or data scoping), which could be clearer.

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

Parameters5/5

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

Schema description coverage is 0%, so the description fully compensates. It explains both parameters: segment (one of three named values) and viewer (either 'LEADERSHIP' or a rep_id like 'REP-02,' required). This adds essential meaning beyond the bare string types in the schema.

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?

The description clearly states the tool's function: 'Q1 2026 closed-won attainment vs. quota for one segment.' This is a specific verb-resource combination with scope (one segment) and time period, effectively distinguishing it from sibling tools that focus on reps at risk, pipeline value, deal reasons, and supported questions.

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?

The description implies usage context by stating 'for one segment,' which suggests using this tool when segment-level attainment data is needed. It does not explicitly name alternatives or exclusions, but the context is clear enough that an agent would understand its purpose relative to sibling tools, which have different focuses.

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

list_supported_questionsB

The governed capability set — what this system can and can't answer.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON 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?

The phrase 'can and can't answer' usefully reveals that the tool covers both supported and unsupported questions, which goes beyond the name. However, with no annotations available, the description carries the full transparency burden and does not explicitly state that this is a read-only operation or describe the output format.

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, concise sentence with no filler. The dash creates a clear appositive, and every word contributes meaning, achieving maximum efficiency.

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 tool is simple and has an output schema, so the description need not explain return values. However, the vague phrasing and lack of usage guidance make it only minimally complete for an agent to understand when and why to call this tool.

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 has zero parameters, so schema coverage is effectively 100%. The description adds no parameter semantics, but none are needed; baseline score for zero-parameter tools is 4.

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

Purpose3/5

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

The description's 'governed capability set' is vague and does not explicitly state that the tool lists supported questions, but the tool name makes the function clear. It does differentiate from sibling data-retrieval tools by focusing on system capabilities rather than specific metrics.

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?

No guidance is provided about when to use this tool versus alternatives. The description lacks any context about discovering capabilities before querying or any comparison with the sibling tools, leaving the agent without decision criteria.

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. 5 tool updatesv0.1.0
    • First observedget_deal_reason
    • First observedget_pipeline_value
    • First observedget_reps_at_risk
    • First observedget_segment_attainment
    • First observedlist_supported_questions

TDQS

A3.9/5.0

Scored across 5 tools

Disambiguation5/5

Each tool addresses a distinct commercial intelligence query: segment attainment, at-risk reps, pipeline value, deal loss reason, and capability listing. There is no overlap in purpose, making selection unambiguous.

Naming Consistency4/5

The majority of tools follow a 'get_' + object pattern (get_segment_attainment, get_reps_at_risk, get_pipeline_value, get_deal_reason), but 'list_supported_questions' deviates by using 'list_' instead. Minor inconsistency, otherwise predictable.

Tool Count5/5

Five tools is well-scoped for a commercial intelligence server. Each tool covers a distinct capability without bloat, and the count is appropriate for the domain.

Completeness4/5

The coverage includes key metrics (attainment, risk, pipeline, loss reasons) and a self-describing capability list. However, some common queries like win rate or quota details are absent, presenting minor gaps that agents may need to work around.

Maintenance

ActivitySlowing
ResponsivenessNo issues

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

  • F
    license
    A
    quality
    D
    maintenance
    Enables users to query enterprise sales data from a local SQLite database and investigate anomalies through an inline dashboard with human-in-the-loop review buttons.
    3
    -
  • F
    license
    Not graded
    quality
    C
    maintenance
    Enables querying and interacting with a SQLite CRM database of sales leads using natural language, offering tools for pipeline summaries, lead search, and weighted forecasting.
    -
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables natural language querying of a sales SQLite database. Provides read-only SQL execution and database statistics tools, allowing AI to answer sales questions using everyday Japanese.
    MIT