Search_petitions_balanced
Search USPTO final petition decisions with advanced filters for detailed analysis, cross-referencing with PFW/PTAB data, and examining petition types, art units, and legal context.
Instructions
Balanced search for Final Petition Decisions with comprehensive fields (10-20 results).
Balanced tier convenience parameters (14 total) - adds 5 advanced filters to minimal tier.
Use for: Detailed petition analysis after minimal search, cross-referencing with PFW/PTAB data, analyzing petition types and legal context. Returns: 18 key fields including petition type, art unit, technology center, prosecution status, legal issues, CFR rules cited, statutes cited, entity status, and invention title.
All Minimal Parameters (9) - same as Search_petitions_minimal:
applicant_name,application_number,patent_numberdecision_type,deciding_officepetition_date_start/end,decision_date_start/end
Additional Balanced Parameters (5):
petition_type_code: Petition type (e.g., '551' = revival, '182' = restriction)art_unit: Art unit number (e.g., '2128') - enables PFW cross-referencetechnology_center: Tech center (e.g., '21', '2100')prosecution_status: Status (e.g., 'During examination', 'Patented Case')entity_status: Entity type (e.g., 'Small', 'Large', 'Undiscounted')
Examples:
Progressive Disclosure Workflow:
Discovery: fpd_search_petitions_minimal(decision_type='DENIED', limit=100)
User selects interesting petitions
Analysis: fpd_search_petitions_balanced with advanced filters (art_unit, petition_type_code)
Cross-reference: Use art_unit with PFW, use patentNumber with PTAB
Cross-MCP Integration:
applicationNumberText -> pfw_search_applications_minimal with fields parameter for targeted data
patentNumber -> ptab_search_proceedings_minimal(patent_number=X)
groupArtUnitNumber -> pfw_search_applications_minimal(art_unit=X, fields=[...])
firstApplicantName -> Match parties across PFW/PTAB MCPs
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | No | ||
| limit | No | ||
| offset | No | ||
| applicant_name | No | ||
| application_number | No | ||
| patent_number | No | ||
| decision_type | No | ||
| deciding_office | No | ||
| petition_date_start | No | ||
| petition_date_end | No | ||
| decision_date_start | No | ||
| decision_date_end | No | ||
| petition_type_code | No | ||
| art_unit | No | ||
| technology_center | No | ||
| prosecution_status | No | ||
| entity_status | No |
Implementation Reference
- src/fpd_mcp/main.py:513-687 (handler)Main handler implementation for the 'Search_petitions_balanced' MCP tool. Builds Lucene query from 14 convenience parameters, performs search with 'petitions_balanced' field set (18 fields), filters response, adds query metadata and LLM guidance.@mcp.tool(name="Search_petitions_balanced") @async_tool_error_handler("balanced_search") async def fpd_search_petitions_balanced( query: str = "", limit: int = 10, offset: int = 0, # All 9 minimal tier parameters applicant_name: Optional[str] = None, application_number: Optional[str] = None, patent_number: Optional[str] = None, decision_type: Optional[str] = None, deciding_office: Optional[str] = None, petition_date_start: Optional[str] = None, petition_date_end: Optional[str] = None, decision_date_start: Optional[str] = None, decision_date_end: Optional[str] = None, # NEW: Balanced tier additional parameters (5 more) # Petition Classification petition_type_code: Optional[str] = None, # e.g., "551" (revival), "182" (restriction) art_unit: Optional[str] = None, # e.g., "2128", "3600" technology_center: Optional[str] = None, # e.g., "21", "2100" # Status Filters prosecution_status: Optional[str] = None, # e.g., "During examination", "Patented Case" entity_status: Optional[str] = None # e.g., "Small", "Large", "Undiscounted" ) -> Dict[str, Any]: """Balanced search for Final Petition Decisions with comprehensive fields (10-20 results). **Balanced tier convenience parameters (14 total) - adds 5 advanced filters to minimal tier.** Use for: Detailed petition analysis after minimal search, cross-referencing with PFW/PTAB data, analyzing petition types and legal context. Returns: 18 key fields including petition type, art unit, technology center, prosecution status, legal issues, CFR rules cited, statutes cited, entity status, and invention title. **All Minimal Parameters (9) - same as Search_petitions_minimal:** - `applicant_name`, `application_number`, `patent_number` - `decision_type`, `deciding_office` - `petition_date_start/end`, `decision_date_start/end` **Additional Balanced Parameters (5):** - `petition_type_code`: Petition type (e.g., '551' = revival, '182' = restriction) - `art_unit`: Art unit number (e.g., '2128') - enables PFW cross-reference - `technology_center`: Tech center (e.g., '21', '2100') - `prosecution_status`: Status (e.g., 'During examination', 'Patented Case') - `entity_status`: Entity type (e.g., 'Small', 'Large', 'Undiscounted') **Examples:** ```python # Revival petitions (type 551) that were denied fpd_search_petitions_balanced(petition_type_code="551", decision_type="DENIED", limit=20) # Complex combination for quality analysis fpd_search_petitions_balanced( art_unit="2128", petition_type_code="551", decision_type="DENIED", prosecution_status="During examination", limit=20 ) ``` **Progressive Disclosure Workflow:** 1. Discovery: fpd_search_petitions_minimal(decision_type='DENIED', limit=100) 2. User selects interesting petitions 3. Analysis: fpd_search_petitions_balanced with advanced filters (art_unit, petition_type_code) 4. Cross-reference: Use art_unit with PFW, use patentNumber with PTAB **Cross-MCP Integration:** - applicationNumberText -> pfw_search_applications_minimal with fields parameter for targeted data - patentNumber -> ptab_search_proceedings_minimal(patent_number=X) - groupArtUnitNumber -> pfw_search_applications_minimal(art_unit=X, fields=[...]) - firstApplicantName -> Match parties across PFW/PTAB MCPs""" try: # Input validation if limit < 1 or limit > 50: return format_error_response("Limit must be between 1 and 50", 400) if offset < 0: return format_error_response("Offset must be non-negative", 400) # Build query from convenience parameters try: final_query, convenience_params_used = _build_convenience_query( query=query, applicant_name=applicant_name, application_number=application_number, patent_number=patent_number, decision_type=decision_type, deciding_office=deciding_office, petition_date_start=petition_date_start, petition_date_end=petition_date_end, decision_date_start=decision_date_start, decision_date_end=decision_date_end, petition_type_code=petition_type_code, art_unit=art_unit, technology_center=technology_center, prosecution_status=prosecution_status, entity_status=entity_status, allow_balanced_params=True # Balanced tier allows all ) except ValueError as e: return format_error_response(str(e), 400) # Additional query length validation if len(final_query) > 2000: return format_error_response("Combined query too long (max 2000 characters)", 400) # Get fields from field manager fields = field_manager.get_fields("petitions_balanced") # Search petitions result = await api_client.search_petitions( query=final_query, fields=fields, limit=limit, offset=offset ) # Check for errors if "error" in result: return result # Filter response using field manager filtered_result = field_manager.filter_response(result, "petitions_balanced") # Add query metadata filtered_result["query_info"] = { "final_query": final_query, "convenience_parameters_used": convenience_params_used, "tier": "balanced", "available_parameters": [ "applicant_name", "application_number", "patent_number", "decision_type", "deciding_office", "petition_date_start", "petition_date_end", "decision_date_start", "decision_date_end", "petition_type_code", "art_unit", "technology_center", "prosecution_status", "entity_status" ] } # Add enhanced usage guidance filtered_result["llm_guidance"] = { "workflow": "Balanced Analysis -> Cross-MCP Integration -> Document Retrieval", "cross_mcp_workflows": { "pfw_prosecution": "pfw_search_applications_minimal with fields parameter for examiner/status context", "ptab_challenges": "ptab_search_proceedings_minimal(patent_number=X) if patentNumber present", "art_unit_analysis": "fpd_search_petitions_by_art_unit(art_unit=X) for pattern analysis" }, "red_flags": { "revival_37cfr1137": "Application abandoned - revival petition filed", "dispute_37cfr1181": "Examiner conflict - supervisory review petition", "denied_petition": "Director denied - weak arguments or procedural errors" }, "next_steps": [ "fpd_get_petition_details for full details + documents", "Cross-reference applicationNumberText with PFW", "Cross-reference patentNumber with PTAB", "Use fpd_search_petitions_by_art_unit for examiner patterns" ] } return filtered_result except ValueError as e: logger.warning(f"Validation error in balanced search: {str(e)}") return format_error_response(str(e), 400) except httpx.HTTPStatusError as e: logger.error(f"API error in balanced search: {e.response.status_code} - {e.response.text}") return format_error_response(f"API error: {e.response.text}", e.response.status_code) except httpx.TimeoutException as e: logger.error(f"API timeout in balanced search: {str(e)}") return format_error_response("Request timeout - please try again", 408) except Exception as e: logger.error(f"Unexpected error in balanced search: {str(e)}") return format_error_response(f"Internal error: {str(e)}", 500)
- src/fpd_mcp/main.py:513-513 (registration)MCP tool registration decorator defining the tool name as 'Search_petitions_balanced'.@mcp.tool(name="Search_petitions_balanced")
- Field configuration schema for 'petitions_balanced' set used by the tool, defining the 18 fields returned in responses for context reduction."petitions_balanced": { "description": "Key fields for petition analysis", "fields": [ "petitionDecisionRecordIdentifier", "applicationNumberText", "patentNumber", "firstApplicantName", "decisionTypeCodeDescriptionText", "petitionMailDate", "decisionDate", "finalDecidingOfficeName", "decisionPetitionTypeCode", "decisionPetitionTypeCodeDescriptionText", "groupArtUnitNumber", "technologyCenter", "businessEntityStatusCategory", "prosecutionStatusCodeDescriptionText", "inventionTitle", "petitionIssueConsideredTextBag", "ruleBag", "statuteBag" ]
- src/fpd_mcp/main.py:226-370 (helper)Helper function to construct the search query from convenience parameters (applicant_name, art_unit, etc.), used by both minimal and balanced search tools.def _build_convenience_query( query: str = "", # Core Identity & Party applicant_name: Optional[str] = None, application_number: Optional[str] = None, patent_number: Optional[str] = None, # Decision Filters decision_type: Optional[str] = None, deciding_office: Optional[str] = None, # Date Ranges petition_date_start: Optional[str] = None, petition_date_end: Optional[str] = None, decision_date_start: Optional[str] = None, decision_date_end: Optional[str] = None, # Balanced tier additional parameters petition_type_code: Optional[str] = None, art_unit: Optional[str] = None, technology_center: Optional[str] = None, prosecution_status: Optional[str] = None, entity_status: Optional[str] = None, # Control which parameters are allowed allow_balanced_params: bool = False ) -> tuple[str, dict]: """Build query string from convenience parameters Returns: tuple: (final_query_string, convenience_parameters_used) """ try: # Build query from convenience parameters query_parts = [] convenience_params_used = {} # Include base query if provided if query and query.strip(): query_parts.append(f"({query})") convenience_params_used["base_query"] = query # Add minimal tier convenience parameters if applicant_name: validated_name = validate_string_param("applicant_name", applicant_name) if validated_name: query_parts.append(f'{QueryFieldNames.APPLICANT_NAME}:"{validated_name}"') convenience_params_used["applicant_name"] = validated_name if application_number: validated_app = validate_application_number(application_number) if validated_app: query_parts.append(f"{QueryFieldNames.APPLICATION_NUMBER}:{validated_app}") convenience_params_used["application_number"] = validated_app if patent_number: validated_patent = validate_string_param("patent_number", patent_number, 15) if validated_patent: query_parts.append(f"{QueryFieldNames.PATENT_NUMBER}:{validated_patent}") convenience_params_used["patent_number"] = validated_patent if decision_type: validated_decision = validate_string_param("decision_type", decision_type, 50) if validated_decision: query_parts.append(f"{QueryFieldNames.DECISION_TYPE}:{validated_decision}") convenience_params_used["decision_type"] = validated_decision if deciding_office: validated_office = validate_string_param("deciding_office", deciding_office) if validated_office: query_parts.append(f'{FPDFields.FINAL_DECIDING_OFFICE_NAME}:"{validated_office}"') convenience_params_used["deciding_office"] = validated_office # Date range filters if petition_date_start or petition_date_end: start = validate_date_range(petition_date_start) if petition_date_start else "*" end = validate_date_range(petition_date_end) if petition_date_end else "*" if start != "*" or end != "*": query_parts.append(f"{QueryFieldNames.PETITION_MAIL_DATE}:[{start} TO {end}]") convenience_params_used["petition_date_range"] = f"{start} TO {end}" if decision_date_start or decision_date_end: start = validate_date_range(decision_date_start) if decision_date_start else "*" end = validate_date_range(decision_date_end) if decision_date_end else "*" if start != "*" or end != "*": query_parts.append(f"{QueryFieldNames.DECISION_DATE}:[{start} TO {end}]") convenience_params_used["decision_date_range"] = f"{start} TO {end}" # Add balanced tier additional parameters (only if allowed) if allow_balanced_params: if petition_type_code: validated_type = validate_string_param("petition_type_code", petition_type_code, 10) if validated_type: query_parts.append(f"{FPDFields.DECISION_PETITION_TYPE_CODE}:{validated_type}") convenience_params_used["petition_type_code"] = validated_type if art_unit: validated_art_unit = validate_string_param("art_unit", art_unit, 10) if validated_art_unit: query_parts.append(f"{QueryFieldNames.ART_UNIT}:{validated_art_unit}") convenience_params_used["art_unit"] = validated_art_unit if technology_center: validated_tc = validate_string_param("technology_center", technology_center, 10) if validated_tc: query_parts.append(f"{QueryFieldNames.TECHNOLOGY_CENTER}:{validated_tc}") convenience_params_used["technology_center"] = validated_tc if prosecution_status: validated_status = validate_string_param("prosecution_status", prosecution_status) if validated_status: query_parts.append(f'{QueryFieldNames.PROSECUTION_STATUS}:"{validated_status}"') convenience_params_used["prosecution_status"] = validated_status if entity_status: validated_entity = validate_string_param("entity_status", entity_status, 50) if validated_entity: query_parts.append(f'{QueryFieldNames.BUSINESS_ENTITY}:"{validated_entity}"') convenience_params_used["entity_status"] = validated_entity else: # Check if balanced-only parameters were provided but not allowed balanced_only_params = [petition_type_code, art_unit, technology_center, prosecution_status, entity_status] provided_balanced_params = [p for p in balanced_only_params if p is not None] if provided_balanced_params: raise ValidationError( "Parameters petition_type_code, art_unit, technology_center, prosecution_status, " "and entity_status are only available in fpd_search_petitions_balanced. " "Use fpd_search_petitions_balanced for advanced filtering.", generate_request_id() ) # Validate we have at least one search criterion if not query_parts: raise ValidationError( "Must provide either 'query' parameter or at least one convenience parameter", generate_request_id() ) # Combine all query parts with AND final_query = " AND ".join(query_parts) return final_query, convenience_params_used except ValidationError: # Re-raise ValidationError as-is raise except Exception as e: raise ValidationError(f"Query building failed: {str(e)}", generate_request_id())