Skip to content
This repository was archived by the owner on Jun 29, 2025. It is now read-only.

Commit 9246d7a

Browse files
committed
Filter: smart embedding of linked resources
1 parent b856292 commit 9246d7a

File tree

1 file changed

+135
-0
lines changed

1 file changed

+135
-0
lines changed

cmd/openapi-mcp/main.go

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,134 @@ import (
77
"regexp"
88
"strings"
99

10+
"github.com/getkin/kin-openapi/openapi3"
1011
"github.com/jedisct1/openapi-mcp/pkg/openapi2mcp"
1112
"gopkg.in/yaml.v3"
1213
)
1314

15+
// collectUsedSchemas traverses the OpenAPI document and collects all schema names that are referenced
16+
func collectUsedSchemas(doc *openapi3.T) map[string]bool {
17+
used := make(map[string]bool)
18+
19+
// Helper function to extract schema name from $ref
20+
extractSchemaName := func(ref string) string {
21+
if strings.HasPrefix(ref, "#/components/schemas/") {
22+
return strings.TrimPrefix(ref, "#/components/schemas/")
23+
}
24+
return ""
25+
}
26+
27+
// Helper function to recursively collect refs from a schema
28+
var collectRefsFromSchema func(*openapi3.SchemaRef)
29+
collectRefsFromSchema = func(schemaRef *openapi3.SchemaRef) {
30+
if schemaRef == nil {
31+
return
32+
}
33+
34+
// Check if this is a reference
35+
if schemaRef.Ref != "" {
36+
if name := extractSchemaName(schemaRef.Ref); name != "" {
37+
if !used[name] {
38+
used[name] = true
39+
// Recursively check the referenced schema
40+
if doc.Components != nil && doc.Components.Schemas != nil {
41+
if refSchema, exists := doc.Components.Schemas[name]; exists {
42+
collectRefsFromSchema(refSchema)
43+
}
44+
}
45+
}
46+
}
47+
return
48+
}
49+
50+
// Check the schema value itself
51+
if schemaRef.Value != nil {
52+
schema := schemaRef.Value
53+
54+
// Check properties
55+
for _, propRef := range schema.Properties {
56+
collectRefsFromSchema(propRef)
57+
}
58+
59+
// Check items (for arrays)
60+
if schema.Items != nil {
61+
collectRefsFromSchema(schema.Items)
62+
}
63+
64+
// Check additionalProperties
65+
if schema.AdditionalProperties.Schema != nil {
66+
collectRefsFromSchema(schema.AdditionalProperties.Schema)
67+
}
68+
69+
// Check allOf, anyOf, oneOf
70+
for _, ref := range schema.AllOf {
71+
collectRefsFromSchema(ref)
72+
}
73+
for _, ref := range schema.AnyOf {
74+
collectRefsFromSchema(ref)
75+
}
76+
for _, ref := range schema.OneOf {
77+
collectRefsFromSchema(ref)
78+
}
79+
80+
// Check not
81+
if schema.Not != nil {
82+
collectRefsFromSchema(schema.Not)
83+
}
84+
}
85+
}
86+
87+
// Traverse all paths and operations
88+
if doc.Paths != nil {
89+
for _, pathItem := range doc.Paths.Map() {
90+
// Check parameters at path level
91+
for _, paramRef := range pathItem.Parameters {
92+
if paramRef != nil && paramRef.Value != nil && paramRef.Value.Schema != nil {
93+
collectRefsFromSchema(paramRef.Value.Schema)
94+
}
95+
}
96+
97+
// Check each operation
98+
for _, op := range pathItem.Operations() {
99+
if op == nil {
100+
continue
101+
}
102+
103+
// Check parameters
104+
for _, paramRef := range op.Parameters {
105+
if paramRef != nil && paramRef.Value != nil && paramRef.Value.Schema != nil {
106+
collectRefsFromSchema(paramRef.Value.Schema)
107+
}
108+
}
109+
110+
// Check request body
111+
if op.RequestBody != nil && op.RequestBody.Value != nil {
112+
for _, mediaType := range op.RequestBody.Value.Content {
113+
if mediaType.Schema != nil {
114+
collectRefsFromSchema(mediaType.Schema)
115+
}
116+
}
117+
}
118+
119+
// Check responses
120+
if op.Responses != nil {
121+
for _, respRef := range op.Responses.Map() {
122+
if respRef != nil && respRef.Value != nil {
123+
for _, mediaType := range respRef.Value.Content {
124+
if mediaType.Schema != nil {
125+
collectRefsFromSchema(mediaType.Schema)
126+
}
127+
}
128+
}
129+
}
130+
}
131+
}
132+
}
133+
}
134+
135+
return used
136+
}
137+
14138
// main is the entrypoint for the openapi-mcp CLI.
15139
// It parses flags, loads the OpenAPI spec, and dispatches to the appropriate mode (server, doc, dry-run, etc).
16140
func main() {
@@ -264,6 +388,17 @@ func main() {
264388
}
265389
}
266390

391+
// Clean up unused components/schemas
392+
if doc.Components != nil && doc.Components.Schemas != nil {
393+
usedSchemas := collectUsedSchemas(doc)
394+
// Remove unused schemas
395+
for schemaName := range doc.Components.Schemas {
396+
if _, used := usedSchemas[schemaName]; !used {
397+
delete(doc.Components.Schemas, schemaName)
398+
}
399+
}
400+
}
401+
267402
// Output the filtered OpenAPI spec as a valid OpenAPI file using kin-openapi's marshaling
268403
ext := ""
269404
if dot := len(specPath) - 1 - len(specPath); dot >= 0 {

0 commit comments

Comments
 (0)