d365fo-agent-developer 0.6.0__tar.gz → 0.6.2__tar.gz

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 (46) hide show
  1. {d365fo_agent_developer-0.6.0/src/d365fo_agent_developer.egg-info → d365fo_agent_developer-0.6.2}/PKG-INFO +19 -13
  2. {d365fo_agent_developer-0.6.0 → d365fo_agent_developer-0.6.2}/README.md +146 -140
  3. {d365fo_agent_developer-0.6.0 → d365fo_agent_developer-0.6.2}/pyproject.toml +59 -57
  4. {d365fo_agent_developer-0.6.0 → d365fo_agent_developer-0.6.2}/src/d365fo_agent/knowledge_fetch.py +70 -70
  5. {d365fo_agent_developer-0.6.0 → d365fo_agent_developer-0.6.2}/src/d365fo_agent/mcp_server.py +10 -4
  6. {d365fo_agent_developer-0.6.0 → d365fo_agent_developer-0.6.2/src/d365fo_agent_developer.egg-info}/PKG-INFO +19 -13
  7. {d365fo_agent_developer-0.6.0 → d365fo_agent_developer-0.6.2}/src/d365fo_agent_developer.egg-info/entry_points.txt +1 -0
  8. {d365fo_agent_developer-0.6.0 → d365fo_agent_developer-0.6.2}/tests/test_mcp_toolkit.py +1 -1
  9. {d365fo_agent_developer-0.6.0 → d365fo_agent_developer-0.6.2}/LICENSE +0 -0
  10. {d365fo_agent_developer-0.6.0 → d365fo_agent_developer-0.6.2}/setup.cfg +0 -0
  11. {d365fo_agent_developer-0.6.0 → d365fo_agent_developer-0.6.2}/src/d365fo_agent/__init__.py +0 -0
  12. {d365fo_agent_developer-0.6.0 → d365fo_agent_developer-0.6.2}/src/d365fo_agent/aot_relations.py +0 -0
  13. {d365fo_agent_developer-0.6.0 → d365fo_agent_developer-0.6.2}/src/d365fo_agent/build.py +0 -0
  14. {d365fo_agent_developer-0.6.0 → d365fo_agent_developer-0.6.2}/src/d365fo_agent/cli.py +0 -0
  15. {d365fo_agent_developer-0.6.0 → d365fo_agent_developer-0.6.2}/src/d365fo_agent/data/aot-type-profiles.json +0 -0
  16. {d365fo_agent_developer-0.6.0 → d365fo_agent_developer-0.6.2}/src/d365fo_agent/data/x++-methodology.md +0 -0
  17. {d365fo_agent_developer-0.6.0 → d365fo_agent_developer-0.6.2}/src/d365fo_agent/data/x++-rules.json +0 -0
  18. {d365fo_agent_developer-0.6.0 → d365fo_agent_developer-0.6.2}/src/d365fo_agent/entity_derive.py +0 -0
  19. {d365fo_agent_developer-0.6.0 → d365fo_agent_developer-0.6.2}/src/d365fo_agent/generator.py +0 -0
  20. {d365fo_agent_developer-0.6.0 → d365fo_agent_developer-0.6.2}/src/d365fo_agent/graph_query.py +0 -0
  21. {d365fo_agent_developer-0.6.0 → d365fo_agent_developer-0.6.2}/src/d365fo_agent/graphify_runner.py +0 -0
  22. {d365fo_agent_developer-0.6.0 → d365fo_agent_developer-0.6.2}/src/d365fo_agent/index_store.py +0 -0
  23. {d365fo_agent_developer-0.6.0 → d365fo_agent_developer-0.6.2}/src/d365fo_agent/indexer.py +0 -0
  24. {d365fo_agent_developer-0.6.0 → d365fo_agent_developer-0.6.2}/src/d365fo_agent/knowledge.py +0 -0
  25. {d365fo_agent_developer-0.6.0 → d365fo_agent_developer-0.6.2}/src/d365fo_agent/linter.py +0 -0
  26. {d365fo_agent_developer-0.6.0 → d365fo_agent_developer-0.6.2}/src/d365fo_agent/models.py +0 -0
  27. {d365fo_agent_developer-0.6.0 → d365fo_agent_developer-0.6.2}/src/d365fo_agent/packageslocal_export.py +0 -0
  28. {d365fo_agent_developer-0.6.0 → d365fo_agent_developer-0.6.2}/src/d365fo_agent/rules.py +0 -0
  29. {d365fo_agent_developer-0.6.0 → d365fo_agent_developer-0.6.2}/src/d365fo_agent/security_wiring.py +0 -0
  30. {d365fo_agent_developer-0.6.0 → d365fo_agent_developer-0.6.2}/src/d365fo_agent/specs.py +0 -0
  31. {d365fo_agent_developer-0.6.0 → d365fo_agent_developer-0.6.2}/src/d365fo_agent/sql_model.py +0 -0
  32. {d365fo_agent_developer-0.6.0 → d365fo_agent_developer-0.6.2}/src/d365fo_agent/type_profile.py +0 -0
  33. {d365fo_agent_developer-0.6.0 → d365fo_agent_developer-0.6.2}/src/d365fo_agent/validate.py +0 -0
  34. {d365fo_agent_developer-0.6.0 → d365fo_agent_developer-0.6.2}/src/d365fo_agent_developer.egg-info/SOURCES.txt +0 -0
  35. {d365fo_agent_developer-0.6.0 → d365fo_agent_developer-0.6.2}/src/d365fo_agent_developer.egg-info/dependency_links.txt +0 -0
  36. {d365fo_agent_developer-0.6.0 → d365fo_agent_developer-0.6.2}/src/d365fo_agent_developer.egg-info/requires.txt +0 -0
  37. {d365fo_agent_developer-0.6.0 → d365fo_agent_developer-0.6.2}/src/d365fo_agent_developer.egg-info/top_level.txt +0 -0
  38. {d365fo_agent_developer-0.6.0 → d365fo_agent_developer-0.6.2}/tests/test_aot_relations.py +0 -0
  39. {d365fo_agent_developer-0.6.0 → d365fo_agent_developer-0.6.2}/tests/test_build.py +0 -0
  40. {d365fo_agent_developer-0.6.0 → d365fo_agent_developer-0.6.2}/tests/test_catalog.py +0 -0
  41. {d365fo_agent_developer-0.6.0 → d365fo_agent_developer-0.6.2}/tests/test_cli.py +0 -0
  42. {d365fo_agent_developer-0.6.0 → d365fo_agent_developer-0.6.2}/tests/test_entity_derive.py +0 -0
  43. {d365fo_agent_developer-0.6.0 → d365fo_agent_developer-0.6.2}/tests/test_linter.py +0 -0
  44. {d365fo_agent_developer-0.6.0 → d365fo_agent_developer-0.6.2}/tests/test_security_wiring.py +0 -0
  45. {d365fo_agent_developer-0.6.0 → d365fo_agent_developer-0.6.2}/tests/test_spec_pipeline.py +0 -0
  46. {d365fo_agent_developer-0.6.0 → d365fo_agent_developer-0.6.2}/tests/test_sql_model.py +0 -0
