Skip to main content
Glama
john-walkoe

USPTO Final Petition Decisions MCP Server

by john-walkoe

Search_petitions_minimal

Search USPTO final petition decisions using simple parameters like applicant name, decision type, or date ranges to discover relevant petitions quickly.

Instructions

Ultra-fast discovery search for Final Petition Decisions (50-100 results).

NEW: Minimal tier convenience parameters (9 total) - no query syntax needed!

Use for: High-volume petition discovery, finding petitions by applicant, decision type, or date range. Returns: 8 essential fields - petition ID, application number, patent number, applicant name, decision type, petition mail date, decision date, deciding office.

Convenience Parameters:

  • applicant_name: Company/party name (e.g., 'Apple Inc.')

  • application_number: Application number (e.g., '17896175')

  • patent_number: Patent number if granted (e.g., '11788453')

  • decision_type: Outcome (e.g., 'GRANTED', 'DENIED', 'DISMISSED')

  • deciding_office: Office that decided (e.g., 'OFFICE OF PETITIONS')

  • petition_date_start/end: Filing date range (YYYY-MM-DD)

  • decision_date_start/end: Decision date range (YYYY-MM-DD)

Examples:

# Denied petitions for company
fpd_search_petitions_minimal(applicant_name="TechCorp Inc.", decision_type="DENIED", limit=50)

# Hybrid: keywords + convenience
fpd_search_petitions_minimal(query="machine learning", decision_type="DENIED", limit=50)

Progressive Disclosure Workflow:

  1. Use THIS TOOL for discovery with minimal params (50-100 results)

  2. Present top results to user for selection

  3. Use fpd_search_petitions_balanced for detailed analysis (10-20 selected)

    • Balanced tier adds: petition_type_code, art_unit, technology_center, prosecution_status, entity_status

  4. Use fpd_get_petition_details for complete petition data

Cross-MCP Integration:

  • {QueryFieldNames.APPLICATION_NUMBER} -> Links to Patent File Wrapper MCP

  • {QueryFieldNames.PATENT_NUMBER} -> Links to PTAB MCP for post-grant challenges

  • Use balanced tier to get {QueryFieldNames.ART_UNIT} for PFW cross-reference

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

