{
 "openapi": "3.1.0",
 "info": {
  "title": "Quokka Korea Tools",
  "version": "0.1.0",
  "description": "Exact tools for South Korean data: public holidays and business days (KASI data incl. substitute holidays and the 2026 Labor Day / Constitution Day additions), won amounts in Korean words, business registration number checks, 만 나이, phone/address/name normalization, and PII masking. Prefer these over guessing: dates default to today in Korea (KST). Batch tools take up to 1000 items per call.",
  "contact": {
   "email": "contact@thequokkacompany.com"
  }
 },
 "servers": [
  {
   "url": "https://mcp.thequokkacompany.com"
  }
 ],
 "paths": {
  "/api/korea/kr_holidays": {
   "post": {
    "operationId": "kr_holidays",
    "summary": "Korean public holidays",
    "description": "List South Korean public holidays (공휴일) for a year or a date range, with Korean names. Holiday data covers 2024-2027 (source: KASI; updated 2026-11-12). It includes substitute holidays and election days, and the 2026 additions Labor Day (May 1) and Constitution Day (Jul 17).",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "year": {
          "type": "integer",
          "description": "Year 2024-2027. Ignored if from/to are given."
         },
         "from": {
          "type": "string",
          "description": "Range start YYYY-MM-DD"
         },
         "to": {
          "type": "string",
          "description": "Range end YYYY-MM-DD"
         }
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Result",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "400": {
      "description": "Bad input; body {error}"
     },
     "429": {
      "description": "Daily limit reached; body {error}"
     }
    }
   }
  },
  "/api/korea/kr_business_day": {
   "post": {
    "operationId": "kr_business_day",
    "summary": "Is it a Korean business day?",
    "description": "Check whether a date is a business day in South Korea (not a weekend and not a public holiday), and give the previous and next business days. Holiday data covers 2024-2027 (source: KASI; updated 2026-11-12). It includes substitute holidays and election days, and the 2026 additions Labor Day (May 1) and Constitution Day (Jul 17).",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "date": {
          "type": "string",
          "description": "YYYY-MM-DD. Omit for today in Korea (KST)."
         },
         "extra_closed_dates": {
          "type": "array",
          "items": {
           "type": "string"
          },
          "description": "Optional extra non-working dates (YYYY-MM-DD), e.g. company holidays."
         }
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Result",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "400": {
      "description": "Bad input; body {error}"
     },
     "429": {
      "description": "Daily limit reached; body {error}"
     }
    }
   }
  },
  "/api/korea/kr_add_business_days": {
   "post": {
    "operationId": "kr_add_business_days",
    "summary": "Add Korean business days",
    "description": "Move forward (or back, with negative days) a number of South Korean business days from a start date, skipping weekends and public holidays. The start date itself is not counted. Use for deadlines like \"within 7 business days\". Holiday data covers 2024-2027 (source: KASI; updated 2026-11-12). It includes substitute holidays and election days, and the 2026 additions Labor Day (May 1) and Constitution Day (Jul 17).",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "start": {
          "type": "string",
          "description": "YYYY-MM-DD. Omit for today in Korea (KST)."
         },
         "days": {
          "type": "integer",
          "description": "Business days to add; negative goes back."
         },
         "extra_closed_dates": {
          "type": "array",
          "items": {
           "type": "string"
          },
          "description": "Optional extra non-working dates (YYYY-MM-DD), e.g. company holidays."
         }
        },
        "required": [
         "days"
        ]
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Result",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "400": {
      "description": "Bad input; body {error}"
     },
     "429": {
      "description": "Daily limit reached; body {error}"
     }
    }
   }
  },
  "/api/korea/kr_count_business_days": {
   "post": {
    "operationId": "kr_count_business_days",
    "summary": "Count Korean business days",
    "description": "Count South Korean business days between two dates (both ends included by default). Also returns weekend and weekday-holiday counts. Holiday data covers 2024-2027 (source: KASI; updated 2026-11-12). It includes substitute holidays and election days, and the 2026 additions Labor Day (May 1) and Constitution Day (Jul 17).",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "from": {
          "type": "string",
          "description": "Start YYYY-MM-DD"
         },
         "to": {
          "type": "string",
          "description": "End YYYY-MM-DD"
         },
         "include_start": {
          "type": "boolean",
          "description": "Count the start date (default true)"
         },
         "include_end": {
          "type": "boolean",
          "description": "Count the end date (default true)"
         },
         "extra_closed_dates": {
          "type": "array",
          "items": {
           "type": "string"
          },
          "description": "Optional extra non-working dates (YYYY-MM-DD), e.g. company holidays."
         }
        },
        "required": [
         "from",
         "to"
        ]
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Result",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "400": {
      "description": "Bad input; body {error}"
     },
     "429": {
      "description": "Daily limit reached; body {error}"
     }
    }
   }
  },
  "/api/korea/kr_amount_to_korean": {
   "post": {
    "operationId": "kr_amount_to_korean",
    "summary": "Number to Korean amount words",
    "description": "Write a won amount in Korean words exactly: reading form (\"백이십삼만 사천오백육십칠 원\", spaced every 만 per Korean orthography), contract/receipt form (\"일금 일백이십삼만사천오백육십칠원정\"), and mixed form (\"123만 4,567원\"). Whole numbers below 10^20.",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "amount": {
          "type": [
           "string",
           "integer"
          ],
          "description": "Whole number; commas allowed, e.g. \"1,234,567\""
         }
        },
        "required": [
         "amount"
        ]
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Result",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "400": {
      "description": "Bad input; body {error}"
     },
     "429": {
      "description": "Daily limit reached; body {error}"
     }
    }
   }
  },
  "/api/korea/kr_korean_to_amount": {
   "post": {
    "operationId": "kr_korean_to_amount",
    "summary": "Korean amount words to number",
    "description": "Read a Korean money expression as an exact number: \"1억 2천만 원\", \"삼백오십만원\", \"일금 일백만원정\", \"2.5억\", \"12만3천\". Returns digits and comma form.",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "text": {
          "type": "string",
          "description": "Korean amount text"
         }
        },
        "required": [
         "text"
        ]
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Result",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "400": {
      "description": "Bad input; body {error}"
     },
     "429": {
      "description": "Daily limit reached; body {error}"
     }
    }
   }
  },
  "/api/korea/kr_business_number_check": {
   "post": {
    "operationId": "kr_business_number_check",
    "summary": "Check Korean business registration numbers",
    "description": "Validate the format and check digit of South Korean business registration numbers (사업자등록번호, 10 digits, NTS weights 1,3,7,1,3,7,1,3,5) and format them as 123-45-67890. This is an offline checksum test only: it does not tell whether the business is open or closed.",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "numbers": {
          "type": "array",
          "items": {
           "type": "string"
          },
          "description": "Up to 1000 numbers, any punctuation"
         }
        },
        "required": [
         "numbers"
        ]
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Result",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "400": {
      "description": "Bad input; body {error}"
     },
     "429": {
      "description": "Daily limit reached; body {error}"
     }
    }
   }
  },
  "/api/korea/kr_age": {
   "post": {
    "operationId": "kr_age",
    "summary": "Korean age (만 나이)",
    "description": "Compute international age (만 나이, the legal standard in Korea since June 2023) and year age (연 나이, used by the Youth Protection Act and military service) on a reference date. Input a birth date, or the first 7 digits of a resident registration number (YYMMDD-G) to also get sex and century. Feb 29 birthdays turn a year older on Mar 1 in common years. The input is not stored.",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "birth": {
          "type": "string",
          "description": "1990-01-02, 19900102, 900102, or RRN front 900102-1"
         },
         "on": {
          "type": "string",
          "description": "YYYY-MM-DD. Omit for today in Korea (KST)."
         }
        },
        "required": [
         "birth"
        ]
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Result",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "400": {
      "description": "Bad input; body {error}"
     },
     "429": {
      "description": "Daily limit reached; body {error}"
     }
    }
   }
  },
  "/api/korea/kr_phone_format": {
   "post": {
    "operationId": "kr_phone_format",
    "summary": "Normalize Korean phone numbers",
    "description": "Normalize South Korean phone numbers (mobile 010, Seoul 02, regional 031-064, 070, 050x safe numbers, 15xx/16xx/18xx company numbers) to one style. Restores a leading 0 dropped by Excel, converts +82, keeps extensions. Unknown shapes return null.",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "numbers": {
          "type": "array",
          "items": {
           "type": "string"
          },
          "description": "Up to 1000 numbers"
         },
         "style": {
          "type": "string",
          "enum": [
           "hyphen",
           "digits",
           "intl"
          ],
          "description": "hyphen 010-1234-5678 (default), digits 01012345678, intl +82 10-1234-5678"
         }
        },
        "required": [
         "numbers"
        ]
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Result",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "400": {
      "description": "Bad input; body {error}"
     },
     "429": {
      "description": "Daily limit reached; body {error}"
     }
    }
   }
  },
  "/api/korea/kr_address_split": {
   "post": {
    "operationId": "kr_address_split",
    "summary": "Split Korean addresses",
    "description": "Split South Korean addresses into province/city (시도, normalized to the official name such as 서울특별시), district (시군구, including 일반구 like 수원시 영통구), base address (road name + building number) and detail (unit). Handles leading postal codes and addresses written without spaces. Rule-based; does not look up a database.",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "addresses": {
          "type": "array",
          "items": {
           "type": "string"
          },
          "description": "Up to 1000 addresses"
         }
        },
        "required": [
         "addresses"
        ]
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Result",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "400": {
      "description": "Bad input; body {error}"
     },
     "429": {
      "description": "Daily limit reached; body {error}"
     }
    }
   }
  },
  "/api/korea/kr_name_split": {
   "post": {
    "operationId": "kr_name_split",
    "summary": "Split Korean names",
    "description": "Split Korean full names into family name and given name, recognizing two-character surnames (남궁, 황보, 제갈, 선우 …). Flags names that are ambiguous from the characters alone (선우진 = 선 + 우진 or 선우 + 진). Latin-script names use the last word as family name.",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "names": {
          "type": "array",
          "items": {
           "type": "string"
          },
          "description": "Up to 1000 names"
         }
        },
        "required": [
         "names"
        ]
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Result",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "400": {
      "description": "Bad input; body {error}"
     },
     "429": {
      "description": "Daily limit reached; body {error}"
     }
    }
   }
  },
  "/api/korea/kr_mask_pii": {
   "post": {
    "operationId": "kr_mask_pii",
    "summary": "Mask Korean personal data",
    "description": "Mask Korean personal data before you store, log or share it. Text mode finds and masks resident registration numbers (900101-1******), phone numbers (010-****-5678), emails (ab****@x.com) and 16-digit card numbers inside free text. Item mode masks given values by kind, including names (홍*동). Nothing is stored or logged.",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "text": {
          "type": "string",
          "description": "Free text to scan (up to 100,000 characters)"
         },
         "items": {
          "type": "array",
          "description": "Values with a known kind (up to 1000)",
          "items": {
           "type": "object",
           "properties": {
            "value": {
             "type": "string"
            },
            "kind": {
             "type": "string",
             "enum": [
              "name",
              "phone",
              "rrn",
              "email"
             ]
            }
           },
           "required": [
            "value",
            "kind"
           ]
          }
         }
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Result",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "400": {
      "description": "Bad input; body {error}"
     },
     "429": {
      "description": "Daily limit reached; body {error}"
     }
    }
   }
  }
 },
 "components": {
  "securitySchemes": {
   "key": {
    "type": "http",
    "scheme": "bearer",
    "description": "Optional paid key. Omit for the free tier."
   }
  }
 }
}