Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/openapi/paths/management/accessprofiles.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,7 @@ access-profiles-activate:
access-profiles-deactivate:
put:
operationId: deactivateAccessProfile
x-bifrost-destructive: true
x-mint:
metadata:
tag: Enterprise
Expand Down Expand Up @@ -393,6 +394,7 @@ access-profiles-clone:
access-profiles-propagate:
post:
operationId: propagateAccessProfile
x-bifrost-destructive: true
x-mint:
metadata:
tag: Enterprise
Expand Down
2 changes: 2 additions & 0 deletions docs/openapi/paths/management/governance.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,7 @@ virtual-keys-by-id:
virtual-keys-rotate-by-id:
post:
operationId: rotateVirtualKey
x-bifrost-destructive: true
x-mint:
content: |
**Required Permissions**
Expand Down Expand Up @@ -538,6 +539,7 @@ virtual-keys-budget-override:
virtual-keys-rotate:
post:
operationId: bulkRotateVirtualKeys
x-bifrost-destructive: true
x-mint:
content: |
**Required Permissions**
Expand Down
1 change: 1 addition & 0 deletions docs/openapi/paths/management/logging.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1370,6 +1370,7 @@ _ranking-parameters:
logs-recalculate-cost:
post:
operationId: recalculateLogCosts
x-bifrost-destructive: true
x-mint:
content: |
**Required Permissions**
Expand Down
2 changes: 2 additions & 0 deletions docs/openapi/paths/management/mcp.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,7 @@ client-initiate-verification:
client-reauthorize:
post:
operationId: reauthorizeMCPClient
x-bifrost-destructive: true
x-mint:
content: |
**Required Permissions**
Expand Down Expand Up @@ -710,6 +711,7 @@ client-reauthorize:
client-reregister:
post:
operationId: reregisterMCPClient
x-bifrost-destructive: true
summary: Reauthorize an MCP client against a newly registered OAuth client
description: |
Registers a replacement OAuth client (RFC 7591 Dynamic Client
Expand Down
1 change: 1 addition & 0 deletions docs/openapi/paths/management/routing.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,7 @@ complexity:
complexity-reset:
post:
operationId: resetComplexityAnalyzerConfig
x-bifrost-destructive: true
x-mint:
content: |
**Required Permissions**
Expand Down
1 change: 1 addition & 0 deletions docs/openapi/paths/management/vault.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
flush-cache:
post:
operationId: flushVaultCache
x-bifrost-destructive: true
x-mint:
metadata:
tag: Enterprise
Expand Down
1 change: 1 addition & 0 deletions docs/openapi/paths/management/webhooks.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ webhooks-by-id:
webhooks-rotate-secret:
post:
operationId: rotateWebhookEndpointSecret
x-bifrost-destructive: true
x-mint:
content: |
**Required Permissions**
Expand Down
16 changes: 16 additions & 0 deletions framework/openapimcp/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ func buildOperationV3(method, path string, op map[string]any, pathParams []Param
Description: strings.TrimSpace(asString(op["description"])),
Deprecated: asBool(op["deprecated"]),
Tags: asStringSlice(op["tags"]),
Extensions: operationExtensions(op),
}
if servers := parseServers(op["servers"], doc, opts); len(servers) > 0 {
operation.Servers = servers
Expand Down Expand Up @@ -272,6 +273,21 @@ func buildOperationV3(method, path string, op map[string]any, pathParams []Param
return operation
}

// operationExtensions returns an operation object's x-* keys (nil when it has
// none), so callers can act on vendor markers such as x-bifrost-destructive.
func operationExtensions(op map[string]any) map[string]any {
var ext map[string]any
for k, v := range op {
if strings.HasPrefix(k, "x-") {
if ext == nil {
ext = map[string]any{}
}
ext[k] = v
}
}
return ext
}

// resolveRequestBody resolves a request body and each of its media types on
// its own, so an alternative that cannot be resolved (an external $ref) is
// dropped rather than rejecting a body that offers a usable one. When every
Expand Down
23 changes: 23 additions & 0 deletions framework/openapimcp/parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -476,3 +476,26 @@ func TestParse_LiteralRefInInstanceDataIsNotAReference(t *testing.T) {
require.NoError(t, err)
assert.Empty(t, findOp(t, doc, "POST", "/s").Unsupported)
}

// Vendor extensions on an operation are kept, in both spec families, so a
// caller can act on markers such as x-bifrost-destructive.
func TestParse_OperationExtensions(t *testing.T) {
v3 := `{"openapi":"3.1.0","info":{"title":"t","version":"1"},"paths":{
"/a":{"post":{"operationId":"a","x-bifrost-destructive":true,"x-note":{"k":"v"},"responses":{"200":{"description":"ok"}}},
"get":{"operationId":"b","responses":{"200":{"description":"ok"}}}}}}`
doc, err := Parse([]byte(v3), ParseOptions{})
require.NoError(t, err)
byID := map[string]Operation{}
for _, op := range doc.Operations {
byID[op.ID] = op
}
assert.Equal(t, map[string]any{"x-bifrost-destructive": true, "x-note": map[string]any{"k": "v"}}, byID["a"].Extensions)
assert.Nil(t, byID["b"].Extensions)

v2 := `{"swagger":"2.0","info":{"title":"t","version":"1"},"host":"api.example","paths":{
"/a":{"delete":{"operationId":"a","x-bifrost-destructive":false,"responses":{"200":{"description":"ok"}}}}}}`
doc, err = Parse([]byte(v2), ParseOptions{})
require.NoError(t, err)
require.Len(t, doc.Operations, 1)
assert.Equal(t, map[string]any{"x-bifrost-destructive": false}, doc.Operations[0].Extensions)
}
1 change: 1 addition & 0 deletions framework/openapimcp/swagger2.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ func buildOperationV2(method, path string, op map[string]any, pathParamsRaw []an
Description: strings.TrimSpace(asString(op["description"])),
Deprecated: asBool(op["deprecated"]),
Tags: asStringSlice(op["tags"]),
Extensions: operationExtensions(op),
}
if _, has := op["security"]; has {
operation.HasSecurity = true
Expand Down
1 change: 1 addition & 0 deletions framework/openapimcp/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ type Operation struct {
HasSecurity bool // op declared its own security (even if empty)
Servers []string // op/path-level server override
Unsupported string // non-empty: reason the operation cannot become a tool
Extensions map[string]any // the operation object's x-* keys, as decoded
}

// Parameter is one path/query/header/cookie/querystring parameter.
Expand Down
Loading
Loading