From baa1802c84660794d47aafa9df178f7b595f74f2 Mon Sep 17 00:00:00 2001 From: RockChinQ Date: Sat, 31 Oct 2026 11:02:12 +0000 Subject: [PATCH] feat(api-tools): fix model and server uuid references, tighten mcp server exposure - Map model_uuid to model.embedding.list / model.rerank.list / model.llm.list based on operation_id prefix - Map server_uuid to mcp.server.list and clarify server_uuid vs server_name in OperationDoc descriptions - Restrict mcp.server.create and mcp.server.update to exposure='assistant' and risk='dangerous' - Add input parameter descriptions to PipelineRunInput and RoutePreviewInput Ref: LANG-229 Co-authored-by: multica-agent --- .../pkg/api/application/operation_docs.py | 16 +++++----- .../pkg/api/application/service_operations.py | 29 ++++++++++++++----- 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/src/langbot/pkg/api/application/operation_docs.py b/src/langbot/pkg/api/application/operation_docs.py index 3d734335a..b2f882070 100644 --- a/src/langbot/pkg/api/application/operation_docs.py +++ b/src/langbot/pkg/api/application/operation_docs.py @@ -486,14 +486,14 @@ OPERATION_DOCS: dict[str, OperationDoc] = { label={'zh_Hans': '创建MCP服务', 'en_US': 'Create MCP Server'}, summary='Configure and register a new MCP server connection.', description='Register a new MCP server in the workspace. Provide server_data with transport type, command/URL, and environment. Side effect: Instantiates MCP server client.', - risk='write', - exposure='all', + risk='dangerous', + exposure='assistant', ), 'mcp.server.delete': OperationDoc( domain='mcp', label={'zh_Hans': '删除MCP服务', 'en_US': 'Delete MCP Server'}, summary='Disconnect and delete an MCP server from the workspace.', - description='Remove an MCP server registration and terminate active subprocess or connection. Prerequisites: Call mcp.server.list to obtain server_name. Side effect: Deletes server registration.', + description='Remove an MCP server registration and terminate active subprocess or connection. Prerequisites: Call mcp.server.list to obtain server_uuid (note: list returns server objects with uuid; get, logs, runtime, and test use server_name). Side effect: Deletes server registration.', risk='dangerous', exposure='all', ), @@ -541,9 +541,9 @@ OPERATION_DOCS: dict[str, OperationDoc] = { domain='mcp', label={'zh_Hans': '更新MCP服务', 'en_US': 'Update MCP Server'}, summary='Update configuration and parameters of an MCP server.', - description='Modify connection parameters, environment variables, or transport settings of an MCP server. Prerequisites: Call mcp.server.list to obtain server_name. Side effect: Restarts MCP client.', - risk='write', - exposure='all', + description='Modify connection parameters, environment variables, or transport settings of an MCP server. Prerequisites: Call mcp.server.list to obtain server_uuid (note: list returns server objects with uuid; get, logs, runtime, and test use server_name). Side effect: Restarts MCP client.', + risk='dangerous', + exposure='assistant', ), 'model.embedding.create': OperationDoc( domain='model', @@ -1405,7 +1405,7 @@ OPERATION_DOCS: dict[str, OperationDoc] = { domain='tool', label={'zh_Hans': '工具详情', 'en_US': 'Get Tool'}, summary='Get parameter schema and description for a specific tool.', - description='Retrieve input schema, argument descriptions, and execution requirements for a tool. Prerequisites: Call tool.list to obtain tool_name and pipeline_uuid.', + description='Retrieve input schema, argument descriptions, and execution requirements for a tool. Prerequisites: Call tool.list to obtain tool_name (and optional pipeline_uuid from pipeline.list).', risk='read', exposure='all', ), @@ -1413,7 +1413,7 @@ OPERATION_DOCS: dict[str, OperationDoc] = { domain='tool', label={'zh_Hans': '工具列表', 'en_US': 'List Tools'}, summary='List all registered function tools available for execution.', - description='Retrieve all available executable function tools, including plugin actions, MCP tools, and skill functions. Optionally filter by pipeline_uuid.', + description='Retrieve all available executable function tools, including plugin actions, MCP tools, and skill functions. Optionally filter by pipeline_uuid (get it from pipeline.list).', risk='read', exposure='all', ), diff --git a/src/langbot/pkg/api/application/service_operations.py b/src/langbot/pkg/api/application/service_operations.py index e9c146ef1..9c04a1430 100644 --- a/src/langbot/pkg/api/application/service_operations.py +++ b/src/langbot/pkg/api/application/service_operations.py @@ -765,6 +765,7 @@ _LIST_OPS_BY_ENTITY = { 'agent': 'agent.list', 'model': 'model.llm.list', 'provider': 'provider.list', + 'server': 'mcp.server.list', 'kb': 'knowledge.base.list', 'knowledge_base': 'knowledge.base.list', 'adapter': 'adapter.list', @@ -791,6 +792,16 @@ def _field_description(name: str, operation_id: str) -> str | None: return 'ISO 8601 timestamp or Unix epoch representing the time boundary' if name in {'query', 'keyword', 'user_query'}: return 'Search query string used to filter results' + if name == 'model_uuid': + if operation_id.startswith('model.embedding.'): + list_op = 'model.embedding.list' + elif operation_id.startswith('model.rerank.'): + list_op = 'model.rerank.list' + else: + list_op = 'model.llm.list' + return f'UUID of the model; get it from {list_op}' + if name == 'server_uuid': + return 'UUID of the MCP server; get it from mcp.server.list' if name.endswith('_uuid'): entity = name[:-5] list_op = _LIST_OPS_BY_ENTITY.get(entity, f'{entity}.list') @@ -876,9 +887,11 @@ def operations() -> tuple[Operation, ...]: class PipelineRunInput(Input): - pipeline_uuid: str = Field(min_length=1) - text: str = Field(min_length=1, max_length=100_000) - timeout: float = Field(default=60.0, gt=0, le=300) + pipeline_uuid: str = Field(min_length=1, description='UUID of the pipeline; get it from pipeline.list') + text: str = Field( + min_length=1, max_length=100_000, description='Input message or query text to trigger the pipeline execution' + ) + timeout: float = Field(default=60.0, gt=0, le=300, description='Maximum execution time in seconds') async def _pipeline_run(ap, context, payload): @@ -933,11 +946,11 @@ async def _assistant(ap, context, payload, method): class RoutePreviewInput(Input): - bot_uuid: str = Field(min_length=1) - event_type: str = Field(min_length=1) - event_data: dict | None = None - event_context: dict | None = None - event_bindings: list[dict] | None = None + bot_uuid: str = Field(min_length=1, description='UUID of the bot; get it from bot.list') + event_type: str = Field(min_length=1, description='Event type name to simulate routing for') + event_data: dict | None = Field(default=None, description='Event payload data to simulate') + event_context: dict | None = Field(default=None, description='Event context metadata') + event_bindings: list[dict] | None = Field(default=None, description='Optional custom route bindings') async def _route_preview(ap, context, payload):