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

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
resultYes

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
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It effectively describes key traits: it's a search tool (implied read-only), specifies result limits ('50-100 results'), mentions 'ultra-fast discovery' (performance hint), and details the return format ('8 essential fields'). However, it lacks explicit information on permissions, rate limits, or error handling, which are important for a tool with 12 parameters.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured with sections like 'Use for:', 'Returns:', 'Convenience Parameters:', 'Examples:', and 'Progressive Disclosure Workflow,' making it easy to scan. However, it includes some verbose elements like 'NEW: Minimal tier convenience parameters (9 total) - no query syntax needed!' and extensive cross-MCP integration details that, while informative, could be trimmed for conciseness without losing core value.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the complexity (12 parameters, no annotations, but has output schema), the description is highly complete. It covers purpose, usage guidelines, parameter details, return fields, examples, workflow integration with sibling tools, and cross-MCP references. The output schema exists, so return values need not be explained in depth, and the description provides enough context for effective tool selection and invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate fully. It adds significant meaning beyond the schema by explaining all 12 parameters in the 'Convenience Parameters' section with examples (e.g., 'applicant_name': Company/party name), clarifying data types and usage. It also describes the 'query' parameter in examples and mentions 'limit' and 'offset' in the schema, though less explicitly, but overall provides comprehensive parameter semantics.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool performs 'Ultra-fast discovery search for Final Petition Decisions' with '50-100 results,' specifying the verb (search), resource (Final Petition Decisions), and scope (minimal tier). It distinguishes from siblings by emphasizing 'minimal tier convenience parameters' and explicitly mentions the sibling tool 'fpd_search_petitions_balanced' for detailed analysis, making the purpose specific and differentiated.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides explicit guidance on when to use this tool vs. alternatives. It states 'Use for: High-volume petition discovery' and outlines a 'Progressive Disclosure Workflow' that directs users to start with this tool for discovery, then use 'fpd_search_petitions_balanced' for detailed analysis, and 'fpd_get_petition_details' for complete data. This includes clear when-to-use and alternative tool references.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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