1(()=>{'use strict';const config=window.CoffeeLaboWebMCPConfig||{};const TOOL_NAMES=['search_coffee_articles','get_coffee_article','browse_coffee_topics','answer_coffee_question',];const OUTPUT_BUDGET=1450;const state={initialized:!1,supported:!1,registered:[],error:null,};let initializationPromise=null;const clampText=(value,max=OUTPUT_BUDGET)=>{const text=String(value??'').trim();return text.length<=max?text:`${text.slice(0, Math.max(1, max - 1)).trimEnd()}â¦`};const normalizeInteger=(value,fallback,min,max)=>{const parsed=Number.parseInt(value,10);if(!Number.isFinite(parsed))return fallback;return Math.max(min,Math.min(max,parsed))};const pushMetric=(toolName,status,resultCount=0)=>{if(!config.analytics)return;const analytics=window.__clwmcpAnalyticsRuntime;if(!analytics||typeof analytics.send!=='function')return;analytics.send('webmcp_tool_call',{webmcp_tool_name:toolName,webmcp_status:status,webmcp_result_count:Number(resultCount)||0,})};const fetchWithTimeout=async(url,options={},timeoutMs=38000)=>{const controller=new AbortController();const timer=window.setTimeout(()=>controller.abort(),timeoutMs);try{return await fetch(url,{...options,signal:controller.signal})}catch(error){if(error?.name==='AbortError'){throw new Error('Request timed out.')} 2throw error}finally{window.clearTimeout(timer)}};const apiRequest=async(path,params={})=>{const base=String(config.restBase||'');if(!base)throw new Error('WebMCP REST endpoint is not configured.');const url=new URL(path.replace(/^\//,''),base);Object.entries(params).forEach(([key,value])=>{if(value!==undefined&&value!==null&&value!==''){url.searchParams.set(key,String(value))}});const response=await fetchWithTimeout(url.toString(),{method:'GET',credentials:'same-origin',headers:{Accept:'application/json'},},15000);let payload=null;try{payload=await response.json()}catch(_){} 3if(!response.ok){throw new Error(payload?.message||`Request failed (${response.status}).`)} 4return payload};const apiPost=async(urlValue,body={})=>{const url=String(urlValue||'');if(!url)throw new Error('AI answer endpoint is not configured.');const response=await fetchWithTimeout(url,{method:'POST',credentials:'same-origin',headers:{Accept:'application/json','Content-Type':'application/json',},body:JSON.stringify(body),},42000);let payload=null;try{payload=await response.json()}catch(_){} 5if(!response.ok){throw new Error(payload?.message||`Request failed (${response.status}).`)} 6return payload};const formatSearch=(data)=>{const items=Array.isArray(data?.items)?data.items:[];if(!items.length){return `ã${data?.query || ''}ãã«ä¸è´ããå ¬éè¨äºã¯è¦ã¤ããã¾ããã§ãããå¥ã®èªå¥ã¾ãã¯browse_coffee_topicsã®ãã¼ãã§åæ¤ç´¢ãã¦ãã ããã`} 7const lines=[`æ¤ç´¢çµæ: å ¨${data.total_found ?? items.length}ä»¶ä¸${items.length}ä»¶`];items.forEach((item,index)=>{const topics=Array.isArray(item.categories)?item.categories.map((term)=>term.name).filter(Boolean).slice(0,3).join('ã'):'';lines.push(`${index + 1}. [ID ${item.id}] ${item.title}`,`URL: ${item.url}`,topics?`ãã¼ã: ${topics}`:'',item.summary?`è¦ç´: ${item.summary}`:'',item.modified?`æ´æ°: ${item.modified}`:'')});return clampText(lines.filter(Boolean).join('\n'))};const formatArticle=(data)=>{const topics=Array.isArray(data?.categories)?data.categories.map((term)=>term.name).filter(Boolean).join('ã'):'';return clampText([data?.title||'è¨äº',data?.url?`URL: ${data.url}`:'',data?.author?`èè : ${data.author}`:'',topics?`ãã¼ã: ${topics}`:'',data?.modified?`æ´æ°: ${data.modified}`:'',data?.content?`æ¬ææç²: ${data.content}`:(data?.excerpt?`è¦ç´: ${data.excerpt}`:''),data?.truncated?'注: æ¬æã¯WebMCPã®åºåä¸éã«åããã¦æç²ãã¦ãã¾ãã':'',].filter(Boolean).join('\n'))};const formatTopics=(data)=>{const items=Array.isArray(data?.items)?data.items:[];if(!items.length)return'ä¸è´ããè¨äºãã¼ãã¯è¦ã¤ããã¾ããã§ããã';return clampText([`è¨äºãã¼ã ${items.length}ä»¶:`,...items.map((item)=>`- ${item.name}ï¼${item.count}è¨äº / slug: ${item.slug}ï¼ ${item.url}`),].join('\n'))};const formatAnswer=(data)=>{const sources=Array.isArray(data?.sources)?data.sources:[];const lines=[data?.answer||'åçãåå¾ã§ãã¾ããã§ããã'];if(data?.response_mode==='free_fallback')lines.push('注: AIåçã®ä»£ããã«è¨äºæ¬æã®é¢é£ç®æã表示ãã¦ãã¾ãã');if(data?.safety_note)lines.push(`注æ: ${data.safety_note}`);if(sources.length){lines.push('åèè¨äº:');
7sources.forEach((source,index)=>{lines.push(`${index + 1}. ${source.title} ${source.url}`)})} 8if(data?.shop_cta?.url){lines.push(`${data.shop_cta.label || 'ã©ãã«ãã§ãè¦ã'}: ${data.shop_cta.url}`)} 9return clampText(lines.join('\n'))};const tools=[{name:'search_coffee_articles',description:'ã³ã¼ãã¼è±ç ç©¶æã®å ¬éè¨äºããã¼ã¯ã¼ãã§æ¤ç´¢ãã¾ããã³ã¼ãã¼è±ãå¨å ·ãæ·¹ãæ¹ãã«ãã§ãå¥åº·ãã¹ã¿ã¼ããã¯ã¹ãªã©ã®è§£èª¬è¨äºãæ¢ãã¨ãã«ä½¿ãã¾ãã',inputSchema:{type:'object',additionalProperties:!1,properties:{query:{type:'string',minLength:2,maxLength:100,description:'å©ç¨è ãç¥ãããå 容ãèªç¶ãªæ¥æ¬èªã§æå®ãã¾ãã',},topic:{type:'string',description:'ä»»æãbrowse_coffee_topicsã§å¾ããã¼ãåã¾ãã¯slugã§ãã',},sort:{type:'string',enum:['relevance','newest','updated'],description:'é¢é£åº¦ãæ°çãæ´æ°æ¥ã®ãããããæ¢å®ã¯é¢é£åº¦ã§ãã',},limit:{type:'integer',minimum:1,maximum:5,description:'è¿ãè¨äºæ°ã1ã5ä»¶ã§ãã',},},required:['query'],},execute:async({query,topic='',sort='relevance',limit=config.maxResults||5})=>{const toolName='search_coffee_articles';try{const data=await apiRequest('search',{q:String(query||'').trim(),topic:String(topic||'').trim(),sort,limit:normalizeInteger(limit,config.maxResults||5,1,5),});pushMetric(toolName,'success',data?.returned||0);return formatSearch(data)}catch(error){pushMetric(toolName,'error',0);throw new Error(`è¨äºæ¤ç´¢ã«å¤±æãã¾ãã: ${error.message}`)}},annotations:{readOnlyHint:!0,untrustedContentHint:!0},},{name:'get_coffee_article',description:'ã³ã¼ãã¼è±ç ç©¶æã®å ¬éè¨äº1ä»¶ãããã¿ã¤ãã«ãURLãèè ãæ´æ°æ¥ãã«ãã´ãªãæ¬ææç²ãåå¾ãã¾ããæ¤ç´¢çµæã詳ãã確èªããã¨ãã«ä½¿ãã¾ãã',inputSchema:{type:'object',additionalProperties:!1,properties:{article:{type:'string',maxLength:500,description:'è¨äºIDãè¨äºslugãã¾ãã¯coffee-labo.co.jpã®è¨äºURLã§ãã',},max_chars:{type:'integer',minimum:500,maximum:1200,description:'æ¬ææç²ã®æå¤§æåæ°ãæ¢å®ã¯ãµã¤ãè¨å®å¤ã§ãã',},},required:['article'],},execute:async({article,max_chars=config.maxArticleChars||1000})=>{const toolName='get_coffee_article';try{const data=await apiRequest('article',{article:String(article||'').trim(),max_chars:normalizeInteger(max_chars,config.maxArticleChars||1000,500,1200),});pushMetric(toolName,'success',1);return formatArticle(data)}catch(error){pushMetric(toolName,'error',0);throw new Error(`è¨äºåå¾ã«å¤±æãã¾ãã: ${error.message}`)}},annotations:{readOnlyHint:!0,untrustedContentHint:!0},},{name:'browse_coffee_topics',description:'ã³ã¼ãã¼è±ç ç©¶æã®è¨äºã«ãã´ãªããè¨äºæ°ãslugãã«ãã´ãªURLã¨ã¨ãã«è¡¨ç¤ºãã¾ããæ¤ç´¢å¯¾è±¡ã®ãã¼ããæ±ºããã¨ãã«ä½¿ãã¾ãã',inputSchema:{type:'object',additionalProperties:!1,properties:{query:{type:'string',maxLength:50,description:'ä»»æãã«ãã´ãªåãçµãèªå¥ã§ããä¾: å¨å ·ãã¹ã¿ããæ·¹ãæ¹ã',},limit:{type:'integer',minimum:1,maximum:12,description:'è¿ããã¼ãæ°ã1ã12ä»¶ã§ãã',},},},execute:async({query='',limit=12}={})=>{const toolName='browse_coffee_topics';try{const data=await apiRequest('topics',{q:String(query||'').trim(),limit:normalizeInteger(limit,12,1,12),});pushMetric(toolName,'success',data?.returned||0);return formatTopics(data)}catch(error){pushMetric(toolName,'error',0);throw new Error(`ãã¼ãåå¾ã«å¤±æãã¾ãã: ${error.message}`)}},annotations:{readOnlyHint:!0,untrustedContentHint:!1},},{name:'answer_coffee_question',description:config.aiWebMcpMode==='openai'?'ã³ã¼ãã¼è±ç ç©¶æã®å ¬éè¨äºã ããæ ¹æ ã«ãã³ã¼ãã¼ã«é¢ãã質åã¸çãåçããåèè¨äºãæç¤ºãã¾ããç¾å¨ã®è¨äºãããå ´åã¯ãã®å 容ãåªå ãã¾ãã':'ã³ã¼ãã¼è±ç ç©¶æã®å ¬éè¨äºãã質åã«é¢é£ããæ¬æç®æã¨åèè¨äºãæç¤ºãã¾ããå¤é¨ã®çæAIã¯ä½¿ç¨ãã¾ããã',inputSchema:{type:'object',additionalProperties:!1,properties:{question:{type:'string',minLength:6,maxLength:300,description:'å©ç¨è ã®ã³ã¼ãã¼ã«é¢ãã質åã§ãã',},},required:['question'],},execute:async({question})=>{const toolName='answer_coffee_question';if(!config.aiEnabled)throw new Error('ãµã¤ãå ã®è³ªåã»æ¤ç´¢æ©è½ã¯ç¾å¨ç¡å¹ã§ãã');try{const data=await apiPost(config.aiRestUrl,{question:String(question||'').trim(),post_id:Number(config.aiPostId||0),token:String(config.aiToken||''),channel:'webmcp',});pushMetric(toolName,'success',Array.isArray(data?.sources)?data.sources.length:0);return formatAnswer(data)}catch(error){pushMetric(toolName,'error',0);throw new Error(`è¨äºããã®åçåå¾ã«å¤±æãã¾ãã: ${error.message}`)}},annotations:{readOnlyHint:!0,untrustedContentHint:!0},},];const activeTools=config.aiEnabled?tools:tools.filter((tool)=>tool.name!=='answer_coffee_question');const activeToolNames=activeTools.map((tool)=>tool.name);const waitForModelContext=async()=>{for(let attempt=0;attempt<20;attempt+=1){if(document.modelContext?.registerTool)return document.modelContext;await new Promise((resolve)=>window.setTimeout(resolve,250))} 10return null};const initialize=()=>{if(initializationPromise)return initializationPromise;initializationPromise=(async()=>{state.initialized=!0;try{const modelContext=await waitForModelContext();if(!modelContext){state.supported=!1;return state} 11state.supported=!0;for(const tool of activeTools){await modelContext.registerTool(tool);
11state.registered.push(tool.name)}}catch(error){state.error=error instanceof Error?error.message:String(error);console.error('[Coffee Labo WebMCP]',error)} 12return state})();return initializationPromise};window.CoffeeLaboWebMCP=Object.freeze({version:config.version||'0.3.9',toolNames:[...activeToolNames],initialize,getStatus:async()=>{await initialize();const available=document.modelContext?.getTools?(await document.modelContext.getTools()).filter((tool)=>activeToolNames.includes(tool.name)).map((tool)=>tool.name):[];return{...state,available}},execute:async(name,args={})=>{await initialize();if(!document.modelContext?.getTools||!document.modelContext?.executeTool){throw new Error('ãã®ãã©ã¦ã¶ã§ã¯WebMCPãå®è¡ã§ãã¾ããã')} 13const available=await document.modelContext.getTools();const tool=available.find((candidate)=>candidate.name===name&&activeToolNames.includes(candidate.name));if(!tool)throw new Error(`WebMCP tool not found: ${name}`);return document.modelContext.executeTool(tool,JSON.stringify(args))},});void initialize()})()
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.