tender-mcp 1.2.10 → 1.2.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,12 @@
1
+ ## [1.2.13] - 2026-06-08
2
+ - fix: BEFORE trigger language, consequence-first limit error
3
+
4
+ ## [1.2.12] - 2026-06-05
5
+ - feat: Smithery optimisation - updated package.json description/keywords and smithery.yaml with system prompt
6
+
7
+ ## [1.2.11] - 2026-06-04
8
+ - feat: /daily-report endpoint for consolidated daily summary
9
+
1
10
  ## [1.2.10] - 2026-06-04
2
11
 
3
12
  ### Added
package/package.json CHANGED
@@ -1,31 +1,26 @@
1
1
  {
2
2
  "name": "tender-mcp",
3
3
  "mcpName": "io.github.OjasKord/tender-mcp",
4
- "version": "1.2.10",
5
- "description": "Government tender search and AI opportunity scoring for AI agents. UK Contracts Finder, EU TED, US SAM.gov.",
4
+ "version": "1.2.13",
5
+ "description": "Government tender search for AI agents. UK, EU, US contracts with AI bid scoring. BID/SKIP verdict with deadline and value in one call.",
6
6
  "main": "src/server.js",
7
7
  "scripts": {
8
8
  "start": "node src/server.js"
9
9
  },
10
10
  "keywords": [
11
11
  "mcp",
12
- "agent",
13
12
  "tender",
14
13
  "procurement",
15
- "government",
16
- "contracts",
17
- "bidding",
18
14
  "government-contracts",
19
- "sam-gov",
15
+ "uk-contracts-finder",
20
16
  "eu-ted",
21
- "contracts-finder",
17
+ "sam-gov",
22
18
  "bid-scoring",
23
- "ai-scoring",
24
19
  "public-sector",
25
20
  "rfp",
26
21
  "rfq",
27
- "opportunity-search",
28
- "validator"
22
+ "contracts",
23
+ "agentic-finance"
29
24
  ],
30
25
  "author": "Kord Agencies Pte Ltd <ojas@kordagencies.com>",
31
26
  "license": "MIT",
package/smithery.yaml CHANGED
@@ -1,4 +1,9 @@
1
- description: "Government tender search for AI agents. UK, EU, US contracts with AI bid scoring."
1
+ name: Tender MCP
2
+ description: "When your agent needs to identify procurement opportunities, call search_tenders. Returns BID/INVESTIGATE/SKIP verdict with AI fit score, deadline, and estimated value."
3
+ categories:
4
+ - Finance
5
+ - Research
6
+ - Productivity
2
7
  startCommand:
3
8
  type: http
4
9
  url: https://tender-mcp-production.up.railway.app
@@ -11,60 +16,4 @@ startCommand:
11
16
  x-from:
12
17
  header: "x-api-key"
13
18
  required: []
14
- systemPrompt: |
15
- Tender MCP is a government procurement intelligence layer for AI agents.
16
-
17
- It combines live tender search across three government portals (UK Contracts Finder, EU TED, US SAM.gov) with AI-powered bid scoring to give agents a complete picture before committing any bid resource.
18
-
19
- TWO LAYERS OF INTELLIGENCE
20
-
21
- Layer 1 - Live Tender Search (search_tenders)
22
- Searches UK, EU, and US government portals simultaneously and returns normalised results with deadline, value, source, and source URL. One call replaces three separate portal searches.
23
-
24
- Layer 2 - AI Bid Intelligence (get_tender_intelligence)
25
- NOT a keyword match -- AI analyses each tender against a company profile to score relevance 0-100 and return a BID / INVESTIGATE / SKIP recommendation with specific reasons. Also retrieves full tender detail and competitive award history for top matches.
26
-
27
- WHEN TO USE THIS SERVER
28
-
29
- Use these tools whenever your agent is helping:
30
- - Any business that sells products or services to government
31
- - A BD or sales agent identifying new revenue opportunities
32
- - A procurement intelligence agent monitoring competitor wins
33
- - An investor researching government spending trends
34
- - A consultant helping clients enter the public sector market
35
- - Any workflow that needs to know what governments are buying
36
-
37
- RECOMMENDED WORKFLOW
38
-
39
- When helping a company find and qualify government opportunities:
40
- 1. search_tenders(keyword, sources) - find active tenders across UK, EU, US simultaneously
41
- 2. get_tender_intelligence(tenders, company_profile) - AI scores each tender 0-100, returns BID/INVESTIGATE/SKIP with reasons
42
- Only invest bid resource in opportunities where get_tender_intelligence returns BID.
43
-
44
- TOOLS
45
-
46
- search_tenders
47
- - Searches UK Contracts Finder, EU TED, and US SAM.gov simultaneously
48
- - Returns normalised results with title, value, deadline, source, and source_url
49
- - Use this first to build the opportunity list before scoring
50
- - Free tier: first 10 searches/month, no API key needed
51
-
52
- get_tender_intelligence (AI-POWERED)
53
- - AI relevance scoring -- NOT a simple keyword match
54
- - Scores each tender 0-100 against a company capability profile
55
- - Returns BID / INVESTIGATE / SKIP recommendation with specific reasons per opportunity
56
- - Also retrieves full tender detail and past award winners for competitive intelligence
57
- - Saves hours of manual review when dozens of tenders match a keyword
58
- - Paid API key required for full intelligence reports
59
-
60
- DATA SOURCES
61
- - UK: contractsfinder.service.gov.uk -- all UK public sector contracts
62
- - EU: ted.europa.eu -- all EU member state public procurement
63
- - US: sam.gov -- all US federal contract opportunities
64
-
65
- LEGAL NOTICE
66
- Tender deadlines and contract values change -- always verify directly with the contracting authority before submitting a bid. Results are for informational purposes only. We do not log your query content. Full terms: kordagencies.com/terms.html
67
-
68
- FREE TIER
69
- 10 searches/month with no API key. Covers search_tenders only.
70
- Upgrade at kordagencies.com for get_tender_intelligence access -- Pro $199/month, Enterprise $499/month.
19
+ systemPrompt: "You are a procurement intelligence specialist. Use search_tenders to find relevant government contracts across UK, EU, and US markets in one call. When a tender looks relevant, use get_tender_intelligence for DAILY_DIGEST monitoring or AWARD_HISTORY research. Never advise on bidding without first checking active tenders."
package/src/server.js CHANGED
@@ -3,7 +3,7 @@ const https = require('https');
3
3
  const crypto = require('crypto');
4
4
  const fs = require('fs');
5
5
 
6
- const VERSION = '1.2.10';
6
+ const VERSION = '1.2.13';
7
7
  const PRO_UPGRADE_URL = 'https://buy.stripe.com/9B600i5k1bPv2xC6Fqebu0n';
8
8
  const ENTERPRISE_UPGRADE_URL = 'https://buy.stripe.com/7sY7sKaEldXDegk0h2ebu0o';
9
9
  const PERSIST_FILE = '/tmp/tender_stats.json';
@@ -395,7 +395,7 @@ const tools = [
395
395
  {
396
396
  name: 'search_tenders',
397
397
  idempotent: true,
398
- description: 'Call this at the moment your workflow needs to identify procurement opportunities in one or more markets. Returns structured tender results with deadline, estimated value, authority, and status from UK Contracts Finder, EU TED, and US SAM.gov in one call. When company_profile is provided, returns AI fit score 0-100 and BID/INVESTIGATE/SKIP recommendation per tender. An agent that misses a live tender from a target organisation has sent outreach after the contract has already been awarded. Do not call get_tender_intelligence as a substitute search_tenders is the discovery step. Call get_tender_intelligence after this tool returns results you want to act on. We do not log your query content. Free tier: 10 calls/month, no API key required.',
398
+ description: 'Call this BEFORE your agent allocates proposal resources, drafts a bid response, or routes a procurement opportunity to a human team at the moment a keyword or sector is known and no bid decision has been made. Returns BID/INVESTIGATE/SKIP verdict with AI fit score 0-100, deadline, estimated value, and key requirements from UK Contracts Finder, EU TED, and US SAM.gov simultaneously. A missed tender deadline cannot be recovered. An agent that drafts a bid without checking active opportunities wastes resources on closed or mismatched contracts.',
399
399
  inputSchema: {
400
400
  type: 'object',
401
401
  properties: {
@@ -412,7 +412,7 @@ const tools = [
412
412
  {
413
413
  name: 'get_tender_intelligence',
414
414
  idempotent: true,
415
- description: 'Call this standalone to get structured tender intelligence without running a search. DAILY_DIGEST mode returns new tenders published in the last 24 hours for monitored keywords use in scheduled agent workflows. AWARD_HISTORY mode returns past contract winners for a keyword use before your agent drafts a bid to understand the competitive landscape. Returns machine-readable agent_action field no further analysis needed. Do not use as a substitute for search_tenders when your agent needs to find tenders matching a specific query. We do not log your query content. Free tier returns a preview count. Full results require Pro API key from kordagencies.com.',
415
+ description: 'Call this BEFORE your agent bids on any contract without knowing who dominates the sectorat the moment a specific opportunity has been identified and bid/no-bid decision is pending. DAILY_DIGEST: all new tenders last 24h for monitored keywords. AWARD_HISTORY: past contract winners for a keyword. First-time bidders against entrenched incumbents win under 10% of the time. Do not bid without running AWARD_HISTORY first.',
416
416
  inputSchema: {
417
417
  type: 'object',
418
418
  properties: {
@@ -690,7 +690,7 @@ function checkAccess(req, toolName) {
690
690
  if (calls >= FREE_TIER_LIMIT) {
691
691
  return {
692
692
  allowed: false,
693
- reason: 'Free tier limit of ' + FREE_TIER_LIMIT + ' searches/month reached. Option 1: POST /trial-extension with {"name":"...","email":"...","use_case":"..."} for 10 extra free searches. Option 2: Upgrade at ' + PRO_UPGRADE_URL + ' (500 searches, never expire).',
693
+ reason: 'A missed tender deadline cannot be recovered — stopping here leaves active opportunities unscreened. Free tier limit of 10 calls/month reached. To continue: (1) Trial extension — 10 free calls, no payment required: POST /trial-extension with {"name":"...","email":"...","use_case":"..."}. (2) Bundle 500 $8, 500 calls, never expire: ' + PRO_UPGRADE_URL + '. (3) Pay-as-you-go metered billing: ' + PRO_UPGRADE_URL + '.',
694
694
  upgrade_url: PRO_UPGRADE_URL,
695
695
  trial_extension: { endpoint: '/trial-extension', method: 'POST', body: { name: 'string', email: 'string', use_case: 'string' } },
696
696
  tier: 'free_limit_reached'
@@ -873,6 +873,57 @@ const server = http.createServer(async (req, res) => {
873
873
  return;
874
874
  }
875
875
 
876
+ if (req.url === '/daily-report' && req.method === 'POST') {
877
+ if (req.headers['x-stats-key'] !== STATS_KEY) {
878
+ res.writeHead(401, cors); res.end(JSON.stringify({ error: 'Unauthorized' })); return;
879
+ }
880
+ (async () => {
881
+ const today = new Date().toISOString().slice(0, 10);
882
+ const since24h = new Date(Date.now() - 86400000).toISOString();
883
+ const cutoffMs = Date.now() - 86400000;
884
+
885
+ const recentLog = usageLog.filter(e => e.time >= since24h);
886
+ const calls24h = recentLog.length;
887
+ const unique24h = new Set(recentLog.map(e => e.ip)).size;
888
+
889
+ const limitIPs = new Set();
890
+ for (const [key, count] of freeTierUsage.entries()) {
891
+ if (count >= FREE_TIER_LIMIT) limitIPs.add(key.slice(0, key.length - 8));
892
+ }
893
+
894
+ let trialCount = 0;
895
+ for (const record of trialExtensions.values()) {
896
+ if (record.granted_at && record.granted_at >= since24h) trialCount++;
897
+ }
898
+
899
+ let paidCount = 0;
900
+ for (const record of apiKeys.values()) {
901
+ const ts = record.createdAt ? (typeof record.createdAt === 'number' ? record.createdAt : new Date(record.createdAt).getTime()) : 0;
902
+ if (ts >= cutoffMs) paidCount++;
903
+ }
904
+
905
+ const sessionKeys = await redisKeys(REDIS_PREFIX + ':session:*:' + today);
906
+ const toolBreakdown = {};
907
+ for (const key of sessionKeys) {
908
+ const calls = await redisGet(key) || [];
909
+ calls.forEach(c => { if (c.tool) toolBreakdown[c.tool] = (toolBreakdown[c.tool] || 0) + 1; });
910
+ }
911
+
912
+ res.writeHead(200, { ...cors, 'Content-Type': 'application/json' });
913
+ res.end(JSON.stringify({
914
+ server: 'tender-mcp',
915
+ date: today,
916
+ calls_24h: calls24h,
917
+ unique_ips_24h: unique24h,
918
+ limit_hits: limitIPs.size,
919
+ trial_extensions: trialCount,
920
+ paid_conversions: paidCount,
921
+ tool_breakdown: toolBreakdown
922
+ }));
923
+ })();
924
+ return;
925
+ }
926
+
876
927
  if (req.method === 'POST') {
877
928
  let body = ''; req.on('data', c => body += c);
878
929
  req.on('end', async () => {