@@ -1,12 +1,12 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: d365fo-agent-developer
3
- Version: 0.6.0
3
+ Version: 0.6.2
4
4
  Summary: Local D365 F&O knowledge toolkit: corpus indexing (SQLite FTS5), deterministic generation, and an MCP server that grounds coding agents (Claude Code, Codex) in real AOT facts.
5
5
  Author-email: David Bru <dbru@fiveforty.fr>
6
6
  License: MIT
7
- Project-URL: Homepage, https://github.com/dbru540/d365fo-agent
8
- Project-URL: Repository, https://github.com/dbru540/d365fo-agent
9
- Project-URL: Issues, https://github.com/dbru540/d365fo-agent/issues
7
+ Project-URL: Homepage, https://github.com/dbru540/d365fo-agent-developer
8
+ Project-URL: Repository, https://github.com/dbru540/d365fo-agent-developer
9
+ Project-URL: Issues, https://github.com/dbru540/d365fo-agent-developer/issues
10
10
  Keywords: dynamics-365,d365fo,x++,aot,mcp,model-context-protocol,claude,claude-code,codex,ai,code-generation,rag
11
11
  Classifier: Development Status :: 4 - Beta
12
12
  Classifier: Intended Audience :: Developers
@@ -29,7 +29,7 @@ Requires-Dist: ruff; extra == "dev"
29
29
  Requires-Dist: build; extra == "dev"
30
30
  Dynamic: license-file
31
31
 
32
- # d365fo-agent — D365 F&O X++ knowledge for Claude Code & Codex
32
+ # d365fo-agent-developer — D365 F&O X++ knowledge for Claude Code & Codex
33
33
 
34
34
  A local **MCP server** that gives an AI coding agent (Claude Code, Codex, any MCP host) a grounded
35
35
  **knowledge base of Dynamics 365 Finance & Operations X++** — so you can develop for D365 quickly
@@ -51,9 +51,14 @@ compiler.
51
51
  ```bash
52
52
  pip install d365fo-agent-developer
53
53
  # or, isolated: pipx install d365fo-agent-developer
54
+ # or zero-install, straight from PyPI at launch time: uvx d365fo-agent-developer
54
55
  ```
55
56
 
56
- This installs two commands: `d365fo-mcp` (the server) and `d365fo-agent` (the CLI).
57
+ With `uvx` you can even skip the install entirely point your MCP client at
58
+ `uvx` with args `["d365fo-agent-developer"]` (e.g. in Claude Desktop's
59
+ `claude_desktop_config.json`) and the latest published server runs on demand.
60
+
61
+ This installs two commands: `d365fo-agent-developer` (the MCP server; `d365fo-mcp` is a short alias) and `d365fo-agent` (the CLI).
57
62
 
58
63
  ## Get the knowledge base (once)
59
64
 
@@ -84,18 +89,18 @@ d365fo-agent build-index \
84
89
  ```json
85
90
  {
86
91
  "mcpServers": {
87
- "d365fo": { "command": "d365fo-mcp", "args": [] }
92
+ "d365fo-agent-developer": { "command": "d365fo-agent-developer", "args": [] }
88
93
  }
89
94
  }
90
95
  ```
91
96
 
92
- …or one command: `claude mcp add d365fo d365fo-mcp`
97
+ …or one command: `claude mcp add d365fo-agent-developer d365fo-agent-developer`
93
98
 
94
99
  **Codex** — add to `~/.codex/config.toml`:
95
100
 
96
101
  ```toml
97
- [mcp_servers.d365fo]
98
- command = "d365fo-mcp"
102
+ [mcp_servers.d365fo-agent-developer]
103
+ command = "d365fo-agent-developer"
99
104
  args = []
100
105
  ```
101
106
 
@@ -109,8 +114,8 @@ Point the server at your D365 source repo so your **custom** classes/tables/EDTs
109
114
  are indexed too, and so the rich tools can read real signatures and clone real examples:
110
115
 
