@startuml semantic-scholar-mcp-sequence-search
!theme plain

title Search Papers Sequence Diagram

actor User
participant "MCP Client" as Client
participant "FastMCP Server" as Server
participant "@mcp.tool search_papers" as SearchTool
participant "mcp_error_handler" as ErrorHandler
participant "SemanticScholarClient" as APIClient
participant "CircuitBreaker" as CB
participant "InMemoryCache" as Cache
participant "MetricsCollector" as Metrics
participant "Semantic Scholar API" as API
participant "StructuredLogger" as Logger

User -> Client: search papers "machine learning"
activate Client

Client -> Server: invoke tool\n"search_papers"
activate Server

Server -> SearchTool: @mcp.tool decorated\nsearch_papers(query="machine learning", limit=10)
activate SearchTool

SearchTool -> ErrorHandler: @mcp_error_handler wrapper
activate ErrorHandler
note right: Error handling decorator\napplied to tool

ErrorHandler -> Logger: log request start
activate Logger
Logger -> Metrics: record_request("search_papers")
activate Metrics

SearchTool -> APIClient: search_papers(search_query)
activate APIClient

APIClient -> Cache: get("search:machine learning:0:10")
activate Cache
Cache --> APIClient: None (cache miss)
deactivate Cache

note right of APIClient: Rate limiting handled\ninternally by client

APIClient -> CB: call(_execute_request)
activate CB

alt Circuit Breaker CLOSED
  CB -> APIClient: _execute_request()
  
  APIClient -> Logger: debug("Making request to /paper/search")
  activate Logger
  Logger --> APIClient: logged
  deactivate Logger
  
  APIClient -> API: GET /paper/search\n?query=machine learning\n&limit=10
  activate API
  
  alt Success Response
    API --> APIClient: 200 OK\n{data: [...], total: 1000}
    deactivate API
    
    CB -> CB: _on_success()
    note right: Reset failure count
    
    APIClient -> APIClient: Parse response\nCreate Paper objects
    
    APIClient -> Cache: set("search:machine learning:0:10",\n     response, ttl=300)
    activate Cache
    Cache --> APIClient: stored
    deactivate Cache
    
    APIClient -> Logger: info("Completed search_papers")
    activate Logger
    Logger --> APIClient: logged
    deactivate Logger
    
  else Rate Limited
    API --> APIClient: 429 Too Many Requests\nRetry-After: 60
    
    APIClient -> APIClient: raise RateLimitError
    
    CB -> CB: _on_failure()
    note right: Increment failure count
    
    APIClient -> APIClient: Retry with\nexponential backoff
    
  else Server Error
    API --> APIClient: 503 Service Unavailable
    
    APIClient -> APIClient: raise ServiceUnavailableError
    
    CB -> CB: _on_failure()
    note right: Check if threshold reached\nMay open circuit
    
  end
  
else Circuit Breaker OPEN
  CB -> APIClient: raise ServiceUnavailableError
  note right: Fast fail without\ncalling API
end

deactivate CB

APIClient --> SearchTool: PaginatedResponse[Paper]
deactivate APIClient

SearchTool -> SearchTool: Format response
note right: Convert to dict\nwith success flag

SearchTool -> Context: __exit__()
deactivate Context

SearchTool --> Server: {\n  "success": true,\n  "data": {\n    "papers": [...],\n    "total": 1000,\n    "has_more": true\n  }\n}
deactivate SearchTool

Server --> Client: Tool result
deactivate Server

Client --> User: Display results
deactivate Client

@enduml