@berthojoris/mcp-mysql-server 1.40.7 → 1.42.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.
@@ -2,6 +2,108 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.validateToolArguments = validateToolArguments;
4
4
  const inputValidation_js_1 = require("../validation/inputValidation.js");
5
+ const validatePlanSeedDataArgs = (args) => {
6
+ const errors = [];
7
+ if (!Array.isArray(args.target_tables) || args.target_tables.length === 0) {
8
+ errors.push("target_tables must be a non-empty array");
9
+ }
10
+ else {
11
+ for (const table of args.target_tables) {
12
+ const validation = (0, inputValidation_js_1.validateTableName)(table);
13
+ if (!validation.valid) {
14
+ errors.push(`Invalid target table '${table}': ${validation.error}`);
15
+ }
16
+ }
17
+ }
18
+ if (args.database !== undefined) {
19
+ const validation = (0, inputValidation_js_1.validateValue)(args.database);
20
+ if (!validation.valid)
21
+ errors.push(validation.error || "Invalid database name");
22
+ }
23
+ validateRowsPerTable(args.rows_per_table, errors);
24
+ return errors.length ? { valid: false, errors } : { valid: true };
25
+ };
26
+ const validateRowsPerTable = (rowsPerTable, errors) => {
27
+ if (rowsPerTable === undefined)
28
+ return;
29
+ if (typeof rowsPerTable === "number") {
30
+ if (!Number.isFinite(rowsPerTable) || rowsPerTable < 0) {
31
+ errors.push("rows_per_table must be a non-negative number");
32
+ }
33
+ return;
34
+ }
35
+ if (typeof rowsPerTable === "object" && rowsPerTable !== null && !Array.isArray(rowsPerTable)) {
36
+ for (const [table, count] of Object.entries(rowsPerTable)) {
37
+ const tableValidation = (0, inputValidation_js_1.validateTableName)(table);
38
+ if (!tableValidation.valid)
39
+ errors.push(`Invalid rows_per_table key '${table}': ${tableValidation.error}`);
40
+ if (typeof count !== "number" || !Number.isFinite(count) || count < 0) {
41
+ errors.push(`rows_per_table.${table} must be a non-negative number`);
42
+ }
43
+ }
44
+ return;
45
+ }
46
+ errors.push("rows_per_table must be a number or object map");
47
+ };
48
+ const validateTableList = (value, key, errors) => {
49
+ if (value === undefined)
50
+ return;
51
+ if (!Array.isArray(value)) {
52
+ errors.push(`${key} must be an array`);
53
+ return;
54
+ }
55
+ for (const table of value) {
56
+ const validation = (0, inputValidation_js_1.validateTableName)(table);
57
+ if (!validation.valid)
58
+ errors.push(`Invalid ${key} table '${table}': ${validation.error}`);
59
+ }
60
+ };
61
+ const validateInferSeedRulesArgs = (args) => {
62
+ const errors = [];
63
+ if (args.database !== undefined) {
64
+ const validation = (0, inputValidation_js_1.validateValue)(args.database);
65
+ if (!validation.valid)
66
+ errors.push(validation.error || "Invalid database name");
67
+ }
68
+ validateTableList(args.tables, "tables", errors);
69
+ if (args.domain !== undefined && !["auto", "generic", "ecommerce", "pos", "crm"].includes(args.domain)) {
70
+ errors.push("domain must be one of auto, generic, ecommerce, pos, crm");
71
+ }
72
+ if (args.sample_size !== undefined && (!Number.isFinite(Number(args.sample_size)) || Number(args.sample_size) < 0)) {
73
+ errors.push("sample_size must be a non-negative number");
74
+ }
75
+ if (args.max_tables !== undefined && (!Number.isFinite(Number(args.max_tables)) || Number(args.max_tables) < 1)) {
76
+ errors.push("max_tables must be a positive number");
77
+ }
78
+ return errors.length ? { valid: false, errors } : { valid: true };
79
+ };
80
+ const validateSeedFromTemplateArgs = (args) => {
81
+ const errors = [];
82
+ if (!args.template || !["ecommerce", "pos", "crm"].includes(args.template)) {
83
+ errors.push("template must be one of ecommerce, pos, crm");
84
+ }
85
+ if (args.database !== undefined) {
86
+ const validation = (0, inputValidation_js_1.validateValue)(args.database);
87
+ if (!validation.valid)
88
+ errors.push(validation.error || "Invalid database name");
89
+ }
90
+ if (args.scale !== undefined && !["small", "medium", "large"].includes(args.scale)) {
91
+ errors.push("scale must be one of small, medium, large");
92
+ }
93
+ validateTableList(args.include, "include", errors);
94
+ validateTableList(args.exclude, "exclude", errors);
95
+ validateRowsPerTable(args.rows_per_table, errors);
96
+ return errors.length ? { valid: false, errors } : { valid: true };
97
+ };
98
+ const validatePlanIdArgs = (args) => {
99
+ if (!args.plan_id || typeof args.plan_id !== "string") {
100
+ return { valid: false, errors: ["plan_id is required"] };
101
+ }
102
+ if (!/^seed_plan_[A-Za-z0-9_]+$/.test(args.plan_id)) {
103
+ return { valid: false, errors: ["plan_id has invalid format"] };
104
+ }
105
+ return { valid: true };
106
+ };
5
107
  function validateToolArguments(name, args) {
6
108
  if (!args)
7
109
  return { valid: true };
@@ -26,6 +128,16 @@ function validateToolArguments(name, args) {
26
128
  });
