Skip to main content
Glama
john-walkoe

USPTO Final Petition Decisions MCP Server

by john-walkoe

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_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:

# 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

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
queryNo
limitNo
offsetNo
applicant_nameNo
application_numberNo
patent_numberNo
decision_typeNo
deciding_officeNo
petition_date_startNo
petition_date_endNo
decision_date_startNo
decision_date_endNo
petition_type_codeNo
art_unitNo
technology_centerNo
prosecution_statusNo
entity_statusNo

Implementation Reference

  • 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)
  • 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" ]
  • 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())

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/john-walkoe/uspto_fpd_mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server