111
116
  ```toml
112
- [mcp_servers.d365fo]
113
- command = "d365fo-mcp"
117
+ [mcp_servers.d365fo-agent-developer]
118
+ command = "d365fo-agent-developer"
114
119
  args = ["--repo-root", "C:/path/to/your/D365Repo",
115
120
  "--rules", "C:/path/to/your/rules.json",
116
121
  "--packages-root", "C:/AOSService/PackagesLocalDirectory"]
@@ -127,7 +132,8 @@ args = ["--repo-root", "C:/path/to/your/D365Repo",
127
132
  `element_exists`, `find_element`, `search_corpus`, `get_signature`, `get_extension_chain`,
128
133
  `get_security_links`, `get_entity_exposure`, `find_similar_examples`, `scaffold_object`,
129
134
  `find_references`, `find_reverse_references`, `analyze_spec`, `generate_from_spec`, `validate_xml`,
130
- `lint_artifact`, `derive_entity`, `wire_security`, `compile_model`, `get_methodology`, `index_stats`.
135
+ `lint_artifact`, `derive_entity`, `wire_security`, `compile_model`, `compile_generated`,
136
+ `get_sql_model`, `explore_functional_unit`, `find_relations`, `get_methodology`, `index_stats`.
131
137
 
132
138
  See [docs/mcp-server.md](docs/mcp-server.md) for the verify-driven workflow and
133
139
  [docs/x++-methodology.md](docs/x++-methodology.md) for the behavioural contract.
@@ -1,140 +1,146 @@
1
- # d365fo-agent — D365 F&O X++ knowledge for Claude Code & Codex
2
-
3
- A local **MCP server** that gives an AI coding agent (Claude Code, Codex, any MCP host) a grounded
4
- **knowledge base of Dynamics 365 Finance & Operations X++** — so you can develop for D365 quickly
5
- **without re-feeding a whole repo for analysis every time**.
6
-
7
- It grounds the agent in real AOT facts: it verifies that a class/table/EDT/enum/entity actually
8
- exists (anti-hallucination), searches the corpus, walks extension/security relationships, serves an
9
- X++ engineering methodology, validates generated XML against learned per-type structure, scaffolds
10
- or deterministically generates artifacts, and (on a Windows D365 host) compiles with the real X++
11
- compiler.
12
-
13
- - **Pure Python standard library** — zero runtime dependencies, runs anywhere Python 3.11+ runs.
14
- - **Vendor-neutral** — Claude Code, Codex, Gemini CLI, or any MCP-speaking client over stdio.
15
- - The standard D365 corpus is the same for everyone, so it is indexed **once** and used as a
16
- portable knowledge base; your own custom code is **optional**.
17
-
18
- ## Install
19
-
20
- ```bash
21
- pip install d365fo-agent-developer
22
- # or, isolated: pipx install d365fo-agent-developer
23
- ```
24
-
25
- This installs two commands: `d365fo-mcp` (the server) and `d365fo-agent` (the CLI).
26
-
27
- ## Get the knowledge base (once)
28
-
29
- Pick one. Both produce a local index at `~/.d365fo-agent/d365fo.db` that the server uses by default.
30
-
31
- **A. Download the prebuilt standard-D365 index** (fastest, no D365 install needed):
32
-
33
- ```bash
34
- d365fo-agent fetch-knowledge # downloads + caches the standard knowledge index
35
- ```
36
-
37
- **B. Build it from your own D365 dev box** (no download; uses metadata you already have):
38
-
39
- ```bash
40
- d365fo-agent build-index \
41
- --db ~/.d365fo-agent/d365fo.db \
42
- --packages-root "C:/AOSService/PackagesLocalDirectory" \
43
- --rebuild
44
- ```
45
-
46
- > The methodology, default lint rules, and a default learned type-profile ship **inside** the
47
- > package, so validation and guidance work out of the box even before the index is built.
48
-
49
- ## Wire it into your agent
50
-
51
- **Claude Code** add to `.mcp.json` (project) or `~/.claude.json` (global):
52
-
53
- ```json
54
- {
55
- "mcpServers": {
56
- "d365fo": { "command": "d365fo-mcp", "args": [] }
57
- }
58
- }
59
- ```
60
-
61
- …or one command: `claude mcp add d365fo d365fo-mcp`
62
-
63
- **Codex** — add to `~/.codex/config.toml`:
64
-
65
- ```toml
66
- [mcp_servers.d365fo]
67
- command = "d365fo-mcp"
68
- args = []
69
- ```
70
-
71
- With no `--db`, the server uses the cached knowledge index automatically. That's it — ask the agent
72
- to build something for D365 and it will verify elements, follow the methodology, and validate its
73
- output instead of guessing.
74
-
75
- ## Add your custom code (optional)
76
-
77
- Point the server at your D365 source repo so your **custom** classes/tables/EDTs/enums/extensions
78
- are indexed too, and so the rich tools can read real signatures and clone real examples:
79
-
80
- ```toml
81
- [mcp_servers.d365fo]
82
- command = "d365fo-mcp"
83
- args = ["--repo-root", "C:/path/to/your/D365Repo",
84
- "--rules", "C:/path/to/your/rules.json",
85
- "--packages-root", "C:/AOSService/PackagesLocalDirectory"]
86
- ```
87
-
88
- | Capability | Knowledge index only | + a PackagesLocalDirectory / repo |
89
- |---|---|---|
90
- | Verify an element exists, search, relations, methodology, validation, scaffolding by template | ✅ | ✅ |
91
- | Read a real signature, clone a real example (`get_signature`, `find_similar_examples`, `scaffold_object`) | needs source files | ✅ |
92
- | Compile with the real X++ compiler (`compile_model`) | — | ✅ (Windows D365 host) |
93
-
94
- ## What the agent gets (MCP tools)
95
-
96
- `element_exists`, `find_element`, `search_corpus`, `get_signature`, `get_extension_chain`,
97
- `get_security_links`, `get_entity_exposure`, `find_similar_examples`, `scaffold_object`,
98
- `find_references`, `find_reverse_references`, `analyze_spec`, `generate_from_spec`, `validate_xml`,
99
- `lint_artifact`, `derive_entity`, `wire_security`, `compile_model`, `get_methodology`, `index_stats`.
100
-
101
- See [docs/mcp-server.md](docs/mcp-server.md) for the verify-driven workflow and
102
- [docs/x++-methodology.md](docs/x++-methodology.md) for the behavioural contract.
103
-
104
- ## Maintainer: publish the knowledge index
105
-
106
- The wheel stays tiny; the ~100 MB standard index is distributed as a downloadable asset.
107
-
108
- ```bash
109
- # 1. Build a STANDARD-only index from a PackagesLocalDirectory (no custom repo)
110
- d365fo-agent build-index --db d365fo-standard.db --packages-root <PLD> --rebuild
111
- # 2. (optional) learn type profiles to ship as the default
112
- d365fo-agent build-type-profiles --db d365fo-standard.db --packages-root <PLD> \
113
- --out src/d365fo_agent/data/aot-type-profiles.json
114
- # 3. Compress and attach to a GitHub release
115
- python -c "import gzip,shutil; shutil.copyfileobj(open('d365fo-standard.db','rb'), gzip.open('d365fo-standard.db.gz','wb'))"
116
- # 4. Point users at it: set DEFAULT_KNOWLEDGE_URL in knowledge_fetch.py (or pass --url)
117
- ```
118
-
119
- > **Note:** the index holds factual AOT metadata (element names, types, packages, labels,
120
- > relations) — not Microsoft source. Confirm your redistribution position before publishing a
121
- > prebuilt standard index; option **B** above lets each user build their own with zero redistribution.
122
-
123
- To publish the package itself: `python -m build` then `python -m twine upload dist/*` (PyPI account
124
- required).
125
-
126
- ## Develop / contribute
127
-
128
- ```bash
129
- pip install -e ".[dev]"
130
- PYTHONPATH=src python -m unittest discover -s tests # full test suite
131
- ruff check src/d365fo_agent tests
132
- ```
133
-
134
- Docs: [Architecture](docs/architecture.md) · [MCP Server](docs/mcp-server.md) ·
135
- [X++ Methodology](docs/x++-methodology.md) · [Specification Contract](docs/specification-contract.md) ·
136
- [Metadata Schema](docs/metadata-schema.md) · [Tool Catalog](docs/tool-catalog.md)
137
-
138
- ## License
139
-
140
- MIT see [LICENSE](LICENSE).
1
+ # d365fo-agent-developer — D365 F&O X++ knowledge for Claude Code & Codex
2
+
3
+ A local **MCP server** that gives an AI coding agent (Claude Code, Codex, any MCP host) a grounded
4
+ **knowledge base of Dynamics 365 Finance & Operations X++** — so you can develop for D365 quickly
5
+ **without re-feeding a whole repo for analysis every time**.
6
+
7
+ It grounds the agent in real AOT facts: it verifies that a class/table/EDT/enum/entity actually
8
+ exists (anti-hallucination), searches the corpus, walks extension/security relationships, serves an
9
+ X++ engineering methodology, validates generated XML against learned per-type structure, scaffolds
10
+ or deterministically generates artifacts, and (on a Windows D365 host) compiles with the real X++
11
+ compiler.
12
+
13
+ - **Pure Python standard library** — zero runtime dependencies, runs anywhere Python 3.11+ runs.
14
+ - **Vendor-neutral** — Claude Code, Codex, Gemini CLI, or any MCP-speaking client over stdio.
15
+ - The standard D365 corpus is the same for everyone, so it is indexed **once** and used as a
16
+ portable knowledge base; your own custom code is **optional**.
17
+
18
+ ## Install
19
+
20
+ ```bash
21
+ pip install d365fo-agent-developer
22
+ # or, isolated: pipx install d365fo-agent-developer
23
+ # or zero-install, straight from PyPI at launch time: uvx d365fo-agent-developer
24
+ ```
25
+
26
+ With `uvx` you can even skip the install entirely — point your MCP client at
27
+ `uvx` with args `["d365fo-agent-developer"]` (e.g. in Claude Desktop's
28
+ `claude_desktop_config.json`) and the latest published server runs on demand.
29
+
30
+ This installs two commands: `d365fo-agent-developer` (the MCP server; `d365fo-mcp` is a short alias) and `d365fo-agent` (the CLI).
31
+
32
+ ## Get the knowledge base (once)
33
+
34
+ Pick one. Both produce a local index at `~/.d365fo-agent/d365fo.db` that the server uses by default.
35
+
36
+ **A. Download the prebuilt standard-D365 index** (fastest, no D365 install needed):
37
+
38
+ ```bash
39
+ d365fo-agent fetch-knowledge # downloads + caches the standard knowledge index
40
+ ```
41
+
42
+ **B. Build it from your own D365 dev box** (no download; uses metadata you already have):
43
+
44
+ ```bash
45
+ d365fo-agent build-index \
46
+ --db ~/.d365fo-agent/d365fo.db \
47
+ --packages-root "C:/AOSService/PackagesLocalDirectory" \
48
+ --rebuild
49
+ ```
50
+
51
+ > The methodology, default lint rules, and a default learned type-profile ship **inside** the
52
+ > package, so validation and guidance work out of the box even before the index is built.
53
+
54
+ ## Wire it into your agent
55
+
56
+ **Claude Code** add to `.mcp.json` (project) or `~/.claude.json` (global):
57
+
58
+ ```json
59
+ {
60
+ "mcpServers": {
61
+ "d365fo-agent-developer": { "command": "d365fo-agent-developer", "args": [] }
62
+ }
63
+ }
64
+ ```
65
+
66
+ …or one command: `claude mcp add d365fo-agent-developer d365fo-agent-developer`
67
+
68
+ **Codex** add to `~/.codex/config.toml`:
69
+
70
+ ```toml
71
+ [mcp_servers.d365fo-agent-developer]
72
+ command = "d365fo-agent-developer"
73
+ args = []
74
+ ```
75
+
76
+ With no `--db`, the server uses the cached knowledge index automatically. That's it — ask the agent
77
+ to build something for D365 and it will verify elements, follow the methodology, and validate its
78
+ output instead of guessing.
79
+
80
+ ## Add your custom code (optional)
81
+
82
+ Point the server at your D365 source repo so your **custom** classes/tables/EDTs/enums/extensions
83
+ are indexed too, and so the rich tools can read real signatures and clone real examples:
84
+
85
+ ```toml
86
+ [mcp_servers.d365fo-agent-developer]
87
+ command = "d365fo-agent-developer"
88
+ args = ["--repo-root", "C:/path/to/your/D365Repo",
89
+ "--rules", "C:/path/to/your/rules.json",
90
+ "--packages-root", "C:/AOSService/PackagesLocalDirectory"]
91
+ ```
92
+
93
+ | Capability | Knowledge index only | + a PackagesLocalDirectory / repo |
94
+ |---|---|---|
95
+ | Verify an element exists, search, relations, methodology, validation, scaffolding by template | ✅ | ✅ |
96
+ | Read a real signature, clone a real example (`get_signature`, `find_similar_examples`, `scaffold_object`) | needs source files | ✅ |
97
+ | Compile with the real X++ compiler (`compile_model`) | — | ✅ (Windows D365 host) |
98
+
99
+ ## What the agent gets (MCP tools)
100
+
101
+ `element_exists`, `find_element`, `search_corpus`, `get_signature`, `get_extension_chain`,
102
+ `get_security_links`, `get_entity_exposure`, `find_similar_examples`, `scaffold_object`,
103
+ `find_references`, `find_reverse_references`, `analyze_spec`, `generate_from_spec`, `validate_xml`,
104
+ `lint_artifact`, `derive_entity`, `wire_security`, `compile_model`, `compile_generated`,
105
+ `get_sql_model`, `explore_functional_unit`, `find_relations`, `get_methodology`, `index_stats`.
106
+
107
+ See [docs/mcp-server.md](docs/mcp-server.md) for the verify-driven workflow and
108
+ [docs/x++-methodology.md](docs/x++-methodology.md) for the behavioural contract.
109
+
110
+ ## Maintainer: publish the knowledge index
111
+
112
+ The wheel stays tiny; the ~100 MB standard index is distributed as a downloadable asset.
113
+
114
+ ```bash
115
+ # 1. Build a STANDARD-only index from a PackagesLocalDirectory (no custom repo)
116
+ d365fo-agent build-index --db d365fo-standard.db --packages-root <PLD> --rebuild
117
+ # 2. (optional) learn type profiles to ship as the default
118
+ d365fo-agent build-type-profiles --db d365fo-standard.db --packages-root <PLD> \
119
+ --out src/d365fo_agent/data/aot-type-profiles.json
120
+ # 3. Compress and attach to a GitHub release
121
+ python -c "import gzip,shutil; shutil.copyfileobj(open('d365fo-standard.db','rb'), gzip.open('d365fo-standard.db.gz','wb'))"
122
+ # 4. Point users at it: set DEFAULT_KNOWLEDGE_URL in knowledge_fetch.py (or pass --url)
123
+ ```
124
+
125
+ > **Note:** the index holds factual AOT metadata (element names, types, packages, labels,
126
+ > relations) not Microsoft source. Confirm your redistribution position before publishing a
127
+ > prebuilt standard index; option **B** above lets each user build their own with zero redistribution.
128
+
129
+ To publish the package itself: `python -m build` then `python -m twine upload dist/*` (PyPI account
130
+ required).
131
+
132
+ ## Develop / contribute
133
+
134
+ ```bash
135
+ pip install -e ".[dev]"
136
+ PYTHONPATH=src python -m unittest discover -s tests # full test suite
137
+ ruff check src/d365fo_agent tests
138
+ ```
139
+
140
+ Docs: [Architecture](docs/architecture.md) · [MCP Server](docs/mcp-server.md) ·
141
+ [X++ Methodology](docs/x++-methodology.md) · [Specification Contract](docs/specification-contract.md) ·
142
+ [Metadata Schema](docs/metadata-schema.md) · [Tool Catalog](docs/tool-catalog.md)
143
+
144
+ ## License
145
+
146
+ MIT — see [LICENSE](LICENSE).
@@ -1,57 +1,59 @@
1
- [build-system]
2
- requires = ["setuptools>=61"]
3
- build-backend = "setuptools.build_meta"
4
-
5
- [project]
6
- name = "d365fo-agent-developer"
7
- version = "0.6.0"
8
- description = "Local D365 F&O knowledge toolkit: corpus indexing (SQLite FTS5), deterministic generation, and an MCP server that grounds coding agents (Claude Code, Codex) in real AOT facts."
9
- readme = "README.md"
10
- requires-python = ">=3.11"
11
- license = { text = "MIT" }
12
- authors = [{ name = "David Bru", email = "dbru@fiveforty.fr" }]
13
- keywords = [
14
- "dynamics-365", "d365fo", "x++", "aot", "mcp", "model-context-protocol",
15
- "claude", "claude-code", "codex", "ai", "code-generation", "rag",
16
- ]
17
- classifiers = [
18
- "Development Status :: 4 - Beta",
19
- "Intended Audience :: Developers",
20
- "License :: OSI Approved :: MIT License",
21
- "Operating System :: OS Independent",
22
- "Programming Language :: Python :: 3",
23
- "Programming Language :: Python :: 3.11",
24
- "Programming Language :: Python :: 3.12",
25
- "Programming Language :: Python :: 3.13",
26
- "Topic :: Software Development :: Code Generators",
27
- "Topic :: Software Development :: Build Tools",
28
- ]
29
- # Standard library only — nothing to install at runtime, which keeps the MCP server portable.
30
- dependencies = []
31
-
32
- [project.urls]
33
- Homepage = "https://github.com/dbru540/d365fo-agent"
34
- Repository = "https://github.com/dbru540/d365fo-agent"
35
- Issues = "https://github.com/dbru540/d365fo-agent/issues"
36
-
37
- [project.optional-dependencies]
38
- # The graph-building engine is the ONLY external dependency, and only the
39
- # `run-graphify-staging` command needs it. Everything else (indexing, generation,
40
- # MCP server, validation) is Python standard library only.
41
- graph = ["graphify"]
42
- dev = ["pytest", "ruff", "build"]
43
-
44
- [project.scripts]
45
- d365fo-agent = "d365fo_agent.cli:main"
46
- d365fo-mcp = "d365fo_agent.mcp_server:main"
47
-
48
- [tool.setuptools]
49
- package-dir = { "" = "src" }
50
-
51
- [tool.setuptools.packages.find]
52
- where = ["src"]
53
-
54
- [tool.setuptools.package-data]
55
- # Methodology, default lint rules, and a default learned type-profile ship inside the package so
56
- # the server works after a plain `pip install` (no source tree needed).
57
- d365fo_agent = ["data/*"]
1
+ [build-system]
2
+ requires = ["setuptools>=61"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "d365fo-agent-developer"
7
+ version = "0.6.2"
8
+ description = "Local D365 F&O knowledge toolkit: corpus indexing (SQLite FTS5), deterministic generation, and an MCP server that grounds coding agents (Claude Code, Codex) in real AOT facts."
9
+ readme = "README.md"
10
+ requires-python = ">=3.11"
11
+ license = { text = "MIT" }
12
+ authors = [{ name = "David Bru", email = "dbru@fiveforty.fr" }]
13
+ keywords = [
14
+ "dynamics-365", "d365fo", "x++", "aot", "mcp", "model-context-protocol",
15
+ "claude", "claude-code", "codex", "ai", "code-generation", "rag",
16
+ ]
17
+ classifiers = [
18
+ "Development Status :: 4 - Beta",
19
+ "Intended Audience :: Developers",
20
+ "License :: OSI Approved :: MIT License",
21
+ "Operating System :: OS Independent",
22
+ "Programming Language :: Python :: 3",
23
+ "Programming Language :: Python :: 3.11",
24
+ "Programming Language :: Python :: 3.12",
25
+ "Programming Language :: Python :: 3.13",
26
+ "Topic :: Software Development :: Code Generators",
27
+ "Topic :: Software Development :: Build Tools",
28
+ ]
29
+ # Standard library only — nothing to install at runtime, which keeps the MCP server portable.
30
+ dependencies = []
31
+
32
+ [project.urls]
33
+ Homepage = "https://github.com/dbru540/d365fo-agent-developer"
34
+ Repository = "https://github.com/dbru540/d365fo-agent-developer"
35
+ Issues = "https://github.com/dbru540/d365fo-agent-developer/issues"
36
+
37
+ [project.optional-dependencies]
38
+ # The graph-building engine is the ONLY external dependency, and only the
39
+ # `run-graphify-staging` command needs it. Everything else (indexing, generation,
40
+ # MCP server, validation) is Python standard library only.
41
+ graph = ["graphify"]
42
+ dev = ["pytest", "ruff", "build"]
43
+
44
+ [project.scripts]
45
+ d365fo-agent = "d365fo_agent.cli:main"
46
+ d365fo-agent-developer = "d365fo_agent.mcp_server:main"
47
+ # Kept as a short alias of d365fo-agent-developer.
48
+ d365fo-mcp = "d365fo_agent.mcp_server:main"
49
+
50
+ [tool.setuptools]
51
+ package-dir = { "" = "src" }
52
+
53
+ [tool.setuptools.packages.find]
54
+ where = ["src"]
55
+
56
+ [tool.setuptools.package-data]
57
+ # Methodology, default lint rules, and a default learned type-profile ship inside the package so
58
+ # the server works after a plain `pip install` (no source tree needed).
59
+ d365fo_agent = ["data/*"]
@@ -1,70 +1,70 @@
1
- """Download a prebuilt standard-D365 knowledge index into the local cache.
2
-
3
- This is what lets the MCP server help with X++ development WITHOUT the user re-indexing a full
4
- repo every time: the standard D365 corpus is the same for everyone, so it is indexed once and
5
- published as a release asset. ``fetch-knowledge`` downloads it to ``~/.d365fo-agent/d365fo.db``
6
- (a ``.gz`` asset is decompressed on the fly). The user's own custom code stays optional
7
- (``--repo-root``). Standard-library only (``urllib`` + ``gzip``).
8
- """
9
-
10
- from __future__ import annotations
11
-
12
- import gzip
13
- import shutil
14
- import urllib.request
15
- from pathlib import Path
16
-
17
- # Published location of the standard-D365 knowledge index (a SQLite .db or .db.gz). The asset is
18
- # decoupled from the code version (tag `knowledge-v1`) so wheel releases don't re-upload 100 MB.
19
- # Override with --url, or build your own from a PLD when the asset is unavailable.
20
- DEFAULT_KNOWLEDGE_URL = (
21
- "https://github.com/dbru540/d365fo-agent/releases/download/knowledge-v1/d365fo-standard.db.gz"
22
- )
23
-
24
-
25
- def _is_gzip(path: Path) -> bool:
26
- with open(path, "rb") as handle:
27
- return handle.read(2) == b"\x1f\x8b"
28
-
29
-
30
- def fetch_knowledge(
31
- url: str | None = None,
32
- dest: str | Path | None = None,
33
- *,
34
- force: bool = False,
35
- opener=urllib.request.urlopen,
36
- ) -> dict[str, object]:
37
- """Download the knowledge index to ``dest`` (default: the local cache). Returns a result dict.
38
-
39
- ``opener`` is injectable for testing. Only http(s) URLs are accepted.
40
- """
41
- from d365fo_agent.mcp_server import default_knowledge_db
42
-
43
- dest = Path(dest) if dest else default_knowledge_db()
44
- url = url or DEFAULT_KNOWLEDGE_URL
45
- if not url:
46
- return {
47
- "ok": False,
48
- "error": "No knowledge URL configured. Pass --url <release asset .db/.db.gz>, or build "
49
- "your own with: d365fo-agent build-index --db <out.db> --packages-root <your "
50
- "D365 PackagesLocalDirectory> --rebuild",
51
- }
52
- if not (url.startswith("http://") or url.startswith("https://")):
53
- return {"ok": False, "error": f"Refusing non-http(s) URL: {url}"}
54
- if dest.exists() and not force:
55
- return {"ok": True, "skipped": True, "dest": str(dest),
56
- "note": "knowledge index already present (use --force to re-download)"}
57
-
58
- dest.parent.mkdir(parents=True, exist_ok=True)
59
- tmp = dest.with_name(dest.name + ".part")
60
- with opener(url) as response, open(tmp, "wb") as out: # noqa: S310 - scheme checked above
61
- shutil.copyfileobj(response, out)
62
-
63
- if url.endswith(".gz") or _is_gzip(tmp):
64
- with gzip.open(tmp, "rb") as gz, open(dest, "wb") as out:
65
- shutil.copyfileobj(gz, out)
66
- tmp.unlink()
67
- else:
68
- tmp.replace(dest)
69
-
70
- return {"ok": True, "dest": str(dest), "bytes": dest.stat().st_size, "source": url}
1
+ """Download a prebuilt standard-D365 knowledge index into the local cache.
2
+
3
+ This is what lets the MCP server help with X++ development WITHOUT the user re-indexing a full
4
+ repo every time: the standard D365 corpus is the same for everyone, so it is indexed once and
5
+ published as a release asset. ``fetch-knowledge`` downloads it to ``~/.d365fo-agent/d365fo.db``
6
+ (a ``.gz`` asset is decompressed on the fly). The user's own custom code stays optional
7
+ (``--repo-root``). Standard-library only (``urllib`` + ``gzip``).
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import gzip
13
+ import shutil
14
+ import urllib.request
15
+ from pathlib import Path
16
+
17
+ # Published location of the standard-D365 knowledge index (a SQLite .db or .db.gz). The asset is
18
+ # decoupled from the code version (tag `knowledge-v1`) so wheel releases don't re-upload 100 MB.
19
+ # Override with --url, or build your own from a PLD when the asset is unavailable.
20
+ DEFAULT_KNOWLEDGE_URL = (
21
+ "https://github.com/dbru540/d365fo-agent-developer/releases/download/knowledge-v1/d365fo-standard.db.gz"
22
+ )
23
+
24
+
25
+ def _is_gzip(path: Path) -> bool:
26
+ with open(path, "rb") as handle:
27
+ return handle.read(2) == b"\x1f\x8b"
28
+
29
+
30
+ def fetch_knowledge(
31
+ url: str | None = None,
32
+ dest: str | Path | None = None,
33
+ *,
34
+ force: bool = False,
35
+ opener=urllib.request.urlopen,
36
+ ) -> dict[str, object]:
37
+ """Download the knowledge index to ``dest`` (default: the local cache). Returns a result dict.
38
+
39
+ ``opener`` is injectable for testing. Only http(s) URLs are accepted.
40
+ """
41
+ from d365fo_agent.mcp_server import default_knowledge_db
42
+
43
+ dest = Path(dest) if dest else default_knowledge_db()
44
+ url = url or DEFAULT_KNOWLEDGE_URL
45
+ if not url:
46
+ return {
47
+ "ok": False,
48
+ "error": "No knowledge URL configured. Pass --url <release asset .db/.db.gz>, or build "
49
+ "your own with: d365fo-agent build-index --db <out.db> --packages-root <your "
50
+ "D365 PackagesLocalDirectory> --rebuild",
51
+ }
52
+ if not (url.startswith("http://") or url.startswith("https://")):
53
+ return {"ok": False, "error": f"Refusing non-http(s) URL: {url}"}
54
+ if dest.exists() and not force:
55
+ return {"ok": True, "skipped": True, "dest": str(dest),
56
+ "note": "knowledge index already present (use --force to re-download)"}
57
+
58
+ dest.parent.mkdir(parents=True, exist_ok=True)
59
+ tmp = dest.with_name(dest.name + ".part")
60
+ with opener(url) as response, open(tmp, "wb") as out: # noqa: S310 - scheme checked above
61
+ shutil.copyfileobj(response, out)
62
+
63
+ if url.endswith(".gz") or _is_gzip(tmp):
64
+ with gzip.open(tmp, "rb") as gz, open(dest, "wb") as out:
65
+ shutil.copyfileobj(gz, out)
66
+ tmp.unlink()
67
+ else:
68
+ tmp.replace(dest)
69
+
70
+ return {"ok": True, "dest": str(dest), "bytes": dest.stat().st_size, "source": url}
@@ -36,13 +36,18 @@ from d365fo_agent.index_store import D365Index
36
36
  from d365fo_agent.validate import validate_xml
37
37
 
38
38
  PROTOCOL_VERSION = "2025-06-18"
39
- SERVER_NAME = "d365fo-agent"
40
- SERVER_VERSION = "0.2.0"
39
+ SERVER_NAME = "d365fo-agent-developer"
40
+ try:
41
+ from importlib.metadata import version as _dist_version
42
+
43
+ SERVER_VERSION = _dist_version("d365fo-agent-developer")
44
+ except Exception: # source tree / not installed
45
+ SERVER_VERSION = "0.0.0-dev"
41
46
 
42
47
 
43
48
  def _log(message: str) -> None:
44
49
  # stdout is the JSON-RPC channel; diagnostics MUST go to stderr.
45
- print(f"[d365fo-mcp] {message}", file=sys.stderr, flush=True)
50
+ print(f"[{SERVER_NAME}] {message}", file=sys.stderr, flush=True)
46
51
 
47
52
 
48
53
  class D365MCPServer:
@@ -799,7 +804,8 @@ def build_server_from_config(
799
804
 
800
805
 
801
806
  def main(argv: list[str] | None = None) -> int:
802
- parser = argparse.ArgumentParser(prog="d365fo-mcp", description="D365 F&O knowledge MCP server (stdio).")
807
+ parser = argparse.ArgumentParser(prog="d365fo-agent-developer",
808
+ description="D365 F&O knowledge MCP server (stdio).")
803
809
  parser.add_argument("--repo-root", default=os.environ.get("D365FO_REPO_ROOT"))
804
810
  parser.add_argument("--rules", default=os.environ.get("D365FO_RULES"))
805
811
  parser.add_argument("--db", default=os.environ.get("D365FO_DB"))
@@ -1,12 +1,12 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: d365fo-agent-developer
3
- Version: 0.6.0
3
+ Version: 0.6.2
4
4
  Summary: Local D365 F&O knowledge toolkit: corpus indexing (SQLite FTS5), deterministic generation, and an MCP server that grounds coding agents (Claude Code, Codex) in real AOT facts.
5
5
  Author-email: David Bru <dbru@fiveforty.fr>
6
6
  License: MIT
7
- Project-URL: Homepage, https://github.com/dbru540/d365fo-agent
8
- Project-URL: Repository, https://github.com/dbru540/d365fo-agent
9
- Project-URL: Issues, https://github.com/dbru540/d365fo-agent/issues
7
+ Project-URL: Homepage, https://github.com/dbru540/d365fo-agent-developer
8
+ Project-URL: Repository, https://github.com/dbru540/d365fo-agent-developer
9
+ Project-URL: Issues, https://github.com/dbru540/d365fo-agent-developer/issues
10
10
  Keywords: dynamics-365,d365fo,x++,aot,mcp,model-context-protocol,claude,claude-code,codex,ai,code-generation,rag
11
11
  Classifier: Development Status :: 4 - Beta
12
12
  Classifier: Intended Audience :: Developers
@@ -29,7 +29,7 @@ Requires-Dist: ruff; extra == "dev"
29
29
  Requires-Dist: build; extra == "dev"
30
30
  Dynamic: license-file
31
31
 
32
- # d365fo-agent — D365 F&O X++ knowledge for Claude Code & Codex
32
+ # d365fo-agent-developer — D365 F&O X++ knowledge for Claude Code & Codex
33
33
 
34
34
  A local **MCP server** that gives an AI coding agent (Claude Code, Codex, any MCP host) a grounded
35
35
  **knowledge base of Dynamics 365 Finance & Operations X++** — so you can develop for D365 quickly
@@ -51,9 +51,14 @@ compiler.
51
51
  ```bash
52
52
  pip install d365fo-agent-developer
53
53
  # or, isolated: pipx install d365fo-agent-developer
54
+ # or zero-install, straight from PyPI at launch time: uvx d365fo-agent-developer
54
55
  ```
55
56
 
56
- This installs two commands: `d365fo-mcp` (the server) and `d365fo-agent` (the CLI).
57
+ With `uvx` you can even skip the install entirely point your MCP client at
58
+ `uvx` with args `["d365fo-agent-developer"]` (e.g. in Claude Desktop's
59
+ `claude_desktop_config.json`) and the latest published server runs on demand.
60
+
61
+ This installs two commands: `d365fo-agent-developer` (the MCP server; `d365fo-mcp` is a short alias) and `d365fo-agent` (the CLI).
57
62
 
58
63
  ## Get the knowledge base (once)
59
64
 
@@ -84,18 +89,18 @@ d365fo-agent build-index \
84
89
  ```json
85
90
  {
86
91
  "mcpServers": {
87
- "d365fo": { "command": "d365fo-mcp", "args": [] }
92
+ "d365fo-agent-developer": { "command": "d365fo-agent-developer", "args": [] }
88
93
  }
89
94
  }
90
95
  ```
91
96
 
92
- …or one command: `claude mcp add d365fo d365fo-mcp`
97
+ …or one command: `claude mcp add d365fo-agent-developer d365fo-agent-developer`
93
98
 
94
99
  **Codex** — add to `~/.codex/config.toml`:
95
100
 
96
101
  ```toml
97
- [mcp_servers.d365fo]
98
- command = "d365fo-mcp"
102
+ [mcp_servers.d365fo-agent-developer]
103
+ command = "d365fo-agent-developer"
99
104
  args = []
100
105
  ```
101
106
 
@@ -109,8 +114,8 @@ Point the server at your D365 source repo so your **custom** classes/tables/EDTs
109
114
  are indexed too, and so the rich tools can read real signatures and clone real examples:
110
115
 
111
116
  ```toml
112
- [mcp_servers.d365fo]
113
- command = "d365fo-mcp"
117
+ [mcp_servers.d365fo-agent-developer]
118
+ command = "d365fo-agent-developer"
114
119
  args = ["--repo-root", "C:/path/to/your/D365Repo",
115
120
  "--rules", "C:/path/to/your/rules.json",
116
121
  "--packages-root", "C:/AOSService/PackagesLocalDirectory"]
@@ -127,7 +132,8 @@ args = ["--repo-root", "C:/path/to/your/D365Repo",
127
132
  `element_exists`, `find_element`, `search_corpus`, `get_signature`, `get_extension_chain`,
128
133
  `get_security_links`, `get_entity_exposure`, `find_similar_examples`, `scaffold_object`,
129
134
  `find_references`, `find_reverse_references`, `analyze_spec`, `generate_from_spec`, `validate_xml`,
130
- `lint_artifact`, `derive_entity`, `wire_security`, `compile_model`, `get_methodology`, `index_stats`.
135
+ `lint_artifact`, `derive_entity`, `wire_security`, `compile_model`, `compile_generated`,
136
+ `get_sql_model`, `explore_functional_unit`, `find_relations`, `get_methodology`, `index_stats`.
131
137
 
132
138
  See [docs/mcp-server.md](docs/mcp-server.md) for the verify-driven workflow and
133
139
  [docs/x++-methodology.md](docs/x++-methodology.md) for the behavioural contract.
@@ -1,3 +1,4 @@
1
1
  [console_scripts]
2
2
  d365fo-agent = d365fo_agent.cli:main
3
+ d365fo-agent-developer = d365fo_agent.mcp_server:main
3
4
  d365fo-mcp = d365fo_agent.mcp_server:main
@@ -463,7 +463,7 @@ class McpServerTests(unittest.TestCase):
463
463
 
464
464
  def test_initialize(self) -> None:
465
465
  resp = self._rpc("initialize", {"protocolVersion": "2025-06-18", "capabilities": {}})
466
- self.assertEqual(resp["result"]["serverInfo"]["name"], "d365fo-agent")
466
+ self.assertEqual(resp["result"]["serverInfo"]["name"], "d365fo-agent-developer")
467
467
  self.assertIn("tools", resp["result"]["capabilities"])
468
468
 
469
469
  def test_tools_list_nonempty(self) -> None: