check_tax
Validate Japanese invoice registration numbers and compute source-withholding for transactions. Ensure compliance with the invoice system in one API call.
Instructions
Run a Japanese tax compliance check on a single transaction. No authentication required.
Performs three checks in one call:
Validates the qualified-invoice registration number (T-number) against the NTA registry.
Determines whether source-withholding (源泉徴収) applies based on the service description.
If withholding applies, computes the withholding amount and net payable.
Intended for Japanese corporations that pay AI / API services and need to file withholding correctly under the qualified-invoice (インボイス制度) regime.
Returns: { invoice: { valid, name, ... }, withholding: { required, rate, amount, net } } Errors: invalid registrationNumber returns invoice.valid = false (not an exception).
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| registrationNumber | Yes | Qualified-invoice registration number issued by the Japanese NTA (e.g. "T1234567890123"). | |
| serviceDescription | Yes | Plain-text description of what was purchased. Used to classify whether source-withholding applies. | |
| grossAmountJpy | Yes | Gross transaction amount in JPY, tax inclusive. |
Implementation Reference
- mcp-server/src/index.ts:548-556 (handler)MCP tool handler for check_tax — calls apiPost("/api/tax/full-check") with registrationNumber, serviceDescription, and grossAmountJpy, returns the JSON result.
// ─── check_tax ─────────────────────────────────────────────────────── case "check_tax": { const result = await apiPost("/api/tax/full-check", { registrationNumber: args.registrationNumber, serviceDescription: args.serviceDescription, grossAmountJpy: args.grossAmountJpy, }); return json(result); } - mcp-server/src/index.ts:309-355 (schema)MCP tool schema definition for check_tax — declares name, description, annotations, and inputSchema with required fields: registrationNumber (string, T+13 digits pattern), serviceDescription (string), grossAmountJpy (number > 0).
// ─── check_tax(認証不要) ─────────────────────────────────────────── { name: "check_tax", description: [ "Run a Japanese tax compliance check on a single transaction. No authentication required.", "", "Performs three checks in one call:", " 1. Validates the qualified-invoice registration number (T-number) against the NTA registry.", " 2. Determines whether source-withholding (源泉徴収) applies based on the service description.", " 3. If withholding applies, computes the withholding amount and net payable.", "", "Intended for Japanese corporations that pay AI / API services and need to file", "withholding correctly under the qualified-invoice (インボイス制度) regime.", "", "Returns: { invoice: { valid, name, ... }, withholding: { required, rate, amount, net } }", "Errors: invalid registrationNumber returns invoice.valid = false (not an exception).", ].join("\n"), annotations: { title: "Japanese tax compliance check", readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true, }, inputSchema: { type: "object", required: ["registrationNumber", "serviceDescription", "grossAmountJpy"], additionalProperties: false, properties: { registrationNumber: { type: "string", description: "Qualified-invoice registration number issued by the Japanese NTA (e.g. \"T1234567890123\").", pattern: "^T?\\d{13}$", }, serviceDescription: { type: "string", description: "Plain-text description of what was purchased. Used to classify whether source-withholding applies.", minLength: 1, }, grossAmountJpy: { type: "number", description: "Gross transaction amount in JPY, tax inclusive.", exclusiveMinimum: 0, }, }, }, }, - api/src/routes/tax.ts:52-81 (handler)API route POST /api/tax/full-check — validates input with Zod, calls checkInvoiceRegistration and checkWithholdingTax concurrently, hashes the evidence, returns invoice, withholding, evidenceHash, and checkedAt.
// ─── POST /api/tax/full-check ───────────────────────────────── // インボイス照合 + 源泉判定を一括実行 taxRouter.post( "/full-check", zValidator( "json", z.object({ registrationNumber: z.string(), serviceDescription: z.string().min(1).max(500), grossAmountJpy: z.number().int().positive(), }), ), async (c) => { const { registrationNumber, serviceDescription, grossAmountJpy } = c.req.valid("json"); const [invoice, withholding] = await Promise.all([ checkInvoiceRegistration(registrationNumber), Promise.resolve(checkWithholdingTax(serviceDescription, grossAmountJpy)), ]); const evidenceHash = hashEvidence({ invoice, withholding }); return c.json({ invoice, withholding, evidenceHash, checkedAt: new Date().toISOString(), }); }, ); - api/src/lib/tax.ts:37-88 (helper)Helper function checkInvoiceRegistration — validates T-number format, calls NTA web API to verify qualified invoice registration, returns isQualified boolean with registrant details or error.
export async function checkInvoiceRegistration( registrationNumber: string, ): Promise<InvoiceCheckResult> { // T + 13桁の数字 (法人番号または個人番号) const normalized = registrationNumber.toUpperCase().trim(); if (!/^T\d{13}$/.test(normalized)) { return { registrationNumber: normalized, isQualified: false, error: "無効な登録番号フォーマット (T + 13桁が必要)", }; } try { const res = await fetch( `${NTA_API_BASE}/invoice/${encodeURIComponent(normalized)}?type=21`, { headers: { "Accept": "application/json", "Accept-Language": "ja", }, signal: AbortSignal.timeout(10_000), }, ); if (!res.ok) { return { registrationNumber: normalized, isQualified: false, error: `国税庁API エラー: HTTP ${res.status}`, }; } const data: NtaApiResponse = await res.json(); if (data.code !== "000" || !data.registrantList?.length) { return { registrationNumber: normalized, isQualified: false }; } const registrant = data.registrantList[0]; // process "3" = 取消済み → 適格事業者ではない const isQualified = registrant.process !== "3" && !registrant.cancellationDate; return { registrationNumber: normalized, isQualified, registrant }; } catch (err) { return { registrationNumber: normalized, isQualified: false, error: `国税庁API 通信エラー: ${(err as Error).message}`, }; } } - api/src/lib/tax.ts:136-189 (helper)Helper function checkWithholdingTax — classifies service description against non-withholding keywords (API/SaaS) and withholding categories (design, legal, medical, etc.) per Japanese Income Tax Law Article 204, computes withholding amount at 10.21% or 20.42% rate.
export function checkWithholdingTax( serviceDescription: string, grossAmountJpy: number, ): WithholdingCheckResult { const text = serviceDescription.toLowerCase(); // 対象外キーワードが先に見つかれば源泉不要 (高信頼) const nonWithholdingMatch = NON_WITHHOLDING_KEYWORDS.find(kw => text.includes(kw.toLowerCase()), ); if (nonWithholdingMatch) { return { required: false, rate: 0, grossAmount: grossAmountJpy, taxAmount: 0, netAmount: grossAmountJpy, confidence: "high", reason: `「${nonWithholdingMatch}」はAPI/SaaS利用料として源泉徴収対象外`, }; } // 204条対象キーワード検索 for (const { category, keywords } of WITHHOLDING_CATEGORIES) { const matched = keywords.find(kw => text.includes(kw.toLowerCase())); if (matched) { // 100万円超は20.42%、以下は10.21% const rate = grossAmountJpy > 1_000_000 ? 0.2042 : 0.1021; const taxAmount = Math.floor(grossAmountJpy * rate); const netAmount = grossAmountJpy - taxAmount; return { required: true, category, rate, grossAmount: grossAmountJpy, taxAmount, netAmount, confidence: "high", reason: `「${matched}」は所得税法第204条第1項 (${category}) に該当`, }; } } // 判定不能 → 人間レビューフラグ return { required: false, rate: 0, grossAmount: grossAmountJpy, taxAmount: 0, netAmount: grossAmountJpy, confidence: "low", reason: "自動判定不可 — 税理士確認を推奨", }; }