blob: b92e94eac9ef761797d324cdce09e10b5357db15 [file]
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
"""Transport fixture for list failure and recovery semantics."""
from __future__ import annotations
import asyncio
import json
import logging
from mcp.server.stdio import stdio_server
from mcp.types import GetPromptResult, Prompt, Resource, Tool
from doris_mcp_server import __version__
from doris_mcp_server.protocol import create_doris_mcp_server
from doris_mcp_server.tools.resources_manager import ResourceMetadataError
SENSITIVE_MARKER = "backend-sensitive-list-error-detail"
class SequentialResourcesManager:
def __init__(self) -> None:
self.calls = 0
async def list_resources(self) -> list[Resource]:
self.calls += 1
if self.calls == 1:
raise ResourceMetadataError(
SENSITIVE_MARKER,
error_code="DORIS_METADATA_BACKEND_ERROR",
status_code=502,
list_error_category="backend_unavailable",
)
if self.calls == 2:
raise ResourceMetadataError(
SENSITIVE_MARKER,
error_code="DORIS_METADATA_PERMISSION_DENIED",
status_code=403,
list_error_category="permission_denied",
)
return []
async def read_resource(self, uri: str) -> str:
return json.dumps({"uri": uri})
class SequentialToolsManager:
def __init__(self) -> None:
self.calls = 0
async def list_tools(self) -> list[Tool]:
self.calls += 1
if self.calls == 1:
raise RuntimeError(SENSITIVE_MARKER)
return []
async def call_tool(self, name: str, arguments: dict) -> str:
return json.dumps({"name": name, "arguments": arguments})
class SequentialPromptsManager:
def __init__(self) -> None:
self.calls = 0
async def list_prompts(self) -> list[Prompt]:
self.calls += 1
if self.calls == 1:
raise RuntimeError(SENSITIVE_MARKER)
return []
async def get_prompt(
self,
name: str,
arguments: dict,
) -> GetPromptResult:
raise AssertionError((name, arguments))
def create_list_error_semantics_server():
return create_doris_mcp_server(
resources_manager=SequentialResourcesManager(),
tools_manager=SequentialToolsManager(),
prompts_manager=SequentialPromptsManager(),
name="doris-mcp-list-error-semantics-test",
version=__version__,
logger=logging.getLogger(__name__),
)
async def main() -> None:
server = create_list_error_semantics_server()
async with stdio_server() as (read_stream, write_stream):
await server.run(
read_stream,
write_stream,
server.create_initialization_options(),
)
if __name__ == "__main__":
asyncio.run(main())