Upgrade to Pro — share decks privately, control downloads, hide ads and more …

輸入実行関税率表をMCPサーバー化してみた

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
Avatar for Qlitre Qlitre
September 11, 2025
470

 輸入実行関税率表をMCPサーバー化してみた

Avatar for Qlitre

Qlitre

September 11, 2025
Tweet

Transcript

  1. ࣗݾ঺հ ͘Γͬͨʔ w 9 !LVSJ@UUFS ɹIUUQTRMJUSFNF w ࢓ࣄ w ߓ࿷෺ྲྀ૔ݿاۀ

    w ݱ৔؂ಜɺྫྷౚ૔ݿӦۀͳͲΛܦͯݱࡏ͸*5ௐୡ w ϓϩάϥϛϯά w झຯͰ)POP 1ZUIPOͳͲɻ w 8PSLFSTY)POP9ͰݸਓϒϩάͳͲެ։ ೥݄஑ାʹͯ
  2. ༌ೖ՟෺͕ྲྀ௨͢Δ·Ͱ ւ֎ อ੫஍Ҭ ʢ֎ࠃ՟෺Λஔ͚Δ৔ॴʣ ɾίϯςφϠʔυ ɾۭߓ ɾ෺ྲྀ૔ݿɹʜFUD ࠃ಺ ࢢ৔ ༌ૹɾൖೖ

    ൖग़ ༌ೖ ਃࠂ ੫ؔ ৹ࠪ ࠃ಺ ؔ੫ ೲ෇ ༌ೖ ڐՄ ͜͜Ͱར༻͢Δͷ͕༌ೖ࣮ߦؔ੫཰දʢλϦϑʣ ՙओʢ঎ࣾɾϝʔΧʔʣ͕ ෺ྲྀۀऀʹ༌ೖਃࠂखଓ͖ Λҕୗ͢Δͷ͕Ұൠతɻ
  3. w ༌ೖ͞ΕΔશͯͷ঎඼ʹ͍ͭ ͯɺܻ̕ͷ౷ܭ඼໨൪߸ͱؔ੫ ཰ΛఆΊͨҰཡද w ̓̕ΧςΰϦͰߏ੒ w ༌ೖਃࠂ࣌ʹඞཁͳؔ੫཰Λௐ ΂ΔͨΊͷඞਢπʔϧ w

    ੫ؔ8&#Ͱແྉެ։ɻ w ʮ༌ೖ࣮ߦؔ੫཰දʯͰ͙͙Δ ͱҰ൪্ʹग़ͯ͘Δ ༌ೖ࣮ߦؔ੫཰දʢλϦϑʣͱ͸ʁ IUUQTXXXDVTUPNTHPKQUBSJ ff @@JOEFYIUN
  4. ه࿥ͨ͠-&7&- ਂ͞ʣΛݩʹೖΕࢠɺ৿Λදݱɻ { "level": 0, "stat_code": "19.02", "desc": "ύελྨɾΫʔεΫʔε", "children":

    [ { "level": 1, "stat_code": "19.02", "desc": "ύελʢௐཧɾௐ੡͍ͯ͠ͳ͍΋ͷʣ", "children": [ { "level": 2, "stat_code": "1902.19", "desc": "ͦͷଞͷ΋ͷ", "children": [ { "level": 3, "stat_code": "1902.19", "desc": "ͦͷଞͷ΋ͷ", "children": [ { "level": 4, "desc": "ϚΧϩχٴͼεύήοςΟ", "children": [ { "level": 5, "stat_code": "1902.19", "hs_code": "093", "desc": "εύήοςΟ" } ] } ] } ] } ] } ] }
  5. )POPϓϩδΣΫτʹKTPOΛ഑ஔɻ γϯϓϧͳΩʔϫʔυݕࡧͰ)POPNDQͰ8PSLFSTʹσϓϩΠɻ DPOTUBQQOFX)POP  BQQBMM  BTZOD D \ DPOTUNDQ4FSWFSBXBJUHFU.DQ4FSWFS

    D  DPOTUUSBOTQPSUOFX4USFBNBCMF)5515SBOTQPSU  BXBJUNDQ4FSWFSDPOOFDU USBOTQPSU  SFUVSOUSBOTQPSUIBOEMF3FRVFTU D  ^  export const getMcpServer = async (c: Context<Env>) => { const server = new McpServer({ name: "japan-tariff-mcp", version: "0.0.1", }); server.tool( "searchTariffByKeywords", "Search tariff data by keywords (comma-separated)", { keywords: z.string().min(1) }, async ({ keywords }) => { const { results, hitCount } = await searchService.searchTariffData( keywords ); const limit = 30; let msg = ""; if (results.length > limit) { msg = `More than the maximum limit of ${limit} items were found. Please refer to hitCount and re-search if necessary.`; } return { content: [ { type: "text", text: JSON.stringify({ message: msg, hitCount: hitCount, results: results.slice(0, limit), }), }, ], }; } ); }; ۪௚ͳઢܗ୳ࡧɻݸͷKTPO ϑΝΠϧΛॱ൪ʹ։͖จࣈ͕ ؚ·ΕΔ͔൑ఆɻ )POPNDQͰ഑৴
  6. w ੈʹʮ8&#λϦϑʯͱݺ͹ΕΔެ ࣜݕࡧαΠτ͸ଘࡏ͢Δɻ w ঎඼໊͕ͦͷ··ࡌ͍ͬͯͳ͍έ ʔε΋ଟ͍ɻ w ྫ͑͹νϡʔϋΠͰݕࡧͯ͠΋ώ οτ͠ͳ͍ɻ w

    .$1͸νϡʔϋΠ মய Ξϧίʔ ϧҿྉͱʮΑ͠ͳʹʯྨޠݕࡧɻ w ݟ͔ͭΔ·ͰʮؤுΔʯɻ .$1ݕࡧπʔϧͷಛ௃ͱ௨ৗͱͷҧ͍
  7. w ΋ͱ΋ͱ୯ҰͷΩʔϫʔυͰ࣮૷ɻ w ݕࡧˠݟ͔ͭΒͳ͍ˠݕࡧʜͱ܁Γ ฦ͢ͷ͕৑௕ɻ w ΩʔϫʔυΛΧϯϚ۠੾ΓͰड͚औ ΔΑ͏ʹ஫ҙॻ͖ɻ w zνϡʔϋΠ

    মய Ξϧίʔϧҿྉz ͱ͍͏จࣈྻΛ"*͕౉ͯ͘͠ΕΔɻ w ϩδοΫଆͰTQMJUͯ͠Ұ୯ޠͣͭ൑ ఆɻࢼߦճ਺Λେ෯ʹ࡟ݮɻ ޻෉ᶃɹݕࡧΩʔϫʔυΛΧϯϚ۠੾ΓͰड͚औΔ server.tool( // ΧϯϚ۠੾ΓͰड͚औΔΑ͏ʹ͢Δ "searchTariffByKeywords", "Search tariff data by keywords (comma-separated)", { keywords: z.string().min(1) }, async ({ keywords }) => { // ϩδοΫଆͰsplitͯ͠ώοτ൑ఆ const { results, hitCount } = await searchService.searchTariffData( keywords ); ɹɹɹ…লུ );
  8. w ྫʣϑϥΠυνΩϯˠʮௐ੔ʯ͕ ݅ɺʮܲ೑ʯ͸݅ɻ ʢzௐ੔৯ྉ඼z͔Β࿈૝ʣ w Ωʔϫʔυ͝ͱͷώοτ݅਺Λه ࿥ͯ͠"*ʹฦ͢ɻ w ্ݶ஋Λ௒͑ͨΒɺ݅਺Λࢀߟʹ ࠶ݕࡧΛࢹ໺ʹೖΕΔɻ

    w ΠΠײ͡ʹيಓमਖ਼ͯ͠ߜΓ͜Μ Ͱ͘ΕΔΑ͏ʹͳͬͨɻ ޻෉ᶄɹҙਤ͠ͳ͍Ωʔϫʔυ͕ώοτͨ͠৔߹ͷيಓमਖ਼ server.tool( …ɹলུ async ({ keywords }) => { // ݕࡧΩʔϫʔυ͝ͱͷώοτ݅਺Λड͚औΔΑ͏ʹ͢Δ const { results, hitCount } = await searchService.searchTariffData( keywords ); // ώοτ਺ͷ্ݶΛઃఆ const limit = 30; let msg = ""; // ্ݶΛ௒͑ͯͨΒɺඞཁʹԠͯ͡࠶ݕࡧΛ͢Δ if (results.length > limit) { msg = `More than the maximum limit of ${limit} items were found. Please refer to hitCount and re-search if necessary.`; } return { // ϝοηʔδͱώοτ݅਺Λ݁Ռʹฦ͢ content: [ { type: "text", text: JSON.stringify({ message: msg, hitCount: hitCount, results: results.slice(0, limit), }), }, ], }; } );