Skip to main content
Glama
john-walkoe

USPTO Final Petition Decisions MCP Server

by john-walkoe

Search_petitions_by_art_unit

Analyze USPTO petition decisions by art unit to identify examiner patterns, assess quality issues, and support cross-referencing with examiner data and PTAB challenge rates.

Instructions

Search petitions by art unit number for examiner/art unit quality analysis.

Use for: Art unit quality assessment, systematic petition patterns, examiner behavior analysis. Returns balanced field set for cross-referencing with PFW examiner data and PTAB challenge rates.

Example:

  • fpd_search_petitions_by_art_unit(art_unit="2128", limit=50)

  • fpd_search_petitions_by_art_unit(art_unit="2128", date_range="2020-01-01:2024-12-31")

Analysis patterns:

  • High petition frequency → Difficult examiners or challenging technology

  • Frequent revival petitions (37 CFR 1.137) → Docketing/procedural issues

  • Examiner disputes (37 CFR 1.181) → Communication/quality problems

  • Denied petitions → Weak prosecution practices

Cross-MCP integration:

  • applicationNumberText → pfw_search_applications_minimal with fields parameter for examiner names

  • Group petitions by examiner to identify individual patterns

  • patentNumber → PTAB MCP to correlate petition history with challenge success

Parameters:

  • art_unit: Art unit number (e.g., "2128", "3600")

  • date_range: Optional date range (format: "YYYY-MM-DD:YYYY-MM-DD")

  • limit: Maximum results (default 50, max 200)

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
art_unitYes
date_rangeNo
limitNo

