@bbradar/mcp 0.1.16 → 0.1.20

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/dist/server.js CHANGED
@@ -5,7 +5,7 @@ import { BBRadarApiError } from "./bbradarClient.js";
5
5
  import { stableStringify, stripUndefined } from "./json.js";
6
6
  import { FixedWindowRateLimiter } from "./rateLimit.js";
7
7
  import { readArray, readBoolean, readNumber, readObject, readString, sanitizeJson, sanitizeChange, sanitizeProgram, sanitizeTarget, sanitizeTargetsForExport } from "./sanitize.js";
8
- const SERVER_VERSION = "0.1.0";
8
+ const SERVER_VERSION = "0.1.19";
9
9
  const MAX_PROGRAMS_PER_SEARCH = 100;
10
10
  const MAX_TARGET_EXPORT = 500;
11
11
  const MAX_RECENT_CHANGES = 100;
@@ -20,7 +20,7 @@ const MAX_FIND_TARGET_SAMPLE_PROGRAMS = 10;
20
20
  const MAX_FIND_TARGET_SAMPLES = 20;
21
21
  const MAX_FIND_UPSTREAM_REQUEST_BUDGET = 50;
22
22
  const DEFAULT_FIND_UPSTREAM_REQUEST_BUDGET = 20;
23
- const DEFAULT_RESOLVE_UPSTREAM_REQUEST_BUDGET = 4;
23
+ const DEFAULT_RESOLVE_UPSTREAM_REQUEST_BUDGET = 12;
24
24
  const MAX_ACCEPTED_NUMERIC_LIMIT = 1_000;
25
25
  const PROGRAM_COLLECTION_CONCURRENCY = 4;
26
26
  const TARGET_SAMPLE_CONCURRENCY = 3;
@@ -31,12 +31,52 @@ const MAX_FILTER_TARGET_SAMPLE_PROGRAMS = 25;
31
31
  const MAX_LOCAL_EXPORT_RESOURCES = 25;
32
32
  const EXPORT_PREVIEW_LIMIT = 25;
33
33
  const STALE_PROGRAM_ID_RESOLVE_PAGES = 1;
34
- const STALE_PROGRAM_ID_RESOLVE_BUDGET = 8;
34
+ const STALE_PROGRAM_ID_RESOLVE_BUDGET = 12;
35
35
  const PROGRAM_FALLBACK_CACHE_MAX_ENTRIES = 200;
36
36
  const MAX_RESOLVE_SEARCH_QUERIES = 4;
37
- const MAX_DIRECT_HANDLE_RESOLUTION_REQUESTS = 8;
37
+ const FAST_RESOLVE_SEARCH_QUERIES = 2;
38
+ const MAX_DIRECT_HANDLE_RESOLUTION_REQUESTS = 96;
38
39
  const SDK_VERSION = "1.29.0";
39
- const PROGRAM_ID_PLATFORM_GUESSES = ["HackerOne", "Bugcrowd", "Intigriti", "HackenProof", "YesWeHack", "Cantina", "Code4rena", "Immunefi"];
40
+ const CORE_TOOL_NAMES = new Set([
41
+ "search_programs",
42
+ "get_program",
43
+ "resolve_program",
44
+ "run_program_name_action",
45
+ "get_program_eligible_targets_by_name",
46
+ "get_program_targets",
47
+ "get_recent_changes",
48
+ "get_latest_added_targets",
49
+ "get_opportunities",
50
+ "find_programs",
51
+ "find_programs_by_target",
52
+ "list_filters",
53
+ "get_bbradar_guide",
54
+ "get_mcp_status",
55
+ "export_targets"
56
+ ]);
57
+ const PROGRAM_ID_PLATFORM_GUESSES = [
58
+ "HackerOne",
59
+ "BugCrowd",
60
+ "Intigriti",
61
+ "HackenProof",
62
+ "YesWeHack",
63
+ "Immunefi",
64
+ "Cantina",
65
+ "Code4rena",
66
+ "Huntr",
67
+ "GObugfree",
68
+ "Bug Bounty Switzerland",
69
+ "Inspectiv",
70
+ "Compass Security",
71
+ "BugRap",
72
+ "IssueHunt",
73
+ "PatchDay",
74
+ "Remedy",
75
+ "Standoff365",
76
+ "Sherlock",
77
+ "CodeHawks"
78
+ ];
79
+ const PRIMARY_PROGRAM_ID_PLATFORM_GUESSES = PROGRAM_ID_PLATFORM_GUESSES.slice(0, 8);
40
80
  const WEB3_TAGS = ["web3", "crypto", "blockchain", "smart-contract", "smart contract", "defi", "nft", "ethereum", "solana", "solidity"];
41
81
  const WEB3_CONTEST_SIGNALS = ["contest", "audit", "competitive", "code4rena", "sherlock", "cantina", "codehawks", "hats", "spearbit", "warden"];
42
82
  const VDP_SIGNALS = ["vdp", "disclosure", "responsible disclosure", "vulnerability disclosure", "no bounty", "non-bounty", "no reward"];
@@ -150,7 +190,7 @@ function stringListSchema(description = "Optional filter values. Empty or omitte
150
190
  .describe(description);
151
191
  }
152
192
  function platformListSchema() {
153
- return stringListSchema("Optional platform filters such as HackerOne, Bugcrowd, Intigriti, or HackenProof. Empty or omitted means all platforms.");
193
+ return stringListSchema("Optional platform filters such as HackerOne, BugCrowd, Intigriti, HackenProof, Immunefi, YesWeHack, Cantina, or GObugfree. Empty or omitted means all platforms.");
154
194
  }
