@cyanheads/brapi-mcp-server 0.6.4 → 0.7.0

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.
Files changed (43) hide show
  1. package/CLAUDE.md +11 -4
  2. package/README.md +7 -3
  3. package/changelog/0.7.x/0.7.0.md +23 -0
  4. package/dist/index.js +2 -0
  5. package/dist/index.js.map +1 -1
  6. package/dist/mcp-server/resources/definitions/brapi-variable.resource.d.ts +30 -0
  7. package/dist/mcp-server/resources/definitions/brapi-variable.resource.d.ts.map +1 -0
  8. package/dist/mcp-server/resources/definitions/brapi-variable.resource.js +78 -0
  9. package/dist/mcp-server/resources/definitions/brapi-variable.resource.js.map +1 -0
  10. package/dist/mcp-server/tools/definitions/brapi-build-phenotype-matrix.tool.d.ts +81 -0
  11. package/dist/mcp-server/tools/definitions/brapi-build-phenotype-matrix.tool.d.ts.map +1 -0
  12. package/dist/mcp-server/tools/definitions/brapi-build-phenotype-matrix.tool.js +366 -0
  13. package/dist/mcp-server/tools/definitions/brapi-build-phenotype-matrix.tool.js.map +1 -0
  14. package/dist/mcp-server/tools/definitions/brapi-export-genotype-matrix.tool.d.ts +88 -0
  15. package/dist/mcp-server/tools/definitions/brapi-export-genotype-matrix.tool.d.ts.map +1 -0
  16. package/dist/mcp-server/tools/definitions/brapi-export-genotype-matrix.tool.js +494 -0
  17. package/dist/mcp-server/tools/definitions/brapi-export-genotype-matrix.tool.js.map +1 -0
  18. package/dist/mcp-server/tools/definitions/brapi-find-genotype-calls.tool.d.ts.map +1 -1
  19. package/dist/mcp-server/tools/definitions/brapi-find-genotype-calls.tool.js +17 -93
  20. package/dist/mcp-server/tools/definitions/brapi-find-genotype-calls.tool.js.map +1 -1
  21. package/dist/mcp-server/tools/definitions/brapi-germplasm-performance.tool.d.ts +60 -0
  22. package/dist/mcp-server/tools/definitions/brapi-germplasm-performance.tool.d.ts.map +1 -0
  23. package/dist/mcp-server/tools/definitions/brapi-germplasm-performance.tool.js +416 -0
  24. package/dist/mcp-server/tools/definitions/brapi-germplasm-performance.tool.js.map +1 -0
  25. package/dist/mcp-server/tools/definitions/index.d.ts +148 -0
  26. package/dist/mcp-server/tools/definitions/index.d.ts.map +1 -1
  27. package/dist/mcp-server/tools/definitions/index.js +6 -0
  28. package/dist/mcp-server/tools/definitions/index.js.map +1 -1
  29. package/dist/mcp-server/tools/shared/canvas-columns.d.ts +32 -0
  30. package/dist/mcp-server/tools/shared/canvas-columns.d.ts.map +1 -0
  31. package/dist/mcp-server/tools/shared/canvas-columns.js +98 -0
  32. package/dist/mcp-server/tools/shared/canvas-columns.js.map +1 -0
  33. package/dist/mcp-server/tools/shared/genotype-calls.d.ts +81 -0
  34. package/dist/mcp-server/tools/shared/genotype-calls.d.ts.map +1 -0
  35. package/dist/mcp-server/tools/shared/genotype-calls.js +172 -0
  36. package/dist/mcp-server/tools/shared/genotype-calls.js.map +1 -0
  37. package/dist/mcp-server/tools/shared/observations.d.ts +87 -0
  38. package/dist/mcp-server/tools/shared/observations.d.ts.map +1 -0
  39. package/dist/mcp-server/tools/shared/observations.js +285 -0
  40. package/dist/mcp-server/tools/shared/observations.js.map +1 -0
  41. package/manifest.json +1 -1
  42. package/package.json +3 -3
  43. package/server.json +3 -3
