d365fo-mcp 1.6.0 → 1.8.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.
- package/README.md +5 -4
- package/bridge/D365MetadataBridge/Protocol/RequestDispatcher.cs +96 -4
- package/bridge/D365MetadataBridge/Services/MetadataWriteService.cs +983 -180
- package/dist/bridge/bridgeAdapter.d.ts +41 -4
- package/dist/bridge/bridgeAdapter.js +106 -9
- package/dist/bridge/bridgeClient.d.ts +18 -3
- package/dist/bridge/bridgeClient.js +25 -5
- package/dist/bridge/index.d.ts +1 -1
- package/dist/bridge/index.js +1 -1
- package/dist/metadata/labelParser.js +8 -4
- package/dist/metadata/modelDescriptor.d.ts +53 -0
- package/dist/metadata/modelDescriptor.js +129 -0
- package/dist/metadata/symbolIndex.js +4 -6
- package/dist/metadata/types.d.ts +8 -0
- package/dist/metadata/xmlParser.d.ts +5 -1
- package/dist/metadata/xmlParser.js +10 -2
- package/dist/metadata/xppDeclaration.d.ts +22 -0
- package/dist/metadata/xppDeclaration.js +36 -2
- package/dist/scripts/build-database.js +14 -10
- package/dist/scripts/build-fts.js +14 -10
- package/dist/scripts/extract-metadata.js +17 -4
- package/dist/server/toolSchemas/d365foFile.js +18 -15
- package/dist/tools/buildProject.d.ts +10 -0
- package/dist/tools/buildProject.js +49 -38
- package/dist/tools/compileLabels.d.ts +62 -0
- package/dist/tools/compileLabels.js +239 -0
- package/dist/tools/createD365File.d.ts +4 -3
- package/dist/tools/createD365File.js +38 -10
- package/dist/tools/createdArtifactLedger.d.ts +5 -1
- package/dist/tools/createdArtifactLedger.js +0 -0
- package/dist/tools/d365foFileOpSpecs.js +42 -3
- package/dist/tools/dataEntityInfo.d.ts +9 -12
- package/dist/tools/dataEntityInfo.js +12 -3
- package/dist/tools/dataEntityViewExtensionXml.d.ts +9 -0
- package/dist/tools/dataEntityViewExtensionXml.js +24 -12
- package/dist/tools/dataEntityXml.d.ts +76 -10
- package/dist/tools/dataEntityXml.js +184 -35
- package/dist/tools/enumInfo.d.ts +10 -3
- package/dist/tools/enumInfo.js +69 -10
- package/dist/tools/formInfo.js +11 -0
- package/dist/tools/generateD365Xml.d.ts +157 -0
- package/dist/tools/generateD365Xml.js +30 -5
- package/dist/tools/modifyD365File.d.ts +19 -0
- package/dist/tools/modifyD365File.js +275 -5
- package/dist/tools/queryInfo.d.ts +10 -3
- package/dist/tools/queryInfo.js +123 -10
- package/dist/tools/reportInfo.js +42 -14
- package/dist/tools/resolveReferences.d.ts +14 -1
- package/dist/tools/resolveReferences.js +160 -14
- package/dist/tools/runBpCheck.js +18 -0
- package/dist/tools/updateSymbolIndex.js +75 -5
- package/dist/tools/validateCode.js +2 -1
- package/dist/tools/viewInfo.d.ts +15 -4
- package/dist/tools/viewInfo.js +162 -9
- package/dist/tools/xppKnowledge.js +55 -10
- package/dist/utils/axTablePropertyOrder.d.ts +1 -1
- package/dist/utils/axTablePropertyOrder.js +5 -0
- package/dist/utils/frameworkBin.d.ts +19 -0
- package/dist/utils/frameworkBin.js +48 -0
- package/dist/utils/indexedXmlLookup.d.ts +54 -0
- package/dist/utils/indexedXmlLookup.js +103 -0
- package/package.json +3 -1
package/README.md
CHANGED
|
@@ -7,10 +7,10 @@
|
|
|
7
7
|
[](https://www.npmjs.com/package/d365fo-mcp)
|
|
8
8
|
[](https://opensource.org/licenses/MIT)
|
|
9
9
|
[](https://nodejs.org/)
|
|
10
|
-
[](https://www.typescriptlang.org/)
|
|
11
|
+
[](docs/TESTING.md)
|
|
12
12
|
<!-- coverage-badge:start -->
|
|
13
|
-
[](eval/COVERAGE.md) [](eval/COVERAGE.md) [](eval/COVERAGE.md)
|
|
14
14
|
<!-- coverage-badge:end -->
|
|
15
15
|
|
|
16
16
|
*Grounded AI development for Dynamics 365 Finance & Operations — works with GitHub Copilot and Claude Code*
|
|
@@ -51,7 +51,7 @@ This server pre-indexes your entire D365FO installation (580 000+ symbols across
|
|
|
51
51
|
| 🔍 **Full-codebase intelligence** | 580K+ symbols indexed: classes, tables, forms, EDTs, enums, labels (20M+ rows), security artifacts — FTS5 search in < 10 ms |
|
|
52
52
|
| 🛡️ **Grounded generation** | Fail-closed gates: `prepare` issues grounding tokens, `validate_code(mode="references")` proves every identifier, `validate_code(mode="syntax")` enforces best practices — hallucinated code never reaches disk |
|
|
53
53
|
| 🧩 **Form pattern engine** | Complete catalog of Microsoft form patterns and sub-patterns: recommends the right pattern, clones reference forms with datasource re-binding, **deterministically expands** patterns that have no reference form, **auto-repairs** a form's missing required controls, validates structure and blocks invalid writes |
|
|
54
|
-
| ✍️ **Safe metadata writes** | C# bridge uses Microsoft's own `IMetadataProvider` —
|
|
54
|
+
| ✍️ **Safe metadata writes** | C# bridge uses Microsoft's own `IMetadataProvider` wherever it can express the object; the few types and ops it cannot go through structured XML writers with ambiguity guards — never blind string replacement. Automatic `.rnrproj` registration, one-call undo |
|
|
55
55
|
| 🏗️ **SDLC integration** | MSBuild compilation with structured diagnostics, DB sync, xppbp best practices, SysTestRunner — all from chat |
|
|
56
56
|
| 📐 **X++ knowledge base** | Queryable rules: select grammar, CoC authoring, financial dimensions, the posting engine (`LedgerVoucher`), number sequences, `SysExtension`, Electronic Reporting, AX2012→D365FO migration — prevents deprecated APIs |
|
|
57
57
|
|
|
@@ -120,6 +120,7 @@ Deployment guide: [docs/SETUP_AZURE.md](docs/SETUP_AZURE.md) — includes CI/CD
|
|
|
120
120
|
| [Claude Code setup](docs/SETUP.md#claude-code-cli) | [Configuration](docs/CONFIGURATION.md) | [Testing](docs/TESTING.md) |
|
|
121
121
|
| [Usage examples](docs/USAGE_EXAMPLES.md) — real tool chains | [Architecture](docs/ARCHITECTURE.md) | [Custom / ISV models](docs/CUSTOM_EXTENSIONS.md) |
|
|
122
122
|
| | | [Coverage](eval/COVERAGE.md) — what the badge counts |
|
|
123
|
+
| | | [Eval loop](docs/AGENT_EVAL_LOOP.md) — the self-improvement harness |
|
|
123
124
|
|
|
124
125
|
## License
|
|
125
126
|
|
|
@@ -457,11 +457,18 @@ namespace D365MetadataBridge.Protocol
|
|
|
457
457
|
?? throw new ArgumentException("Missing: objectName");
|
|
458
458
|
var fieldName = request.GetStringParam("fieldName")
|
|
459
459
|
?? throw new ArgumentException("Missing: fieldName");
|
|
460
|
+
// dataField/dataSource select the data-entity-extension mapped-field
|
|
461
|
+
// path inside AddField; both are absent for table/table-extension.
|
|
462
|
+
// This is the single-op RPC that BridgeClient.addField() calls —
|
|
463
|
+
// it must forward the same parameters as the batch-modify case below.
|
|
460
464
|
return _writeService!.AddField(tableName, fieldName,
|
|
461
465
|
request.GetStringParam("fieldType") ?? "String",
|
|
462
466
|
request.GetStringParam("edt"),
|
|
463
467
|
request.GetBoolParam("mandatory") ?? false,
|
|
464
|
-
request.GetStringParam("label")
|
|
468
|
+
request.GetStringParam("label"),
|
|
469
|
+
request.GetStringParam("dataField"),
|
|
470
|
+
request.GetStringParam("dataSource"),
|
|
471
|
+
request.GetStringParam("fieldGroupName"));
|
|
465
472
|
});
|
|
466
473
|
|
|
467
474
|
case "setproperty":
|
|
@@ -528,6 +535,53 @@ namespace D365MetadataBridge.Protocol
|
|
|
528
535
|
return _writeService!.RemoveIndex(tableName, indexName);
|
|
529
536
|
});
|
|
530
537
|
|
|
538
|
+
// This is the single-op RPC that BridgeClient.addFullTextIndex()/
|
|
539
|
+
// addTableMapping() actually call — it must carry the same four cases
|
|
540
|
+
// HandleBatchModify() has below, or every real request dies with
|
|
541
|
+
// "-32601 Unknown method" no matter how correct the C# write path is.
|
|
542
|
+
case "addfulltextindex":
|
|
543
|
+
return HandleWrite(request, () =>
|
|
544
|
+
{
|
|
545
|
+
var tableName = request.GetStringParam("objectName")
|
|
546
|
+
?? throw new ArgumentException("Missing: objectName");
|
|
547
|
+
var indexName = request.GetStringParam("indexName")
|
|
548
|
+
?? throw new ArgumentException("Missing: indexName");
|
|
549
|
+
return _writeService!.AddFullTextIndex(tableName, indexName,
|
|
550
|
+
request.GetParam<System.Collections.Generic.List<string>>("fields"));
|
|
551
|
+
});
|
|
552
|
+
|
|
553
|
+
case "removefulltextindex":
|
|
554
|
+
return HandleWrite(request, () =>
|
|
555
|
+
{
|
|
556
|
+
var tableName = request.GetStringParam("objectName")
|
|
557
|
+
?? throw new ArgumentException("Missing: objectName");
|
|
558
|
+
var indexName = request.GetStringParam("indexName")
|
|
559
|
+
?? throw new ArgumentException("Missing: indexName");
|
|
560
|
+
return _writeService!.RemoveFullTextIndex(tableName, indexName);
|
|
561
|
+
});
|
|
562
|
+
|
|
563
|
+
case "addtablemapping":
|
|
564
|
+
return HandleWrite(request, () =>
|
|
565
|
+
{
|
|
566
|
+
var tableName = request.GetStringParam("objectName")
|
|
567
|
+
?? throw new ArgumentException("Missing: objectName");
|
|
568
|
+
var mapName = request.GetStringParam("mapName")
|
|
569
|
+
?? throw new ArgumentException("Missing: mapName");
|
|
570
|
+
return _writeService!.AddTableMapping(tableName, mapName,
|
|
571
|
+
request.GetStringParam("mappingTable"),
|
|
572
|
+
request.GetParam<System.Collections.Generic.List<WriteMappingConnection>>("connections"));
|
|
573
|
+
});
|
|
574
|
+
|
|
575
|
+
case "removetablemapping":
|
|
576
|
+
return HandleWrite(request, () =>
|
|
577
|
+
{
|
|
578
|
+
var tableName = request.GetStringParam("objectName")
|
|
579
|
+
?? throw new ArgumentException("Missing: objectName");
|
|
580
|
+
var mapName = request.GetStringParam("mapName")
|
|
581
|
+
?? throw new ArgumentException("Missing: mapName");
|
|
582
|
+
return _writeService!.RemoveTableMapping(tableName, mapName);
|
|
583
|
+
});
|
|
584
|
+
|
|
531
585
|
case "addrelation":
|
|
532
586
|
return HandleWrite(request, () =>
|
|
533
587
|
{
|
|
@@ -588,7 +642,12 @@ namespace D365MetadataBridge.Protocol
|
|
|
588
642
|
?? throw new ArgumentException("Missing: fieldGroupName");
|
|
589
643
|
var fieldName = request.GetStringParam("fieldName")
|
|
590
644
|
?? throw new ArgumentException("Missing: fieldName");
|
|
591
|
-
|
|
645
|
+
// This is the single-op RPC BridgeClient.addFieldToFieldGroup() actually
|
|
646
|
+
// calls — dropping extendBaseFieldGroup here silently reverts every
|
|
647
|
+
// caller to the extension-owns-the-group path (see HandleBatchModify()
|
|
648
|
+
// below, which forwards it correctly).
|
|
649
|
+
return _writeService!.AddFieldToFieldGroup(tableName, groupName, fieldName,
|
|
650
|
+
request.GetBoolParam("extendBaseFieldGroup") ?? false);
|
|
592
651
|
});
|
|
593
652
|
|
|
594
653
|
case "modifyfield":
|
|
@@ -911,12 +970,17 @@ namespace D365MetadataBridge.Protocol
|
|
|
911
970
|
|
|
912
971
|
case "addfield":
|
|
913
972
|
case "add-field":
|
|
973
|
+
// dataField/dataSource select the data-entity-extension mapped-field
|
|
974
|
+
// path inside AddField; both are absent for table/table-extension.
|
|
914
975
|
writeResult = _writeService.AddField(objectName,
|
|
915
976
|
S("fieldName") ?? throw new ArgumentException("Missing: fieldName"),
|
|
916
977
|
S("fieldType") ?? "String",
|
|
917
978
|
S("edt"),
|
|
918
979
|
B("mandatory") ?? false,
|
|
919
|
-
S("label")
|
|
980
|
+
S("label"),
|
|
981
|
+
S("dataField"),
|
|
982
|
+
S("dataSource"),
|
|
983
|
+
S("fieldGroupName"));
|
|
920
984
|
break;
|
|
921
985
|
|
|
922
986
|
case "modifyfield":
|
|
@@ -963,6 +1027,33 @@ namespace D365MetadataBridge.Protocol
|
|
|
963
1027
|
S("indexName") ?? throw new ArgumentException("Missing: indexName"));
|
|
964
1028
|
break;
|
|
965
1029
|
|
|
1030
|
+
case "addfulltextindex":
|
|
1031
|
+
case "add-full-text-index":
|
|
1032
|
+
writeResult = _writeService.AddFullTextIndex(objectName,
|
|
1033
|
+
S("indexName") ?? throw new ArgumentException("Missing: indexName"),
|
|
1034
|
+
op.GetTypedParam<System.Collections.Generic.List<string>>("fields"));
|
|
1035
|
+
break;
|
|
1036
|
+
|
|
1037
|
+
case "removefulltextindex":
|
|
1038
|
+
case "remove-full-text-index":
|
|
1039
|
+
writeResult = _writeService.RemoveFullTextIndex(objectName,
|
|
1040
|
+
S("indexName") ?? throw new ArgumentException("Missing: indexName"));
|
|
1041
|
+
break;
|
|
1042
|
+
|
|
1043
|
+
case "addtablemapping":
|
|
1044
|
+
case "add-table-mapping":
|
|
1045
|
+
writeResult = _writeService.AddTableMapping(objectName,
|
|
1046
|
+
S("mapName") ?? throw new ArgumentException("Missing: mapName"),
|
|
1047
|
+
S("mappingTable"),
|
|
1048
|
+
op.GetTypedParam<System.Collections.Generic.List<WriteMappingConnection>>("connections"));
|
|
1049
|
+
break;
|
|
1050
|
+
|
|
1051
|
+
case "removetablemapping":
|
|
1052
|
+
case "remove-table-mapping":
|
|
1053
|
+
writeResult = _writeService.RemoveTableMapping(objectName,
|
|
1054
|
+
S("mapName") ?? throw new ArgumentException("Missing: mapName"));
|
|
1055
|
+
break;
|
|
1056
|
+
|
|
966
1057
|
case "addrelation":
|
|
967
1058
|
case "add-relation":
|
|
968
1059
|
writeResult = _writeService.AddRelation(objectName,
|
|
@@ -998,7 +1089,8 @@ namespace D365MetadataBridge.Protocol
|
|
|
998
1089
|
case "add-field-to-field-group":
|
|
999
1090
|
writeResult = _writeService.AddFieldToFieldGroup(objectName,
|
|
1000
1091
|
S("fieldGroupName") ?? S("groupName") ?? throw new ArgumentException("Missing: fieldGroupName"),
|
|
1001
|
-
S("fieldName") ?? throw new ArgumentException("Missing: fieldName")
|
|
1092
|
+
S("fieldName") ?? throw new ArgumentException("Missing: fieldName"),
|
|
1093
|
+
B("extendBaseFieldGroup") ?? false);
|
|
1002
1094
|
break;
|
|
1003
1095
|
|
|
1004
1096
|
case "addenumvalue":
|