Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
輸入実行関税率表をMCPサーバー化してみた
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
Qlitre
September 11, 2025
510
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
輸入実行関税率表をMCPサーバー化してみた
Qlitre
September 11, 2025
Featured
See All Featured
The Hidden Cost of Media on the Web [PixelPalooza 2025]
tammyeverts
2
330
Noah Learner - AI + Me: how we built a GSC Bulk Export data pipeline
techseoconnect
PRO
0
200
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
230
23k
Learning to Love Humans: Emotional Interface Design
aarron
275
41k
Ruling the World: When Life Gets Gamed
codingconduct
0
260
DBのスキルで生き残る技術 - AI時代におけるテーブル設計の勘所
soudai
PRO
66
55k
State of Search Keynote: SEO is Dead Long Live SEO
ryanjones
0
210
Leo the Paperboy
mayatellez
7
1.9k
Deep Space Network (abreviated)
tonyrice
0
210
The Cult of Friendly URLs
andyhume
79
6.9k
Designing for Timeless Needs
cassininazir
1
260
The Language of Interfaces
destraynor
162
27k
Transcript
!LVSJ@UUFSɹ ༌ೖ࣮ߦؔ੫දΛ .$1αʔόʔԽͯ͠Έͨ
ࣗݾհ ͘Γͬͨʔ w 9 !LVSJ@UUFS ɹIUUQTRMJUSFNF w ࣄ w ߓྲྀݿاۀ
w ݱಜɺྫྷౚݿӦۀͳͲΛܦͯݱࡏ*5ௐୡ w ϓϩάϥϛϯά w झຯͰ)POP 1ZUIPOͳͲɻ w 8PSLFSTY)POP9ͰݸਓϒϩάͳͲެ։ ݄ାʹͯ
࣍ w ༌ೖ࣮ߦؔ੫දʹ͍ͭͯ w .$1࣮֓ཁ w σϞ w ධՁ
༌ೖ࣮ߦؔ੫දʹ͍ͭͯ
༌ೖ՟͕ྲྀ௨͢Δ·Ͱ ւ֎ อ੫Ҭ ʢ֎ࠃ՟Λஔ͚Δॴʣ ɾίϯςφϠʔυ ɾۭߓ ɾྲྀݿɹʜFUD ࠃ ࢢ ༌ૹɾൖೖ
ൖग़ ༌ೖ ਃࠂ ੫ؔ ৹ࠪ ࠃ ؔ੫ ೲ ༌ೖ ڐՄ ͜͜Ͱར༻͢Δͷ͕༌ೖ࣮ߦؔ੫දʢλϦϑʣ ՙओʢࣾɾϝʔΧʔʣ͕ ྲྀۀऀʹ༌ೖਃࠂखଓ͖ Λҕୗ͢Δͷ͕Ұൠతɻ
w ༌ೖ͞ΕΔશͯͷʹ͍ͭ ͯɺܻ̕ͷ౷ܭ൪߸ͱؔ੫ ΛఆΊͨҰཡද w ̓̕ΧςΰϦͰߏ w ༌ೖਃࠂ࣌ʹඞཁͳؔ੫Λௐ ΔͨΊͷඞਢπʔϧ w
੫ؔ8&#Ͱແྉެ։ɻ w ʮ༌ೖ࣮ߦؔ੫දʯͰ͙͙Δ ͱҰ൪্ʹग़ͯ͘Δ ༌ೖ࣮ߦؔ੫දʢλϦϑʣͱʁ IUUQTXXXDVTUPNTHPKQUBSJ ff @@JOEFYIUN
ύελͷ༌ೖ੫൪Λಛఆ͢Δ߹ (15Ͱੜ
ύελখഴคͰग़དྷ͍ͯΔɻୈྨΛΈΔɻ
ʹʼʹ֘ɹؔ੫جຊԁLH850ՃໍࠃԁLH ੫ϦϯΫΛ։͘ͱIUNMςʔϒϧ͕͋Γɺৄࡉͳ͕ܝࡌ
w ίʔυ छྨఔ͋ΓɺਓྗͰͷಛఆ͚ͬ͜ ͏͕͔͔࣌ؒΔɻ w ༌ೖ݅૿Ճɻͷຊʹ͓͚Δ༌ೖਃࠂ݅ ɺߤۭɾւ্Λซͤԯ ສ݅ w ʢࢀߟɿIUUQTXXXOBDDTKQBSDIJWFTVOLZPV
TIJSZPQEGʣ ՝ͱϞνϕʔγϣϯ ϦϞʔτ.$1αʔόʔԽ͢Εͷಛఆޮ ԽͰ͖ͦ͏ͳؾ͕ͨ͠ɻ ॻ੶͋Δɻ ஈɿ ԁ
.$1࣮֓ཁ
༌ೖ࣮ߦؔ੫දΛσʔλԽ IPOPNDQϔϧύʔͰΩʔϫʔυݕࡧΛ࣮ $MPVE fl BSF8PSLFSTʹσϓϩΠ ࣮ͷ֓ཁ
ߏɻDTWΑΓKTPO
1ZUIPOͷ#FBVUJGVMTPVQͰ8&#εΫϨΠϐϯάͯ͠σʔλԽ UETUZMFlQBEEJOHMFGUFNzύελʢՃʹΑΔௐཧΛʜʣUE-&7&- UETUZMFlQBEEJOHMFGUFNͦͷଞͷͷUE-&7&- UETUZMFQBEEJOHMFGUFNͦͷଞͷͷUE-&7&- UETUZMFQBEEJOHMFGUFN - ϚΧϩχٴͼεύήοςΟUE-&7&- ࢠؔʢʹͷਂ͞ʣIUNMTUZMFͷQBEEJOHͷͱlzͰఆ def extract_level(td)
-> int: """style="padding-left:…em" ͔Β֊ϨϕϧΛͰฦ͢""" # paddingͷΛൈ͖ग़͢ m = re.search(r"padding-left\s*:\s*([\d.]+)\s*em", td.get("style", "")) level = int(float(m.group(1))) if m else 0 # - ͷΛ͑Δ cnt = 0 for c in td.text.strip(): if c == "−": cnt += 1 else: break return level + cnt
هͨ͠-&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": "εύήοςΟ" } ] } ] } ] } ] } ] }
̍ྨɿಈʢੜ͖͍ͯΔͷʹݶΔʣʙ̓̕ྨɿඒज़ɺऩूٴͼͭ͜ͱ͏
)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Ͱ৴
w ੈʹʮ8&#λϦϑʯͱݺΕΔެ ࣜݕࡧαΠτଘࡏ͢Δɻ w ໊͕ͦͷ··ࡌ͍ͬͯͳ͍έ ʔεଟ͍ɻ w ྫ͑νϡʔϋΠͰݕࡧͯ͠ώ οτ͠ͳ͍ɻ w
.$1νϡʔϋΠ মய Ξϧίʔ ϧҿྉͱʮΑ͠ͳʹʯྨޠݕࡧɻ w ݟ͔ͭΔ·ͰʮؤுΔʯɻ .$1ݕࡧπʔϧͷಛͱ௨ৗͱͷҧ͍
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 ); ɹɹɹ…লུ );
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), }), }, ], }; } );
None
σϞ
ධՁ
w γϯϓϧͳϓϩάϥϜ͕ͩɺް͍λϦϑදΛΊ͘Δखؒল͚Δ w ࣾͷ༗ࣝऀʢ௨ؔ࢜ʣʹͬͯΒͬͨͱ͜Ζײ৮ͩͬͨɻ w ˋٻΊͣௐࠪͷऔֻ͔ͬΓͰ͑Εे༗༻ɻ w ίετ΄΅͔͔Βͳ͍ͱࢥΘΕΔɻ ධՁ
w HJUIVCൃදݩͱͳͬͨιʔείʔυશจ w IUUQTHJUIVCDPNRMJUSFKBQBOUBSJ ff NDQ
͋Γ͕ͱ͏͍͟͝·ͨ͠