Files
玉澜 6d97bf7204 Merge upstream/main into feat/schema-on-main
Complete the registry-first Schema delivery invariants, bind the event command surface, and preserve the event subprocess contract from main.
2026-07-14 01:25:05 +08:00

154 lines
6.3 KiB
Go

// Copyright 2026 Alibaba Group
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package ir
import (
"strings"
)
type Catalog struct {
Products []CanonicalProduct `json:"products"`
}
type LifecycleInfo struct {
DeprecatedBy int `json:"deprecated_by,omitempty"`
DeprecationDate string `json:"deprecation_date,omitempty"`
MigrationURL string `json:"migration_url,omitempty"`
DeprecatedCandidate bool `json:"deprecated_candidate,omitempty"`
}
type ProductCLIMetadata struct {
Command string `json:"command,omitempty"`
Group string `json:"group,omitempty"`
Hidden bool `json:"hidden,omitempty"`
Skip bool `json:"skip,omitempty"`
Aliases []string `json:"aliases,omitempty"`
Prefixes []string `json:"prefixes,omitempty"`
}
type CLIFlagHint struct {
Shorthand string `json:"shorthand,omitempty"`
Alias string `json:"alias,omitempty"`
}
// FlagOverlay carries CLI-layer transformation metadata for a single
// MCP parameter: the flag alias the user types, the transform applied
// before dispatch, env-var fallback, default value, and whether the flag
// is hidden from help. Sourced from market.CLIToolOverride.Flags.
type FlagOverlay struct {
Alias string `json:"alias,omitempty"`
Transform string `json:"transform,omitempty"`
TransformArgs map[string]any `json:"transform_args,omitempty"`
EnvDefault string `json:"env_default,omitempty"`
Default string `json:"default,omitempty"`
Description string `json:"description,omitempty"`
Hidden bool `json:"hidden,omitempty"`
}
// ToolAnnotations mirrors MCP 2025+ tool annotations. All hints are
// nullable: absence means "unknown", not "false". Populate only when the
// source has a clear signal — don't guess.
type ToolAnnotations struct {
DestructiveHint *bool `json:"destructive_hint,omitempty"`
ReadOnlyHint *bool `json:"read_only_hint,omitempty"`
IdempotentHint *bool `json:"idempotent_hint,omitempty"`
OpenWorldHint *bool `json:"open_world_hint,omitempty"`
}
type CanonicalProduct struct {
ID string `json:"id"`
DisplayName string `json:"display_name"`
Description string `json:"description,omitempty"`
ServerKey string `json:"server_key"`
Endpoint string `json:"endpoint"`
SchemaURI string `json:"schema_uri,omitempty"`
NegotiatedProtocolVersion string `json:"negotiated_protocol_version,omitempty"`
Source string `json:"source,omitempty"`
Degraded bool `json:"degraded"`
Lifecycle *LifecycleInfo `json:"lifecycle,omitempty"`
CLI *ProductCLIMetadata `json:"cli,omitempty"`
Tools []ToolDescriptor `json:"tools"`
}
type ToolDescriptor struct {
RPCName string `json:"rpc_name"`
CLIName string `json:"cli_name,omitempty"`
Group string `json:"group,omitempty"`
Title string `json:"title,omitempty"`
Description string `json:"description,omitempty"`
InputSchema map[string]any `json:"input_schema,omitempty"`
OutputSchema map[string]any `json:"output_schema,omitempty"`
Sensitive bool `json:"sensitive"`
Auth *ToolAuthMetadata `json:"auth,omitempty"`
Annotations *ToolAnnotations `json:"annotations,omitempty"`
Hidden bool `json:"hidden,omitempty"`
FlagHints map[string]CLIFlagHint `json:"flag_hints,omitempty"`
FlagOverlay map[string]FlagOverlay `json:"flag_overlay,omitempty"`
SourceServerKey string `json:"source_server_key"`
CanonicalPath string `json:"canonical_path"`
}
type ToolAuthMetadata struct {
Version string `json:"version,omitempty"`
ProductCode string `json:"productCode,omitempty"`
Domain string `json:"domain,omitempty"`
ClientObservedScopes []string `json:"clientObservedScopes,omitempty"`
RequiredScopes []string `json:"requiredScopes,omitempty"`
RequiredPermissions []string `json:"requiredPermissions,omitempty"`
RecommendedScopes []string `json:"recommendedScopes,omitempty"`
ExcludedScopes []string `json:"excludedScopes,omitempty"`
GrantProductCodes []string `json:"grantProductCodes,omitempty"`
RiskHint string `json:"riskHint,omitempty"`
RiskAction string `json:"riskAction,omitempty"`
ConfirmationRequired bool `json:"confirmationRequired,omitempty"`
Identities []string `json:"identities,omitempty"`
Source string `json:"source,omitempty"`
AuthMetaVersion string `json:"authMetaVersion,omitempty"`
AuthMetaHash string `json:"authMetaHash,omitempty"`
}
func (c Catalog) FindProduct(id string) (CanonicalProduct, bool) {
for _, product := range c.Products {
if product.ID == id {
return product, true
}
}
return CanonicalProduct{}, false
}
func (c Catalog) FindTool(path string) (CanonicalProduct, ToolDescriptor, bool) {
productID, toolName, ok := strings.Cut(path, ".")
if !ok || productID == "" || toolName == "" {
return CanonicalProduct{}, ToolDescriptor{}, false
}
product, ok := c.FindProduct(productID)
if !ok {
return CanonicalProduct{}, ToolDescriptor{}, false
}
tool, ok := product.FindTool(toolName)
if !ok {
return CanonicalProduct{}, ToolDescriptor{}, false
}
return product, tool, true
}
func (p CanonicalProduct) FindTool(name string) (ToolDescriptor, bool) {
for _, tool := range p.Tools {
if tool.RPCName == name {
return tool, true
}
}
return ToolDescriptor{}, false
}