Commit e1c5cb0
committed
feat(mcp): add read-only OOXML structural tools (Phase 4)
Six new MCP tools, gated by the ENABLE_OOXML_TOOLS env var. tools/list
filters them out and tools/call returns method-not-found until the flag
is set, so api.ooxml.dev/mcp's existing surface (search_ecma_spec /
get_section / list_parts) is unaffected.
Tools:
ooxml_lookup_element qname (w:tbl, {ns}local, or bare) -> symbol info
ooxml_lookup_type qname -> complexType or simpleType symbol
ooxml_children element/type/group qname -> ordered child + group ref list
ooxml_attributes element/type qname -> attrs unfolded through inheritance
and attributeGroup refs
ooxml_enum simpleType qname -> enumeration values in declared order
ooxml_namespace_info uri -> profiles + symbol counts per profile
Query layer (apps/mcp-server/src/ooxml-queries.ts):
- parseQName accepts known OOXML prefixes (w/r/s/m/a/wp/pic/c/dgm/xsd),
Clark form, or bare local names (defaults to wml-main).
- lookupElement / lookupType / lookupSymbolByTypeRef walk
xsd_symbol_profiles for profile-scoped hits.
- getChildren walks the xsd_inheritance_edges chain via a recursive CTE
and unions self + base xsd_child_edges and xsd_group_edges (group refs)
in document order. Each entry carries its compositor kind and the type
that contributed it.
- getAttributes does the same and additionally recurses through
attributeGroup refs; each entry carries 'self' / 'inherited' /
'attributeGroup' provenance with the owning name.
- getEnums and getNamespaceInfo are direct profile-scoped lookups.
Tool dispatch (apps/mcp-server/src/ooxml-tools.ts):
- For element qnames passed to ooxml_children / ooxml_attributes the
handler looks up the element, follows type_ref to its complexType,
then reads from there (per the Phase 4 caveat in PLAN.md).
- ooxml_children also falls back to looking up groups by name so users
can call it on EG_PContent etc.
- Unknown qnames produce a 'Not found' card listing alternative formats
and the searched profile.
- Default profile is literal 'transitional' until Phase 6.
Response shape per PLAN.md: canonical symbol, namespace, type_ref where
relevant, source, and a behavior-notes placeholder hooked up to nothing
yet (Phase 5 fills it).
Tests: 15 query-layer tests against a fresh ingest of the existing
fixtures; passes alongside 21 ingest tests for a 36 / 0 total.
Worker bundle dry-runs at 263 KiB (67 KiB gzip).1 parent c742f43 commit e1c5cb0
6 files changed
Lines changed: 1125 additions & 8 deletions
File tree
- apps/mcp-server/src
- scripts/ingest-xsd
- tests/mcp-server
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
16 | 16 | | |
17 | 17 | | |
18 | 18 | | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
19 | 25 | | |
20 | 26 | | |
21 | 27 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
7 | 7 | | |
8 | 8 | | |
9 | 9 | | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
10 | 16 | | |
11 | 17 | | |
12 | 18 | | |
| |||
132 | 138 | | |
133 | 139 | | |
134 | 140 | | |
135 | | - | |
| 141 | + | |
| 142 | + | |
136 | 143 | | |
137 | 144 | | |
138 | 145 | | |
139 | | - | |
140 | | - | |
141 | | - | |
| 146 | + | |
142 | 147 | | |
143 | 148 | | |
144 | 149 | | |
| |||
162 | 167 | | |
163 | 168 | | |
164 | 169 | | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
165 | 189 | | |
166 | 190 | | |
167 | 191 | | |
| |||
374 | 398 | | |
375 | 399 | | |
376 | 400 | | |
377 | | - | |
| 401 | + | |
378 | 402 | | |
379 | 403 | | |
380 | 404 | | |
| |||
0 commit comments