@bbradar/mcp 0.1.10 → 0.1.11

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/README.md CHANGED
@@ -58,17 +58,17 @@ The server needs your [bbradar.io](https://bbradar.io) Pro key. In the MCP clien
58
58
  Add with the Codex CLI:
59
59
 
60
60
  ```bash
61
- codex mcp add bbradar.io --env BBRADAR_API_KEY="your_pro_mcp_api_key" -- npx -y @bbradar/mcp
61
+ codex mcp add bbradar_io --env BBRADAR_API_KEY="your_pro_mcp_api_key" -- npx -y @bbradar/mcp
62
62
  ```
63
63
 
64
64
  Or add it to `~/.codex/config.toml`:
65
65
 
66
66
  ```toml
67
- [mcp_servers."bbradar.io"]
67
+ [mcp_servers.bbradar_io]
68
68
  command = "npx"
69
69
  args = ["-y", "@bbradar/mcp"]
70
70
 
71
- [mcp_servers."bbradar.io".env]
71
+ [mcp_servers.bbradar_io.env]
72
72
  BBRADAR_API_KEY = "your_pro_mcp_api_key"
73
73
  ```
74
74
 
@@ -77,13 +77,13 @@ BBRADAR_API_KEY = "your_pro_mcp_api_key"
77
77
  Add a private user-level server:
78
78
 
79
79
  ```bash
80
- claude mcp add bbradar.io --scope user --env BBRADAR_API_KEY="your_pro_mcp_api_key" -- npx -y @bbradar/mcp
80
+ claude mcp add bbradar_io --scope user --env BBRADAR_API_KEY="your_pro_mcp_api_key" -- npx -y @bbradar/mcp
81
81
  ```
82
82
 
83
83
  On native Windows, wrap `npx` with `cmd /c`:
84
84
 
85
85
  ```bash
86
- claude mcp add bbradar.io --scope user --env BBRADAR_API_KEY="your_pro_mcp_api_key" -- cmd /c npx -y @bbradar/mcp
86
+ claude mcp add bbradar_io --scope user --env BBRADAR_API_KEY="your_pro_mcp_api_key" -- cmd /c npx -y @bbradar/mcp
87
87
  ```
88
88
 
89
89
  ### Generic MCP JSON
@@ -127,6 +127,7 @@ After adding the MCP config, restart your client and call `get_mcp_status`. A wo
127
127
  - `find_stack_matches`
128
128
  - `find_low_noise_programs`
129
129
  - `find_recent_by_type`
130
+ - `find_recently_updated_programs`
130
131
  - `find_programs_by_target`
131
132
  - `find_program_candidates`
132
133
  - `find_hunt_candidates`
package/dist/server.js CHANGED
@@ -94,7 +94,7 @@ const filterValueSchema = z
94
94
  });
95
95
  const stringListSchema = z
96
96
  .preprocess(normalizeStringListInput, z.array(filterValueSchema).max(50).default([]))
97
- .describe("Filter values.");
97
+ .describe("Optional filter values. Empty or omitted means all values; do not infer a platform filter.");
98
98
  const acceptedTargetLimitSchema = z.number().int().min(1).max(MAX_TARGETS_PER_PROGRAM);
99
99
  const searchTextSchema = z
100
100
  .string()
@@ -228,7 +228,8 @@ export function createBbradarServer(client, config) {
228
228
  "For BBRadar asks, use these tools first and avoid external skills unless methodology is explicitly requested.",
229
229
  "Partial program name + action: run_program_name_action. Partial program name only: resolve_program.",
230
230
  "Default to bounty-eligible in-scope data. Include out-of-scope, ineligible, VDP, disclosure-only, or no-bounty data only when the user explicitly asks.",
231
- "Freshness: get_latest_added_targets, check_program_new_targets, check_watchlist_new_targets, find_recent_by_type, get_program_scope_delta.",
231
+ "Recently updated programs across platforms: find_recently_updated_programs. Do not infer a platform such as Immunefi unless the user explicitly names it.",
232
+ "Freshness: find_recently_updated_programs, get_latest_added_targets, check_program_new_targets, check_watchlist_new_targets, find_recent_by_type, get_program_scope_delta.",
232
233
  "Discovery: find_program_candidates, find_stack_matches, find_language_programs, find_target_type_programs, find_reward_programs, find_paid_programs, find_vdp_programs, find_web3_contests, find_low_noise_programs.",
233
234
  "Details: get_program_brief, get_program_scope_summary, get_program_target_breakdown, find_programs_by_target, compare_programs_compact.",
234
235
  "Prefer compact/identifier outputs and disclose sampled ranking scope when present."
@@ -1146,6 +1147,31 @@ export function createBbradarServer(client, config) {
1146
1147
  output_mode: args.output_mode,
1147
1148
  upstream_request_budget: args.upstream_request_budget
1148
1149
  })));
1150
+ server.registerTool("find_recently_updated_programs", {
1151
+ title: "Find Recently Updated Programs",
1152
+ description: "Recently updated program shortlist across all platforms by default. Platform filters are applied only when explicitly provided.",
1153
+ inputSchema: {
1154
+ platforms: stringListSchema,
1155
+ tags: stringListSchema,
1156
+ target_types: stringListSchema,
1157
+ language_tags: stringListSchema,
1158
+ web3: z.boolean().default(false),
1159
+ updated_since: isoDateTimeSchema.optional(),
1160
+ require_bounty: z.boolean().default(false),
1161
+ min_eligible_targets: z.number().int().min(0).optional(),
1162
+ exclude_ctf: z.boolean().default(true),
1163
+ vdp_mode: vdpModeSchema.default("exclude").describe("VDP/no-bounty filter mode."),
1164
+ max_pages: z.number().int().min(1).max(MAX_ACCEPTED_NUMERIC_LIMIT).default(5),
1165
+ max_results: z.number().int().min(1).max(MAX_ACCEPTED_NUMERIC_LIMIT).default(10),
1166
+ include_target_samples: z.boolean().default(false),
1167
+ target_sample_programs: z.number().int().min(0).max(MAX_ACCEPTED_NUMERIC_LIMIT).default(3),
1168
+ target_sample_size: z.number().int().min(1).max(MAX_ACCEPTED_NUMERIC_LIMIT).default(3),
1169
+ output_mode: programListModeSchema.default("compact"),
1170
+ upstream_request_budget: z.number().int().min(1).max(MAX_ACCEPTED_NUMERIC_LIMIT).default(DEFAULT_FIND_UPSTREAM_REQUEST_BUDGET)
1171
+ },
1172
+ outputSchema: findProgramsOutputShape,
1173
+ annotations: readOnlyAnnotations
1174
+ }, (args) => runTool("find_recently_updated_programs", config, rateLimiter, async () => findRecentlyUpdatedPrograms(client, config, args)));
1149
1175
  server.registerTool("list_filters", {
1150
1176
  title: "List BBRadar Filters",
1151
1177
  description: "Discover observed filter values.",
@@ -2280,6 +2306,48 @@ function findProgramCandidates(client, config, input) {
2280
2306
  upstream_request_budget: input.upstream_request_budget
2281
2307
  });
2282
2308
  }
2309
+ function findRecentlyUpdatedPrograms(client, config, input) {
2310
+ return findPrograms(client, config, {
2311
+ platforms: input.platforms,
2312
+ tags: input.tags,
2313
+ scope_tags: [],
2314
+ target_types: input.target_types,
2315
+ language_tags: input.language_tags,
2316
+ web3: input.web3,
2317
+ opportunity_levels: [],
2318
+ updated_since: input.updated_since,
2319
+ min_bounty_min: undefined,
2320
+ min_bounty_max: undefined,
2321
+ max_bounty_max: undefined,
2322
+ require_bounty: input.require_bounty,
2323
+ max_public_report_count: undefined,
2324
+ require_known_report_count: false,
2325
+ include_unknown_report_count: true,
2326
+ exclude_ctf: input.exclude_ctf,
2327
+ exclude_mobile_only: false,
2328
+ exclude_non_web: false,
2329
+ has_api_scope: input.target_types.some((targetType) => normalizeTag(targetType).includes("api")),
2330
+ contest_like: false,
2331
+ vdp_mode: input.vdp_mode,
2332
+ fresh_launch_days: undefined,
2333
+ min_wildcards: 0,
2334
+ min_eligible_targets: input.min_eligible_targets,
2335
+ min_total_targets: undefined,
2336
+ min_added_24h: undefined,
2337
+ min_added_7d: undefined,
2338
+ max_pages: input.max_pages,
2339
+ max_results: input.max_results,
2340
+ sort_by: "recently_updated",
2341
+ include_target_samples: input.include_target_samples,
2342
+ target_sample_programs: input.target_sample_programs,
2343
+ target_sample_size: input.target_sample_size,
2344
+ only_in_scope_targets: true,
2345
+ only_bounty_eligible_targets: true,
2346
+ target_samples_only_wildcards: false,
2347
+ output_mode: input.output_mode ?? "compact",
2348
+ upstream_request_budget: input.upstream_request_budget
2349
+ });
2350
+ }
2283
2351
  function findRewardPrograms(client, config, input) {
2284
2352
  return findPrograms(client, config, {
2285
2353
  platforms: input.platforms,
@@ -4876,6 +4944,9 @@ async function findPrograms(client, config, input) {
4876
4944
  .sort((left, right) => compareProgramCandidates(left, right, input.sort_by));
4877
4945
  const candidates = filteredCandidates.slice(0, input.max_results);
4878
4946
  const targetSamplePrograms = Math.min(input.target_sample_programs, candidates.length, Math.max(0, budget.remaining));
4947
+ if (input.sort_by === "recently_updated" && input.platforms.length === 0) {
4948
+ addUniqueWarning(warnings, "No platform filter was provided; recently updated ranking considered all platforms returned by the scanned BBRadar pages.");
4949
+ }
4879
4950
  if (input.include_target_samples && input.target_sample_programs > targetSamplePrograms) {
4880
4951
  warnings.push(`target_sample_programs was reduced from ${input.target_sample_programs} to ${targetSamplePrograms} to stay within the upstream request budget.`);
4881
4952
  }
@@ -4923,6 +4994,7 @@ async function findPrograms(client, config, input) {
4923
4994
  },
4924
4995
  ranking_scope: {
4925
4996
  mode: "sampled",
4997
+ platform_filter: input.platforms.length > 0 ? input.platforms : "all_platforms",
4926
4998
  max_pages_scanned_per_source: input.max_pages,
4927
4999
  upstream_total_pages: collected.totalPagesBySource,
4928
5000
  possibly_incomplete: isRankingPossiblyIncomplete(collected.totalPagesBySource, input.max_pages)