155
195
  function tagListSchema() {
156
196
  return stringListSchema("Optional combined scope/language/target-type tags. Empty or omitted means all tags.");
@@ -206,7 +246,7 @@ const programIdSchema = z
206
246
  .trim()
207
247
  .min(3)
208
248
  .max(256)
209
- .regex(/^[A-Za-z0-9_-]+:[^?#]+$/, "Use platform:handle, for example HackerOne:example-handle.")
249
+ .regex(/^[^:/?#\u0000-\u001F\u007F]+:[^?#\u0000-\u001F\u007F]+$/, "Use platform:handle, for example HackerOne:example-handle.")
210
250
  .refine((value) => !/[\u0000-\u001F\u007F]/.test(value), {
211
251
  message: "program_id cannot contain control characters."
212
252
  })
@@ -324,12 +364,26 @@ const programCandidatePresetInputSchema = {
324
364
  output_mode: programListModeSchema.default("compact"),
325
365
  upstream_request_budget: z.number().int().min(1).max(MAX_ACCEPTED_NUMERIC_LIMIT).default(30)
326
366
  };
367
+ function createProfiledToolRegistrar(server, profile) {
368
+ return (name, toolConfig, callback) => {
369
+ const registeredTool = server.registerTool(name, toolConfig, callback);
370
+ if (profile === "core" && !CORE_TOOL_NAMES.has(name)) {
371
+ registeredTool.disable();
372
+ }
373
+ return registeredTool;
374
+ };
375
+ }
327
376
  export function createBbradarServer(client, config) {
328
- const server = new McpServer({
329
- name: "bbradar.io",
330
- version: SERVER_VERSION
331
- }, {
332
- instructions: [
377
+ const instructions = config.toolProfile === "core"
378
+ ? [
379
+ "Use BBRadar only for passive bug bounty intelligence; never scan or contact targets.",
380
+ "This server uses the compact core tool profile. Start with get_bbradar_guide when unsure.",
381
+ "Use resolve_program or run_program_name_action for a named program.",
382
+ "Use find_programs for general discovery and find_programs_by_target for reverse target lookup.",
383
+ "Default to bounty-eligible in-scope data unless the user explicitly requests broader results.",
384
+ "Prefer compact/identifier outputs and disclose sampled ranking scope when present."
385
+ ]
386
+ : [
333
387
  "Use BBRadar only for passive bug bounty intelligence; never scan or contact targets.",
334
388
  "When unsure which BBRadar tool to use, call get_bbradar_guide first. It is local-only and cheap.",
335
389
  "Simple default path: find_program_candidates for discovery, run_program_name_action for one named program, get_program_eligible_targets_by_name for target lists by program name.",
@@ -338,14 +392,20 @@ export function createBbradarServer(client, config) {
338
392
  "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.",
339
393
  "Recently updated programs across platforms: find_recently_updated_programs. Do not infer a platform such as Immunefi unless the user explicitly names it.",
340
394
  "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.",
341
- "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.",
395
+ "Discovery: find_program_candidates, find_wildcard_programs, find_recently_added_wildcards, find_low_competition_high_reward, 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.",
342
396
  "Details: get_program_brief, get_program_scope_summary, get_program_target_breakdown, find_programs_by_target, compare_programs_compact.",
343
397
  "Prefer compact/identifier outputs and disclose sampled ranking scope when present."
344
- ].join("\n")
398
+ ];
399
+ const server = new McpServer({
400
+ name: "bbradar.io",
401
+ version: SERVER_VERSION
402
+ }, {
403
+ instructions: instructions.join("\n")
345
404
  });
405
+ const registerTool = createProfiledToolRegistrar(server, config.toolProfile);
346
406
  const rateLimiter = new FixedWindowRateLimiter();
347
407
  const exportStore = new Map();
348
- server.registerTool("search_programs", {
408
+ registerTool("search_programs", {
349
409
  title: "Search BBRadar Programs",
350
410
  description: `List active programs. page_size max ${MAX_PROGRAMS_PER_SEARCH}.`,
351
411
  inputSchema: {
@@ -371,7 +431,7 @@ export function createBbradarServer(client, config) {
371
431
  meta: sanitizeJson(data?.meta)
372
432
  });
373
433
  }));
374
- server.registerTool("get_program", {
434
+ registerTool("get_program", {
375
435
  title: "Get BBRadar Program",
376
436
  description: "Get one program by platform:handle program_id, handle, or human program name. Names are resolved automatically when unambiguous.",
377
437
  inputSchema: {
@@ -407,7 +467,7 @@ export function createBbradarServer(client, config) {
407
467
  }
408
468
  }));
409
469
  }));
410
- server.registerTool("resolve_program", {
470
+ registerTool("resolve_program", {
411
471
  title: "Resolve Program",
412
472
  description: "Resolve partial name/handle text to likely program_ids. Use this when the user gives a program name fragment like Nado.",
413
473
  inputSchema: {
@@ -431,7 +491,7 @@ export function createBbradarServer(client, config) {
431
491
  },
432
492
  annotations: readOnlyAnnotations
433
493
  }, (args) => runTool("resolve_program", config, rateLimiter, async () => resolveProgram(client, config, args)));
434
- server.registerTool("run_program_name_action", {
494
+ registerTool("run_program_name_action", {
435
495
  title: "Run Program Name Action",
436
496
  description: "Start here for one named program. Resolves a partial program name, then runs targets, new_targets, scope_delta, brief, or target_breakdown.",
437
497
  inputSchema: {
@@ -465,7 +525,7 @@ export function createBbradarServer(client, config) {
465
525
  },
466
526
  annotations: readOnlyAnnotations
467
527
  }, (args) => runTool("run_program_name_action", config, rateLimiter, async () => runProgramNameAction(client, config, args)));
468
- server.registerTool("get_program_eligible_targets_by_name", {
528
+ registerTool("get_program_eligible_targets_by_name", {
469
529
  title: "Get Eligible Targets By Program Name",
470
530
  description: "Fast one-call path for user asks like 'find in-scope eligible targets for Aztec': resolve the program name, fetch targets, and return filtered in-scope bounty-eligible targets. Prefer this over separate resolve_program + get_program_targets calls when the user asks for a target list by name.",
471
531
  inputSchema: {
@@ -496,7 +556,7 @@ export function createBbradarServer(client, config) {
496
556
  },
497
557
  annotations: readOnlyAnnotations
498
558
  }, (args) => runTool("get_program_eligible_targets_by_name", config, rateLimiter, async () => getProgramEligibleTargetsByName(client, config, args)));
499
- server.registerTool("get_program_targets", {
559
+ registerTool("get_program_targets", {
500
560
  title: "Get Program Targets",
501
561
  description: `Get active targets for one program_id, handle, or human program name. This is a final source for eligible target lists; do not call summary/breakdown unless grouped counts are needed. For a program name query, get_program_eligible_targets_by_name is the simplest path. limit max ${MAX_TARGETS_PER_PROGRAM}.`,
502
562
  inputSchema: {
@@ -518,7 +578,7 @@ export function createBbradarServer(client, config) {
518
578
  }, (args) => runTool("get_program_targets", config, rateLimiter, async () => {
519
579
  return runProgramIdTool(client, config, args.program_id, async (programId) => getProgramTargetsPayload(client, args, programId), async (indexFallback) => getProgramTargetsExportFallbackPayload(client, args, indexFallback.resolvedProgramId));
520
580
  }));
521
- server.registerTool("get_recent_changes", {
581
+ registerTool("get_recent_changes", {
522
582
  title: "Get Recent Target Changes",
523
583
  description: `List recent target changes. page_size max ${MAX_RECENT_CHANGES}.`,
524
584
  inputSchema: {
@@ -557,15 +617,22 @@ export function createBbradarServer(client, config) {
557
617
  facets: sanitizeJson(data?.facets)
558
618
  });
559
619
  }));
560
- server.registerTool("get_latest_added_targets", {
620
+ registerTool("get_latest_added_targets", {
561
621
  title: "Get Latest Added Targets",
562
- description: "Latest added targets by type, optionally with that program's target list.",
622
+ description: "Latest added targets by type with optional platform, reward, and report-count filters. For fast wildcard discovery use target_type=wildcard and include_full_target_list=false.",
563
623
  inputSchema: {
564
624
  target_type: filterValueSchema().default("domain"),
625
+ platforms: platformListSchema(),
626
+ min_reward: z.number().int().min(0).optional(),
627
+ reward_threshold_mode: rewardThresholdModeSchema.default("max_at_least"),
628
+ max_public_report_count: z.number().int().min(0).optional(),
629
+ require_known_report_count: z.boolean().default(false),
630
+ include_unknown_report_count: z.boolean().default(true),
565
631
  include_out_of_scope: z.boolean().default(false).describe("Include out-of-scope."),
566
632
  include_ineligible: z.boolean().default(false).describe("Include ineligible."),
567
633
  recent_changes_page_size: recentChangesPageSizeSchema.default(MAX_RECENT_CHANGES),
568
- include_full_target_list: z.boolean().default(true),
634
+ max_results: z.number().int().min(1).max(MAX_RECENT_CHANGES).default(10),
635
+ include_full_target_list: z.boolean().default(true).describe("Fetch the newest matching program's complete target list. Set false for the fastest cross-program discovery."),
569
636
  full_target_list_mode: targetListModeSchema.default("identifiers"),
570
637
  full_target_limit: z.number().int().min(1).max(MAX_TARGETS_PER_PROGRAM).default(MAX_TARGETS_PER_PROGRAM),
571
638
  full_list_include_out_of_scope: z.boolean().default(false),
@@ -577,13 +644,14 @@ export function createBbradarServer(client, config) {
577
644
  query: jsonRecordSchema().optional(),
578
645
  latest_added_at: z.string().optional(),
579
646
  program: programOutputSchema().optional(),
647
+ matches: z.array(jsonRecordSchema()).optional(),
580
648
  new_targets: z.array(z.unknown()).optional(),
581
649
  full_targets: z.array(z.unknown()).optional(),
582
650
  meta: jsonRecordSchema().optional()
583
651
  },
584
652
  annotations: readOnlyAnnotations
585
653
  }, (args) => runTool("get_latest_added_targets", config, rateLimiter, async () => getLatestAddedTargets(client, config, args)));
586
- server.registerTool("get_program_scope_summary", {
654
+ registerTool("get_program_scope_summary", {
587
655
  title: "Get Program Scope Summary",
588
656
  description: "Grouped compact scope for one program.",
589
657
  inputSchema: {
@@ -602,7 +670,7 @@ export function createBbradarServer(client, config) {
602
670
  },
603
671
  annotations: readOnlyAnnotations
604
672
  }, (args) => runTool("get_program_scope_summary", config, rateLimiter, async () => runProgramIdTool(client, config, args.program_id, (programId) => getProgramScopeSummary(client, config, { ...args, program_id: programId }), (indexFallback) => getProgramScopeSummaryFromIndexFallback(client, indexFallback, { ...args, program_id: indexFallback.resolvedProgramId }))));
605
- server.registerTool("get_program_target_breakdown", {
673
+ registerTool("get_program_target_breakdown", {
606
674
  title: "Get Program Target Breakdown",
607
675
  description: "Target type, scope tag, language tag, and bucket counts for one program.",
608
676
  inputSchema: {
@@ -621,7 +689,7 @@ export function createBbradarServer(client, config) {
621
689
  },
622
690
  annotations: readOnlyAnnotations
623
691
  }, (args) => runTool("get_program_target_breakdown", config, rateLimiter, async () => runProgramIdTool(client, config, args.program_id, (programId) => getProgramTargetBreakdown(client, config, { ...args, program_id: programId }), (indexFallback) => getProgramTargetBreakdownFromIndexFallback(client, indexFallback, { ...args, program_id: indexFallback.resolvedProgramId }))));
624
- server.registerTool("get_program_scope_delta", {
692
+ registerTool("get_program_scope_delta", {
625
693
  title: "Get Program Scope Delta",
626
694
  description: "Compact recent scope changes for one program.",
627
695
  inputSchema: {
@@ -647,7 +715,7 @@ export function createBbradarServer(client, config) {
647
715
  },
648
716
  annotations: readOnlyAnnotations
649
717
  }, (args) => runTool("get_program_scope_delta", config, rateLimiter, async () => runProgramIdTool(client, config, args.program_id, (programId) => getProgramScopeDelta(client, config, { ...args, program_id: programId }), (indexFallback) => getProgramScopeDeltaFromIndexedProgram(client, config, { ...args, program_id: indexFallback.resolvedProgramId }, indexFallback.program))));
650
- server.registerTool("get_recent_target_activity", {
718
+ registerTool("get_recent_target_activity", {
651
719
  title: "Get Recent Target Activity",
652
720
  description: "Recent target changes grouped by program.",
653
721
  inputSchema: {
@@ -673,7 +741,7 @@ export function createBbradarServer(client, config) {
673
741
  },
674
742
  annotations: readOnlyAnnotations
675
743
  }, (args) => runTool("get_recent_target_activity", config, rateLimiter, async () => getRecentTargetActivity(client, config, args)));
676
- server.registerTool("check_program_new_targets", {
744
+ registerTool("check_program_new_targets", {
677
745
  title: "Check Program New Targets",
678
746
  description: "Yes/no new in-scope targets for one program.",
679
747
  inputSchema: {
@@ -698,7 +766,7 @@ export function createBbradarServer(client, config) {
698
766
  },
699
767
  annotations: readOnlyAnnotations
700
768
  }, (args) => runTool("check_program_new_targets", config, rateLimiter, async () => runProgramIdTool(client, config, args.program_id, (programId) => checkProgramNewTargets(client, config, { ...args, program_id: programId }), (indexFallback) => checkProgramNewTargetsFromIndexedProgram(client, config, { ...args, program_id: indexFallback.resolvedProgramId }, indexFallback.program))));
701
- server.registerTool("check_watchlist_new_targets", {
769
+ registerTool("check_watchlist_new_targets", {
702
770
  title: "Check Watchlist New Targets",
703
771
  description: "New in-scope targets across many known program_ids.",
704
772
  inputSchema: {
@@ -719,7 +787,7 @@ export function createBbradarServer(client, config) {
719
787
  },
720
788
  annotations: readOnlyAnnotations
721
789
  }, (args) => runTool("check_watchlist_new_targets", config, rateLimiter, async () => checkWatchlistNewTargets(client, config, args)));
722
- server.registerTool("get_opportunities", {
790
+ registerTool("get_opportunities", {
723
791
  title: "Get BBRadar Opportunities",
724
792
  description: `List programs in one opportunity tier. page_size max ${MAX_PROGRAMS_PER_SEARCH}.`,
725
793
  inputSchema: {
@@ -750,7 +818,7 @@ export function createBbradarServer(client, config) {
750
818
  meta: sanitizeJson(data?.meta)
751
819
  });
752
820
  }));
753
- server.registerTool("find_programs", {
821
+ registerTool("find_programs", {
754
822
  title: "Find BBRadar Programs",
755
823
  description: "Ranked program discovery with filters and compact output.",
756
824
  inputSchema: {
@@ -798,24 +866,30 @@ export function createBbradarServer(client, config) {
798
866
  ...args,
799
867
  target_samples_only_wildcards: args.min_wildcards > 0
800
868
  })));
801
- server.registerTool("find_wildcard_programs", {
869
+ registerTool("find_wildcard_programs", {
802
870
  title: "Find Wildcard Programs",
803
- description: "Wildcard program shortlist.",
871
+ description: "Wildcard program shortlist with platform, minimum reward, freshness, and report-count filters.",
804
872
  inputSchema: {
805
873
  platforms: platformListSchema(),
806
874
  tags: tagListSchema(),
807
875
  updated_since: isoDateTimeSchema.optional(),
876
+ min_reward: z.number().int().min(0).optional(),
877
+ reward_threshold_mode: rewardThresholdModeSchema.default("max_at_least"),
808
878
  max_public_report_count: z.number().int().min(0).default(25),
809
879
  require_known_report_count: z.boolean().default(true),
810
880
  include_unknown_report_count: z.boolean().default(false),
811
881
  exclude_ctf: z.boolean().default(true),
812
882
  require_bounty: z.boolean().default(true),
813
883
  min_wildcards: z.number().int().min(1).max(100).default(1),
884
+ min_added_24h: z.number().int().min(0).optional(),
885
+ min_added_7d: z.number().int().min(0).optional(),
886
+ sort_by: programSortSchema.default("best_hunt_value"),
814
887
  max_pages: z.number().int().min(1).max(MAX_ACCEPTED_NUMERIC_LIMIT).default(3),
815
888
  max_results: z.number().int().min(1).max(MAX_ACCEPTED_NUMERIC_LIMIT).default(10),
816
889
  include_target_samples: z.boolean().default(false),
817
890
  target_sample_programs: z.number().int().min(0).max(MAX_ACCEPTED_NUMERIC_LIMIT).default(3),
818
891
  target_sample_size: z.number().int().min(1).max(MAX_ACCEPTED_NUMERIC_LIMIT).default(5),
892
+ output_mode: programListModeSchema.default("compact"),
819
893
  upstream_request_budget: z.number().int().min(1).max(MAX_ACCEPTED_NUMERIC_LIMIT).default(DEFAULT_FIND_UPSTREAM_REQUEST_BUDGET)
820
894
  },
821
895
  outputSchema: findProgramsOutputShape(),
@@ -829,8 +903,8 @@ export function createBbradarServer(client, config) {
829
903
  web3: false,
830
904
  opportunity_levels: [],
831
905
  updated_since: args.updated_since,
832
- min_bounty_min: undefined,
833
- min_bounty_max: undefined,
906
+ min_bounty_min: args.min_reward !== undefined && args.reward_threshold_mode === "min_at_least" ? args.min_reward : undefined,
907
+ min_bounty_max: args.min_reward !== undefined && args.reward_threshold_mode === "max_at_least" ? args.min_reward : undefined,
834
908
  max_bounty_max: undefined,
835
909
  require_bounty: args.require_bounty,
836
910
  max_public_report_count: args.max_public_report_count,
@@ -845,20 +919,21 @@ export function createBbradarServer(client, config) {
845
919
  min_wildcards: args.min_wildcards,
846
920
  min_eligible_targets: undefined,
847
921
  min_total_targets: undefined,
848
- min_added_24h: undefined,
849
- min_added_7d: undefined,
922
+ min_added_24h: args.min_added_24h,
923
+ min_added_7d: args.min_added_7d,
850
924
  max_pages: args.max_pages,
851
925
  max_results: args.max_results,
852
- sort_by: "best_hunt_value",
926
+ sort_by: args.sort_by,
853
927
  include_target_samples: args.include_target_samples,
854
928
  target_sample_programs: args.target_sample_programs,
855
929
  target_sample_size: args.target_sample_size,
856
930
  only_in_scope_targets: true,
857
931
  only_bounty_eligible_targets: true,
858
932
  target_samples_only_wildcards: true,
933
+ output_mode: args.output_mode,
859
934
  upstream_request_budget: args.upstream_request_budget
860
935
  })));
861
- server.registerTool("find_web3_programs", {
936
+ registerTool("find_web3_programs", {
862
937
  title: "Find Web3 Programs",
863
938
  description: "Web3/blockchain/smart-contract program shortlist.",
864
939
  inputSchema: {
@@ -919,7 +994,7 @@ export function createBbradarServer(client, config) {
919
994
  target_samples_only_wildcards: args.min_wildcards > 0,
920
995
  upstream_request_budget: args.upstream_request_budget
921
996
  })));
922
- server.registerTool("find_reward_programs", {
997
+ registerTool("find_reward_programs", {
923
998
  title: "Find Reward Programs",
924
999
  description: "Programs matching reward thresholds.",
925
1000
  inputSchema: {
@@ -948,7 +1023,7 @@ export function createBbradarServer(client, config) {
948
1023
  outputSchema: findProgramsOutputShape(),
949
1024
  annotations: readOnlyAnnotations
950
1025
  }, (args) => runTool("find_reward_programs", config, rateLimiter, async () => findRewardPrograms(client, config, args)));
951
- server.registerTool("find_web3_contests", {
1026
+ registerTool("find_web3_contests", {
952
1027
  title: "Find Web3 Contests",
953
1028
  description: "Web3 contest or competitive audit shortlist.",
954
1029
  inputSchema: {
@@ -971,7 +1046,7 @@ export function createBbradarServer(client, config) {
971
1046
  outputSchema: findProgramsOutputShape(),
972
1047
  annotations: readOnlyAnnotations
973
1048
  }, (args) => runTool("find_web3_contests", config, rateLimiter, async () => findWeb3Contests(client, config, args)));
974
- server.registerTool("find_language_programs", {
1049
+ registerTool("find_language_programs", {
975
1050
  title: "Find Language Programs",
976
1051
  description: "Language-specific program shortlist.",
977
1052
  inputSchema: {
@@ -998,7 +1073,7 @@ export function createBbradarServer(client, config) {
998
1073
  outputSchema: findProgramsOutputShape(),
999
1074
  annotations: readOnlyAnnotations
1000
1075
  }, (args) => runTool("find_language_programs", config, rateLimiter, async () => findLanguagePrograms(client, config, args)));
1001
- server.registerTool("find_target_type_programs", {
1076
+ registerTool("find_target_type_programs", {
1002
1077
  title: "Find Target Type Programs",
1003
1078
  description: "Target-type program shortlist.",
1004
1079
  inputSchema: {
@@ -1024,7 +1099,7 @@ export function createBbradarServer(client, config) {
1024
1099
  outputSchema: findProgramsOutputShape(),
1025
1100
  annotations: readOnlyAnnotations
1026
1101
  }, (args) => runTool("find_target_type_programs", config, rateLimiter, async () => findTargetTypePrograms(client, config, args)));
1027
- server.registerTool("find_vdp_programs", {
1102
+ registerTool("find_vdp_programs", {
1028
1103
  title: "Find VDP Programs",
1029
1104
  description: "VDP/disclosure-only/no-bounty program shortlist.",
1030
1105
  inputSchema: {
@@ -1044,7 +1119,7 @@ export function createBbradarServer(client, config) {
1044
1119
  outputSchema: findProgramsOutputShape(),
1045
1120
  annotations: readOnlyAnnotations
1046
1121
  }, (args) => runTool("find_vdp_programs", config, rateLimiter, async () => findVdpPrograms(client, config, args)));
1047
- server.registerTool("find_paid_programs", {
1122
+ registerTool("find_paid_programs", {
1048
1123
  title: "Find Paid Programs",
1049
1124
  description: "Paid bounty program shortlist.",
1050
1125
  inputSchema: {
@@ -1067,7 +1142,7 @@ export function createBbradarServer(client, config) {
1067
1142
  outputSchema: findProgramsOutputShape(),
1068
1143
  annotations: readOnlyAnnotations
1069
1144
  }, (args) => runTool("find_paid_programs", config, rateLimiter, async () => findPaidPrograms(client, config, args)));
1070
- server.registerTool("find_stack_matches", {
1145
+ registerTool("find_stack_matches", {
1071
1146
  title: "Find Stack Matches",
1072
1147
  description: "Combined stack/language/type/reward shortlist.",
1073
1148
  inputSchema: {
@@ -1097,7 +1172,7 @@ export function createBbradarServer(client, config) {
1097
1172
  outputSchema: findProgramsOutputShape(),
1098
1173
  annotations: readOnlyAnnotations
1099
1174
  }, (args) => runTool("find_stack_matches", config, rateLimiter, async () => findStackMatches(client, config, args)));
1100
- server.registerTool("find_low_noise_programs", {
1175
+ registerTool("find_low_noise_programs", {
1101
1176
  title: "Find Low Noise Programs",
1102
1177
  description: "Low-public-report program shortlist.",
1103
1178
  inputSchema: {
@@ -1123,7 +1198,7 @@ export function createBbradarServer(client, config) {
1123
1198
  outputSchema: findProgramsOutputShape(),
1124
1199
  annotations: readOnlyAnnotations
1125
1200
  }, (args) => runTool("find_low_noise_programs", config, rateLimiter, async () => findLowNoisePrograms(client, config, args)));
1126
- server.registerTool("find_recent_by_type", {
1201
+ registerTool("find_recent_by_type", {
1127
1202
  title: "Find Recent By Type",
1128
1203
  description: "Recent changes by target type grouped by program.",
1129
1204
  inputSchema: {
@@ -1149,7 +1224,7 @@ export function createBbradarServer(client, config) {
1149
1224
  },
1150
1225
  annotations: readOnlyAnnotations
1151
1226
  }, (args) => runTool("find_recent_by_type", config, rateLimiter, async () => findRecentByType(client, config, args)));
1152
- server.registerTool("find_programs_by_target", {
1227
+ registerTool("find_programs_by_target", {
1153
1228
  title: "Find Programs By Target",
1154
1229
  description: "Reverse lookup target/domain ownership. Accepts domains, URLs, wildcards, target names, and partial target text.",
1155
1230
  inputSchema: {
@@ -1172,21 +1247,21 @@ export function createBbradarServer(client, config) {
1172
1247
  },
1173
1248
  annotations: readOnlyAnnotations
1174
1249
  }, (args) => runTool("find_programs_by_target", config, rateLimiter, async () => findProgramsByTarget(client, config, args)));
1175
- server.registerTool("find_program_candidates", {
1250
+ registerTool("find_program_candidates", {
1176
1251
  title: "Find BBRadar Program Candidates",
1177
1252
  description: "Start here for broad program discovery. Default ranked hunt-candidate preset with safe filters and compact output.",
1178
1253
  inputSchema: programCandidatePresetInputSchema,
1179
1254
  outputSchema: findProgramsOutputShape(),
1180
1255
  annotations: readOnlyAnnotations
1181
1256
  }, (args) => runTool("find_program_candidates", config, rateLimiter, async () => findProgramCandidates(client, config, args)));
1182
- server.registerTool("find_hunt_candidates", {
1257
+ registerTool("find_hunt_candidates", {
1183
1258
  title: "Find BBRadar Hunt Candidates",
1184
1259
  description: "Legacy alias for find_program_candidates. Prefer find_program_candidates for new calls.",
1185
1260
  inputSchema: programCandidatePresetInputSchema,
1186
1261
  outputSchema: findProgramsOutputShape(),
1187
1262
  annotations: readOnlyAnnotations
1188
1263
  }, (args) => runTool("find_hunt_candidates", config, rateLimiter, async () => findProgramCandidates(client, config, args)));
1189
- server.registerTool("find_fresh_hunt_candidates", {
1264
+ registerTool("find_fresh_hunt_candidates", {
1190
1265
  title: "Find Fresh Hunt Candidates",
1191
1266
  description: "Freshness-first hunt shortlist.",
1192
1267
  inputSchema: {
@@ -1255,7 +1330,7 @@ export function createBbradarServer(client, config) {
1255
1330
  output_mode: args.output_mode,
1256
1331
  upstream_request_budget: args.upstream_request_budget
1257
1332
  })));
1258
- server.registerTool("find_recently_updated_programs", {
1333
+ registerTool("find_recently_updated_programs", {
1259
1334
  title: "Find Recently Updated Programs",
1260
1335
  description: "Recently updated program shortlist across all platforms by default. Platform filters are applied only when explicitly provided.",
1261
1336
  inputSchema: {
@@ -1280,7 +1355,7 @@ export function createBbradarServer(client, config) {
1280
1355
  outputSchema: findProgramsOutputShape(),
1281
1356
  annotations: readOnlyAnnotations
1282
1357
  }, (args) => runTool("find_recently_updated_programs", config, rateLimiter, async () => findRecentlyUpdatedPrograms(client, config, args)));
1283
- server.registerTool("list_filters", {
1358
+ registerTool("list_filters", {
1284
1359
  title: "List BBRadar Filters",
1285
1360
  description: "Discover observed filter values.",
1286
1361
  inputSchema: {
@@ -1299,7 +1374,7 @@ export function createBbradarServer(client, config) {
1299
1374
  },
1300
1375
  annotations: readOnlyAnnotations
1301
1376
  }, (args) => runTool("list_filters", config, rateLimiter, async () => listFilters(client, args)));
1302
- server.registerTool("get_bbradar_guide", {
1377
+ registerTool("get_bbradar_guide", {
1303
1378
  title: "Get BBRadar Tool Guide",
1304
1379
  description: "Local quick-start guide for choosing BBRadar tools. Call this when the user's request is ambiguous or when a smaller model may need a decision tree.",
1305
1380
  inputSchema: {
@@ -1312,9 +1387,9 @@ export function createBbradarServer(client, config) {
1312
1387
  annotations: readOnlyAnnotations
1313
1388
  }, (args) => runTool("get_bbradar_guide", config, rateLimiter, async () => ({
1314
1389
  request_id: randomUUID(),
1315
- guide: bbradarGuide(args.topic)
1390
+ guide: bbradarGuide(args.topic, config.toolProfile)
1316
1391
  })));
1317
- server.registerTool("get_mcp_status", {
1392
+ registerTool("get_mcp_status", {
1318
1393
  title: "Get BBRadar MCP Status",
1319
1394
  description: "Local MCP status and timing metrics.",
1320
1395
  inputSchema: {},
@@ -1333,10 +1408,14 @@ export function createBbradarServer(client, config) {
1333
1408
  web_base_url: config.webBaseUrl,
1334
1409
  response_cache_enabled: config.cacheTtlMs > 0 && config.cacheMaxEntries > 0,
1335
1410
  cache_ttl_ms: config.cacheTtlMs,
1411
+ negative_cache_ttl_ms: config.negativeCacheTtlMs,
1336
1412
  cache_max_entries: config.cacheMaxEntries,
1337
1413
  local_program_index_enabled: false,
1338
1414
  default_rate_limit_per_minute: config.defaultRateLimitPerMinute,
1339
1415
  export_rate_limit_per_minute: config.exportRateLimitPerMinute,
1416
+ max_concurrent_upstream_requests: config.maxConcurrentRequests,
1417
+ compact_tool_text: config.compactToolText,
1418
+ tool_profile: config.toolProfile,
1340
1419
  request_timeout_ms: config.requestTimeoutMs,
1341
1420
  validate_on_startup: config.validateOnStartup,
1342
1421
  transport: "stdio",
@@ -1345,7 +1424,7 @@ export function createBbradarServer(client, config) {
1345
1424
  client: client.diagnostics()
1346
1425
  }
1347
1426
  })));
1348
- server.registerTool("compare_programs", {
1427
+ registerTool("compare_programs", {
1349
1428
  title: "Compare BBRadar Programs",
1350
1429
  description: "Compare programs.",
1351
1430
  inputSchema: {
@@ -1359,7 +1438,7 @@ export function createBbradarServer(client, config) {
1359
1438
  outputSchema: decisionOutputShape(),
1360
1439
  annotations: readOnlyAnnotations
1361
1440
  }, (args) => runTool("compare_programs", config, rateLimiter, async () => comparePrograms(client, config, args)));
1362
- server.registerTool("compare_programs_compact", {
1441
+ registerTool("compare_programs_compact", {
1363
1442
  title: "Compare Programs Compact",
1364
1443
  description: "Compact program comparison.",
1365
1444
  inputSchema: {
@@ -1372,7 +1451,7 @@ export function createBbradarServer(client, config) {
1372
1451
  outputSchema: decisionOutputShape(),
1373
1452
  annotations: readOnlyAnnotations
1374
1453
  }, (args) => runTool("compare_programs_compact", config, rateLimiter, async () => comparePrograms(client, config, { ...args, output_mode: "compact" })));
1375
- server.registerTool("summarize_program_activity", {
1454
+ registerTool("summarize_program_activity", {
1376
1455
  title: "Summarize Program Activity",
1377
1456
  description: "Summarize one program's activity.",
1378
1457
  inputSchema: {
@@ -1387,7 +1466,7 @@ export function createBbradarServer(client, config) {
1387
1466
  },
1388
1467
  annotations: readOnlyAnnotations
1389
1468
  }, (args) => runTool("summarize_program_activity", config, rateLimiter, async () => runProgramIdTool(client, config, args.program_id, (programId) => summarizeProgramActivity(client, config, programId, args.recent_changes_limit))));
1390
- server.registerTool("get_program_brief", {
1469
+ registerTool("get_program_brief", {
1391
1470
  title: "Get Program Brief",
1392
1471
  description: "Compact worth-hunting brief for one program.",
1393
1472
  inputSchema: {
@@ -1410,17 +1489,28 @@ export function createBbradarServer(client, config) {
1410
1489
  },
1411
1490
  annotations: readOnlyAnnotations
1412
1491
  }, (args) => runTool("get_program_brief", config, rateLimiter, async () => runProgramIdTool(client, config, args.program_id, (programId) => getProgramBrief(client, config, { ...args, program_id: programId }))));
1413
- server.registerTool("find_recently_added_wildcards", {
1492
+ registerTool("find_recently_added_wildcards", {
1414
1493
  title: "Find Recently Added Wildcards",
1415
- description: "Recently added wildcard programs.",
1494
+ description: "Recently added wildcard programs with platform, minimum reward, and report-count filters. Returns bounded wildcard target samples.",
1416
1495
  inputSchema: {
1417
1496
  platforms: platformListSchema(),
1418
1497
  tags: tagListSchema(),
1498
+ min_added_24h: z.number().int().min(0).optional(),
1419
1499
  min_added_7d: z.number().int().min(1).default(1),
1500
+ min_reward: z.number().int().min(0).optional(),
1501
+ reward_threshold_mode: rewardThresholdModeSchema.default("max_at_least"),
1420
1502
  max_public_report_count: z.number().int().min(0).optional(),
1503
+ require_known_report_count: z.boolean().default(false),
1504
+ include_unknown_report_count: z.boolean().default(false),
1421
1505
  require_bounty: z.boolean().default(true),
1506
+ min_wildcards: z.number().int().min(1).max(100).default(1),
1507
+ sort_by: programSortSchema.default("most_new_targets"),
1422
1508
  max_pages: z.number().int().min(1).max(MAX_ACCEPTED_NUMERIC_LIMIT).default(3),
1423
1509
  max_results: z.number().int().min(1).max(MAX_ACCEPTED_NUMERIC_LIMIT).default(10),
1510
+ include_target_samples: z.boolean().default(true),
1511
+ target_sample_programs: z.number().int().min(0).max(MAX_ACCEPTED_NUMERIC_LIMIT).default(3),
1512
+ target_sample_size: z.number().int().min(1).max(MAX_ACCEPTED_NUMERIC_LIMIT).default(5),
1513
+ output_mode: programListModeSchema.default("compact"),
1424
1514
  upstream_request_budget: z.number().int().min(1).max(MAX_ACCEPTED_NUMERIC_LIMIT).default(DEFAULT_FIND_UPSTREAM_REQUEST_BUDGET)
1425
1515
  },
1426
1516
  outputSchema: findProgramsOutputShape(),
@@ -1434,37 +1524,38 @@ export function createBbradarServer(client, config) {
1434
1524
  web3: false,
1435
1525
  opportunity_levels: [],
1436
1526
  updated_since: undefined,
1437
- min_bounty_min: undefined,
1438
- min_bounty_max: undefined,
1527
+ min_bounty_min: args.min_reward !== undefined && args.reward_threshold_mode === "min_at_least" ? args.min_reward : undefined,
1528
+ min_bounty_max: args.min_reward !== undefined && args.reward_threshold_mode === "max_at_least" ? args.min_reward : undefined,
1439
1529
  max_bounty_max: undefined,
1440
1530
  require_bounty: args.require_bounty,
1441
1531
  max_public_report_count: args.max_public_report_count,
1442
- require_known_report_count: false,
1443
- include_unknown_report_count: false,
1532
+ require_known_report_count: args.require_known_report_count,
1533
+ include_unknown_report_count: args.include_unknown_report_count,
1444
1534
  exclude_ctf: true,
1445
1535
  exclude_mobile_only: false,
1446
1536
  exclude_non_web: false,
1447
1537
  has_api_scope: false,
1448
1538
  fresh_launch_days: undefined,
1449
- min_wildcards: 1,
1539
+ min_wildcards: args.min_wildcards,
1450
1540
  min_eligible_targets: undefined,
1451
1541
  min_total_targets: undefined,
1452
- min_added_24h: undefined,
1542
+ min_added_24h: args.min_added_24h,
1453
1543
  min_added_7d: args.min_added_7d,
1454
1544
  max_pages: args.max_pages,
1455
1545
  max_results: args.max_results,
1456
- sort_by: "best_hunt_value",
1457
- include_target_samples: true,
1458
- target_sample_programs: Math.min(args.max_results, MAX_FIND_TARGET_SAMPLE_PROGRAMS),
1459
- target_sample_size: 5,
1546
+ sort_by: args.sort_by,
1547
+ include_target_samples: args.include_target_samples,
1548
+ target_sample_programs: args.target_sample_programs,
1549
+ target_sample_size: args.target_sample_size,
1460
1550
  only_in_scope_targets: true,
1461
1551
  only_bounty_eligible_targets: true,
1462
1552
  target_samples_only_wildcards: true,
1553
+ output_mode: args.output_mode,
1463
1554
  upstream_request_budget: args.upstream_request_budget
1464
1555
  })));
1465
- server.registerTool("find_low_competition_high_reward", {
1556
+ registerTool("find_low_competition_high_reward", {
1466
1557
  title: "Find Low Competition High Reward",
1467
- description: "Legacy low-report high-reward shortlist.",
1558
+ description: "Low-report, high-reward shortlist with optional wildcard and technology filters.",
1468
1559
  inputSchema: {
1469
1560
  platforms: platformListSchema(),
1470
1561
  tags: tagListSchema(),
@@ -1473,6 +1564,7 @@ export function createBbradarServer(client, config) {
1473
1564
  max_public_report_count: z.number().int().min(0).default(10),
1474
1565
  min_bounty_max: z.number().int().min(0).default(5_000),
1475
1566
  min_eligible_targets: z.number().int().min(0).default(1),
1567
+ min_wildcards: z.number().int().min(0).max(100).default(0),
1476
1568
  exclude_ctf: z.boolean().default(true),
1477
1569
  exclude_mobile_only: z.boolean().default(false),
1478
1570
  exclude_non_web: z.boolean().default(false),
@@ -1480,6 +1572,10 @@ export function createBbradarServer(client, config) {
1480
1572
  fresh_launch_days: z.number().int().min(1).max(MAX_ACCEPTED_NUMERIC_LIMIT).optional(),
1481
1573
  max_pages: z.number().int().min(1).max(MAX_ACCEPTED_NUMERIC_LIMIT).default(3),
1482
1574
  max_results: z.number().int().min(1).max(MAX_ACCEPTED_NUMERIC_LIMIT).default(10),
1575
+ include_target_samples: z.boolean().default(true),
1576
+ target_sample_programs: z.number().int().min(0).max(MAX_ACCEPTED_NUMERIC_LIMIT).default(3),
1577
+ target_sample_size: z.number().int().min(1).max(MAX_ACCEPTED_NUMERIC_LIMIT).default(5),
1578
+ output_mode: programListModeSchema.default("compact"),
1483
1579
  upstream_request_budget: z.number().int().min(1).max(MAX_ACCEPTED_NUMERIC_LIMIT).default(DEFAULT_FIND_UPSTREAM_REQUEST_BUDGET)
1484
1580
  },
1485
1581
  outputSchema: findProgramsOutputShape(),
@@ -1505,7 +1601,7 @@ export function createBbradarServer(client, config) {
1505
1601
  exclude_non_web: args.exclude_non_web,
1506
1602
  has_api_scope: args.has_api_scope,
1507
1603
  fresh_launch_days: args.fresh_launch_days,
1508
- min_wildcards: 0,
1604
+ min_wildcards: args.min_wildcards,
1509
1605
  min_eligible_targets: args.min_eligible_targets,
1510
1606
  min_total_targets: undefined,
1511
1607
  min_added_24h: undefined,
@@ -1513,15 +1609,16 @@ export function createBbradarServer(client, config) {
1513
1609
  max_pages: args.max_pages,
1514
1610
  max_results: args.max_results,
1515
1611
  sort_by: "best_hunt_value",
1516
- include_target_samples: true,
1517
- target_sample_programs: Math.min(args.max_results, MAX_FIND_TARGET_SAMPLE_PROGRAMS),
1518
- target_sample_size: 5,
1612
+ include_target_samples: args.include_target_samples,
1613
+ target_sample_programs: args.target_sample_programs,
1614
+ target_sample_size: args.target_sample_size,
1519
1615
  only_in_scope_targets: true,
1520
1616
  only_bounty_eligible_targets: true,
1521
- target_samples_only_wildcards: false,
1617
+ target_samples_only_wildcards: args.min_wildcards > 0,
1618
+ output_mode: args.output_mode,
1522
1619
  upstream_request_budget: args.upstream_request_budget
1523
1620
  })));
1524
- server.registerTool("get_program_delta", {
1621
+ registerTool("get_program_delta", {
1525
1622
  title: "Get Program Delta",
1526
1623
  description: "Recent target changes for one program.",
1527
1624
  inputSchema: {
@@ -1539,7 +1636,7 @@ export function createBbradarServer(client, config) {
1539
1636
  },
1540
1637
  annotations: readOnlyAnnotations
1541
1638
  }, (args) => runTool("get_program_delta", config, rateLimiter, async () => runProgramIdTool(client, config, args.program_id, (programId) => getProgramDelta(client, config, { ...args, program_id: programId }))));
1542
- server.registerTool("export_targets", {
1639
+ registerTool("export_targets", {
1543
1640
  title: "Export BBRadar Targets",
1544
1641
  description: `Read-only target export. limit max ${MAX_TARGET_EXPORT}.`,
1545
1642
  inputSchema: {
@@ -1596,11 +1693,14 @@ export function createBbradarServer(client, config) {
1596
1693
  });
1597
1694
  }
1598
1695
  }));
1599
- registerPrompts(server);
1696
+ registerPrompts(server, config.toolProfile);
1600
1697
  registerResources(server, client, config, exportStore);
1601
1698
  return server;
1602
1699
  }
1603
- function bbradarGuide(topic) {
1700
+ function bbradarGuide(topic, profile) {
1701
+ if (profile === "core") {
1702
+ return coreBbradarGuide(topic);
1703
+ }
1604
1704
  const primaryEntryPoints = [
1605
1705
  {
1606
1706
  tool: "find_program_candidates",
@@ -1652,6 +1752,27 @@ function bbradarGuide(topic) {
1652
1752
  first_tool: "find_recently_updated_programs",
1653
1753
  then: "Use get_latest_added_targets for global added targets, or check_program_new_targets when the user names one program."
1654
1754
  },
1755
+ {
1756
+ user_goal: "latest added wildcard targets with platform, reward, or report-count filters",
1757
+ first_tool: "get_latest_added_targets",
1758
+ arguments: {
1759
+ target_type: "wildcard",
1760
+ platforms: ["requested platform"],
1761
+ min_reward: 5000,
1762
+ max_public_report_count: 10,
1763
+ include_full_target_list: false
1764
+ }
1765
+ },
1766
+ {
1767
+ user_goal: "wildcard programs with low report count and good rewards",
1768
+ first_tool: "find_wildcard_programs",
1769
+ arguments: {
1770
+ platforms: ["requested platform"],
1771
+ min_reward: 5000,
1772
+ max_public_report_count: 10,
1773
+ include_target_samples: true
1774
+ }
1775
+ },
1655
1776
  {
1656
1777
  user_goal: "compare a short list",
1657
1778
  first_tool: "compare_programs_compact",
@@ -1669,8 +1790,8 @@ function bbradarGuide(topic) {
1669
1790
  }
1670
1791
  ];
1671
1792
  const advancedTools = {
1672
- discovery: ["find_stack_matches", "find_language_programs", "find_target_type_programs", "find_reward_programs", "find_paid_programs", "find_web3_contests", "find_low_noise_programs"],
1673
- freshness: ["find_recently_updated_programs", "find_fresh_hunt_candidates", "get_latest_added_targets", "get_recent_target_activity", "get_program_scope_delta", "check_watchlist_new_targets"],
1793
+ discovery: ["find_wildcard_programs", "find_low_competition_high_reward", "find_stack_matches", "find_language_programs", "find_target_type_programs", "find_reward_programs", "find_paid_programs", "find_web3_contests", "find_low_noise_programs"],
1794
+ freshness: ["find_recently_added_wildcards", "find_recently_updated_programs", "find_fresh_hunt_candidates", "get_latest_added_targets", "get_recent_target_activity", "get_program_scope_delta", "check_watchlist_new_targets"],
1674
1795
  details: ["get_program_brief", "get_program_scope_summary", "get_program_target_breakdown", "find_programs_by_target"],
1675
1796
  exports: ["export_targets"]
1676
1797
  };
@@ -1702,6 +1823,20 @@ function bbradarGuide(topic) {
1702
1823
  {
1703
1824
  user_says: "who owns https://api.example.com/v1/users",
1704
1825
  call: { tool: "find_programs_by_target", arguments: { target_query: "https://api.example.com/v1/users" } }
1826
+ },
1827
+ {
1828
+ user_says: "latest HackerOne wildcard targets with rewards over 5000",
1829
+ call: {
1830
+ tool: "get_latest_added_targets",
1831
+ arguments: { target_type: "wildcard", platforms: ["HackerOne"], min_reward: 5000, include_full_target_list: false }
1832
+ }
1833
+ },
1834
+ {
1835
+ user_says: "wildcard programs with under 10 reports and good rewards",
1836
+ call: {
1837
+ tool: "find_wildcard_programs",
1838
+ arguments: { max_public_report_count: 10, min_reward: 5000, include_target_samples: true }
1839
+ }
1705
1840
  }
1706
1841
  ];
1707
1842
  return {
@@ -1722,6 +1857,67 @@ function bbradarGuide(topic) {
1722
1857
  examples
1723
1858
  };
1724
1859
  }
1860
+ function coreBbradarGuide(topic) {
1861
+ const decisionTree = [
1862
+ {
1863
+ user_goal: "find programs to hunt",
1864
+ first_tool: "find_programs",
1865
+ arguments: { max_results: 10, output_mode: "compact" }
1866
+ },
1867
+ {
1868
+ user_goal: "named program summary or action",
1869
+ first_tool: "run_program_name_action",
1870
+ arguments: { query: "program name", action: "brief" }
1871
+ },
1872
+ {
1873
+ user_goal: "named program targets",
1874
+ first_tool: "get_program_eligible_targets_by_name",
1875
+ arguments: { query: "program name", target_list_mode: "identifiers" }
1876
+ },
1877
+ {
1878
+ user_goal: "find which program owns a target",
1879
+ first_tool: "find_programs_by_target",
1880
+ arguments: { target_query: "domain, URL, wildcard, package/repo name, or short target phrase", match_mode: "smart" }
1881
+ },
1882
+ {
1883
+ user_goal: "fresh or recently changed scope",
1884
+ first_tool: "get_recent_changes",
1885
+ then: "Use get_latest_added_targets when only newly added targets are needed."
1886
+ },
1887
+ {
1888
+ user_goal: "export targets",
1889
+ first_tool: "export_targets",
1890
+ then: "Use the returned bbradar://exports resource_uri for the full local export payload."
1891
+ },
1892
+ {
1893
+ user_goal: "unknown filter values",
1894
+ first_tool: "list_filters",
1895
+ then: "Reuse observed platforms, tags, target types, and language tags in find_programs."
1896
+ }
1897
+ ];
1898
+ return {
1899
+ topic,
1900
+ tool_profile: "core",
1901
+ rule_zero: "BBRadar is passive intelligence only. Never scan or contact targets.",
1902
+ defaults: {
1903
+ output_mode: "compact",
1904
+ target_list_mode: "identifiers",
1905
+ target_match_mode: "smart",
1906
+ include_out_of_scope: false,
1907
+ include_ineligible: false,
1908
+ require_bounty: true
1909
+ },
1910
+ primary_entry_points: [
1911
+ "find_programs",
1912
+ "run_program_name_action",
1913
+ "get_program_eligible_targets_by_name",
1914
+ "find_programs_by_target",
1915
+ "get_bbradar_guide"
1916
+ ],
1917
+ decision_tree: decisionTree.filter((entry) => topic === "start" || guideEntryMatchesTopic(topic, entry)),
1918
+ available_tools: [...CORE_TOOL_NAMES]
1919
+ };
1920
+ }
1725
1921
  function guideEntryMatchesTopic(topic, entry) {
1726
1922
  const goal = typeof entry.user_goal === "string" ? entry.user_goal : "";
1727
1923
  const firstTool = typeof entry.first_tool === "string" ? entry.first_tool : "";
@@ -3156,13 +3352,27 @@ async function findProgramsByTarget(client, config, input) {
3156
3352
  };
3157
3353
  const sourceRequests = [];
3158
3354
  const matches = [];
3355
+ const directHandleFirst = !queryLooksLikeTargetIdentifier(input.target_query) &&
3356
+ !/\s/.test(input.target_query.trim()) &&
3357
+ looksLikeDirectProgramHandleQuery(input.target_query);
3358
+ if (input.use_api_search && !directHandleFirst) {
3359
+ const directResult = await searchProgramsByTargetApi(client, config, input, budget, warnings, sourceRequests);
3360
+ if (directResult) {
3361
+ return directResult;
3362
+ }
3363
+ }
3159
3364
  const directHandles = await collectDirectHandlePrograms(client, {
3160
3365
  query: input.target_query,
3161
3366
  platforms: input.platforms,
3162
3367
  budget,
3163
3368
  warnings,
3164
3369
  source: "target_query_program_id_guess",
3165
- maxProgramIds: 1,
3370
+ maxProgramIds: input.use_api_search && directHandleFirst
3371
+ ? 4
3372
+ : queryLooksLikeTargetIdentifier(input.target_query) || looksLikeDirectProgramHandleQuery(input.target_query)
3373
+ ? MAX_DIRECT_HANDLE_RESOLUTION_REQUESTS
3374
+ : 4,
3375
+ maxHandleVariants: 1,
3166
3376
  stopOnFirstMatch: true
3167
3377
  });
3168
3378
  sourceRequests.push(...directHandles.sourceRequests);
@@ -3181,8 +3391,8 @@ async function findProgramsByTarget(client, config, input) {
3181
3391
  }
3182
3392
  });
3183
3393
  }
3184
- if (input.use_api_search) {
3185
- const directResult = await searchProgramsByTargetApi(client, config, input, warnings);
3394
+ if (input.use_api_search && directHandleFirst) {
3395
+ const directResult = await searchProgramsByTargetApi(client, config, input, budget, warnings, sourceRequests);
3186
3396
  if (directResult) {
3187
3397
  return directResult;
3188
3398
  }
@@ -3287,13 +3497,18 @@ function programsByTargetResult(input, warnings, sourceRequests, matches, budget
3287
3497
  meta: options.meta
3288
3498
  });
3289
3499
  }
3290
- async function searchProgramsByTargetApi(client, config, input, warnings) {
3500
+ async function searchProgramsByTargetApi(client, config, input, budget, warnings, sourceRequests) {
3291
3501
  const searchQueries = targetApiSearchQueries(input.target_query);
3292
3502
  const grouped = new Map();
3293
- const sourceRequests = [];
3294
3503
  let rawMatchesScanned = 0;
3504
+ let searchQueriesChecked = 0;
3295
3505
  let lastMeta;
3296
3506
  for (const searchQuery of searchQueries) {
3507
+ if (!tryConsumeBudget(budget)) {
3508
+ addUniqueWarning(warnings, "Upstream request budget was exhausted before all target search variants could be checked.");
3509
+ break;
3510
+ }
3511
+ searchQueriesChecked += 1;
3297
3512
  let api;
3298
3513
  try {
3299
3514
  api = await client.searchTargets({
@@ -3306,8 +3521,10 @@ async function searchProgramsByTargetApi(client, config, input, warnings) {
3306
3521
  page: 1,
3307
3522
  page_size: Math.max(input.max_results * input.max_targets_per_program, input.max_results)
3308
3523
  });
3524
+ refundBudgetIfNoUpstreamRequest(budget, api);
3309
3525
  }
3310
3526
  catch (error) {
3527
+ refundBudgetIfNoUpstreamError(budget, error);
3311
3528
  if (error instanceof BBRadarApiError && (error.status === 404 || error.status === 405)) {
3312
3529
  warnings.push("Direct target search API is unavailable; fell back to sampled program target lists.");
3313
3530
  return undefined;
@@ -3348,15 +3565,93 @@ async function searchProgramsByTargetApi(client, config, input, warnings) {
3348
3565
  if (!targetMatchesQuery(target, input.target_query, input.match_mode)) {
3349
3566
  continue;
3350
3567
  }
3351
- const existing = grouped.get(programId) ?? { program: addProgramResourceLinks({ ...program, id: programId }), targets: [] };
3352
- existing.targets.push(target);
3568
+ const existing = grouped.get(programId) ?? {
3569
+ program: addProgramResourceLinks({ ...program, id: programId }),
3570
+ targets: [],
3571
+ targetKeys: new Set()
3572
+ };
3573
+ const targetKey = stableStringify({
3574
+ identifier: targetIdentifier(target),
3575
+ target_type: stringField(target, "target_type")
3576
+ });
3577
+ if (!existing.targetKeys.has(targetKey)) {
3578
+ existing.targetKeys.add(targetKey);
3579
+ existing.targets.push(target);
3580
+ }
3353
3581
  grouped.set(programId, existing);
3354
3582
  }
3355
3583
  }
3356
- if (grouped.size >= input.max_results) {
3584
+ if (grouped.size >= input.max_results ||
3585
+ (grouped.size > 0 && input.match_mode === "smart")) {
3357
3586
  break;
3358
3587
  }
3359
3588
  }
3589
+ if (grouped.size > 0 && input.match_mode === "smart") {
3590
+ await mapWithConcurrency([...grouped.entries()].slice(0, input.max_results), TARGET_SAMPLE_CONCURRENCY, async ([programId, entry]) => {
3591
+ if (!tryConsumeBudget(budget)) {
3592
+ addUniqueWarning(warnings, "Upstream request budget was exhausted before matched program target lists could be hydrated.");
3593
+ return;
3594
+ }
3595
+ try {
3596
+ const targetsApi = await client.getProgramTargets(programId);
3597
+ refundBudgetIfNoUpstreamRequest(budget, targetsApi);
3598
+ sourceRequests.push({
3599
+ source: "program_targets",
3600
+ program_id: programId,
3601
+ request_id: targetsApi.requestId,
3602
+ upstream_request_id: targetsApi.upstreamRequestId,
3603
+ ...apiSourceMetadata(targetsApi)
3604
+ });
3605
+ const targetsData = readObject(targetsApi.data);
3606
+ const hydratedTargets = readArray(targetsData?.targets).map(sanitizeTarget);
3607
+ const hydratedTargetOrder = new Map(hydratedTargets.map((target, index) => [
3608
+ stableStringify({
3609
+ identifier: targetIdentifier(target),
3610
+ target_type: stringField(target, "target_type")
3611
+ }),
3612
+ index
3613
+ ]));
3614
+ for (const target of hydratedTargets) {
3615
+ if (!targetIdentifier(target) ||
3616
+ !targetHasAllowedScope(target, {
3617
+ include_out_of_scope: input.include_out_of_scope,
3618
+ include_ineligible: input.include_ineligible,
3619
+ strict_scope_filter: false
3620
+ }) ||
3621
+ !targetMatchesQuery(target, input.target_query, input.match_mode)) {
3622
+ continue;
3623
+ }
3624
+ const targetKey = stableStringify({
3625
+ identifier: targetIdentifier(target),
3626
+ target_type: stringField(target, "target_type")
3627
+ });
3628
+ if (!entry.targetKeys.has(targetKey)) {
3629
+ entry.targetKeys.add(targetKey);
3630
+ entry.targets.push(target);
3631
+ }
3632
+ }
3633
+ entry.targets.sort((left, right) => {
3634
+ const leftKey = stableStringify({
3635
+ identifier: targetIdentifier(left),
3636
+ target_type: stringField(left, "target_type")
3637
+ });
3638
+ const rightKey = stableStringify({
3639
+ identifier: targetIdentifier(right),
3640
+ target_type: stringField(right, "target_type")
3641
+ });
3642
+ return ((hydratedTargetOrder.get(leftKey) ?? Number.MAX_SAFE_INTEGER) -
3643
+ (hydratedTargetOrder.get(rightKey) ?? Number.MAX_SAFE_INTEGER));
3644
+ });
3645
+ }
3646
+ catch (error) {
3647
+ refundBudgetIfNoUpstreamError(budget, error);
3648
+ if (!isProgramNotFoundError(error)) {
3649
+ throw error;
3650
+ }
3651
+ addUniqueWarning(warnings, `Could not hydrate target matches for ${programId}; returned direct target-search matches only.`);
3652
+ }
3653
+ });
3654
+ }
3360
3655
  const matches = [...grouped.values()].slice(0, input.max_results).map((entry) => stripUndefined({
3361
3656
  program: formatProgram(entry.program, "compact"),
3362
3657
  match_count: entry.targets.length,
@@ -3384,6 +3679,14 @@ async function searchProgramsByTargetApi(client, config, input, warnings) {
3384
3679
  },
3385
3680
  matches,
3386
3681
  programs: matches.map((match) => readObject(match.program)).filter((program) => program !== undefined),
3682
+ upstream_budget: {
3683
+ used: budget.initial - budget.remaining,
3684
+ remaining: budget.remaining
3685
+ },
3686
+ ranking_scope: {
3687
+ mode: "target_search_api",
3688
+ possibly_incomplete: grouped.size < input.max_results && searchQueriesChecked < searchQueries.length
3689
+ },
3387
3690
  meta: stripUndefined({
3388
3691
  ...(lastMeta ?? {}),
3389
3692
  returned: matches.length,
@@ -3480,7 +3783,8 @@ async function listFilters(client, input) {
3480
3783
  }
3481
3784
  }
3482
3785
  }
3483
- catch {
3786
+ catch (error) {
3787
+ refundBudgetIfNoUpstreamError(budget, error);
3484
3788
  // Facets are best-effort; list_filters should still return observed program filters.
3485
3789
  }
3486
3790
  if (input.include_target_facets && input.target_sample_programs > 0) {
@@ -3616,11 +3920,15 @@ async function comparePrograms(client, config, input) {
3616
3920
  });
3617
3921
  }
3618
3922
  async function summarizeProgramActivity(client, config, programId, recentChangesLimit) {
3619
- const programApi = await client.getProgram(programId);
3923
+ const [programApi, changes] = await Promise.all([
3924
+ client.getProgram(programId),
3925
+ recentChangesLimit > 0
3926
+ ? fetchProgramChanges(client, config, programId, recentChangesLimit, true, true, true)
3927
+ : Promise.resolve(undefined)
3928
+ ]);
3620
3929
  const program = addProgramResourceLinks(sanitizeProgram(programApi.data, config.webBaseUrl));
3621
3930
  const scopeSummary = readObject(program.scope_summary);
3622
3931
  const targetActivity = readObject(scopeSummary?.target_activity);
3623
- const changes = recentChangesLimit > 0 ? await fetchProgramChanges(client, config, programId, recentChangesLimit, true, true, true) : undefined;
3624
3932
  return {
3625
3933
  request_id: randomUUID(),
3626
3934
  source_requests: [
@@ -3647,12 +3955,14 @@ async function getLatestAddedTargets(client, config, input) {
3647
3955
  include_removed: false,
3648
3956
  include_ineligible: input.include_ineligible,
3649
3957
  include_out_of_scope: input.include_out_of_scope,
3958
+ platforms: input.platforms,
3650
3959
  tags: [input.target_type],
3651
3960
  page: 1,
3652
3961
  page_size: input.recent_changes_page_size
3653
3962
  });
3654
3963
  const recentData = readObject(recentApi.data);
3655
3964
  const changes = readArray(recentData?.results).map((change) => sanitizeChange(change, config.webBaseUrl));
3965
+ const platformFilters = new Set(input.platforms.map(normalizeTag));
3656
3966
  const matchingChanges = changes
3657
3967
  .filter((change) => {
3658
3968
  const target = readObject(change.target);
@@ -3661,6 +3971,7 @@ async function getLatestAddedTargets(client, config, input) {
3661
3971
  programId !== undefined &&
3662
3972
  target !== undefined &&
3663
3973
  targetMatchesRequestedType(target, input.target_type) &&
3974
+ latestAddedProgramMatches(change, input, platformFilters) &&
3664
3975
  targetHasAllowedScope(target, {
3665
3976
  include_out_of_scope: input.include_out_of_scope,
3666
3977
  include_ineligible: input.include_ineligible,
@@ -3668,6 +3979,11 @@ async function getLatestAddedTargets(client, config, input) {
3668
3979
  }));
3669
3980
  })
3670
3981
  .sort((left, right) => timestampField(right, "changed_at") - timestampField(left, "changed_at"));
3982
+ const limitedMatches = matchingChanges.slice(0, input.max_results);
3983
+ const matches = limitedMatches.map((change, index) => ({
3984
+ rank: index + 1,
3985
+ ...formatChange(change, "compact")
3986
+ }));
3671
3987
  const latest = matchingChanges[0];
3672
3988
  const sourceRequests = [
3673
3989
  {
@@ -3682,9 +3998,12 @@ async function getLatestAddedTargets(client, config, input) {
3682
3998
  request_id: randomUUID(),
3683
3999
  source_requests: sourceRequests,
3684
4000
  query: latestAddedTargetsQuery(input),
4001
+ matches: [],
3685
4002
  new_targets: [],
3686
4003
  meta: {
3687
4004
  recent_changes_scanned: changes.length,
4005
+ matching_changes_scanned: 0,
4006
+ matches_returned: 0,
3688
4007
  no_match: true
3689
4008
  }
3690
4009
  };
@@ -3727,11 +4046,14 @@ async function getLatestAddedTargets(client, config, input) {
3727
4046
  query: latestAddedTargetsQuery(input),
3728
4047
  latest_added_at: latestAddedAt,
3729
4048
  program,
4049
+ matches,
3730
4050
  new_targets: formatTargetList(latestNewTargets, input.full_target_list_mode),
3731
4051
  full_targets: input.include_full_target_list ? formatTargetList(limitedFullTargets, input.full_target_list_mode) : undefined,
3732
4052
  meta: stripUndefined({
3733
4053
  recent_changes_scanned: changes.length,
3734
4054
  matching_changes_scanned: matchingChanges.length,
4055
+ matches_returned: matches.length,
4056
+ matches_has_more: matches.length < matchingChanges.length,
3735
4057
  new_targets_returned: formatTargetList(latestNewTargets, input.full_target_list_mode).length,
3736
4058
  full_targets_total_active: totalActiveTargets,
3737
4059
  full_targets_total_after_filters: totalAfterFilters,
@@ -3740,6 +4062,39 @@ async function getLatestAddedTargets(client, config, input) {
3740
4062
  })
3741
4063
  });
3742
4064
  }
4065
+ function latestAddedProgramMatches(change, input, platformFilters) {
4066
+ const rawProgram = readObject(change.program);
4067
+ if (!rawProgram) {
4068
+ return false;
4069
+ }
4070
+ const program = addProgramResourceLinks(rawProgram);
4071
+ const rewardRange = readObject(program.reward_range);
4072
+ const platform = normalizeTag(stringField(program, "platform") ?? "");
4073
+ const bountyMin = numberField(rewardRange, "min");
4074
+ const bountyMax = numberField(rewardRange, "max");
4075
+ const publicReportCount = numberField(program, "public_report_count");
4076
+ if (platformFilters.size > 0 && !platformFilters.has(platform)) {
4077
+ return false;
4078
+ }
4079
+ if (input.min_reward !== undefined) {
4080
+ const reward = input.reward_threshold_mode === "min_at_least" ? bountyMin : bountyMax;
4081
+ if ((reward ?? 0) < input.min_reward) {
4082
+ return false;
4083
+ }
4084
+ }
4085
+ if (input.require_known_report_count && publicReportCount === undefined) {
4086
+ return false;
4087
+ }
4088
+ if (input.max_public_report_count !== undefined) {
4089
+ if (publicReportCount === undefined) {
4090
+ return input.include_unknown_report_count;
4091
+ }
4092
+ if (publicReportCount > input.max_public_report_count) {
4093
+ return false;
4094
+ }
4095
+ }
4096
+ return true;
4097
+ }
3743
4098
  async function getProgramTargetsPayload(client, input, programId) {
3744
4099
  const api = await client.getProgramTargets(programId);
3745
4100
  const data = readObject(api.data);
@@ -4296,9 +4651,11 @@ async function getProgramTargetBreakdownFromIndexFallback(client, indexFallback,
4296
4651
  });
4297
4652
  }
4298
4653
  async function getProgramScopeDelta(client, config, input) {
4299
- const programApi = await client.getProgram(input.program_id);
4654
+ const [programApi, changesPayload] = await Promise.all([
4655
+ client.getProgram(input.program_id),
4656
+ fetchProgramChanges(client, config, input.program_id, input.page_size, input.include_removed || input.change_type === "removed", input.include_ineligible, input.include_out_of_scope, input.max_targets)
4657
+ ]);
4300
4658
  const program = addProgramResourceLinks(sanitizeProgram(programApi.data, config.webBaseUrl));
4301
- const changesPayload = await fetchProgramChanges(client, config, input.program_id, input.page_size, input.include_removed || input.change_type === "removed", input.include_ineligible, input.include_out_of_scope, input.max_targets);
4302
4659
  const filteredChanges = filterProgramScopeDeltaChanges(changesPayload.changes, input);
4303
4660
  const limitedChanges = filteredChanges.slice(0, input.max_targets);
4304
4661
  return stripUndefined({
@@ -4753,9 +5110,11 @@ async function getProgramBrief(client, config, input) {
4753
5110
  });
4754
5111
  }
4755
5112
  async function getProgramDelta(client, config, input) {
4756
- const programApi = await client.getProgram(input.program_id);
5113
+ const [programApi, changes] = await Promise.all([
5114
+ client.getProgram(input.program_id),
5115
+ fetchProgramChanges(client, config, input.program_id, input.page_size, input.include_removed, input.include_ineligible, input.include_out_of_scope)
5116
+ ]);
4757
5117
  const program = addProgramResourceLinks(sanitizeProgram(programApi.data, config.webBaseUrl));
4758
- const changes = await fetchProgramChanges(client, config, input.program_id, input.page_size, input.include_removed, input.include_ineligible, input.include_out_of_scope);
4759
5118
  return {
4760
5119
  request_id: randomUUID(),
4761
5120
  source_requests: [
@@ -5346,7 +5705,11 @@ function programResolutionMatch(candidate, query) {
5346
5705
  };
5347
5706
  }
5348
5707
  function hasHighConfidenceProgramResolutionMatch(programs, webBaseUrl, query) {
5349
- return programs.some((program) => programResolutionMatch(toProgramCandidate(program, webBaseUrl), query).score >= 85);
5708
+ const threshold = looksLikeDirectProgramHandleQuery(query) ? 95 : 85;
5709
+ return programs.some((program) => programResolutionMatch(toProgramCandidate(program, webBaseUrl), query).score >= threshold);
5710
+ }
5711
+ function hasViableProgramResolutionMatch(programs, scorePrograms) {
5712
+ return scorePrograms ? scorePrograms(programs) >= 80 : programs.length > 0;
5350
5713
  }
5351
5714
  function bestProgramResolutionScore(programs, webBaseUrl, query) {
5352
5715
  return programs.reduce((best, program) => Math.max(best, programResolutionMatch(toProgramCandidate(program, webBaseUrl), query).score), 0);
@@ -5357,6 +5720,7 @@ function programResolutionSearchQueries(query) {
5357
5720
  function programResolutionQueryVariants(query) {
5358
5721
  const normalized = normalizeTag(query);
5359
5722
  const meaningfulTokens = [...meaningfulProgramQueryTokens(query)];
5723
+ const searchTokens = meaningfulTokens.filter((token) => token.length >= 3);
5360
5724
  const meaningfulPhrase = meaningfulTokens.join(" ");
5361
5725
  const singleTokenNameVariants = meaningfulTokens.length === 1
5362
5726
  ? [
@@ -5370,7 +5734,7 @@ function programResolutionQueryVariants(query) {
5370
5734
  normalized,
5371
5735
  meaningfulPhrase,
5372
5736
  meaningfulTokens.join("-"),
5373
- ...meaningfulTokens,
5737
+ ...searchTokens,
5374
5738
  ...singleTokenNameVariants
5375
5739
  ];
5376
5740
  return uniqueStrings(values.filter((value) => value.length >= 2));
@@ -5486,7 +5850,13 @@ async function findPrograms(client, config, input) {
5486
5850
  initial: input.upstream_request_budget,
5487
5851
  remaining: input.upstream_request_budget
5488
5852
  };
5489
- const upstreamTags = uniqueStrings([...input.tags, ...input.scope_tags, ...input.target_types, ...input.language_tags]);
5853
+ const upstreamTags = uniqueStrings([
5854
+ ...input.tags,
5855
+ ...input.scope_tags,
5856
+ ...input.target_types,
5857
+ ...input.language_tags,
5858
+ ...(input.min_wildcards > 0 ? ["wildcard"] : [])
5859
+ ]);
5490
5860
  const collected = await collectPrograms(client, {
5491
5861
  platforms: input.platforms,
5492
5862
  tags: upstreamTags,
@@ -5598,15 +5968,43 @@ async function collectProgramsForResolution(client, options) {
5598
5968
  const collections = [];
5599
5969
  const queryCollections = [];
5600
5970
  const queries = options.searchQueries.length > 0 ? options.searchQueries : [undefined];
5601
- const primaryDirectProgramIds = new Set(directProgramIdCandidates(options.query, options.platforms).slice(0, 1));
5971
+ const fastQueries = queries.slice(0, FAST_RESOLVE_SEARCH_QUERIES);
5972
+ const remainingQueries = queries.slice(FAST_RESOLVE_SEARCH_QUERIES);
5973
+ const primaryDirectPlatforms = options.platforms.length > 0 ? options.platforms : PRIMARY_PROGRAM_ID_PLATFORM_GUESSES;
5974
+ const primaryDirectProgramIds = new Set(directProgramIdCandidates(options.query, primaryDirectPlatforms, { maxHandleVariants: 1 }));
5975
+ for (const search of fastQueries) {
5976
+ if (options.budget.remaining <= 0) {
5977
+ addUniqueWarning(options.warnings, "Program name search stopped at the request budget; pass a higher upstream_request_budget for a deeper resolution attempt.");
5978
+ break;
5979
+ }
5980
+ const collection = await collectPrograms(client, {
5981
+ search,
5982
+ platforms: options.platforms,
5983
+ tags: options.tags,
5984
+ updated_since: undefined,
5985
+ opportunity_levels: options.opportunity_levels,
5986
+ max_pages: 1,
5987
+ budget: options.budget,
5988
+ warnings: options.warnings
5989
+ });
5990
+ collections.push(collection);
5991
+ queryCollections.push({ search, collection });
5992
+ const merged = mergeProgramCollections(collections);
5993
+ if (options.isHighConfidenceMatch?.(merged.programs) ||
5994
+ hasViableProgramResolutionMatch(merged.programs, options.scorePrograms)) {
5995
+ return merged;
5996
+ }
5997
+ }
5602
5998
  if (primaryDirectProgramIds.size > 0 && options.budget.remaining > 0) {
5603
5999
  const primaryDirectHandles = await collectDirectHandlePrograms(client, {
5604
6000
  query: options.query,
5605
- platforms: options.platforms,
6001
+ platforms: primaryDirectPlatforms,
5606
6002
  budget: options.budget,
5607
6003
  warnings: options.warnings,
5608
6004
  source: "program_id_handle_guess",
5609
- maxProgramIds: 1,
6005
+ maxProgramIds: MAX_DIRECT_HANDLE_RESOLUTION_REQUESTS,
6006
+ maxHandleVariants: 1,
6007
+ acceptEmptyTargetsAsPrograms: true,
5610
6008
  stopOnFirstMatch: true
5611
6009
  });
5612
6010
  if (primaryDirectHandles.programs.length > 0 || primaryDirectHandles.requestsScanned > 0) {
@@ -5616,7 +6014,7 @@ async function collectProgramsForResolution(client, options) {
5616
6014
  return mergeProgramCollections(collections);
5617
6015
  }
5618
6016
  }
5619
- for (const search of queries) {
6017
+ for (const search of remainingQueries) {
5620
6018
  if (options.budget.remaining <= 0) {
5621
6019
  addUniqueWarning(options.warnings, "Program name search stopped at the request budget; pass a higher upstream_request_budget for a deeper resolution attempt.");
5622
6020
  break;
@@ -5637,7 +6035,9 @@ async function collectProgramsForResolution(client, options) {
5637
6035
  return mergeProgramCollections(collections);
5638
6036
  }
5639
6037
  }
5640
- if (options.budget.remaining > 0) {
6038
+ const searchedCollection = collections.length > 0 ? mergeProgramCollections(collections) : undefined;
6039
+ if (options.budget.remaining > 0 &&
6040
+ (!searchedCollection || !hasViableProgramResolutionMatch(searchedCollection.programs, options.scorePrograms))) {
5641
6041
  const directHandles = await collectDirectHandlePrograms(client, {
5642
6042
  query: options.query,
5643
6043
  platforms: options.platforms,
@@ -5645,6 +6045,8 @@ async function collectProgramsForResolution(client, options) {
5645
6045
  warnings: options.warnings,
5646
6046
  source: "program_id_handle_guess",
5647
6047
  skipProgramIds: primaryDirectProgramIds,
6048
+ maxHandleVariants: 4,
6049
+ acceptEmptyTargetsAsPrograms: true,
5648
6050
  stopOnFirstMatch: true
5649
6051
  });
5650
6052
  if (directHandles.programs.length > 0 || directHandles.requestsScanned > 0) {
@@ -5715,7 +6117,7 @@ function mergeProgramCollections(collections) {
5715
6117
  };
5716
6118
  }
5717
6119
  async function collectDirectHandlePrograms(client, options) {
5718
- const programIds = directProgramIdCandidates(options.query, options.platforms)
6120
+ const programIds = directProgramIdCandidates(options.query, options.platforms, { maxHandleVariants: options.maxHandleVariants })
5719
6121
  .filter((programId) => !options.skipProgramIds?.has(programId))
5720
6122
  .slice(0, options.maxProgramIds ?? MAX_DIRECT_HANDLE_RESOLUTION_REQUESTS);
5721
6123
  const programs = [];
@@ -5723,70 +6125,45 @@ async function collectDirectHandlePrograms(client, options) {
5723
6125
  let requestsScanned = 0;
5724
6126
  for (const programId of programIds) {
5725
6127
  if (!tryConsumeBudget(options.budget)) {
6128
+ addUniqueWarning(options.warnings, "Upstream request budget was exhausted before all direct program handle guesses could be checked.");
5726
6129
  break;
5727
6130
  }
5728
6131
  requestsScanned += 1;
5729
6132
  try {
5730
- const api = await client.getProgram(programId);
5731
- programs.push(api.data);
6133
+ const targetsApi = await client.getProgramTargets(programId);
6134
+ refundBudgetIfNoUpstreamRequest(options.budget, targetsApi);
6135
+ const targetsData = readObject(targetsApi.data);
6136
+ const hasTargetsArray = Array.isArray(targetsData?.targets);
6137
+ const targets = readArray(targetsData?.targets).map(sanitizeTarget);
6138
+ const programEndpointExists = targets.length > 0 || (options.acceptEmptyTargetsAsPrograms === true && hasTargetsArray);
6139
+ if (programEndpointExists) {
6140
+ programs.push(syntheticProgramFromProgramId(programId, targets));
6141
+ }
5732
6142
  sourceRequests.push({
5733
6143
  source: options.source,
6144
+ endpoint: "program_targets",
5734
6145
  program_id: programId,
5735
- request_id: api.requestId,
5736
- upstream_request_id: api.upstreamRequestId,
5737
- ...apiSourceMetadata(api)
6146
+ request_id: targetsApi.requestId,
6147
+ upstream_request_id: targetsApi.upstreamRequestId,
6148
+ ...apiSourceMetadata(targetsApi)
5738
6149
  });
5739
- if (options.stopOnFirstMatch) {
6150
+ if (programEndpointExists && options.stopOnFirstMatch) {
5740
6151
  break;
5741
6152
  }
5742
6153
  }
5743
6154
  catch (error) {
6155
+ refundBudgetIfNoUpstreamError(options.budget, error);
5744
6156
  if (error instanceof BBRadarApiError && error.status === 404) {
5745
6157
  sourceRequests.push({
5746
6158
  source: options.source,
5747
- endpoint: "program_detail",
6159
+ endpoint: "program_targets",
5748
6160
  program_id: programId,
5749
6161
  request_id: error.requestId,
5750
6162
  upstream_request_id: error.upstreamRequestId,
5751
- status: error.status
6163
+ status: error.status,
6164
+ cache_hit: error.cached,
6165
+ cache_expires_at: error.cacheExpiresAt
5752
6166
  });
5753
- if (!tryConsumeBudget(options.budget)) {
5754
- break;
5755
- }
5756
- requestsScanned += 1;
5757
- try {
5758
- const targetsApi = await client.getProgramTargets(programId);
5759
- const targetsData = readObject(targetsApi.data);
5760
- const targets = readArray(targetsData?.targets).map(sanitizeTarget);
5761
- if (targets.length > 0) {
5762
- programs.push(syntheticProgramFromProgramId(programId, targets));
5763
- }
5764
- sourceRequests.push({
5765
- source: options.source,
5766
- endpoint: "program_targets",
5767
- program_id: programId,
5768
- request_id: targetsApi.requestId,
5769
- upstream_request_id: targetsApi.upstreamRequestId,
5770
- ...apiSourceMetadata(targetsApi)
5771
- });
5772
- if (targets.length > 0 && options.stopOnFirstMatch) {
5773
- break;
5774
- }
5775
- }
5776
- catch (targetError) {
5777
- if (targetError instanceof BBRadarApiError && targetError.status === 404) {
5778
- sourceRequests.push({
5779
- source: options.source,
5780
- endpoint: "program_targets",
5781
- program_id: programId,
5782
- request_id: targetError.requestId,
5783
- upstream_request_id: targetError.upstreamRequestId,
5784
- status: targetError.status
5785
- });
5786
- continue;
5787
- }
5788
- throw targetError;
5789
- }
5790
6167
  continue;
5791
6168
  }
5792
6169
  throw error;
@@ -5804,11 +6181,12 @@ function syntheticProgramFromProgramId(programId, targets) {
5804
6181
  const separatorIndex = programId.indexOf(":");
5805
6182
  const platform = separatorIndex >= 0 ? programId.slice(0, separatorIndex) : undefined;
5806
6183
  const handle = separatorIndex >= 0 ? programId.slice(separatorIndex + 1) : programId;
6184
+ const displayHandle = handle.split("/").filter(Boolean).at(-1) ?? handle;
5807
6185
  const scopeTags = uniqueStrings(targets.flatMap((target) => readStringArrayField(target, "scope_tags")));
5808
6186
  return stripUndefined({
5809
6187
  id: programId,
5810
6188
  handle,
5811
- name: titleizeProgramHandle(handle),
6189
+ name: titleizeProgramHandle(displayHandle),
5812
6190
  platform,
5813
6191
  scope_tags: scopeTags,
5814
6192
  target_counts: {
@@ -5827,38 +6205,75 @@ function titleizeProgramHandle(handle) {
5827
6205
  .map((part) => part.slice(0, 1).toUpperCase() + part.slice(1))
5828
6206
  .join(" ");
5829
6207
  }
5830
- function directProgramIdCandidates(query, platforms) {
6208
+ function directProgramIdCandidates(query, platforms, options = {}) {
5831
6209
  const platformGuesses = (platforms.length > 0 ? platforms : PROGRAM_ID_PLATFORM_GUESSES).map(canonicalProgramIdPlatform);
5832
- const handles = directProgramHandleVariants(query);
5833
- return uniqueStrings(platformGuesses.flatMap((platform) => handles.map((handle) => `${platform}:${handle}`))).slice(0, MAX_DIRECT_HANDLE_RESOLUTION_REQUESTS);
6210
+ const handles = directProgramHandleVariants(query).slice(0, options.maxHandleVariants ?? Number.POSITIVE_INFINITY);
6211
+ return uniqueStrings(handles.flatMap((handle) => platformGuesses.flatMap((platform) => normalizeTag(platform) === "bugcrowd"
6212
+ ? [`${platform}:engagements/${handle}`, `${platform}:${handle}`]
6213
+ : [`${platform}:${handle}`]))).slice(0, MAX_DIRECT_HANDLE_RESOLUTION_REQUESTS);
5834
6214
  }
5835
6215
  function canonicalProgramIdPlatform(platform) {
5836
6216
  const normalized = normalizeTag(platform).replace(/[^a-z0-9]/g, "");
5837
6217
  const knownPlatforms = {
5838
6218
  hackerone: "HackerOne",
5839
- bugcrowd: "Bugcrowd",
6219
+ bugcrowd: "BugCrowd",
5840
6220
  intigriti: "Intigriti",
5841
6221
  hackenproof: "HackenProof",
5842
6222
  yeswehack: "YesWeHack",
6223
+ immunefi: "Immunefi",
5843
6224
  cantina: "Cantina",
5844
6225
  code4rena: "Code4rena",
5845
- immunefi: "Immunefi"
6226
+ huntr: "Huntr",
6227
+ gobugfree: "GObugfree",
6228
+ bugbountyswitzerland: "Bug Bounty Switzerland",
6229
+ inspectiv: "Inspectiv",
6230
+ compasssecurity: "Compass Security",
6231
+ bugrap: "BugRap",
6232
+ issuehunt: "IssueHunt",
6233
+ patchday: "PatchDay",
6234
+ remedy: "Remedy",
6235
+ standoff365: "Standoff365",
6236
+ sherlock: "Sherlock",
6237
+ codehawks: "CodeHawks"
5846
6238
  };
5847
6239
  return knownPlatforms[normalized] ?? platform.trim();
5848
6240
  }
5849
6241
  function directProgramHandleVariants(query) {
5850
6242
  const handleText = query.includes(":") ? query.slice(query.indexOf(":") + 1) : query;
5851
6243
  const normalized = normalizeTargetIdentifierForMatch(handleText);
6244
+ const literal = directProgramLiteralHandleVariant(handleText);
5852
6245
  const dashed = normalized.replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
5853
6246
  const compact = dashed.replace(/-/g, "");
5854
6247
  const tokens = [...meaningfulProgramQueryTokens(handleText)];
5855
- return uniqueStrings([
5856
- ...targetBrandTokens(handleText),
5857
- dashed,
5858
- compact,
5859
- tokens.join("-"),
5860
- tokens.join("")
5861
- ]).filter((handle) => /^[a-z0-9][a-z0-9_.-]{3,100}$/i.test(handle));
6248
+ const brandTokens = targetBrandTokens(handleText);
6249
+ const literalVariants = [literal, dashed, compact, tokens.join("-"), tokens.join("")];
6250
+ const values = queryLooksLikeTargetIdentifier(handleText) ? [...brandTokens, ...literalVariants] : [...literalVariants, ...brandTokens];
6251
+ return uniqueStrings(values).filter(isDirectProgramHandleVariant);
6252
+ }
6253
+ function looksLikeDirectProgramHandleQuery(query) {
6254
+ const handleText = query.includes(":") ? query.slice(query.indexOf(":") + 1) : query;
6255
+ return isDirectProgramHandleVariant(directProgramLiteralHandleVariant(handleText));
6256
+ }
6257
+ function directProgramLiteralHandleVariant(value) {
6258
+ const normalized = value
6259
+ .trim()
6260
+ .replace(/\\/g, "/")
6261
+ .replace(/^['"`<]+|['"`>]+$/g, "")
6262
+ .replace(/^[a-z][a-z0-9+.-]*:\/\//i, "")
6263
+ .replace(/^www\./i, "");
6264
+ const queryStart = normalized.search(/[?#]/);
6265
+ return (queryStart >= 0 ? normalized.slice(0, queryStart) : normalized).replace(/\/+$/, "");
6266
+ }
6267
+ function isDirectProgramHandleVariant(value) {
6268
+ if (!value) {
6269
+ return false;
6270
+ }
6271
+ if (value.length < 2 || value.length > 150 || /[\u0000-\u001F\u007F?#:]/.test(value)) {
6272
+ return false;
6273
+ }
6274
+ return value
6275
+ .split("/")
6276
+ .every((segment) => segment.length > 0 && segment !== "." && segment !== ".." && !/^[\s.]+$/.test(segment));
5862
6277
  }
5863
6278
  async function collectProgramSources(client, sources, options) {
5864
6279
  const pages = [];
@@ -6160,7 +6575,8 @@ async function collectTargetSamples(client, candidates, input, budget) {
6160
6575
  .slice(0, input.target_sample_size);
6161
6576
  samples[programId] = targets;
6162
6577
  }
6163
- catch {
6578
+ catch (error) {
6579
+ refundBudgetIfNoUpstreamError(budget, error);
6164
6580
  samples[programId] = [];
6165
6581
  }
6166
6582
  });
@@ -6223,6 +6639,11 @@ function refundBudgetIfNoUpstreamRequest(budget, api, cost = 1) {
6223
6639
  budget.remaining = Math.min(budget.initial, budget.remaining + cost);
6224
6640
  }
6225
6641
  }
6642
+ function refundBudgetIfNoUpstreamError(budget, error, cost = 1) {
6643
+ if (error instanceof BBRadarApiError && (error.cached || error.coalesced)) {
6644
+ budget.remaining = Math.min(budget.initial, budget.remaining + cost);
6645
+ }
6646
+ }
6226
6647
  function addUniqueWarning(warnings, warning) {
6227
6648
  if (warnings && !warnings.includes(warning)) {
6228
6649
  warnings.push(warning);
@@ -6325,7 +6746,12 @@ function readStringArrayField(value, field) {
6325
6746
  const fieldValue = value[field];
6326
6747
  return Array.isArray(fieldValue) ? fieldValue.filter((entry) => typeof entry === "string") : [];
6327
6748
  }
6328
- function registerPrompts(server) {
6749
+ function registerPrompts(server, profile) {
6750
+ const discoveryToolInstructions = profile === "core"
6751
+ ? `- Start with find_programs and pass opportunity_levels from the requested value below unless the user asked for a broader search.
6752
+ - Express language, target type, reward, Web3, wildcard, VDP, and platform needs through find_programs filters.`
6753
+ : `- Start with find_program_candidates unless the user needs custom filters; pass opportunity_levels from the requested value below.
6754
+ - Use find_language_programs for language asks, find_target_type_programs for API/mobile/source-code/domain asks, find_reward_programs or find_paid_programs for reward asks, find_vdp_programs only for explicit VDP/no-bounty asks, find_web3_contests for Web3 contest/audit asks, find_web3_programs for general Web3 requests, and find_wildcard_programs for wildcard-specific requests.`;
6329
6755
  server.registerPrompt("find_best_programs_to_hunt", {
6330
6756
  title: "Find Best Programs To Hunt",
6331
6757
  description: "Rank fresh BBRadar program data only. Do not invoke external bug bounty skills unless the user explicitly asks for methodology.",
@@ -6338,8 +6764,8 @@ function registerPrompts(server) {
6338
6764
  }, (args) => promptResult(`Use the BBRadar MCP tools only. Do not invoke local bug bounty skills, methodology files, worklogs, or non-BBRadar tools unless the user explicitly asks for methodology. Do not perform active scanning or contact third-party targets. Treat results as fresh API reads; do not describe them as cached.
6339
6765
 
6340
6766
  Find the best BBRadar program candidates.
6341
- - Start with find_program_candidates unless the user needs custom filters; pass opportunity_levels from this JSON array unless the user asked for a broader search: ${promptJson([args.opportunity_level ?? "elite"])}.
6342
- - Use find_language_programs for language asks, find_target_type_programs for API/mobile/source-code/domain asks, find_reward_programs or find_paid_programs for reward asks, find_vdp_programs only for explicit VDP/no-bounty asks, find_web3_contests for Web3 contest/audit asks, find_web3_programs for general Web3 requests, and find_wildcard_programs for wildcard-specific requests.
6767
+ ${discoveryToolInstructions}
6768
+ - Use this opportunity level JSON array: ${promptJson([args.opportunity_level ?? "elite"])}.
6343
6769
  - Apply platform filters from this JSON string if provided: ${promptJson(args.platforms ?? "")}.
6344
6770
  - Apply tag filters from this JSON string if provided: ${promptJson(args.tags ?? "")}.
6345
6771
  - Keep the shortlist to this JSON value: ${promptJson(args.max_programs ?? "10")}.
@@ -6399,7 +6825,7 @@ async function runTool(toolName, config, rateLimiter, callback) {
6399
6825
  },
6400
6826
  mcp_rate_limit: toRateLimitPayload(decision),
6401
6827
  mcp_timing: toolTimingPayload(toolName, durationMs)
6402
- }, true);
6828
+ }, true, config.compactToolText);
6403
6829
  }
6404
6830
  try {
6405
6831
  const payload = await callback();
@@ -6409,21 +6835,21 @@ async function runTool(toolName, config, rateLimiter, callback) {
6409
6835
  ...payload,
6410
6836
  mcp_rate_limit: toRateLimitPayload(decision),
6411
6837
  mcp_timing: toolTimingPayload(toolName, durationMs)
6412
- });
6838
+ }, false, config.compactToolText);
6413
6839
  }
6414
6840
  catch (error) {
6415
6841
  const durationMs = Date.now() - startedAt;
6416
6842
  recordToolMetric(toolName, durationMs, "error");
6417
- return toolResult(errorPayload(error, decision, toolName, durationMs), true);
6843
+ return toolResult(errorPayload(error, decision, toolName, durationMs), true, config.compactToolText);
6418
6844
  }
6419
6845
  }
6420
- function toolResult(payload, isError = false) {
6846
+ function toolResult(payload, isError = false, compactText = false) {
6421
6847
  const resourceLinks = collectResourceLinks(payload);
6422
6848
  return {
6423
6849
  content: [
6424
6850
  {
6425
6851
  type: "text",
6426
- text: JSON.stringify(payload)
6852
+ text: compactText ? compactToolText(payload, isError) : JSON.stringify(payload)
6427
6853
  },
6428
6854
  ...resourceLinks
6429
6855
  ],
@@ -6431,6 +6857,28 @@ function toolResult(payload, isError = false) {
6431
6857
  ...(isError ? { isError: true } : {})
6432
6858
  };
6433
6859
  }
6860
+ function compactToolText(payload, isError) {
6861
+ if (isError) {
6862
+ return JSON.stringify(stripUndefined({
6863
+ request_id: payload.request_id,
6864
+ error: payload.error,
6865
+ mcp_timing: payload.mcp_timing
6866
+ }));
6867
+ }
6868
+ const meta = readObject(payload.meta);
6869
+ const returned = numberField(meta, "returned") ??
6870
+ [
6871
+ readArray(payload.programs).length,
6872
+ readArray(payload.targets).length,
6873
+ readArray(payload.changes).length
6874
+ ].find((count) => count > 0);
6875
+ return JSON.stringify(stripUndefined({
6876
+ request_id: payload.request_id,
6877
+ summary: "Full tool result is available in structuredContent.",
6878
+ returned,
6879
+ mcp_timing: payload.mcp_timing
6880
+ }));
6881
+ }
6434
6882
  function promptResult(text) {
6435
6883
  return {
6436
6884
  messages: [
@@ -6570,18 +7018,25 @@ function compactRecord(values) {
6570
7018
  }));
6571
7019
  }
6572
7020
  function latestAddedTargetsQuery(input) {
6573
- return {
7021
+ return stripUndefined({
6574
7022
  change_type: "added",
6575
7023
  target_type: input.target_type,
7024
+ platforms: input.platforms.length > 0 ? input.platforms : undefined,
7025
+ min_reward: input.min_reward,
7026
+ reward_threshold_mode: input.reward_threshold_mode,
7027
+ max_public_report_count: input.max_public_report_count,
7028
+ require_known_report_count: input.require_known_report_count,
7029
+ include_unknown_report_count: input.include_unknown_report_count,
6576
7030
  include_out_of_scope: input.include_out_of_scope,
6577
7031
  include_ineligible: input.include_ineligible,
6578
7032
  recent_changes_page_size: input.recent_changes_page_size,
7033
+ max_results: input.max_results,
6579
7034
  include_full_target_list: input.include_full_target_list,
6580
7035
  full_target_list_mode: input.full_target_list_mode,
6581
7036
  full_target_limit: input.full_target_limit,
6582
7037
  full_list_include_out_of_scope: input.full_list_include_out_of_scope,
6583
7038
  full_list_include_ineligible: input.full_list_include_ineligible
6584
- };
7039
+ });
6585
7040
  }
6586
7041
  function formatTargetList(targets, mode) {
6587
7042
  if (mode === "identifiers") {
@@ -6633,7 +7088,7 @@ function targetMatchesQuery(target, query, mode) {
6633
7088
  }
6634
7089
  return (containsMatch ||
6635
7090
  profile.values.some((value) => queryValues.some((queryValue) => targetSuffixMatch(value, queryValue) || targetWildcardMatch(value, queryValue))) ||
6636
- targetTokensMatch(profile.tokens, query));
7091
+ (!queryLooksLikeTargetIdentifier(query) && targetTokensMatch(profile.tokens, query)));
6637
7092
  }
6638
7093
  function upstreamTargetMatchMode(mode) {
6639
7094
  return mode === "smart" ? "contains" : mode;
@@ -6671,7 +7126,11 @@ function targetSearchProfile(target) {
6671
7126
  };
6672
7127
  }
6673
7128
  function targetQueryVariants(query) {
6674
- return targetStringVariants(query);
7129
+ const variants = targetStringVariants(query);
7130
+ if (!queryLooksLikeTargetIdentifier(query)) {
7131
+ return variants;
7132
+ }
7133
+ return variants.filter(targetValueCanContainQuery);
6675
7134
  }
6676
7135
  function targetApiSearchQueries(query) {
6677
7136
  const normalized = normalizeTargetIdentifierForMatch(query);