get_subject_persons
Retrieve a formatted list of staff and cast members linked to a specific subject on Bangumi TV using its subject ID. Ideal for quickly accessing key contributors in anime, manga, music, or game content.
Instructions
List persons (staff, cast) related to a subject.
Args:
subject_id: The ID of the subject.
Returns:
Formatted list of related persons or an error message.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| subject_id | Yes |
Input Schema (JSON Schema)
{
"properties": {
"subject_id": {
"title": "Subject Id",
"type": "integer"
}
},
"required": [
"subject_id"
],
"title": "get_subject_personsArguments",
"type": "object"
}
Implementation Reference
- main.py:599-649 (handler)The core handler function decorated with @mcp.tool(), which registers and implements the get_subject_persons tool. It makes an API request to fetch related persons for a subject, processes the response using PersonType enum for typing, formats the output as a string list, and handles errors.@mcp.tool() async def get_subject_persons(subject_id: int) -> str: """ List persons (staff, cast) related to a subject. Args: subject_id: The ID of the subject. Returns: Formatted list of related persons or an error message. """ response = await make_bangumi_request( method="GET", path=f"/v0/subjects/{subject_id}/persons" ) error_msg = handle_api_error_response(response) if error_msg: return error_msg # Expecting a list of persons if not isinstance(response, list): return f"Unexpected API response format for get_subject_persons: {response}" persons = response if not persons: return f"No persons found related to subject ID {subject_id}." formatted_results = [] for person in persons: name = person.get("name") person_id = person.get("id") relation = person.get("relation") # e.g., "导演", "动画制作", "声优" career = ", ".join( person.get("career", []) or [] ) # person.get('career') could be None or empty list eps = person.get("eps") # Participation in episodes/tracks for THIS subject # Safely get person type name if available and is valid enum value person_type_int = person.get("type") person_type_str = "Unknown Type" if person_type_int is not None: try: person_type_str = PersonType(person_type_int).name except ValueError: person_type_str = f"Unknown Type ({person_type_int})" formatted_results.append( f"Person ID: {person_id}, Name: {name}, Type: {person_type_str}, Relation (in subject): {relation}, Overall Career: {career}, Participating Episodes/Tracks: {eps}" ) return "Related Persons:\n" + "\n---\n".join(formatted_results)
- main.py:66-74 (schema)IntEnum defining PersonType used in the handler to categorize and label persons in the output (e.g., Individual, Corporation, Association). Serves as type definition/schema for output formatting.class PersonType(IntEnum): """ type of a person or company 1 = 个人, 2 = 公司, 3 = 组合 """ INDIVIDUAL = 1 CORPORATION = 2 ASSOCIATION = 3
- main.py:1361-1369 (helper)MCP prompt that references and utilizes the 'get_subject_persons' tool as part of fetching full subject information.def get_subject_full_info(subject_id: int) -> str: """ Get detailed information, related persons, characters, and relations for a subject. Args: subject_id: The ID of the subject to get information for. """ return f"Get the full details for subject ID {subject_id} using 'get_subject_details'. Also get related persons using 'get_subject_persons', related characters using 'get_subject_characters', and other related subjects using 'get_subject_relations'. Summarize the key information from all these tool outputs."
- main.py:105-169 (helper)Core helper function called by the handler to make authenticated HTTP requests to Bangumi API.async def make_bangumi_request( method: str, path: str, query_params: Optional[Dict[str, Any]] = None, json_body: Optional[Dict[str, Any]] = None, headers: Optional[Dict[str, str]] = None, ) -> Any: """Make a request to the Bangumi API with proper headers and error handling.""" request_headers = headers.copy() if headers else {} request_headers["User-Agent"] = USER_AGENT request_headers["Accept"] = "application/json" if BANGUMI_TOKEN: request_headers["Authorization"] = f"Bearer {BANGUMI_TOKEN}" url = f"{BANGUMI_API_BASE}{path}" async with httpx.AsyncClient() as client: try: print( f"DEBUG: Making {method} request to {url} with params={query_params}, json={json_body}" ) response = await client.request( method=method, url=url, params=query_params, json=json_body, headers=request_headers, timeout=30.0, ) response.raise_for_status() # Return the raw JSON response, let the calling tool handle its structure (dict or list) json_response = response.json() print( f"DEBUG: Received response (type: {type(json_response)}, keys/length: {list(json_response.keys()) if isinstance(json_response, dict) else len(json_response) if isinstance(json_response, list) else 'N/A'})" ) return json_response except httpx.HTTPStatusError as e: error_msg = ( f"HTTP error occurred: {e.response.status_code} - {e.response.text}" ) print(f"ERROR: {error_msg}") # Try to parse the error response body if it's JSON try: error_details = e.response.json() return { "error": error_msg, "status_code": e.response.status_code, "details": error_details, } except json.JSONDecodeError: return { "error": error_msg, "status_code": e.response.status_code, "details": e.response.text, } except httpx.RequestError as e: error_msg = f"An error occurred while requesting {e.request.url!r}: {e}" print(f"ERROR: {error_msg}") return {"error": error_msg} except Exception as e: error_msg = f"An unexpected error occurred: {e}" print(f"ERROR: {error_msg}") return {"error": error_msg}
- main.py:172-205 (helper)Helper function used by the handler to detect and format API errors into user-friendly strings.def handle_api_error_response(response: Any) -> Optional[str]: """ Checks if the API response indicates an error and returns a formatted error message. Handles both dictionary-based errors and returns from make_bangumi_request on failure. """ # Check for error structure returned by make_bangumi_request on HTTPStatusError or RequestError if isinstance(response, dict) and ( "error" in response or "status_code" in response ): # This is an error dictionary created by our helper status_code = response.get("status_code", "N/A") error_msg = response.get("error", "Unknown error during request.") details = response.get("details", "") return f"Bangumi API Request Error (Status {status_code}): {error_msg}. Details: {details}".strip() # Check for error structure returned by Bangumi API itself (often dictionaries) # Safely check if the response is a dictionary before accessing its keys if isinstance(response, dict): if "title" in response and "description" in response: # This looks like a common Bangumi error response structure error_title = response.get("title", "API Error") error_description = response.get("description", "No description provided.") # The API might return a status code in the body too, or rely on HTTP status return f"Bangumi API Error: {error_title}. {error_description}".strip() # Check if it's a dictionary but *not* empty and *doesn't* look like a success response from list endpoints # Check for specific error fields if structure varies # Add more checks here if other error dictionary formats are observed # Example: if "message" in response and "code" in response: return f"API Error {response['code']}: {response['message']}" pass # If it's a dictionary but doesn't match known error formats, assume it's a valid data response for now # If it's not a dictionary, or it's a dictionary that doesn't match known error formats, assume it's not an error return None