Implementation Reference

  • Primary handler for Search_petitions_minimal tool. Includes @mcp.tool registration decorator. Validates inputs, builds Lucene query from 9 convenience parameters, calls FPDClient.search_petitions with petitions_minimal fields, filters response with FieldManager, adds metadata and LLM guidance.
    @mcp.tool(name="Search_petitions_minimal")
    @async_tool_error_handler("minimal_search")
    async def fpd_search_petitions_minimal(
        query: str = "",
        limit: int = 50,
        offset: int = 0,
    
        # NEW: Minimal tier convenience parameters (9 total)
        # Core Identity & Party
        applicant_name: Optional[str] = None,         # e.g., "Apple Inc.", "TechCorp"
        application_number: Optional[str] = None,     # e.g., "17896175"
        patent_number: Optional[str] = None,          # e.g., "11788453"
    
        # Decision Filters
        decision_type: Optional[str] = None,          # e.g., "GRANTED", "DENIED", "DISMISSED"
        deciding_office: Optional[str] = None,        # e.g., "OFFICE OF PETITIONS"
    
        # Date Ranges
        petition_date_start: Optional[str] = None,    # e.g., "2024-01-01" (YYYY-MM-DD)
        petition_date_end: Optional[str] = None,      # e.g., "2024-12-31" (YYYY-MM-DD)
        decision_date_start: Optional[str] = None,    # e.g., "2024-01-01" (YYYY-MM-DD)
        decision_date_end: Optional[str] = None       # e.g., "2024-12-31" (YYYY-MM-DD)
    ) -> Dict[str, Any]:
        """Ultra-fast discovery search for Final Petition Decisions (50-100 results).
    
    **NEW: Minimal tier convenience parameters (9 total) - no query syntax needed!**
    
    Use for: High-volume petition discovery, finding petitions by applicant, decision type, or date range.
    Returns: 8 essential fields - petition ID, application number, patent number, applicant name,
    decision type, petition mail date, decision date, deciding office.
    
    **Convenience Parameters:**
    - `applicant_name`: Company/party name (e.g., 'Apple Inc.')
    - `application_number`: Application number (e.g., '17896175')
    - `patent_number`: Patent number if granted (e.g., '11788453')
    - `decision_type`: Outcome (e.g., 'GRANTED', 'DENIED', 'DISMISSED')
    - `deciding_office`: Office that decided (e.g., 'OFFICE OF PETITIONS')
    - `petition_date_start/end`: Filing date range (YYYY-MM-DD)
    - `decision_date_start/end`: Decision date range (YYYY-MM-DD)
    
    **Examples:**
    ```python
    # Denied petitions for company
    fpd_search_petitions_minimal(applicant_name="TechCorp Inc.", decision_type="DENIED", limit=50)
    
    # Hybrid: keywords + convenience
    fpd_search_petitions_minimal(query="machine learning", decision_type="DENIED", limit=50)
    ```
    
    **Progressive Disclosure Workflow:**
    1. Use THIS TOOL for discovery with minimal params (50-100 results)
    2. Present top results to user for selection
    3. Use fpd_search_petitions_balanced for detailed analysis (10-20 selected)
       - Balanced tier adds: petition_type_code, art_unit, technology_center, prosecution_status, entity_status
    4. Use fpd_get_petition_details for complete petition data
    
    **Cross-MCP Integration:**
    - {QueryFieldNames.APPLICATION_NUMBER} -> Links to Patent File Wrapper MCP
    - {QueryFieldNames.PATENT_NUMBER} -> Links to PTAB MCP for post-grant challenges
    - Use balanced tier to get {QueryFieldNames.ART_UNIT} for PFW cross-reference"""
        # Input validation
        if limit < api_constants.MIN_SEARCH_LIMIT or limit > api_constants.MAX_SEARCH_LIMIT:
            raise ValidationError(f"Limit must be between {api_constants.MIN_SEARCH_LIMIT} and {api_constants.MAX_SEARCH_LIMIT}", generate_request_id())
        if offset < 0:
            raise ValidationError("Offset must be non-negative", generate_request_id())
    
        # Build query from convenience parameters
        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,
            allow_balanced_params=False  # Minimal tier only
        )
    
        # Additional query length validation
        if len(final_query) > 2000:
            raise ValidationError("Combined query too long (max 2000 characters)", generate_request_id())
    
        # Get fields from field manager
        fields = field_manager.get_fields("petitions_minimal")
    
        # 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_minimal")
    
        # Add query metadata
        filtered_result["query_info"] = {
            "final_query": final_query,
            "convenience_parameters_used": convenience_params_used,
            "tier": "minimal",
            "available_parameters": [
                "applicant_name", "application_number", "patent_number",
                "decision_type", "deciding_office",
                "petition_date_start", "petition_date_end",
                "decision_date_start", "decision_date_end"
            ]
        }
    
        # Add usage guidance
        filtered_result["llm_guidance"] = {
            "workflow": "Discovery -> User Selection -> Balanced Analysis -> Cross-MCP Integration",
            "parameter_guidance": {
                "current_tier": "minimal (9 convenience parameters available)",
                "next_tier": "Use fpd_search_petitions_balanced for 5 additional parameters: petition_type_code, art_unit, technology_center, prosecution_status, entity_status",
                "progressive_disclosure": "Start here for discovery, advance to balanced for analysis"
            },
            "next_steps": [
                "Present top results to user for selection",
                "Use fpd_search_petitions_balanced for detailed analysis of selected petitions",
                "Use fpd_search_petitions_by_application to get all petitions for specific application",
                "Cross-reference with PFW using applicationNumberText for prosecution history",
                "Cross-reference with PTAB using patentNumber for post-grant challenges"
            ],
            "red_flags": {
                "revival_petitions": "Look for ruleBag containing '37 CFR 1.137' (abandoned applications)",
                "examiner_disputes": "Look for ruleBag containing '37 CFR 1.181' (supervisory review)",
                "denied_petitions": "decisionTypeCodeDescriptionText: 'DENIED' indicates potential quality issues"
            }
        }
    
        return filtered_result
  • MCP tool registration decorator specifying the exact tool name 'Search_petitions_minimal'.
    @mcp.tool(name="Search_petitions_minimal")
  • Output schema definition for minimal field set (8 essential fields). Used by field_manager.get_fields('petitions_minimal') and filter_response to reduce context by 95-99%.
    "petitions_minimal": {
        "description": "Essential fields for petition discovery",
        "fields": [
            "petitionDecisionRecordIdentifier",
            "applicationNumberText",
            "patentNumber",
            "firstApplicantName",
            "decisionTypeCodeDescriptionText",
            "petitionMailDate",
            "decisionDate",
            "finalDecidingOfficeName"
        ]
  • Type definitions and constants for all input query fields and output response fields used in the tool.
    class FPDFields:
        """
        Constants for USPTO Final Petition Decisions API field names.
    
        These constants represent the exact field names used by the USPTO API.
        Use these instead of hardcoded strings to enable:
        - IDE autocomplete
        - Easier refactoring
        - Catching typos at development time
        """
    
        # === TOP-LEVEL FIELDS ===
        PETITION_DECISION_DATA_BAG = "petitionDecisionDataBag"
    
        # === CORE IDENTIFICATION FIELDS ===
        PETITION_DECISION_RECORD_IDENTIFIER = "petitionDecisionRecordIdentifier"  # UUID
        APPLICATION_NUMBER_TEXT = "applicationNumberText"  # Links to PFW MCP
        PATENT_NUMBER = "patentNumber"  # Links to PTAB MCP
    
        # === APPLICANT/INVENTOR FIELDS ===
        FIRST_APPLICANT_NAME = "firstApplicantName"
        INVENTOR_BAG = "inventorBag"
        CUSTOMER_NUMBER = "customerNumber"
        FIRST_INVENTOR_TO_FILE_INDICATOR = "firstInventorToFileIndicator"  # AIA indicator
    
        # === DECISION FIELDS ===
        DECISION_TYPE_CODE_DESCRIPTION_TEXT = "decisionTypeCodeDescriptionText"  # GRANTED/DENIED/DISMISSED
        PETITION_MAIL_DATE = "petitionMailDate"  # When petition filed
        DECISION_DATE = "decisionDate"  # When Director decided
        DECISION_MAIL_DATE = "decisionMailDate"  # When decision mailed
        FINAL_DECIDING_OFFICE_NAME = "finalDecidingOfficeName"  # Deciding office
    
        # === PETITION TYPE FIELDS ===
        DECISION_PETITION_TYPE_CODE = "decisionPetitionTypeCode"  # Type code (551, etc.)
        DECISION_PETITION_TYPE_CODE_DESCRIPTION_TEXT = "decisionPetitionTypeCodeDescriptionText"
    
        # === CLASSIFICATION FIELDS ===
        GROUP_ART_UNIT_NUMBER = "groupArtUnitNumber"  # Art unit (→ PFW cross-ref)
        TECHNOLOGY_CENTER = "technologyCenter"  # TC
    
        # === STATUS FIELDS ===
        PROSECUTION_STATUS_CODE = "prosecutionStatusCode"
        PROSECUTION_STATUS_CODE_DESCRIPTION_TEXT = "prosecutionStatusCodeDescriptionText"
        BUSINESS_ENTITY_STATUS_CATEGORY = "businessEntityStatusCategory"  # Small/Undiscounted
    
        # === LEGAL CONTEXT FIELDS (ARRAYS) ===
        PETITION_ISSUE_CONSIDERED_TEXT_BAG = "petitionIssueConsideredTextBag"  # Issues raised
        RULE_BAG = "ruleBag"  # CFR rules cited (e.g., "37 CFR 1.137")
        STATUTE_BAG = "statuteBag"  # Statutes cited
    
        # === COURT INFORMATION ===
        COURT_ACTION_INDICATOR = "courtActionIndicator"  # Boolean
        ACTION_TAKEN_BY_COURT_NAME = "actionTakenByCourtName"
    
        # === INVENTION DETAILS ===
        INVENTION_TITLE = "inventionTitle"
    
        # === METADATA ===
        LAST_INGESTION_DATE_TIME = "lastIngestionDateTime"  # Data freshness
    
        # === DOCUMENT FIELDS ===
        DOCUMENT_BAG = "documentBag"
        DOCUMENT_IDENTIFIER = "documentIdentifier"
        DOCUMENT_CODE = "documentCode"
        DOCUMENT_CODE_DESCRIPTION_TEXT = "documentCodeDescriptionText"
        DOCUMENT_FILE_NAME = "documentFileName"
        PAGE_COUNT = "pageCount"
    
        # === DOWNLOAD FIELDS ===
        DOWNLOAD_OPTION_BAG = "downloadOptionBag"
        MIME_TYPE_IDENTIFIER = "mimeTypeIdentifier"  # PDF, etc.
        DOWNLOAD_URL = "downloadUrl"
        PAGE_TOTAL_QUANTITY = "pageTotalQuantity"
    
    
    class QueryFieldNames:
        """
        Field names as they appear in Lucene/search queries.
    
        Use these for building search queries with convenience parameters.
        """
        # Core search fields
        APPLICATION_NUMBER = "applicationNumberText"
        PATENT_NUMBER = "patentNumber"
        APPLICANT_NAME = "firstApplicantName"
    
        # Classification search
        ART_UNIT = "groupArtUnitNumber"
        TECHNOLOGY_CENTER = "technologyCenter"
    
        # Date search
        PETITION_MAIL_DATE = "petitionMailDate"
        DECISION_DATE = "decisionDate"
    
        # Decision search
        DECISION_TYPE = "decisionTypeCodeDescriptionText"
        PETITION_TYPE = "decisionPetitionTypeCodeDescriptionText"
    
        # Status search
        PROSECUTION_STATUS = "prosecutionStatusCodeDescriptionText"
        BUSINESS_ENTITY = "businessEntityStatusCategory"
    
        # Legal search
        RULE = "ruleBag"  # Search for CFR rules
        STATUTE = "statuteBag"  # Search for statutes
    
        # Metadata search
        INVENTION_TITLE = "inventionTitle"
    
    
    # === RED FLAG RULES FOR PETITION QUALITY ASSESSMENT ===
    class PetitionRedFlags:
        """
        Common petition types and rules that indicate potential quality issues.
    
        Use these constants when analyzing petition patterns for red flags.
        """
        # Revival petitions (application was abandoned)
        RULE_REVIVAL = "37 CFR 1.137"
    
        # Petitions for supervisory review (examiner disputes)
        RULE_SUPERVISORY_REVIEW = "37 CFR 1.181"
    
        # Petitions for reconsideration (restriction issues)
        RULE_RECONSIDERATION = "37 CFR 1.182"
    
        # Special petitions
        RULE_SPECIAL_PETITION = "37 CFR 1.183"
    
        # Decision outcomes
        DECISION_DENIED = "DENIED"
        DECISION_GRANTED = "GRANTED"
  • Supporting service method with caching and performance monitoring. Similar logic to tool handler but with added cache_manager and structured logging.
    async def search_petitions_minimal(
        self,
        query: str,
        limit: int = 50,
        offset: int = 0
    ) -> Dict[str, Any]:
        """
        Perform minimal petition search with context reduction and caching
    
        Args:
            query: Search query
            limit: Number of results to return
            offset: Offset for pagination
    
        Returns:
            Filtered search results
        """
        with PerformanceTimer(self.structured_logger, "search_petitions_minimal", {"query_length": len(query), "limit": limit, "offset": offset}):
            # Check cache first
            cache_key_args = (query, limit, offset)
            cached_result = self.cache_manager.get("search_petitions_minimal", *cache_key_args)
            if cached_result is not None:
                self.structured_logger.log_cache_event(
                    cache_key=str(hash(cache_key_args)),
                    hit=True,
                    method_name="search_petitions_minimal",
                    ttl_seconds=300
                )
                return cached_result
    
            # Log cache miss
            self.structured_logger.log_cache_event(
                cache_key=str(hash(cache_key_args)),
                hit=False,
                method_name="search_petitions_minimal"
            )
    
            # Get minimal field set
            fields = self.field_manager.get_fields("petitions_minimal")
    
            # Perform search
            result = await self.api_client.search_petitions(
                query=query,
                fields=fields,
                limit=limit,
                offset=offset
            )
    
            # Check for errors
            if "error" in result:
                return result
    
            # Filter response using field manager
            filtered_result = self.field_manager.filter_response(result, "petitions_minimal")
    
            # Cache successful results
            self.cache_manager.set("search_petitions_minimal", filtered_result, *cache_key_args)
    
            return filtered_result

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