27
129
  case "bulk_insert":
28
130
  return (0, inputValidation_js_1.validateBulkInsert)(args);
131
+ case "plan_seed_data":
132
+ return validatePlanSeedDataArgs(args);
133
+ case "generate_seed_preview":
134
+ case "execute_seed_plan":
135
+ case "validate_seed_integrity":
136
+ return validatePlanIdArgs(args);
137
+ case "infer_seed_rules":
138
+ return validateInferSeedRulesArgs(args);
139
+ case "seed_from_template":
140
+ return validateSeedFromTemplateArgs(args);
29
141
  case "list_tables":
30
142
  case "get_schema_erd":
31
143
  case "get_schema_rag_context":
@@ -366,12 +366,20 @@ class UtilityTools {
366
366
  "execute_in_transaction",
367
367
  "commit_transaction or rollback_transaction",
368
368
  ],
369
+ seed_relational_data: [
370
+ "infer_seed_rules or seed_from_template when domain/sample-based rules are useful",
371
+ "plan_seed_data",
372
+ "generate_seed_preview",
373
+ "execute_seed_plan with dry_run=false and confirm_token after user approval",
374
+ "validate_seed_integrity",
375
+ ],
369
376
  },
370
377
  selection_rules: [
371
378
  "Use get_schema_rag_context before generating SQL to reduce token usage.",
372
379
  "Use run_select_query only for SELECT statements.",
373
380
  "Use execute_write_query for INSERT, UPDATE, and DELETE.",
374
381
  "Use execute_ddl only for CREATE, ALTER, DROP, TRUNCATE, and RENAME.",
382
+ "Use seed_operations for relational dummy data instead of manually chaining bulk_insert across foreign keys.",
375
383
  "Prefer structured tools over raw SQL when possible.",
376
384
  ],
377
385
  },
package/manifest.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mysql-mcp",
3
3
  "description": "A Model Context Protocol for MySQL database interaction",
4
- "version": "1.40.7",
4
+ "version": "1.42.0",
5
5
  "tools": [
6
6
  {
7
7
  "name": "list_databases",
@@ -532,6 +532,368 @@
532
532
  "type": "object"
533
533
  }
534
534
  },
