tender-radar-mcp
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., "@tender-radar-mcpWhich open UK tenders fit a 50-person data consultancy?"
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.
Tender Radar
A Public Tender Intelligence Agent: unified UK + EU procurement data, served to AI agents through a governed MCP server, proven by an eval suite.
Ask it "Which open tenders fit a 50-person UK data consultancy?" and it answers with ranked matches and cited source links — through any MCP-capable AI client, MCP Inspector, or the bundled CLI agent.
The problem
Public-sector contracts are a huge market that small and mid-sized companies systematically miss, for a mundane reason: the notices are scattered.
The UK publishes above-threshold tenders on Find a Tender and lower-value ones on Contracts Finder — in OCDS format, and often the same tender appears on both portals with different IDs.
The EU publishes on TED — in a completely different standard (eForms), across 24 languages.
An SME bid team can't watch three portals in two data standards. And if you put an LLM on top of raw data, you trade one problem for another: agents that write their own SQL produce confident, wrong numbers — silently adding euros to pounds, averaging framework ceilings into contract values, citing tenders that don't exist.
Tender Radar solves both halves: one unified dataset and an agent that can only query it through governed, tested paths.
Related MCP server: oro-intel-mcp
What it does
Capability | How |
Unifies 3 portals, 2 standards | One OCDS-shaped schema; one mapper per standard |
Deduplicates | Lifecycle grouping by OCDS |
Serves agents | MCP server (stdio) with 5 tools + a discoverable semantic-layer resource |
Governs queries | Agents aggregate only via |
Matches companies | YAML company profiles (Pydantic-validated) ranked against open tenders with reasons |
Proves it works | 52 agent evals with SQL-derived gold answers, incl. governance negatives and prompt-injection tests |
Architecture overview
UK Find a Tender UK Contracts Finder EU TED
(OCDS releases) (OCDS releases) (eForms API)
│ │ │
└───────── one OCDS mapper ──────────── eForms mapper
│ │
▼ ▼
Python ingest → data/raw/{source}.parquet
(idempotent merge, keyed per notice)
│
▼
dbt on DuckDB
staging (views) → core (notices, tenders, CPV) → marts
│
fct_tenders ← enforced model contract
│
┌─────────────────────┼─────────────────────┐
▼ ▼ ▼
semantic layer MCP server (stdio) dedupe matcher
(YAML → SQL 5 tools, 1 resource, links + confidence,
compiler) NO free-SQL tool measured P/R
│
▼
any MCP client: desktop AI apps,
MCP Inspector, or the CLI agent
(Gemini Flash, swappable)
│
▼
evals: 52 questions, SQL gold
answers, frozen 511-notice fixtureThe flow in words: Python clients fetch each portal and map every notice
into one UnifiedNotice schema, merging idempotently into per-source Parquet.
dbt builds the warehouse in textbook layers — staging views per source, a
core layer that groups a tender's lifecycle notices (planning → tender →
award) by their shared ocid, and a single mart (fct_tenders) protected by
an enforced dbt contract. On top of that mart sit three consumers: a
hand-rolled semantic layer that compiles declared metrics to SQL, the MCP
server that exposes everything agents may do, and the cross-portal matcher
that links the same tender across UK portals. Deep dive: ARCHITECTURE.md,
decisions: docs/adr/.
Design invariants:
Governance lives in the server, not the agent. There is no tool that accepts SQL, so no client — however prompted or jailbroken — can bypass the semantic layer (ADR-0001).
The clock is injectable (
TENDER_RADAR_TODAY), so "open tender" and "deadline within 7 days" mean the same thing on live data and the frozen test fixture.Money is guarded. Value metrics refuse to mix currencies and exclude framework ceilings by default — the YAML documents both rules.
Tender text is data, not instructions. Descriptions are third-party input; prompt-injection evals against a planted hostile tender verify the agent treats them that way.
Tech stack
Layer | Technology | Why |
Language | Python 3.12, | Fast, reproducible env management |
Ingestion |
| Typed unified schema at the edge |
Storage | Parquet + DuckDB | Zero-infra analytical warehouse |
Transform | dbt ( | Layered models, tests, contracts, source freshness |
Semantic layer | Hand-rolled YAML + compiler | Governance legible in one file (ADR-0003) |
Agent interface | MCP Python SDK (stdio) | Works with MCP Inspector and any MCP-capable client |
LLM | Gemini Flash via | Free tier; swappable behind a 3-method protocol |
CI/CD | GitHub Actions | Tier-1 checks per push; on-demand data refresh + LLM evals |
Data persistence | GitHub Release assets | No credentials, one-command download (ADR-0004) |
Lint/test | ruff, pytest | 42 deterministic tests incl. the eval scorer itself |
Project structure
tender-radar/
├── src/tender_radar/
│ ├── config.py # paths + the injectable clock (TENDER_RADAR_TODAY)
│ ├── profiles.py # Pydantic company profiles (YAML + generated JSON Schema)
│ ├── ingest/ # source clients, mappers, idempotent parquet store
│ │ ├── models.py # UnifiedNotice — the one schema everything maps into
│ │ ├── ocds.py # shared mapper for both UK portals
│ │ ├── ted.py # eForms → unified mapper (the cross-standard one)
│ │ └── store.py # keyed merge: reruns never duplicate
│ ├── dedupe/ # cross-portal matcher (blocking + scoring + links)
│ ├── semantic/ # layer.yaml (the governed surface) + SQL compiler
│ ├── mcp_server/ # stdio MCP server: 5 tools, semantic://layer resource
│ └── agent/ # ~100-line loop + swappable LLM provider
├── dbt/ # staging → core → marts; CPV seed; contracts
├── profiles/ # company profiles as data (+ JSON Schema)
├── evals/ # 52 questions, SQL golds, harness, dedupe labels
├── fixtures/ # frozen 511-notice eval fixture (script-built)
├── scripts/ # fixture builder, matcher evaluation, schema gen
├── tests/ # 42 deterministic tests (tier 1)
├── .github/workflows/ # ci.yml (every push) + data-refresh.yml (on demand)
├── ARCHITECTURE.md # diagrams and component walkthrough
├── docs/adr/ # six architecture decision records
└── DATA_LICENSE.md # OGL v3 / EU reuse attributionUse it right now — no install
The server is hosted as a public MCP connector:
https://tender-radar-lime.vercel.app/mcpAdd it in Claude → Settings → Connectors → Add custom connector (works on claude.ai and Claude Desktop; ChatGPT's connector settings accept the same URL). Then ask: "Which open tenders fit a 50-person UK data consultancy?" — or read a real transcript of exactly that.
The hosted copy serves a bundled snapshot of the warehouse (published notices from all three sources); run it yourself for fresher data.
Security, privacy & scale
The hosted connector is public and unauthenticated by design, so the deployment is built to make that safe and free:
No SQL surface. There is deliberately no tool that accepts SQL. Every filter is parameterized server-side, and every database connection is opened read-only — even a bug cannot write.
No secrets. The server holds no API keys. The LLM runs on the caller's side (their own Claude/ChatGPT account); the server only executes typed tool calls against a local file.
Nothing stored. No accounts, no query logs, no analytics. Requests are processed in memory against a read-only snapshot and forgotten; platform logs are ephemeral. The only data the server has is public procurement data.
Rate limited. Each client IP gets 100 requests/minute per instance (HTTP 429 beyond that, verified end-to-end), on top of the platform's built-in DDoS mitigation — one looping client can't exhaust the free-tier quota for everyone else.
Concurrent users are free. The warehouse ships inside the deployment as a read-only DuckDB file, so parallel reads don't contend. Measured with
scripts/load_test.pyagainst production (10 parallel clients × 3 rounds): 30/30 succeeded, p50 0.52 s, p95 0.99 s; the only slow call (5.4 s) was a cold start.
How to run it
Prerequisites: uv (manages Python itself).
Everything below is idempotent — rerunning is always safe. Every step also
has a make shortcut — run make help for the list.
1. Install
git clone https://github.com/ZohaibAamer/tender-radar && cd tender-radar
uv sync2. Get data and build the warehouse
# ingest live notices from all three portals (public APIs, no keys needed)
uv run python -m tender_radar.ingest --source all --since 2026-10-01
# build the DuckDB warehouse with dbt
DBT_PROFILES_DIR=dbt uv run dbt deps --project-dir dbt
DBT_PROFILES_DIR=dbt uv run dbt build --project-dir dbt
# compute cross-portal duplicate links
uv run python -m tender_radar.dedupe(If a data-latest release has been published, you can skip ingestion:
gh release download data-latest --dir data/raw.)
3. Use it from an MCP client
Fastest look — the official Inspector UI:
npx @modelcontextprotocol/inspector uv run tender-radar-mcpAny MCP-capable AI client (standard mcpServers config):
{
"tender-radar": {
"command": "uv",
"args": ["run", "--directory", "/path/to/tender-radar", "tender-radar-mcp"]
}
}Tools: search_tenders · get_tender · match_profile ·
upcoming_deadlines · query_metric · list_company_profiles. The
semantic layer is readable as the semantic://layer resource, so agents
discover metrics instead of guessing.
4. Ask the CLI agent
export GEMINI_API_KEY=... # free tier: https://aistudio.google.com
uv run python -m tender_radar.agent \
"Which open tenders fit a 50-person UK data consultancy?"Company profiles are plain YAML — copy profiles/example-uk-data-consultancy.yaml and describe your own company.
5. Run the tests and evals
# tier 1 — deterministic, no LLM, what CI runs on every push
uv run ruff check . && uv run pytest
# the matcher's measured scorecard (precision/recall sweep)
uv run python scripts/evaluate_matcher.py
# tier 2 — the 52-question agent eval suite (needs GEMINI_API_KEY)
TENDER_RADAR_DATA_DIR=$PWD/fixtures DBT_PROFILES_DIR=dbt \
uv run dbt build --project-dir dbt # fixture warehouse, once
uv run python evals/harness.py # responses cached per question
uv run python evals/harness.py --category injectionData refresh and storage
The Data refresh & evals workflow (Actions tab, run on demand) ingests
the last 7 days from all three sources, rebuilds the warehouse, runs
dbt source freshness as the pipeline health check, recomputes dedup links,
and uploads Parquet to the rolling data-latest release,
optionally cutting a dated snapshot. Nothing runs unattended by design —
this is a reference implementation, not an operated service. To run it
nightly on your own fork, add the cron trigger shown at the top of
data-refresh.yml.
Licensing
Code is MIT. Tender data belongs to its sources and is reused under their terms — Open Government Licence v3.0 (both UK portals declare it in their API responses) and the EU's reuse policy for TED. Full attribution and the synthetic-test-row disclosure: DATA_LICENSE.md.
Honest limitations
The TED mapper carries a pragmatic field subset (title, buyer, CPV, value, deadline, links); eForms is far richer than any flat schema.
Cross-portal matching is title-driven: a renamed re-publication scoring below the measured 0.75 threshold is missed — a trade-off that is measured (P 0.93 / R 0.89), not hidden.
Disclosed values are floors, not market sizes: many notices omit value, and the semantic layer's metric descriptions say so.
Available Tools
6 toolsget_tenderB
Full detail for one tender by tender_ref, including cross-portal links.
| Name | Required | Description | Default |
|---|---|---|---|
| tender_ref | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full behavioral burden. It clarifies that the response includes full detail and cross-portal links, but does not mention permissions, rate limits, read-only behavior, or whether the cross-portal links are always present.
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 a single front-loaded sentence with no unnecessary wording. It efficiently conveys the core purpose and the notable inclusion of cross-portal links.
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 tool is simple with one required parameter, and an output schema exists to explain return values. However, the description does not explain how to obtain or format tender_ref and does not clarify usage relative to sibling tools, leaving some gaps.
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%, and the description only repeats that the single required parameter is tender_ref. It does not explain the expected format, source, or example of a tender reference, adding minimal meaning beyond the schema property name.
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 states a clear retrieval purpose: full detail for one tender identified by tender_ref, including cross-portal links. It distinguishes the tool from list/search siblings by focusing on a single tender, though it does not explicitly name search_tenders as the alternative.
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 phrase 'by tender_ref' implies the tool is used when a known tender reference is available, but there is no explicit guidance on when to use this versus search_tenders or other siblings. 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_company_profilesB
Names of the company profiles available to match_profile.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are supplied, so the description carries the full behavioral burden. 'available' suggests a read-only enumeration, but the description does not explicitly state read-only/non-destructive behavior, permission requirements, or ordering/pagination characteristics.
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?
It is a single short fragment with no wasted words, which keeps it concise. The fragmentary grammar makes it slightly less immediately actionable than a complete sentence, but there is no bloat.
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 tool has no parameters, has an output schema, and is a simple list operation, so the description does not need to explain return values. It establishes the resource and its link to match_profile, but leaves the exact invocation relationship and read-only nature implicit.
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 has zero parameters and schema coverage is 100%, so the baseline is 4. There are no parameter semantics for the description to add, and it does not introduce any misleading parameter information.
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 names the resource ('Names of the company profiles') and ties it to 'match_profile', but it is a noun phrase rather than a verb-led statement of what the tool does. It implies a name-list lookup but does not fully distinguish its purpose from the sibling match_profile tool.
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?
'available to match_profile' implies this is a precursor lookup for match_profile, but the description never explicitly says to call this before match_profile. It also gives no when-not-to-use guidance or alternatives, leaving usage only implied.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
match_profileB
Rank tenders fitting a company profile (profiles/*.yaml), with reasons.
Available profiles can be listed by passing an unknown name.
| Name | Required | Description | Default |
|---|---|---|---|
| open_only | No | ||
| max_results | No | ||
| profile_name | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden. It does usefully disclose that results come with reasons and that an unknown profile name triggers a profile-listing response, but it omits that this is a read-only operation, how open_only silently excludes closed tenders, and how max_results truncates the ranking.
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, front-loaded with the core ranking purpose, with no filler. The second sentence's invalid-input discovery trick is a slightly awkward structure but still earns its place informationally.
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?
For a tool with no annotations, no output schema, and 0% schema coverage on three parameters, the description does not say enough. An agent cannot tell whether results are paginated, what 'reasons' look like, or how open_only and max_results affect the ranking, so it would likely need trial calls to use the tool 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%, so the description must compensate, and it only partially does: it explains profile_name's source (profiles/*.yaml) and its special unknown-name behavior. Neither open_only (which defaults to true and filters results) nor max_results (default 20) is mentioned anywhere, leaving two of three parameters semantically empty.
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?
Uses a specific verb ('Rank') with a specific resource ('tenders') and an explicit scoping input ('a company profile (profiles/*.yaml)'), plus a note that results include reasons. This distinguishes it from search_tenders by intent, though it never names that sibling to make the contrast explicit.
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?
Implied usage is clear from the purpose: call it when you have a named company profile and want ranked tenders. However, there is no guidance on when to prefer search_tenders, and the only explicit tip is an odd discovery hack (pass an unknown name to list profiles) even though a dedicated list_company_profiles sibling exists — the description never points to it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
query_metricB
Run a governed metric from the semantic layer (see semantic://layer).
This is the only way to aggregate. Free SQL does not exist on this server. GovernanceError messages explain how to correct a refused query.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| metric | Yes | ||
| filters | No | ||
| dimensions | No | ||
| horizon_days | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations exist, so the description carries the full behavioral burden. It usefully discloses the governance/refusal model and that errors are self-correcting, which is real value beyond structured fields. It does not state side-effect profile, permission prerequisites, or rate/cost limits, leaving meaningful gaps for a tool with zero 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?
Four short sentences, front-loaded with the core action, then the exclusivity constraint, then error behavior. Nothing is bloated. The 'only way to aggregate' and 'free SQL does not exist' lines are near-duplicates, costing a little tightness.
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 is present, so return values need no explanation, and the governance framing is well covered. However, with five undocumented parameters at 0% coverage and no annotations, an agent still lacks guidance on how to build a valid metric/filters/dimensions call. Adequate but with a clear structural 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?
Schema description coverage is 0% across five parameters, and the description names none of them (metric, filters, dimensions, limit, horizon_days). The pointer to semantic://layer is a partial offset, since metric and dimension names likely live there, but no parameter meaning, format, or default behavior is conveyed in the description itself.
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 a governed metric from the semantic layer.' The exclusivity claim ('the only way to aggregate') further pins down its role relative to the sibling search/get tools, though it never names those siblings directly. An agent knows what this does without opening the schema.
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?
Explicit routing guidance: this is the only aggregation path, free SQL does not exist, and refused queries surface corrective GovernanceError messages. It tells the agent when to reach for this tool and what to do on failure. It stops short of saying which sibling to use for non-aggregate retrieval, so 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.
search_tendersB
Search tenders by keyword and filters.
Args: query: keyword matched against title and description. source: fts | contracts_finder | ted (empty = all). country: ISO alpha-2 buyer country, e.g. GB. cpv_division: 2-digit CPV division, e.g. 72. open_only: only tenders whose deadline has not passed. max_results: at most 50.
| Name | Required | Description | Default |
|---|---|---|---|
| query | No | ||
| source | No | ||
| country | No | ||
| open_only | No | ||
| max_results | No | ||
| cpv_division | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are supplied, so the description carries the full behavioral burden, yet it says nothing about result ordering/ranking, whether results are paginated or truncated, or what happens when no filters are supplied. It only implies a hard cap of 50 via the max_results arg, which is parameter semantics rather than behavioral context.
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-loaded one-line purpose followed by a compact per-parameter list with zero filler. The docstring 'Args:' framing is slightly code-styled but does not impede comprehension.
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 explained, and parameters are well covered. What is missing for a six-parameter search tool is behavioral context: how results are ordered, whether result sets are capped or paged beyond max_results, and how this tool relates to its search-adjacent siblings.
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, and it largely does: it defines each of the six parameters with real meaning — query is matched against title and description, source enumerates fts/contracts_finder/ted with empty meaning all, country is ISO alpha-2 with an example, cpv_division is a 2-digit division with an example, open_only keys on deadline, and max_results caps at 50. It stops short of stating how source values interact or whether query is required.
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 ('Search tenders') plus the mechanism (keyword and filters), which is enough to distinguish it from get_tender. It does not distinguish it from match_profile or upcoming_deadlines, which are the siblings an agent could plausibly confuse it with.
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 when-to-use or when-not-to-use guidance, and no mention of the sibling alternatives (match_profile for profile-based matching, upcoming_deadlines for deadline-driven retrieval). The agent must infer selection purely from the tool name and parameter list.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
upcoming_deadlinesC
Open tenders with deadlines within horizon_days, optionally for a profile.
| Name | Required | Description | Default |
|---|---|---|---|
| max_results | No | ||
| horizon_days | No | ||
| profile_name | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden. It implies a read-only listing of open tenders but says nothing about pagination, ordering, the default 14-day horizon, how max_results truncates results, or what a 'profile' match actually means. That leaves several behavioral gaps for a query tool with three parameters.
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?
It is a single tight sentence with the core filter front-loaded and no wasted words. The terseness borders on under-specification, but structurally it 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?
For a three-parameter query tool with no annotations and no output schema, the description is too thin: it does not explain max_results, defaults, return shape, or how profile scoping interacts with the deadline filter. An agent would have to guess at several invocation details.
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. It only clarifies horizon_days and hints at profile_name; max_results is never mentioned, and there is no explanation of units, defaults, or whether profile_name must match an existing profile exactly. Meaning added beyond the bare schema is minimal.
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 names a specific resource (open tenders) and a clear filter condition (deadlines within horizon_days), plus an optional profile scoping. It distinguishes itself reasonably from generic search_tenders by implying a deadline-window view, though it never explicitly names that sibling or contrasts the two.
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 a use case (finding tenders closing soon) but gives no explicit when-to-use vs when-not guidance, no mention of when to prefer search_tenders or match_profile, and no prerequisites. The optional profile filter is mentioned but not explained as a usage decision.
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
get_tender - First observed
list_company_profiles - First observed
match_profile - First observed
query_metric - First observed
search_tenders - First observed
upcoming_deadlines
TDQS
Scored across 6 tools
Each tool has a distinguishable role: keyword search, ref-based detail, profile ranking, profile listing, deadline windows, and governed aggregation. The only mild overlap is that search_tenders, match_profile, and upcoming_deadlines all return tender lists, but the descriptions make the distinguishing dimension (keywords vs. profile fit vs. deadline horizon) clear.
Five of six names follow a clean verb_noun pattern (search_tenders, get_tender, match_profile, list_company_profiles, query_metric). upcoming_deadlines breaks the pattern as a bare noun phrase, a minor but noticeable deviation.
Six tools is well-scoped for a tender discovery service: discovery, detail, profiling, and aggregation each get one entry point. No redundant or filler tools are present.
The surface covers the core read-only lifecycle: find tenders, inspect one in full with cross-portal links, rank by profile, track deadlines, and aggregate via a governed metric. Minor gaps exist around exporting/saving results or listing available sources, but these are workarounds rather than dead ends.
Maintenance
Related MCP Connectors
UK public procurement data for AI agents: tenders, contracts, buyer and supplier profiles.
EU tenders and grant calls, matched to your company and qualified, inside the AI you already use
Government tender search for AI agents. UK, EU and US procurement opportunities.
Connect your AI assistant to governed tender and RFP dossiers: sources, versions, decisions.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceEnables AI agents to search, retrieve, and answer grounded questions over procurement documents (invoices, purchase orders, contracts, etc.) using hybrid SQL and vector retrieval.-

oro-intel-mcpofficial
AlicenseNot gradedqualityDmaintenanceUK public procurement data for AI agents. Tenders, contracts, buyer and supplier profiles over MCP and REST. 250 free credits.MIT- AlicenseAqualityCmaintenanceEnables AI agents to find, score, and monitor government contract opportunities across UK, EU, and US with AI-powered relevance scoring.2103 npm1MIT
- AlicenseNot gradedqualityCmaintenanceEnables searching and analyzing government tenders, contract awards, and pre-tender pipelines from 21 official sources, with tools for tender search, award intelligence, and detailed notice retrieval.MIT