Implementation Reference

  • Primary MCP tool handler: decorated with @mcp.tool(name="Search_petitions_by_art_unit"), performs validation, delegates to API client, applies balanced field filtering, adds specialized LLM guidance for art unit analysis.
    @mcp.tool(name="Search_petitions_by_art_unit")
    @async_tool_error_handler("art_unit_search")
    async def fpd_search_petitions_by_art_unit(
        art_unit: str,
        date_range: Optional[str] = None,
        limit: int = 50
    ) -> Dict[str, Any]:
        """Search petitions by art unit number for examiner/art unit quality analysis.
    
    **Use for:** Art unit quality assessment, systematic petition patterns, examiner behavior analysis.
    Returns balanced field set for cross-referencing with PFW examiner data and PTAB challenge rates.
    
    **Example:**
    - fpd_search_petitions_by_art_unit(art_unit="2128", limit=50)
    - fpd_search_petitions_by_art_unit(art_unit="2128", date_range="2020-01-01:2024-12-31")
    
    **Analysis patterns:**
    - High petition frequency → Difficult examiners or challenging technology
    - Frequent revival petitions (37 CFR 1.137) → Docketing/procedural issues
    - Examiner disputes (37 CFR 1.181) → Communication/quality problems
    - Denied petitions → Weak prosecution practices
    
    **Cross-MCP integration:**
    - applicationNumberText → pfw_search_applications_minimal with fields parameter for examiner names
    - Group petitions by examiner to identify individual patterns
    - patentNumber → PTAB MCP to correlate petition history with challenge success
    
    **Parameters:**
    - art_unit: Art unit number (e.g., "2128", "3600")
    - date_range: Optional date range (format: "YYYY-MM-DD:YYYY-MM-DD")
    - limit: Maximum results (default 50, max 200)"""
        try:
            # Input validation
            if not art_unit or len(art_unit.strip()) == 0:
                return format_error_response("Art unit cannot be empty", 400)
            if limit < api_constants.MIN_SEARCH_LIMIT or limit > api_constants.MAX_SEARCH_LIMIT:
                return format_error_response(f"Limit must be between {api_constants.MIN_SEARCH_LIMIT} and {api_constants.MAX_SEARCH_LIMIT}", 400)
            if date_range:
                # Basic date range format validation
                parts = date_range.split(":")
                if len(parts) != 2:
                    return format_error_response(
                        "Date range must be in format YYYY-MM-DD:YYYY-MM-DD", 400
                    )
    
            # Use API client's search_by_art_unit method
            result = await api_client.search_by_art_unit(
                art_unit=art_unit,
                date_range=date_range,
                limit=limit
            )
    
            # Check for errors
            if "error" in result:
                return result
    
            # Filter response using balanced field set
            fields = field_manager.get_fields("petitions_balanced")
            filtered_result = field_manager.filter_response(result, "petitions_balanced")
    
            # Add art unit analysis guidance
            filtered_result["llm_guidance"] = {
                "workflow": "Art Unit Discovery -> Examiner Mapping -> PTAB Correlation",
                "analysis_patterns": {
                    "high_frequency": "Many petitions → Difficult examiners/technology/systematic issues",
                    "revival_clustering": "Multiple 37 CFR 1.137 → Docketing/procedural problems",
                    "examiner_disputes": "Multiple 37 CFR 1.181 → Communication/quality issues",
                    "ptab_correlation": "High petitions + high PTAB invalidation → Quality issues"
                },
                "next_steps": [
                    "Use pfw_search_applications_minimal with fields parameter for examiner mapping",
                    "Group petitions by examiner to identify individual patterns",
                    "Check GRANTED/DENIED outcomes to assess Director overturn rates",
                    "Cross-reference patentNumbers with PTAB for challenge correlation"
                ],
                "red_flags": {
                    "high_denial_rate": "Weak prosecution practices",
                    "multiple_examiners": "Art unit-wide problem",
                    "temporal_clustering": "Process breakdown in specific periods"
                }
            }
    
            return filtered_result
    
        except ValueError as e:
            logger.warning(f"Validation error in art unit search: {str(e)}")
            return format_error_response(str(e), 400)
        except httpx.HTTPStatusError as e:
            logger.error(f"API error in art unit 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 art unit search: {str(e)}")
            return format_error_response("Request timeout - please try again", 408)
        except Exception as e:
            logger.error(f"Unexpected error in art unit search: {str(e)}")
            return format_error_response(f"Internal error: {str(e)}", 500)
  • Service layer handler that delegates to API client and applies field filtering.
    async def search_by_art_unit(
        self,
        art_unit: str,
        date_range: Optional[str] = None,
        limit: int = 50
    ) -> Dict[str, Any]:
        """
        Search petitions by art unit
    
        Args:
            art_unit: Art unit number
            date_range: Optional date range filter
            limit: Number of results to return
    
        Returns:
            Search results for the art unit
        """
        result = await self.api_client.search_by_art_unit(
            art_unit=art_unit,
            date_range=date_range,
            limit=limit
        )
    
        # Filter response using balanced field set
        if "error" not in result:
            result = self.field_manager.filter_response(result, "petitions_balanced")
    
        return result
  • Core API client implementation: constructs Lucene query for art unit search, applies date range filters, delegates to generic search_petitions method.
    async def search_by_art_unit(
        self,
        art_unit: str,
        date_range: Optional[str] = None,
        limit: int = 50
    ) -> Dict[str, Any]:
        """
        Search petitions by art unit number
    
        Args:
            art_unit: Art unit number (e.g., "2128")
            date_range: Optional date range filter (e.g., "2020-01-01:2024-12-31")
            limit: Maximum number of results
    
        Returns:
            Dict containing search results
        """
        try:
            # Build query
            query = f"{QueryFieldNames.ART_UNIT}:{art_unit}"
    
            # Build filters for date range if provided
            filters = []
            if date_range:
                # Parse date range
                parts = date_range.split(":")
                if len(parts) == 2:
                    filters.append({
                        "field": FPDFields.PETITION_MAIL_DATE,
                        "valueFrom": parts[0],
                        "valueTo": parts[1]
                    })
    
            return await self.search_petitions(
                query=query,
                filters=filters if filters else None,
                limit=limit
            )
    
        except Exception as e:
            logger.error(f"Error in search_by_art_unit: {str(e)}")
            return format_error_response(str(e), 500, generate_request_id())
  • MCP tool registration decorator specifying the tool name.
    @mcp.tool(name="Search_petitions_by_art_unit")
  • Input schema defined by function parameters: art_unit (required str), date_range (optional str), limit (optional int=50). Output: Dict[str, Any] with filtered results and guidance.
    async def fpd_search_petitions_by_art_unit(
        art_unit: str,
        date_range: Optional[str] = None,
        limit: int = 50
    ) -> Dict[str, Any]:

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