535
+ {
536
+ "name": "plan_seed_data",
537
+ "description": "🌱 RELATIONAL SEEDER: Analyzes target tables, foreign keys, constraints, and row counts to build a safe parent-first seed plan. Use this before generating preview or inserting dummy relational data.",
538
+ "input_schema": {
539
+ "type": "object",
540
+ "properties": {
541
+ "database": {
542
+ "type": "string",
543
+ "description": "Optional: specific connected database name"
544
+ },
545
+ "target_tables": {
546
+ "type": "array",
547
+ "description": "Target tables to seed",
548
+ "minItems": 1,
549
+ "items": {
550
+ "type": "string"
551
+ }
552
+ },
553
+ "rows_per_table": {
554
+ "oneOf": [
555
+ {
556
+ "type": "number",
557
+ "minimum": 0
558
+ },
559
+ {
560
+ "type": "object",
561
+ "additionalProperties": {
562
+ "type": "number",
563
+ "minimum": 0
564
+ }
565
+ }
566
+ ],
567
+ "description": "Rows to create for target tables, either a single number or table-to-count map (default: 10)"
568
+ },
569
+ "include_dependencies": {
570
+ "type": "boolean",
571
+ "description": "Include parent tables required by foreign keys (default: true)"
572
+ },
573
+ "include_children": {
574
+ "type": "boolean",
575
+ "description": "Include child tables that reference included tables for nested relational seeding (default: false)"
576
+ },
577
+ "child_rows_per_parent": {
578
+ "type": "number",
579
+ "description": "Rows to create in child tables for each parent row (default: 2)",
580
+ "minimum": 1,
581
+ "maximum": 20
582
+ },
583
+ "respect_existing_data": {
584
+ "type": "boolean",
585
+ "description": "Reuse existing parent records when possible instead of creating new parent rows (default: true)"
586
+ },
587
+ "strategy": {
588
+ "type": "string",
589
+ "enum": [
590
+ "append"
591
+ ],
592
+ "description": "Seed strategy (currently append)"
593
+ },
594
+ "random_seed": {
595
+ "type": "number",
596
+ "description": "Deterministic seed for repeatable preview and execution (default: 42)"
597
+ },
598
+ "max_rows_per_table": {
599
+ "type": "number",
600
+ "description": "Safety cap for generated rows per table (default: 1000)",
601
+ "minimum": 1,
602
+ "maximum": 10000
603
+ },
604
+ "max_related_tables": {
605
+ "type": "number",
606
+ "description": "Safety cap for dependency/child expansion (default: 25)",
607
+ "minimum": 1,
608
+ "maximum": 100
609
+ },
610
+ "seed_rules": {
611
+ "type": "object",
612
+ "description": "Optional generator overrides keyed by table.column or column name",
613
+ "additionalProperties": true
614
+ },
615
+ "require_confirmation": {
616
+ "type": "boolean",
617
+ "description": "Require confirm_token for non-dry-run execution (default: true)"
618
+ }
619
+ },
620
+ "required": [
621
+ "target_tables"
622
+ ]
623
+ },
624
+ "output_schema": {
625
+ "type": "object"
626
+ }
627
+ },
628
+ {
629
+ "name": "generate_seed_preview",
630
+ "description": "🌱 RELATIONAL SEEDER: Generates deterministic dummy row previews from a seed plan without writing to the database. Shows symbolic foreign-key placeholders for review before execution.",
631
+ "input_schema": {
632
+ "type": "object",
633
+ "properties": {
634
+ "plan_id": {
635
+ "type": "string",
636
+ "description": "Seed plan ID returned by plan_seed_data"
637
+ },
638
+ "locale": {
639
+ "type": "string",
640
+ "description": "Optional locale hint for generated values (default: en_US)"
641
+ },
642
+ "realistic": {
643
+ "type": "boolean",
644
+ "description": "Whether to prefer realistic generated values (default: true)"
645
+ },
646
+ "max_preview_rows_per_table": {
647
+ "type": "number",
648
+ "description": "Maximum preview rows per table (default: 3)",
649
+ "minimum": 1,
650
+ "maximum": 25
651
+ },
652
+ "email_domain": {
653
+ "type": "string",
654
+ "description": "Safe email domain for generated emails (default: example.test)"
655
+ }
656
+ },
657
+ "required": [
658
+ "plan_id"
659
+ ]
660
+ },
661
+ "output_schema": {
662
+ "type": "object"
663
+ }
664
+ },
665
+ {
666
+ "name": "execute_seed_plan",
667
+ "description": "🌱 RELATIONAL SEEDER: Executes a confirmed seed plan with dry-run enabled by default, production-name guard, transaction rollback on errors, and foreign-key ID resolution.",
668
+ "input_schema": {
669
+ "type": "object",
670
+ "properties": {
671
+ "plan_id": {
672
+ "type": "string",
673
+ "description": "Seed plan ID returned by plan_seed_data"
674
+ },
675
+ "dry_run": {
676
+ "type": "boolean",
677
+ "description": "If true, returns execution preview without inserting rows (default: true)"
678
+ },
679
+ "use_transaction": {
680
+ "type": "boolean",
681
+ "description": "Use a transaction and rollback on error (default: true)"
682
+ },
683
+ "batch_size": {
684
+ "type": "number",
685
+ "description": "Reserved batch-size hint for large plans (default: 1 for ID-safe inserts)",
686
+ "minimum": 1,
687
+ "maximum": 10000
688
+ },
689
+ "on_error": {
690
+ "type": "string",
691
+ "enum": [
692
+ "rollback",
693
+ "stop"
694
+ ],
695
+ "description": "Error behavior (default: rollback)"
696
+ },
697
+ "confirm_token": {
698
+ "type": "string",
699
+ "description": "Confirmation token returned by plan_seed_data; required when dry_run is false"
700
+ },
701
+ "allow_production": {
702
+ "type": "boolean",
703
+ "description": "Allow writes to production-like database names (default: false)"
704
+ },
705
+ "email_domain": {
706
+ "type": "string",
707
+ "description": "Safe email domain for generated emails (default: example.test)"
708
+ }
709
+ },
710
+ "required": [
711
+ "plan_id"
712
+ ]
713
+ },
714
+ "output_schema": {
715
+ "type": "object"
716
+ }
717
+ },
718
+ {
719
+ "name": "validate_seed_integrity",
720
+ "description": "🌱 RELATIONAL SEEDER: Validates seed results with FK orphan checks, required-column checks, unique-collision checks, and inserted row-count checks.",
721
+ "input_schema": {
722
+ "type": "object",
723
+ "properties": {
724
+ "plan_id": {
725
+ "type": "string",
726
+ "description": "Seed plan ID returned by plan_seed_data"
727
+ },
728
+ "tables": {
729
+ "type": "array",
730
+ "description": "Optional table subset to validate",
731
+ "items": {
732
+ "type": "string"
733
+ }
734
+ },
735
+ "check_foreign_keys": {
736
+ "type": "boolean",
737
+ "description": "Check foreign key integrity (default: true)"
738
+ },
739
+ "check_orphans": {
740
+ "type": "boolean",
741
+ "description": "Alias for check_foreign_keys"
742
+ },
743
+ "check_required_columns": {
744
+ "type": "boolean",
745
+ "description": "Check NOT NULL required columns (default: true)"
746
+ },
747
+ "check_unique_collisions": {
748
+ "type": "boolean",
749
+ "description": "Check unique index collisions (default: true)"
750
+ },
751
+ "check_row_counts": {
752
+ "type": "boolean",
753
+ "description": "Check inserted row counts when execution metadata is available (default: true)"
754
+ }
755
+ },
756
+ "required": [
757
+ "plan_id"
758
+ ]
759
+ },
760
+ "output_schema": {
761
+ "type": "object"
762
+ }
763
+ },
764
+ {
765
+ "name": "infer_seed_rules",
766
+ "description": "🌱 ADVANCED SEEDER: Infers safe seed generator rules from schema metadata, sample row patterns, unique constraints, and optional ecommerce/POS/CRM domain presets without returning raw PII samples.",
767
+ "input_schema": {
768
+ "type": "object",
769
+ "properties": {
770
+ "database": {
771
+ "type": "string",
772
+ "description": "Optional: specific connected database name"
773
+ },
774
+ "tables": {
775
+ "type": "array",
776
+ "description": "Optional table subset to analyze; defaults to schema tables up to max_tables",
777
+ "items": {
778
+ "type": "string"
779
+ }
780
+ },
781
+ "domain": {
782
+ "type": "string",
783
+ "enum": [
784
+ "auto",
785
+ "generic",
786
+ "ecommerce",
787
+ "pos",
788
+ "crm"
789
+ ],
790
+ "description": "Optional domain preset for better business-like dummy data (default: auto)"
791
+ },
792
+ "sample_size": {
793
+ "type": "number",
794
+ "description": "Number of sample rows per table used to infer ranges and enum-like choices (default: 25, max: 100)",
795
+ "minimum": 0,
796
+ "maximum": 100
797
+ },
798
+ "max_tables": {
799
+ "type": "number",
800
+ "description": "Maximum number of tables to analyze when tables is omitted (default: 50)",
801
+ "minimum": 1,
802
+ "maximum": 200
803
+ }
804
+ }
805
+ },
806
+ "output_schema": {
807
+ "type": "object"
808
+ }
809
+ },
810
+ {
811
+ "name": "seed_from_template",
812
+ "description": "🌱 TEMPLATE SEEDER: Creates a plan-first FK-aware seed workflow from ecommerce, POS, or CRM templates. It detects matching tables, applies domain rules, and returns a seed plan for preview/execution.",
813
+ "input_schema": {
814
+ "type": "object",
815
+ "properties": {
816
+ "database": {
817
+ "type": "string",
818
+ "description": "Optional: specific connected database name"
819
+ },
820
+ "template": {
821
+ "type": "string",
822
+ "enum": [
823
+ "ecommerce",
824
+ "pos",
825
+ "crm"
826
+ ],
827
+ "description": "Business seed template to apply"
828
+ },
829
+ "scale": {
830
+ "type": "string",
831
+ "enum": [
832
+ "small",
833
+ "medium",
834
+ "large"
835
+ ],
836
+ "description": "Template size preset (default: small)"
837
+ },
838
+ "include": {
839
+ "type": "array",
840
+ "description": "Optional concrete table list to seed instead of auto-detected template matches",
841
+ "items": {
842
+ "type": "string"
843
+ }
844
+ },
845
+ "exclude": {
846
+ "type": "array",
847
+ "description": "Optional table names to ignore during template matching",
848
+ "items": {
849
+ "type": "string"
850
+ }
851
+ },
852
+ "rows_per_table": {
853
+ "oneOf": [
854
+ {
855
+ "type": "number",
856
+ "minimum": 0
857
+ },
858
+ {
859
+ "type": "object",
860
+ "additionalProperties": {
861
+ "type": "number",
862
+ "minimum": 0
863
+ }
864
+ }
865
+ ],
866
+ "description": "Optional row-count override for the generated plan"
867
+ },
868
+ "include_dependencies": {
869
+ "type": "boolean",
870
+ "description": "Include parent tables required by foreign keys (default: true)"
871
+ },
872
+ "include_children": {
873
+ "type": "boolean",
874
+ "description": "Include child tables that reference included template tables (default: false)"
875
+ },
876
+ "respect_existing_data": {
877
+ "type": "boolean",
878
+ "description": "Reuse existing parent records when possible instead of creating new parent rows (default: true)"
879
+ },
880
+ "random_seed": {
881
+ "type": "number",
882
+ "description": "Deterministic seed for repeatable preview and execution"
883
+ },
884
+ "require_confirmation": {
885
+ "type": "boolean",
886
+ "description": "Require confirm_token for non-dry-run execution (default: true)"
887
+ }
888
+ },
889
+ "required": [
890
+ "template"
891
+ ]
892
+ },
893
+ "output_schema": {
894
+ "type": "object"
895
+ }
896
+ },
535
897
  {
536
898
  "name": "run_select_query",
537
899
  "description": "⚡ PRIMARY TOOL FOR SELECT QUERIES. Executes read-only SELECT statements with parameterization, optimizer hints, query caching, and dry-run mode. Supports complex queries with JOINs, subqueries, and aggregations. ⚠️ ONLY for SELECT - use execute_write_query for INSERT/UPDATE/DELETE, use execute_ddl for CREATE/ALTER/DROP.",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@berthojoris/mcp-mysql-server",
3
- "version": "1.40.7",
3
+ "version": "1.42.0",
4
4
  "description": "Model Context Protocol server for MySQL database integration with dynamic per-project permissions",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",