@@ -230,6 +230,65 @@ export declare const readOnlyToolDefinitions: (import("@cyanheads/mcp-ts-core").
230
230
  readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.NotFound;
231
231
  readonly when: "Upstream returned no study record for the requested DbId";
232
232
  readonly recovery: "Verify the studyDbId on the target server, or run brapi_find_studies to discover valid IDs.";
233
+ }], undefined> | import("@cyanheads/mcp-ts-core").ToolDefinition<import("zod").ZodObject<{
234
+ alias: import("zod").ZodOptional<import("zod").ZodString>;
235
+ studies: import("zod").ZodArray<import("zod").ZodString>;
236
+ variables: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString>>;
237
+ germplasm: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString>>;
238
+ shape: import("zod").ZodDefault<import("zod").ZodEnum<{
239
+ wide: "wide";
240
+ long: "long";
241
+ }>>;
242
+ aggregate: import("zod").ZodDefault<import("zod").ZodEnum<{
243
+ all: "all";
244
+ mean: "mean";
245
+ median: "median";
246
+ first: "first";
247
+ }>>;
248
+ loadLimit: import("zod").ZodOptional<import("zod").ZodNumber>;
249
+ extraFilters: import("zod").ZodOptional<import("zod").ZodRecord<import("zod").ZodString, import("zod").ZodUnknown>>;
250
+ }, import("zod/v4/core").$strip>, import("zod").ZodObject<{
251
+ alias: import("zod").ZodString;
252
+ studies: import("zod").ZodArray<import("zod").ZodString>;
253
+ shape: import("zod").ZodEnum<{
254
+ wide: "wide";
255
+ long: "long";
256
+ }>;
257
+ aggregate: import("zod").ZodEnum<{
258
+ all: "all";
259
+ mean: "mean";
260
+ median: "median";
261
+ first: "first";
262
+ }>;
263
+ observationCount: import("zod").ZodNumber;
264
+ germplasmCount: import("zod").ZodNumber;
265
+ variableCount: import("zod").ZodNumber;
266
+ variableLegend: import("zod").ZodRecord<import("zod").ZodString, import("zod").ZodString>;
267
+ dataframe: import("zod").ZodOptional<import("zod").ZodObject<{
268
+ tableName: import("zod").ZodString;
269
+ rowCount: import("zod").ZodNumber;
270
+ columns: import("zod").ZodArray<import("zod").ZodString>;
271
+ createdAt: import("zod").ZodString;
272
+ expiresAt: import("zod").ZodString;
273
+ truncated: import("zod").ZodOptional<import("zod").ZodBoolean>;
274
+ maxRows: import("zod").ZodOptional<import("zod").ZodNumber>;
275
+ }, import("zod/v4/core").$strip>>;
276
+ warnings: import("zod").ZodArray<import("zod").ZodString>;
277
+ }, import("zod/v4/core").$strip>, readonly [{
278
+ readonly reason: "unknown_alias";
279
+ readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.NotFound;
280
+ readonly when: "No connection has been registered under the requested alias";
281
+ readonly recovery: "Run brapi_connect with this alias (or omit `alias` to use the default connection) before calling brapi_build_phenotype_matrix.";
282
+ }, {
283
+ readonly reason: "all_filters_dropped";
284
+ readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.ValidationError;
285
+ readonly when: "The active dialect dropped every filter supplied — the call would silently widen to the unfiltered baseline";
286
+ readonly recovery: "Drop unsupported filters or use studies / germplasm / variables to scope the query to supported filter paths on the active dialect.";
287
+ }, {
288
+ readonly reason: "no_observation_path";
289
+ readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.ServiceUnavailable;
290
+ readonly when: "Neither /observations nor /observationunits returned data for any requested study after probing both paths";
291
+ readonly recovery: "Verify the studyDbIds exist and the BrAPI server exposes /observations or /observationunits. Use brapi_server_info to inspect the capability list.";
233
292
  }], undefined> | import("@cyanheads/mcp-ts-core").ToolDefinition<import("zod").ZodObject<{
234
293
  baseUrl: import("zod").ZodOptional<import("zod").ZodString>;
235
294
  auth: import("zod").ZodOptional<import("zod").ZodDiscriminatedUnion<[import("zod").ZodObject<{
@@ -363,6 +422,61 @@ export declare const readOnlyToolDefinitions: (import("@cyanheads/mcp-ts-core").
363
422
  readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.ValidationError;
364
423
  readonly when: "SQL violated read-only rules (multi-statement, non-SELECT, or disallowed operation)";
365
424
  readonly recovery: "Submit a single SELECT statement using only registered dataframes. For changes, use `registerAs` in this tool to materialize a result, or brapi_dataframe_drop to remove a dataframe.";
425
+ }], undefined> | import("@cyanheads/mcp-ts-core").ToolDefinition<import("zod").ZodObject<{
426
+ alias: import("zod").ZodOptional<import("zod").ZodString>;
427
+ germplasmDbIds: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString>>;
428
+ variantSetDbId: import("zod").ZodString;
429
+ format: import("zod").ZodEnum<{
430
+ plink: "plink";
431
+ "vcf-lite": "vcf-lite";
432
+ "matrix-json": "matrix-json";
433
+ }>;
434
+ maxCalls: import("zod").ZodOptional<import("zod").ZodNumber>;
435
+ }, import("zod/v4/core").$strip>, import("zod").ZodObject<{
436
+ alias: import("zod").ZodString;
437
+ format: import("zod").ZodEnum<{
438
+ plink: "plink";
439
+ "vcf-lite": "vcf-lite";
440
+ "matrix-json": "matrix-json";
441
+ }>;
442
+ rowCount: import("zod").ZodNumber;
443
+ columnCount: import("zod").ZodNumber;
444
+ variantColumnLegend: import("zod").ZodRecord<import("zod").ZodString, import("zod").ZodString>;
445
+ callFormatting: import("zod").ZodObject<{
446
+ expandHomozygotes: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodBoolean>>;
447
+ unknownString: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
448
+ sepPhased: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
449
+ sepUnphased: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
450
+ }, import("zod/v4/core").$strip>;
451
+ dataframe: import("zod").ZodObject<{
452
+ tableName: import("zod").ZodString;
453
+ rowCount: import("zod").ZodNumber;
454
+ columns: import("zod").ZodArray<import("zod").ZodString>;
455
+ createdAt: import("zod").ZodString;
456
+ expiresAt: import("zod").ZodString;
457
+ truncated: import("zod").ZodOptional<import("zod").ZodBoolean>;
458
+ maxRows: import("zod").ZodOptional<import("zod").ZodNumber>;
459
+ }, import("zod/v4/core").$strip>;
460
+ vcf: import("zod").ZodOptional<import("zod").ZodString>;
461
+ ped: import("zod").ZodOptional<import("zod").ZodString>;
462
+ map: import("zod").ZodOptional<import("zod").ZodString>;
463
+ truncated: import("zod").ZodBoolean;
464
+ warnings: import("zod").ZodArray<import("zod").ZodString>;
465
+ }, import("zod/v4/core").$strip>, readonly [{
466
+ readonly reason: "unknown_alias";
467
+ readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.NotFound;
468
+ readonly when: "No connection has been registered under the requested alias";
469
+ readonly recovery: "Run brapi_connect with this alias (or omit `alias` to use the default connection) before calling brapi_export_genotype_matrix.";
470
+ }, {
471
+ readonly reason: "no_filters";
472
+ readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.ValidationError;
473
+ readonly when: "No variantSetDbId was provided";
474
+ readonly recovery: "Provide variantSetDbId before retrying — unfiltered genotype-call pulls are too expensive.";
475
+ }, {
476
+ readonly reason: "search_endpoint_disabled";
477
+ readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.ValidationError;
478
+ readonly when: "The active dialect declares POST /search/calls as known-dead on this server";
479
+ readonly recovery: "Connect to a different BrAPI server that exposes a working /search/calls route — genotype-call workflows are not viable here.";
366
480
  }], undefined> | import("@cyanheads/mcp-ts-core").ToolDefinition<import("zod").ZodObject<{
367
481
  alias: import("zod").ZodOptional<import("zod").ZodString>;
368
482
  variantSetDbId: import("zod").ZodOptional<import("zod").ZodString>;
@@ -919,6 +1033,40 @@ export declare const readOnlyToolDefinitions: (import("@cyanheads/mcp-ts-core").
919
1033
  readonly notice: import("zod").ZodOptional<import("zod").ZodString>;
920
1034
  readonly warnings: import("zod").ZodArray<import("zod").ZodString>;
921
1035
  }> | import("@cyanheads/mcp-ts-core").ToolDefinition<import("zod").ZodObject<{
1036
+ alias: import("zod").ZodOptional<import("zod").ZodString>;
1037
+ germplasmDbId: import("zod").ZodString;
1038
+ variables: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString>>;
1039
+ }, import("zod/v4/core").$strip>, import("zod").ZodObject<{
1040
+ alias: import("zod").ZodString;
1041
+ germplasmDbId: import("zod").ZodString;
1042
+ germplasmName: import("zod").ZodOptional<import("zod").ZodString>;
1043
+ studyCount: import("zod").ZodNumber;
1044
+ studyDbIds: import("zod").ZodArray<import("zod").ZodString>;
1045
+ perVariable: import("zod").ZodArray<import("zod").ZodObject<{
1046
+ observationVariableDbId: import("zod").ZodString;
1047
+ observationVariableName: import("zod").ZodOptional<import("zod").ZodString>;
1048
+ n: import("zod").ZodNumber;
1049
+ mean: import("zod").ZodOptional<import("zod").ZodNumber>;
1050
+ median: import("zod").ZodOptional<import("zod").ZodNumber>;
1051
+ sd: import("zod").ZodOptional<import("zod").ZodNumber>;
1052
+ min: import("zod").ZodOptional<import("zod").ZodString>;
1053
+ max: import("zod").ZodOptional<import("zod").ZodString>;
1054
+ studyCount: import("zod").ZodNumber;
1055
+ studyDbIds: import("zod").ZodArray<import("zod").ZodString>;
1056
+ seasons: import("zod").ZodArray<import("zod").ZodString>;
1057
+ }, import("zod/v4/core").$strip>>;
1058
+ warnings: import("zod").ZodArray<import("zod").ZodString>;
1059
+ }, import("zod/v4/core").$strip>, readonly [{
1060
+ readonly reason: "unknown_alias";
1061
+ readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.NotFound;
1062
+ readonly when: "No connection has been registered under the requested alias";
1063
+ readonly recovery: "Run brapi_connect with this alias (or omit `alias` to use the default connection) before calling brapi_germplasm_performance.";
1064
+ }, {
1065
+ readonly reason: "germplasm_not_found";
1066
+ readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.NotFound;
1067
+ readonly when: "Upstream returned no germplasm record for the requested germplasmDbId";
1068
+ readonly recovery: "Verify the germplasmDbId on the target server, or run brapi_find_germplasm to discover valid IDs.";
1069
+ }], undefined> | import("@cyanheads/mcp-ts-core").ToolDefinition<import("zod").ZodObject<{
922
1070
  imageDbIds: import("zod").ZodArray<import("zod").ZodString>;
923
1071
  alias: import("zod").ZodOptional<import("zod").ZodString>;
924
1072
  }, import("zod/v4/core").$strip>, import("zod").ZodObject<{
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAyBH;;;;GAIG;AACH,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAoBnC,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB;;;;;yDAAuB,CAAC;AAExD;;;;GAIG;AACH,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gBAAyB,CAAC;AAE5D,qEAAqE;AACrE,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gBAA4B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AA4BH;;;;GAIG;AACH,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAuBnC,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB;;;;;yDAAuB,CAAC;AAExD;;;;GAIG;AACH,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gBAAyB,CAAC;AAE5D,qEAAqE;AACrE,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gBAA4B,CAAC"}
@@ -10,12 +10,14 @@
10
10
  *
11
11
  * @module mcp-server/tools/definitions/index
12
12
  */
13
+ import { brapiBuildPhenotypeMatrix } from './brapi-build-phenotype-matrix.tool.js';
13
14
  import { brapiConnect } from './brapi-connect.tool.js';
14
15
  import { brapiDataframeDescribe } from './brapi-dataframe-describe.tool.js';
15
16
  import { brapiDataframeDrop } from './brapi-dataframe-drop.tool.js';
16
17
  import { brapiDataframeExport } from './brapi-dataframe-export.tool.js';
17
18
  import { brapiDataframeQuery } from './brapi-dataframe-query.tool.js';
18
19
  import { brapiDescribeFilters } from './brapi-describe-filters.tool.js';
20
+ import { brapiExportGenotypeMatrix } from './brapi-export-genotype-matrix.tool.js';
19
21
  import { brapiFindGenotypeCalls } from './brapi-find-genotype-calls.tool.js';
20
22
  import { brapiFindGermplasm } from './brapi-find-germplasm.tool.js';
21
23
  import { brapiFindImages } from './brapi-find-images.tool.js';
@@ -24,6 +26,7 @@ import { brapiFindObservations } from './brapi-find-observations.tool.js';
24
26
  import { brapiFindStudies } from './brapi-find-studies.tool.js';
25
27
  import { brapiFindVariables } from './brapi-find-variables.tool.js';
26
28
  import { brapiFindVariants } from './brapi-find-variants.tool.js';
29
+ import { brapiGermplasmPerformance } from './brapi-germplasm-performance.tool.js';
27
30
  import { brapiGetGermplasm } from './brapi-get-germplasm.tool.js';
28
31
  import { brapiGetImage } from './brapi-get-image.tool.js';
29
32
  import { brapiGetStudy } from './brapi-get-study.tool.js';
@@ -39,6 +42,7 @@ import { brapiWalkPedigree } from './brapi-walk-pedigree.tool.js';
39
42
  */
40
43
  export const readOnlyToolDefinitions = [
41
44
  brapiConnect,
45
+ brapiBuildPhenotypeMatrix,
42
46
  brapiServerInfo,
43
47
  brapiDescribeFilters,
44
48
  brapiFindStudies,
@@ -46,6 +50,7 @@ export const readOnlyToolDefinitions = [
46
50
  brapiFindGermplasm,
47
51
  brapiGetGermplasm,
48
52
  brapiWalkPedigree,
53
+ brapiGermplasmPerformance,
49
54
  brapiFindVariables,
50
55
  brapiFindObservations,
51
56
  brapiFindImages,
@@ -53,6 +58,7 @@ export const readOnlyToolDefinitions = [
53
58
  brapiFindLocations,
54
59
  brapiFindVariants,
55
60
  brapiFindGenotypeCalls,
61
+ brapiExportGenotypeMatrix,
56
62
  brapiDataframeDescribe,
57
63
  brapiDataframeQuery,
58
64
  brapiRawGet,
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,sBAAsB,EAAE,MAAM,oCAAoC,CAAC;AAC5E,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,kCAAkC,CAAC;AACxE,OAAO,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,EAAE,oBAAoB,EAAE,MAAM,kCAAkC,CAAC;AACxE,OAAO,EAAE,sBAAsB,EAAE,MAAM,qCAAqC,CAAC;AAC7E,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACpE,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACpE,OAAO,EAAE,qBAAqB,EAAE,MAAM,mCAAmC,CAAC;AAC1E,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACpE,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,uBAAuB,EAAE,MAAM,qCAAqC,CAAC;AAC9E,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAElE;;;;GAIG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG;IACrC,YAAY;IACZ,eAAe;IACf,oBAAoB;IACpB,gBAAgB;IAChB,aAAa;IACb,kBAAkB;IAClB,iBAAiB;IACjB,iBAAiB;IACjB,kBAAkB;IAClB,qBAAqB;IACrB,eAAe;IACf,aAAa;IACb,kBAAkB;IAClB,iBAAiB;IACjB,sBAAsB;IACtB,sBAAsB;IACtB,mBAAmB;IACnB,WAAW;IACX,cAAc;CACf,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,kBAAkB,CAAC,CAAC;AAExD;;;;GAIG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,oBAAoB,CAAC,CAAC;AAE5D,qEAAqE;AACrE,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,uBAAuB,CAAC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,yBAAyB,EAAE,MAAM,wCAAwC,CAAC;AACnF,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,sBAAsB,EAAE,MAAM,oCAAoC,CAAC;AAC5E,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,kCAAkC,CAAC;AACxE,OAAO,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,EAAE,oBAAoB,EAAE,MAAM,kCAAkC,CAAC;AACxE,OAAO,EAAE,yBAAyB,EAAE,MAAM,wCAAwC,CAAC;AACnF,OAAO,EAAE,sBAAsB,EAAE,MAAM,qCAAqC,CAAC;AAC7E,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACpE,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACpE,OAAO,EAAE,qBAAqB,EAAE,MAAM,mCAAmC,CAAC;AAC1E,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACpE,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,EAAE,yBAAyB,EAAE,MAAM,uCAAuC,CAAC;AAClF,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,uBAAuB,EAAE,MAAM,qCAAqC,CAAC;AAC9E,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAElE;;;;GAIG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG;IACrC,YAAY;IACZ,yBAAyB;IACzB,eAAe;IACf,oBAAoB;IACpB,gBAAgB;IAChB,aAAa;IACb,kBAAkB;IAClB,iBAAiB;IACjB,iBAAiB;IACjB,yBAAyB;IACzB,kBAAkB;IAClB,qBAAqB;IACrB,eAAe;IACf,aAAa;IACb,kBAAkB;IAClB,iBAAiB;IACjB,sBAAsB;IACtB,yBAAyB;IACzB,sBAAsB;IACtB,mBAAmB;IACnB,WAAW;IACX,cAAc;CACf,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,kBAAkB,CAAC,CAAC;AAExD;;;;GAIG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,oBAAoB,CAAC,CAAC;AAE5D,qEAAqE;AACrE,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,uBAAuB,CAAC,CAAC"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * @fileoverview Shared canvas column-name sanitizer. The two matrix-building
3
+ * tools (`brapi_build_phenotype_matrix`, `brapi_export_genotype_matrix`) pivot
4
+ * upstream IDs (`observationVariableDbId`, `variantDbId`) into dataframe column
5
+ * names. The framework's canvas registers tables through `assertValidIdentifier`,
6
+ * which rejects any column whose name fails `/^[A-Za-z_][A-Za-z0-9_]{0,62}$/` or
7
+ * matches a reserved SQL keyword. BrAPI DbIds are routinely numeric (Breedbase
8
+ * uses integers) or collide with reserved words, so column names must be
9
+ * sanitized to SQL-safe identifiers before registration — paired with a legend
10
+ * mapping the safe name back to the original ID so the correlation is never lost.
11
+ *
12
+ * @module mcp-server/tools/shared/canvas-columns
13
+ */
14
+ /**
15
+ * Sanitize an arbitrary upstream ID into a valid DuckDB column identifier.
16
+ * Mirrors the framework's `CANVAS_IDENTIFIER_REGEX` (`/^[A-Za-z_][A-Za-z0-9_]{0,62}$/`):
17
+ * replace illegal characters with `_`, prefix `v_` when the result would start
18
+ * with a digit, truncate to 63 chars, and suffix `_` when the result collides
19
+ * with a reserved SQL keyword.
20
+ */
21
+ export declare function sanitizeColumnName(raw: string): string;
22
+ /**
23
+ * Sanitize a list of IDs into unique column names, preserving input order. When
24
+ * two IDs sanitize to the same name, later collisions get a numeric suffix
25
+ * (`_2`, `_3`, …). Returns the column names in order plus a legend mapping each
26
+ * safe column name back to its original ID.
27
+ */
28
+ export declare function buildUniqueColumns(ids: readonly string[]): {
29
+ columns: string[];
30
+ toOriginal: Record<string, string>;
31
+ };
32
+ //# sourceMappingURL=canvas-columns.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canvas-columns.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/shared/canvas-columns.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AA+CH;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAStD;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,SAAS,MAAM,EAAE,GAAG;IAC1D,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACpC,CAaA"}
@@ -0,0 +1,98 @@
1
+ /**
2
+ * @fileoverview Shared canvas column-name sanitizer. The two matrix-building
3
+ * tools (`brapi_build_phenotype_matrix`, `brapi_export_genotype_matrix`) pivot
4
+ * upstream IDs (`observationVariableDbId`, `variantDbId`) into dataframe column
5
+ * names. The framework's canvas registers tables through `assertValidIdentifier`,
6
+ * which rejects any column whose name fails `/^[A-Za-z_][A-Za-z0-9_]{0,62}$/` or
7
+ * matches a reserved SQL keyword. BrAPI DbIds are routinely numeric (Breedbase
8
+ * uses integers) or collide with reserved words, so column names must be
9
+ * sanitized to SQL-safe identifiers before registration — paired with a legend
10
+ * mapping the safe name back to the original ID so the correlation is never lost.
11
+ *
12
+ * @module mcp-server/tools/shared/canvas-columns
13
+ */
14
+ /**
15
+ * Reserved SQL keywords rejected by the framework canvas gate
16
+ * (`assertValidIdentifier`, reason `identifierReserved`). Kept in sync with the
17
+ * framework's `RESERVED_IDENTIFIERS` set — a sanitized name matching one of
18
+ * these (case-insensitive) is suffixed with `_` to clear the gate.
19
+ */
20
+ const RESERVED_IDENTIFIERS = new Set([
21
+ 'select',
22
+ 'from',
23
+ 'where',
24
+ 'order',
25
+ 'group',
26
+ 'having',
27
+ 'limit',
28
+ 'offset',
29
+ 'union',
30
+ 'intersect',
31
+ 'except',
32
+ 'all',
33
+ 'distinct',
34
+ 'as',
35
+ 'and',
36
+ 'or',
37
+ 'not',
38
+ 'null',
39
+ 'true',
40
+ 'false',
41
+ 'case',
42
+ 'when',
43
+ 'then',
44
+ 'else',
45
+ 'end',
46
+ 'join',
47
+ 'inner',
48
+ 'outer',
49
+ 'left',
50
+ 'right',
51
+ 'full',
52
+ 'cross',
53
+ 'on',
54
+ 'using',
55
+ 'with',
56
+ 'recursive',
57
+ ]);
58
+ /**
59
+ * Sanitize an arbitrary upstream ID into a valid DuckDB column identifier.
60
+ * Mirrors the framework's `CANVAS_IDENTIFIER_REGEX` (`/^[A-Za-z_][A-Za-z0-9_]{0,62}$/`):
61
+ * replace illegal characters with `_`, prefix `v_` when the result would start
62
+ * with a digit, truncate to 63 chars, and suffix `_` when the result collides
63
+ * with a reserved SQL keyword.
64
+ */
65
+ export function sanitizeColumnName(raw) {
66
+ let name = raw.replace(/[^A-Za-z0-9_]/g, '_');
67
+ if (/^[0-9]/.test(name))
68
+ name = `v_${name}`;
69
+ if (name.length > 63)
70
+ name = name.slice(0, 63);
71
+ if (name.length === 0)
72
+ name = 'v_unknown';
73
+ if (RESERVED_IDENTIFIERS.has(name.toLowerCase())) {
74
+ name = name.length >= 63 ? `${name.slice(0, 62)}_` : `${name}_`;
75
+ }
76
+ return name;
77
+ }
78
+ /**
79
+ * Sanitize a list of IDs into unique column names, preserving input order. When
80
+ * two IDs sanitize to the same name, later collisions get a numeric suffix
81
+ * (`_2`, `_3`, …). Returns the column names in order plus a legend mapping each
82
+ * safe column name back to its original ID.
83
+ */
84
+ export function buildUniqueColumns(ids) {
85
+ const used = new Map();
86
+ const columns = [];
87
+ const toOriginal = {};
88
+ for (const id of ids) {
89
+ const base = sanitizeColumnName(id);
90
+ const count = (used.get(base) ?? 0) + 1;
91
+ used.set(base, count);
92
+ const colName = count === 1 ? base : `${base}_${count}`;
93
+ columns.push(colName);
94
+ toOriginal[colName] = id;
95
+ }
96
+ return { columns, toOriginal };
97
+ }
98
+ //# sourceMappingURL=canvas-columns.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canvas-columns.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/shared/canvas-columns.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH;;;;;GAKG;AACH,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAAC;IACnC,QAAQ;IACR,MAAM;IACN,OAAO;IACP,OAAO;IACP,OAAO;IACP,QAAQ;IACR,OAAO;IACP,QAAQ;IACR,OAAO;IACP,WAAW;IACX,QAAQ;IACR,KAAK;IACL,UAAU;IACV,IAAI;IACJ,KAAK;IACL,IAAI;IACJ,KAAK;IACL,MAAM;IACN,MAAM;IACN,OAAO;IACP,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,KAAK;IACL,MAAM;IACN,OAAO;IACP,OAAO;IACP,MAAM;IACN,OAAO;IACP,MAAM;IACN,OAAO;IACP,IAAI;IACJ,OAAO;IACP,MAAM;IACN,WAAW;CACZ,CAAC,CAAC;AAEH;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAW;IAC5C,IAAI,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC,gBAAgB,EAAE,GAAG,CAAC,CAAC;IAC9C,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;IAC5C,IAAI,IAAI,CAAC,MAAM,GAAG,EAAE;QAAE,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC/C,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,IAAI,GAAG,WAAW,CAAC;IAC1C,IAAI,oBAAoB,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC;QACjD,IAAI,GAAG,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC;IAClE,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAsB;IAIvD,MAAM,IAAI,GAAG,IAAI,GAAG,EAAkB,CAAC;IACvC,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,MAAM,UAAU,GAA2B,EAAE,CAAC;IAC9C,KAAK,MAAM,EAAE,IAAI,GAAG,EAAE,CAAC;QACrB,MAAM,IAAI,GAAG,kBAAkB,CAAC,EAAE,CAAC,CAAC;QACpC,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;QACxC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QACtB,MAAM,OAAO,GAAG,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,KAAK,EAAE,CAAC;QACxD,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACtB,UAAU,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC;IAC3B,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC;AACjC,CAAC"}
@@ -0,0 +1,81 @@
1
+ /**
2
+ * @fileoverview Shared genotype-call pull logic — the async-search machinery
3
+ * (`POST /search/calls` → poll → page-walk) and the `CallRow` schema extracted
4
+ * from `brapi-find-genotype-calls.tool.ts` so that `brapi_export_genotype_matrix`
5
+ * can reuse the same pull infrastructure without duplicating it.
6
+ *
7
+ * This module owns: the `CallRowSchema`, `CallFormatting` type, and the
8
+ * `collectCalls` / `consumePage` helpers. It does NOT contain `spillCalls` or
9
+ * any tool-level concerns — those stay in the consuming tool files.
10
+ *
11
+ * @module mcp-server/tools/shared/genotype-calls
12
+ */
13
+ import { type Context, z } from '@cyanheads/mcp-ts-core';
14
+ import type { BrapiClient } from '../../../services/brapi-client/index.js';
15
+ import type { RegisteredServer } from '../../../services/server-registry/types.js';
16
+ export declare const CallRowSchema: z.ZodObject<{
17
+ callSetDbId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
18
+ callSetName: z.ZodOptional<z.ZodNullable<z.ZodString>>;
19
+ variantDbId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
20
+ variantName: z.ZodOptional<z.ZodNullable<z.ZodString>>;
21
+ variantSetDbId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
22
+ genotype: z.ZodOptional<z.ZodNullable<z.ZodObject<{
23
+ values: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString>>>;
24
+ }, z.core.$loose>>>;
25
+ genotypeValue: z.ZodOptional<z.ZodNullable<z.ZodString>>;
26
+ phaseSet: z.ZodOptional<z.ZodNullable<z.ZodString>>;
27
+ }, z.core.$loose>;
28
+ export type CallRow = z.infer<typeof CallRowSchema>;
29
+ export interface CallFormatting {
30
+ expandHomozygotes?: boolean | null;
31
+ sepPhased?: string | null;
32
+ sepUnphased?: string | null;
33
+ unknownString?: string | null;
34
+ }
35
+ export interface CollectCallsInput {
36
+ body: Record<string, unknown>;
37
+ client: BrapiClient;
38
+ connection: RegisteredServer;
39
+ ctx: Context;
40
+ maxCalls: number;
41
+ warnings: string[];
42
+ }
43
+ export interface CollectCallsResult {
44
+ callFormatting: CallFormatting;
45
+ rows: CallRow[];
46
+ truncated: boolean;
47
+ }
48
+ /**
49
+ * Build the POST /search/calls body from named filter params. Handles both the
50
+ * singular `variantSetDbId` convenience and the plural `variantSetDbIds` array,
51
+ * merging and deduplicating them.
52
+ */
53
+ export declare function buildCallsSearchBody(input: {
54
+ variantSetDbId?: string | undefined;
55
+ variantSetDbIds?: string[] | undefined;
56
+ germplasmDbIds?: string[] | undefined;
57
+ callSetDbIds?: string[] | undefined;
58
+ variantDbIds?: string[] | undefined;
59
+ callFormat?: string | undefined;
60
+ }): Record<string, unknown>;
61
+ /**
62
+ * Pull all genotype call pages for a given search body, capping at `maxCalls`.
63
+ * Uses BrAPI's async-search pattern: `POST /search/calls` → `GET /search/calls/{id}`
64
+ * with 202-retry. Pages are collected until all results are fetched or `maxCalls`
65
+ * is reached.
66
+ */
67
+ export declare function collectCalls(input: CollectCallsInput): Promise<CollectCallsResult>;
68
+ /**
69
+ * Extract call rows and `callFormatting` hints from one BrAPI envelope page.
70
+ * Mutates `rows` in-place; invokes `setCallFormatting` when formatting hints
71
+ * are present so the caller can merge across pages.
72
+ */
73
+ export declare function consumePage(envelope: Awaited<ReturnType<BrapiClient['get']>>, rows: CallRow[], setCallFormatting: (f: CallFormatting) => void): void;
74
+ /**
75
+ * Render the genotype string for one call row given the server's callFormatting
76
+ * hints. Prefers `genotype.values` joined with the appropriate separator;
77
+ * falls back to `genotypeValue`; returns the `unknownString` (or ".") when
78
+ * no data is available.
79
+ */
80
+ export declare function renderGenotypeString(row: CallRow, callFormatting: CallFormatting, phased?: boolean): string;
81
+ //# sourceMappingURL=genotype-calls.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"genotype-calls.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/shared/genotype-calls.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,KAAK,OAAO,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qCAAqC,CAAC;AAK5E,eAAO,MAAM,aAAa;;;;;;;;;;;iBAkCW,CAAC;AAEtC,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAEpD,MAAM,WAAW,cAAc;IAC7B,iBAAiB,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IACnC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,MAAM,EAAE,WAAW,CAAC;IACpB,UAAU,EAAE,gBAAgB,CAAC;IAC7B,GAAG,EAAE,OAAO,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,kBAAkB;IACjC,cAAc,EAAE,cAAc,CAAC;IAC/B,IAAI,EAAE,OAAO,EAAE,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE;IAC1C,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,eAAe,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IACvC,cAAc,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IACtC,YAAY,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IACpC,YAAY,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IACpC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACjC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAc1B;AAED;;;;;GAKG;AACH,wBAAsB,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAmFxF;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CACzB,QAAQ,EAAE,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,EACjD,IAAI,EAAE,OAAO,EAAE,EACf,iBAAiB,EAAE,CAAC,CAAC,EAAE,cAAc,KAAK,IAAI,GAC7C,IAAI,CAmBN;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,OAAO,EACZ,cAAc,EAAE,cAAc,EAC9B,MAAM,CAAC,EAAE,OAAO,GACf,MAAM,CASR"}
@@ -0,0 +1,172 @@
1
+ /**
2
+ * @fileoverview Shared genotype-call pull logic — the async-search machinery
3
+ * (`POST /search/calls` → poll → page-walk) and the `CallRow` schema extracted
4
+ * from `brapi-find-genotype-calls.tool.ts` so that `brapi_export_genotype_matrix`
5
+ * can reuse the same pull infrastructure without duplicating it.
6
+ *
7
+ * This module owns: the `CallRowSchema`, `CallFormatting` type, and the
8
+ * `collectCalls` / `consumePage` helpers. It does NOT contain `spillCalls` or
9
+ * any tool-level concerns — those stay in the consuming tool files.
10
+ *
11
+ * @module mcp-server/tools/shared/genotype-calls
12
+ */
13
+ import { z } from '@cyanheads/mcp-ts-core';
14
+ import { buildRequestOptions } from './find-helpers.js';
15
+ const PAGE_SIZE = 10_000;
16
+ export const CallRowSchema = z
17
+ .object({
18
+ callSetDbId: z
19
+ .string()
20
+ .nullish()
21
+ .describe('FK to the call set (one germplasm × one variant set = one call set).'),
22
+ callSetName: z.string().nullish().describe('Display name of the call set.'),
23
+ variantDbId: z.string().nullish().describe('FK to the variant being called.'),
24
+ variantName: z.string().nullish().describe('Display name / alias of the variant.'),
25
+ variantSetDbId: z.string().nullish().describe('FK to the variant set the call belongs to.'),
26
+ genotype: z
27
+ .object({
28
+ values: z
29
+ .array(z.string().describe('Per-allele value string.'))
30
+ .nullish()
31
+ .describe('Encoded allele values — interpret using top-level `callFormatting`.'),
32
+ })
33
+ .passthrough()
34
+ .nullish()
35
+ .describe('Structured genotype payload (array of allele values plus server-specific fields).'),
36
+ genotypeValue: z
37
+ .string()
38
+ .nullish()
39
+ .describe('Legacy flat string form of the call (provided by some servers instead of `genotype`).'),
40
+ phaseSet: z
41
+ .string()
42
+ .nullish()
43
+ .describe('Phase-set identifier linking calls that share a haplotype phase.'),
44
+ })
45
+ .passthrough()
46
+ .describe('One genotype call row.');
47
+ /**
48
+ * Build the POST /search/calls body from named filter params. Handles both the
49
+ * singular `variantSetDbId` convenience and the plural `variantSetDbIds` array,
50
+ * merging and deduplicating them.
51
+ */
52
+ export function buildCallsSearchBody(input) {
53
+ const body = {};
54
+ if (input.variantSetDbId)
55
+ body.variantSetDbIds = [input.variantSetDbId];
56
+ if (input.variantSetDbIds?.length) {
57
+ body.variantSetDbIds = Array.from(new Set([...(body.variantSetDbIds ?? []), ...input.variantSetDbIds]));
58
+ }
59
+ if (input.germplasmDbIds?.length)
60
+ body.germplasmDbIds = input.germplasmDbIds;
61
+ if (input.callSetDbIds?.length)
62
+ body.callSetDbIds = input.callSetDbIds;
63
+ if (input.variantDbIds?.length)
64
+ body.variantDbIds = input.variantDbIds;
65
+ if (input.callFormat)
66
+ body.callFormat = input.callFormat;
67
+ body.pageSize = PAGE_SIZE;
68
+ return body;
69
+ }
70
+ /**
71
+ * Pull all genotype call pages for a given search body, capping at `maxCalls`.
72
+ * Uses BrAPI's async-search pattern: `POST /search/calls` → `GET /search/calls/{id}`
73
+ * with 202-retry. Pages are collected until all results are fetched or `maxCalls`
74
+ * is reached.
75
+ */
76
+ export async function collectCalls(input) {
77
+ const rows = [];
78
+ let callFormatting = {};
79
+ let truncated = false;
80
+ const firstBody = { ...input.body, page: 0 };
81
+ const first = await input.client.postSearch(input.connection.baseUrl, 'calls', firstBody, input.ctx, buildRequestOptions(input.connection));
82
+ let envelope;
83
+ let searchResultsDbId;
84
+ if (first.kind === 'sync') {
85
+ envelope = first.envelope;
86
+ }
87
+ else {
88
+ searchResultsDbId = first.searchResultsDbId;
89
+ envelope = await input.client.getSearchResults(input.connection.baseUrl, 'calls', first.searchResultsDbId, input.ctx, buildRequestOptions(input.connection));
90
+ }
91
+ consumePage(envelope, rows, (cf) => {
92
+ callFormatting = cf;
93
+ });
94
+ const totalPages = envelope.metadata?.pagination?.totalPages;
95
+ for (let page = 1; page < (totalPages ?? 1); page++) {
96
+ if (rows.length >= input.maxCalls) {
97
+ truncated = true;
98
+ break;
99
+ }
100
+ if (input.ctx.signal.aborted)
101
+ break;
102
+ let pageEnvelope;
103
+ if (searchResultsDbId) {
104
+ pageEnvelope = await input.client.getSearchResults(input.connection.baseUrl, 'calls', searchResultsDbId, input.ctx, buildRequestOptions(input.connection, { page, pageSize: PAGE_SIZE }));
105
+ }
106
+ else {
107
+ const nextSearch = await input.client.postSearch(input.connection.baseUrl, 'calls', { ...input.body, page }, input.ctx, buildRequestOptions(input.connection));
108
+ if (nextSearch.kind === 'sync') {
109
+ pageEnvelope = nextSearch.envelope;
110
+ }
111
+ else {
112
+ pageEnvelope = await input.client.getSearchResults(input.connection.baseUrl, 'calls', nextSearch.searchResultsDbId, input.ctx, buildRequestOptions(input.connection));
113
+ }
114
+ }
115
+ consumePage(pageEnvelope, rows, (cf) => {
116
+ callFormatting = cf;
117
+ });
118
+ }
119
+ if (rows.length > input.maxCalls) {
120
+ rows.length = input.maxCalls;
121
+ truncated = true;
122
+ input.warnings.push(`Truncated at the deployment pull limit (${input.maxCalls} rows). Narrow the filters and re-pull; the captured slice is preserved in the spilled dataframe.`);
123
+ }
124
+ return { rows, callFormatting, truncated };
125
+ }
126
+ /**
127
+ * Extract call rows and `callFormatting` hints from one BrAPI envelope page.
128
+ * Mutates `rows` in-place; invokes `setCallFormatting` when formatting hints
129
+ * are present so the caller can merge across pages.
130
+ */
131
+ export function consumePage(envelope, rows, setCallFormatting) {
132
+ const result = envelope.result;
133
+ if (!result || typeof result !== 'object')
134
+ return;
135
+ const record = result;
136
+ const cf = {};
137
+ if (typeof record.expandHomozygotes === 'boolean')
138
+ cf.expandHomozygotes = record.expandHomozygotes;
139
+ if (typeof record.unknownString === 'string')
140
+ cf.unknownString = record.unknownString;
141
+ if (typeof record.sepPhased === 'string')
142
+ cf.sepPhased = record.sepPhased;
143
+ if (typeof record.sepUnphased === 'string')
144
+ cf.sepUnphased = record.sepUnphased;
145
+ setCallFormatting(cf);
146
+ const data = record.data;
147
+ if (!Array.isArray(data))
148
+ return;
149
+ for (const entry of data) {
150
+ if (typeof entry === 'object' && entry !== null) {
151
+ rows.push(entry);
152
+ }
153
+ }
154
+ }
155
+ /**
156
+ * Render the genotype string for one call row given the server's callFormatting
157
+ * hints. Prefers `genotype.values` joined with the appropriate separator;
158
+ * falls back to `genotypeValue`; returns the `unknownString` (or ".") when
159
+ * no data is available.
160
+ */
161
+ export function renderGenotypeString(row, callFormatting, phased) {
162
+ const unknown = callFormatting.unknownString ?? '.';
163
+ const values = row.genotype?.values;
164
+ if (values && values.length > 0) {
165
+ const sep = phased ? (callFormatting.sepPhased ?? '|') : (callFormatting.sepUnphased ?? '/');
166
+ return values.join(sep);
167
+ }
168
+ if (row.genotypeValue)
169
+ return row.genotypeValue;
170
+ return unknown;
171
+ }
172
+ //# sourceMappingURL=genotype-calls.js.map