93 lines
2.9 KiB
Python
93 lines
2.9 KiB
Python
"""外部系统 provider 注册表。
|
|
|
|
标准 OpenAPI 与 Streamable HTTP MCP 系统均通过数据库配置接入。
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
from typing import Any
|
|
|
|
from .auth import ExternalAuthError, get_auth_strategy
|
|
|
|
@dataclass(frozen=True)
|
|
class ProviderSpec:
|
|
provider: str
|
|
title: str
|
|
connector: str
|
|
default_auth_type: str
|
|
allowed_auth_types: tuple[str, ...]
|
|
defaults: dict[str, Any]
|
|
|
|
|
|
_PROVIDERS = {
|
|
"generic_openapi": ProviderSpec(
|
|
provider="generic_openapi",
|
|
title="通用 OpenAPI 系统",
|
|
connector="openapi",
|
|
default_auth_type="password_jwt",
|
|
allowed_auth_types=("password_jwt", "api_key", "bearer_token"),
|
|
defaults={
|
|
"login_path": "/api/auth/token/",
|
|
"username_field": "username",
|
|
"password_field": "password",
|
|
"token_field": "access",
|
|
"auth_header_name": "Authorization",
|
|
"auth_header_template": "Bearer {token}",
|
|
"query_guidance": "",
|
|
"recommended_operation_ids": [],
|
|
"operation_mode": "query",
|
|
"operation_policies": {},
|
|
},
|
|
),
|
|
"generic_mcp": ProviderSpec(
|
|
provider="generic_mcp",
|
|
title="通用 MCP 系统",
|
|
connector="mcp",
|
|
default_auth_type="password_jwt",
|
|
allowed_auth_types=("password_jwt", "api_key", "bearer_token"),
|
|
defaults={
|
|
"login_path": "/api/auth/token/",
|
|
"username_field": "username",
|
|
"password_field": "password",
|
|
"token_field": "access",
|
|
"auth_header_name": "Authorization",
|
|
"auth_header_template": "Bearer {token}",
|
|
"query_guidance": "",
|
|
"recommended_operation_ids": [],
|
|
"operation_mode": "upstream_managed",
|
|
"operation_policies": {},
|
|
},
|
|
),
|
|
}
|
|
|
|
|
|
def get_provider(provider: str) -> ProviderSpec:
|
|
result = _PROVIDERS.get((provider or "").strip())
|
|
if result is None:
|
|
raise ValueError(f"不支持的外部系统 provider: {provider}")
|
|
return result
|
|
|
|
|
|
def provider_specs() -> tuple[ProviderSpec, ...]:
|
|
return tuple(_PROVIDERS.values())
|
|
|
|
|
|
def merged_config(provider: str, config: dict[str, Any]) -> dict[str, Any]:
|
|
spec = get_provider(provider)
|
|
result = {**spec.defaults, **(config or {})}
|
|
auth_type = str(result.get("auth_type") or spec.default_auth_type).strip()
|
|
if auth_type not in spec.allowed_auth_types:
|
|
raise ValueError(f"{spec.title} 不支持认证方式 {auth_type}")
|
|
result["auth_type"] = auth_type
|
|
return result
|
|
|
|
|
|
def credential_fields(provider: str, config: dict[str, Any]) -> list[dict[str, Any]]:
|
|
merged = merged_config(provider, config)
|
|
try:
|
|
strategy = get_auth_strategy(merged["auth_type"])
|
|
except ExternalAuthError as exc:
|
|
raise ValueError(str(exc)) from exc
|
|
return [field.as_dict() for field in strategy.credential_fields]
|