somamcp 1.0.13 → 1.0.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -353,7 +353,7 @@ type GithubFeedbackOptions = {
353
353
  baseUrl?: string;
354
354
  defaultLabels?: ReadonlyArray<string>;
355
355
  fetchImpl?: typeof fetch;
356
- getToken: () => string | undefined;
356
+ getToken: () => Option<string>;
357
357
  repo: `${string}/${string}`;
358
358
  };
359
359
  declare const createGithubFeedback: (options: GithubFeedbackOptions) => FeedbackProvider;
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import{t as e}from"./backend-G2JeUHpG.js";import{Option as t,Ref as n,Try as r}from"functype";import{Client as i}from"@modelcontextprotocol/sdk/client/index.js";import{StreamableHTTPClientTransport as a}from"@modelcontextprotocol/sdk/client/streamableHttp.js";import{createDirectConsoleLogger as o}from"functype-log";import{appendFile as s,mkdir as c,readFile as l}from"node:fs/promises";import{dirname as u,extname as d}from"node:path";import{z as f}from"zod";const p=e=>e.json({error:`Unauthorized`},401),m=e=>async(t,n)=>{if(!e)return p(t);try{await e(t.env?.incoming??t.req.raw)}catch{return p(t)}await n()},h=(e,t,n)=>{t.forEach(t=>{switch(t.protected&&e.use(t.path,m(n)),t.type){case`static`:e.get(t.path,e=>e.body(t.content,{headers:{"Content-Type":t.contentType}}));break;case`dynamic`:e.get(t.path,e=>t.handler(e));break;case`directory`:break}})},g=(e,t,n)=>({handler:()=>{let r=_(e(),t(),n());return new Response(r,{headers:{"Content-Type":`text/html; charset=utf-8`}})},path:`/dashboard`,protected:!0,type:`dynamic`}),_=(e,t,n)=>`<!DOCTYPE html>
1
+ import{t as e}from"./backend-G2JeUHpG.js";import{Map as t,Option as n,Ref as r,Set as i,Try as a,Tuple as o}from"functype";import{Client as s}from"@modelcontextprotocol/sdk/client/index.js";import{StreamableHTTPClientTransport as c}from"@modelcontextprotocol/sdk/client/streamableHttp.js";import{createDirectConsoleLogger as l}from"functype-log";import{appendFile as u,mkdir as d,readFile as f}from"node:fs/promises";import{dirname as p,extname as m}from"node:path";import{z as h}from"zod";const g=e=>e.json({error:`Unauthorized`},401),_=e=>async(t,r)=>{if(!e)return g(t);let i=n(t.env).flatMap(e=>n(e.incoming)).orElse(t.req.raw);if((await a.fromPromise(e(i))).isFailure())return g(t);await r()},ee=(e,t,n)=>{t.forEach(t=>{switch(t.protected&&e.use(t.path,_(n)),t.type){case`static`:e.get(t.path,e=>e.body(t.content,{headers:{"Content-Type":t.contentType}}));break;case`dynamic`:e.get(t.path,e=>t.handler(e));break;case`directory`:break}})},v=(e,t,n)=>({handler:()=>{let r=y(e(),t(),n());return new Response(r,{headers:{"Content-Type":`text/html; charset=utf-8`}})},path:`/dashboard`,protected:!0,type:`dynamic`}),y=(e,t,n)=>`<!DOCTYPE html>
2
2
  <html lang="en">
3
3
  <head>
4
4
  <meta charset="UTF-8">
@@ -32,7 +32,7 @@ import{t as e}from"./backend-G2JeUHpG.js";import{Option as t,Ref as n,Try as r}f
32
32
  <div class="card">
33
33
  <h2>Health</h2>
34
34
  <div class="metric"><span class="metric-label">Status:</span> <span class="status ${e.status}">${e.status}</span></div>
35
- <div class="metric"><span class="metric-label">Uptime:</span> <span class="metric-value">${v(e.uptime)}</span></div>
35
+ <div class="metric"><span class="metric-label">Uptime:</span> <span class="metric-value">${b(e.uptime)}</span></div>
36
36
  <div class="metric"><span class="metric-label">Sessions:</span> <span class="metric-value">${e.activeSessions}</span></div>
37
37
  <div class="metric"><span class="metric-label">Gateways:</span> <span class="metric-value">${e.gateways.connected}/${e.gateways.total}</span></div>
38
38
  </div>
@@ -54,9 +54,9 @@ import{t as e}from"./backend-G2JeUHpG.js";import{Option as t,Ref as n,Try as r}f
54
54
  </div>`:``}
55
55
  </div>
56
56
  </body>
57
- </html>`,v=e=>{let t=Math.floor(e/1e3),n=Math.floor(t/60),r=Math.floor(n/60),i=Math.floor(r/24);return i>0?`${String(i)}d ${String(r%24)}h`:r>0?`${String(r)}h ${String(n%60)}m`:n>0?`${String(n)}m ${String(t%60)}s`:`${String(t)}s`},y=`/health`,b=`/health/detail`,ee=(e,t=y)=>({handler:()=>{let t=e(),n=t.status===`running`?200:503;return new Response(JSON.stringify({name:t.name,status:t.status}),{headers:{"Content-Type":`application/json`},status:n})},path:t,type:`dynamic`}),x=(e,t=b)=>({handler:()=>{let t=e(),n=t.status===`running`?200:503;return new Response(JSON.stringify(t),{headers:{"Content-Type":`application/json`},status:n})},path:t,protected:!0,type:`dynamic`}),S=`/info`,C=(e,t=S)=>({handler:()=>new Response(JSON.stringify(e()),{headers:{"Content-Type":`application/json`},status:200}),path:t,protected:!0,type:`dynamic`}),w=e=>{let t=process.env[e];return t&&t.length>0?t:void 0},T=()=>({branch:w(`SOMAMCP_BUILD_BRANCH`),commit:w(`SOMAMCP_BUILD_COMMIT`),date:w(`SOMAMCP_BUILD_DATE`),environment:w(`SOMAMCP_ENVIRONMENT`)}),te=e=>{let t=T();return{branch:e?.branch??t.branch,commit:e?.commit??t.commit,date:e?.date??t.date,environment:e?.environment??t.environment}},E=()=>({arch:process.arch,nodeVersion:process.version,platform:process.platform}),D=(e,o)=>{let s=n(t.none()),c=n(t.none()),l=n([]),u=n(`disconnected`),d=n(t.none()),f=e.name??e.id,p=()=>{let n=e.reconnectIntervalMs??5e3;d.set(t(setTimeout(()=>{m.connect()},n)))},m={get config(){return e},get info(){return{id:e.id,name:f,remoteTools:l.get().map(e=>({description:e.description,name:e.name})),status:u.get(),url:e.url}},get name(){return f},get status(){return u.get()},get tools(){return l.get()},async callTool(t,n={}){let r=s.get();if(r.isEmpty||u.get()!==`connected`)throw Error(`Gateway ${e.id} is not connected`);return r.orThrow(Error(`Gateway ${e.id} is not connected`)).callTool({arguments:n,name:t})},async connect(){if(u.get()===`connected`)return;u.set(`connecting`);let n=Date.now();(await r.fromPromise((async()=>{let n=new a(new URL(e.url));c.set(t(n));let r=new i({name:`soma-gateway-${e.id}`,version:`1.0.0`});s.set(t(r)),await r.connect(n);let o=await r.listTools();l.set(o.tools)})())).fold(t=>{u.set(`error`),o.recordEvent({data:{id:e.id,url:e.url},error:t instanceof Error?t.message:String(t),name:f,timestamp:n,type:`gateway.error`}),e.reconnect!==!1&&p()},()=>{u.set(`connected`),o.recordEvent({data:{id:e.id,remoteToolCount:l.get().length,url:e.url},durationMs:Date.now()-n,name:f,timestamp:n,type:`gateway.connect`})})},async disconnect(){d.get().match({None:()=>void 0,Some:e=>clearTimeout(e)}),d.set(t.none());let n=s.get();n.isSome()&&await r.fromPromise(n.value.close()),s.set(t.none()),c.set(t.none()),l.set([]),u.set(`disconnected`),o.recordEvent({data:{id:e.id},name:f,timestamp:Date.now(),type:`gateway.disconnect`})}};return m},O=e=>{let n=new Map;return{get connectedCount(){return[...n.values()].filter(e=>e.status===`connected`).length},get totalCount(){return n.size},add(t){let r=D(t,e);return n.set(t.id,r),r},async connectAll(){await Promise.allSettled([...n.values()].map(e=>e.connect()))},async disconnectAll(){await Promise.allSettled([...n.values()].map(e=>e.disconnect()))},get(e){return t(n.get(e))},getAll(){return[...n.values()]},getInfoAll(){return[...n.values()].map(e=>e.info)}}},k=e=>({flush:async()=>{await Promise.all(e.map(e=>e.flush?e.flush():Promise.resolve()))},recordEvent:t=>{e.forEach(e=>e.recordEvent(t))}}),A=e=>({flush:()=>Promise.resolve(),recordEvent:t=>{let n={durationMs:t.durationMs,eventName:t.name,timestamp:new Date(t.timestamp).toISOString(),type:t.type,...t.sessionId&&{sessionId:t.sessionId},...t.requestId&&{requestId:t.requestId},...t.errorCategory&&{errorCategory:t.errorCategory},...t.data};t.error?e.withError(Error(t.error)).error(t.type,n):e.info(t.type,n)}}),j=(e=`[soma]`)=>A(o({prefix:e,stream:`stderr`})),M=e=>{if(e instanceof Error){let t=e.message.toLowerCase();if(t.includes(`validation`)||t.includes(`invalid`)||t.includes(`schema`))return`validation`;if(t.includes(`timeout`)||t.includes(`timed out`)||t.includes(`etimedout`))return`timeout`;if(t.includes(`gateway`)||t.includes(`not connected`)||t.includes(`econnrefused`)||t.includes(`connection refused`))return`gateway`;if(t.includes(`auth`)||t.includes(`unauthorized`)||t.includes(`forbidden`))return`auth`;if(t.includes(`not found`)||t.includes(`404`))return`not_found`}return typeof e==`object`&&e&&`name`in e&&e.name===`UserError`?`validation`:`internal`},N=(e,t)=>{switch(e){case`validation`:return[`Check the tool's parameter schema and provide valid input`];case`timeout`:return[`The operation timed out. Try again or reduce the scope of the request`];case`gateway`:return[`Gateway is ${t?.gatewayStatus??`unavailable`}. The remote service may be down`,`Try again later or check the remote service status`];case`auth`:return[`Authentication failed. Check credentials or permissions`];case`not_found`:return[`The requested resource was not found. Verify the identifier`];case`internal`:return[`An internal error occurred. The tool maintainer should investigate`]}},P=(e,t)=>{let n=M(e),r=e instanceof Error?e.message:String(e),i=N(n,t),a={...t?.gatewayStatus&&{gatewayStatus:t.gatewayStatus},...t?.toolName&&{toolName:t.toolName}};return{errorCategory:n,message:r,...Object.keys(a).length>0&&{relatedState:a},suggestions:i}},F=e=>{let r=n([]),i=n(t.none()),a=n(!1),o=async()=>{let t=r.getAndSet([]);if(t.length===0)return;a.get()||(await c(u(e.filePath),{recursive:!0}),a.set(!0));let n=`${t.map(e=>JSON.stringify(e)).join(`
58
- `)}\n`;await s(e.filePath,n)},l=()=>{i.get().isSome()||i.set(t(setTimeout(()=>{i.set(t.none()),o()},e.flushIntervalMs??1e3)))};return{flush:async()=>{i.get().match({None:()=>void 0,Some:e=>clearTimeout(e)}),i.set(t.none()),await o()},recordEvent:e=>{r.update(t=>[...t,e]),l()}}},I={flush:()=>Promise.resolve(),recordEvent:()=>{}},L=(e,t)=>!t||t.length===0?e:Object.fromEntries(Object.entries(e).map(([e,n])=>[e,t.includes(e)?`[REDACTED]`:n])),R=(e,t=1e4)=>{let n=typeof e==`string`?e:JSON.stringify(e);return n&&n.length>t?`${n.slice(0,t)}...[truncated, ${n.length} total chars]`:e},z=e=>r.fromPromise(e),B=(e,t,n)=>({...e,execute:async(r,i)=>{let a=n?.captureLevel??`full`;if(a===`none`)return e.execute(r,i);let o=Date.now(),{requestId:s,sessionId:c}=i,l=a===`full`?L(r,n?.redactInputFields):void 0;return(await z(e.execute(r,i))).fold(n=>{let r=P(n,{toolName:e.name});return t.recordEvent({data:{name:e.name},durationMs:Date.now()-o,error:r.message,errorCategory:r.errorCategory,errorStack:n.stack,input:l,name:e.name,requestId:s,sessionId:c,timestamp:o,type:`tool.error`}),{content:[{text:JSON.stringify(r,null,2),type:`text`}],isError:!0}},r=>(t.recordEvent({data:{name:e.name},durationMs:Date.now()-o,input:l,name:e.name,output:a===`full`?R(r,n?.maxOutputSize):void 0,requestId:s,sessionId:c,timestamp:o,type:`tool.execute`}),r))}}),V=(e,t)=>({...e,load:async n=>{let r=Date.now();return(await z(e.load(n))).fold(n=>{let i=P(n);throw t.recordEvent({data:{name:e.name,uri:e.uri},durationMs:Date.now()-r,error:i.message,errorCategory:i.errorCategory,errorStack:n.stack,name:e.name,timestamp:r,type:`resource.error`}),n},n=>(t.recordEvent({data:{name:e.name,uri:e.uri},durationMs:Date.now()-r,name:e.name,timestamp:r,type:`resource.load`}),n))}}),H=(e,t)=>({...e,load:async(n,r)=>{let i=Date.now();return(await z(e.load(n,r))).fold(n=>{let r=P(n);throw t.recordEvent({data:{name:e.name},durationMs:Date.now()-i,error:r.message,errorCategory:r.errorCategory,errorStack:n.stack,name:e.name,timestamp:i,type:`prompt.error`}),n},n=>(t.recordEvent({data:{name:e.name},durationMs:Date.now()-i,name:e.name,timestamp:i,type:`prompt.load`}),n))}}),U=e=>r.fromPromise(e),W=(e,t)=>{let n=e.config.toolPrefix??`${e.config.id}_`;return e.tools.map(r=>({annotations:{openWorldHint:!0,readOnlyHint:!0},description:`[${e.name}] ${r.description??`Remote tool`}`,execute:async i=>{let a=Date.now(),o=`${n}${r.name}`;return(await U(e.callTool(r.name,i))).fold(n=>{let s=P(n,{gatewayStatus:e.status,toolName:r.name});return t?.recordEvent({data:{gateway:e.config.id,remoteTool:r.name},durationMs:Date.now()-a,error:s.message,errorCategory:s.errorCategory,errorStack:n.stack,input:i,name:o,timestamp:a,type:`tool.error`}),{content:[{text:JSON.stringify(s,null,2),type:`text`}],isError:!0}},n=>(t?.recordEvent({data:{gateway:e.config.id,remoteTool:r.name},durationMs:Date.now()-a,input:i,name:o,output:n,timestamp:a,type:`tool.execute`}),JSON.stringify(n,null,2)))},name:`${n}${r.name}`}))},G=(e,t=`info`)=>({annotations:{readOnlyHint:!0},description:`Returns identity and build information for this server (name, version, build commit, runtime, capability counts)`,execute:()=>Promise.resolve(JSON.stringify(e(),null,2)),name:t}),K=t=>{let{artifacts:r,backendOptions:i,build:a,enableDashboard:o,enableHealthEndpoint:s,enableInfoEndpoint:c,enableIntrospection:l,gateways:u,healthDetailPath:d,healthPath:f,infoPath:p,introspectionPrefix:m,logLayer:_,telemetry:v,...y}=t,b=y.name,S=y.version,w=te(a),T=E(),D=m??``,k=v??(_?A(_):I),j=e(y,i),M=O(k),N=[],P=[],F=[],L=n(0);u?.forEach(e=>M.add(e));let R=()=>{let e=L.get(),t=e>0?Date.now()-e:0;return{activeSessions:j.sessions.length,gateways:{connected:M.connectedCount,total:M.totalCount},name:b,startedAt:e,status:j.serverState,uptime:t}},z=()=>({prompts:F,resources:P,tools:N}),U=()=>({build:w,capabilities:{prompts:F.length,resources:P.length,tools:N.length},name:b,runtime:T,version:S});l!==!1&&j.addTool(G(()=>U(),`${D}info`));let K=[...r??[]];s!==!1&&(K.push(ee(()=>R(),f)),K.push(x(()=>R(),d))),c!==!1&&K.push(C(()=>U(),p)),o!==!1&&K.push(g(()=>R(),()=>z(),()=>M.getInfoAll())),K.length>0&&h(j.getApp(),K,y.authenticate),j.on(`connect`,({session:e})=>{k.recordEvent({data:{sessionId:e.sessionId},name:b,timestamp:Date.now(),type:`session.connect`})}),j.on(`disconnect`,({session:e})=>{k.recordEvent({data:{sessionId:e.sessionId},name:b,timestamp:Date.now(),type:`session.disconnect`})});let q=e=>{let t=B(e,k,`captureConfig`in e?e.captureConfig:void 0);j.addTool(t),N.push({description:e.description,name:e.name})},J=e=>{let t=V(e,k);j.addResource(t),P.push({description:e.description,name:e.name,uri:e.uri})},Y=e=>{let t=H(e,k);j.addPrompt(t),F.push({description:e.description,name:e.name})};return{get name(){return b},get serverState(){return j.serverState},get sessions(){return j.sessions},addPrompt:Y,addPrompts:e=>{e.forEach(Y)},addResource:J,addResources:e=>{e.forEach(J)},addResourceTemplate:(...e)=>{j.addResourceTemplate(...e)},addTool:q,addTools:e=>{e.forEach(e=>q(e))},getApp:()=>j.getApp(),getCapabilities:z,getGatewayManager:()=>M,getHealth:R,getInfo:U,removePrompt:e=>{j.removePrompt(e)},removeResource:e=>{j.removeResource(e)},removeTool:e=>{j.removeTool(e)},async start(e){L.set(Date.now()),k.recordEvent({name:b,timestamp:L.get(),type:`server.start`}),await j.start(e),await M.connectAll(),M.getAll().filter(e=>e.status===`connected`&&e.config.proxyTools!==!1).forEach(e=>{W(e,k).forEach(e=>j.addTool(e))})},async stop(){await M.disconnectAll(),await j.stop(),k.recordEvent({name:b,timestamp:Date.now(),type:`server.stop`}),k.flush&&await k.flush()}}};var q=class extends Error{constructor(e){super(e),this.name=`UserError`}};const J={".avif":`image/avif`,".bmp":`image/bmp`,".gif":`image/gif`,".ico":`image/x-icon`,".jpeg":`image/jpeg`,".jpg":`image/jpeg`,".png":`image/png`,".svg":`image/svg+xml`,".tiff":`image/tiff`,".webp":`image/webp`},Y={".aac":`audio/aac`,".flac":`audio/flac`,".m4a":`audio/mp4`,".mp3":`audio/mpeg`,".ogg":`audio/ogg`,".opus":`audio/opus`,".wav":`audio/wav`,".weba":`audio/webm`},X=(e,t,n)=>t[d(new URL(e,`file:///`).pathname).toLowerCase()]??n,Z=async(e,t)=>{if(`url`in e){let n=await fetch(e.url);if(!n.ok)throw Error(`Failed to fetch ${t} from URL (${e.url}): ${n.status} ${n.statusText}`);return{data:Buffer.from(await n.arrayBuffer()),source:e.url}}return`path`in e?{data:await l(e.path),source:e.path}:{data:e.buffer}},ne=async e=>{let{data:t,source:n}=await Z(e,`image`),r=n?X(n,J,`image/png`):`image/png`;return{data:t.toString(`base64`),mimeType:r,type:`image`}},re=async e=>{let{data:t,source:n}=await Z(e,`audio`),r=n?X(n,Y,`audio/mpeg`):`audio/mpeg`;return{data:t.toString(`base64`),mimeType:r,type:`audio`}},ie=e=>o({prefix:`[${e}]`,stream:`stderr`}).withContext({cell:e}),ae=e=>({annotations:{readOnlyHint:!0},description:`Lists all tools, resources, and prompts registered on this server`,execute:()=>Promise.resolve(JSON.stringify(e(),null,2)),name:`soma_capabilities`}),oe=e=>({annotations:{readOnlyHint:!0},description:`Lists all gateway connections to remote servers with their status and available tools`,execute:()=>Promise.resolve(JSON.stringify(e(),null,2)),name:`soma_connections`}),se=e=>({annotations:{readOnlyHint:!0},description:`Returns health and status information for this server including uptime, sessions, and gateway status`,execute:()=>Promise.resolve(JSON.stringify(e(),null,2)),name:`soma_health`}),Q=[{description:`GitHub personal access token`,name:`github_pat`,pattern:/\b(?:ghp|gho|ghu|ghs|ghr|github_pat)_[A-Za-z0-9_]{20,}\b/g},{description:`AWS access key ID`,name:`aws_access_key`,pattern:/\bAKIA[0-9A-Z]{16}\b/g},{description:`AWS secret access key (heuristic)`,name:`aws_secret_key`,pattern:/(?<![A-Za-z0-9/+])[A-Za-z0-9/+]{40}(?![A-Za-z0-9/+])/g},{description:`Stripe secret/publishable key`,name:`stripe_key`,pattern:/\b(?:sk|pk|rk)_(?:live|test)_[A-Za-z0-9]{20,}\b/g},{description:`Slack token`,name:`slack_token`,pattern:/\bxox[abprs]-[A-Za-z0-9-]{10,}\b/g},{description:`JSON Web Token`,name:`jwt`,pattern:/\beyJ[A-Za-z0-9_-]{8,}\.eyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]+\b/g},{description:`OpenAI / Anthropic style API key`,name:`ai_api_key`,pattern:/\b(?:sk-ant-|sk-)[A-Za-z0-9_-]{20,}\b/g},{description:`Generic bearer-style secret prefix`,name:`bearer_authorization`,pattern:/\b[Bb]earer\s+[A-Za-z0-9._\-+/]{16,}\b/g},{description:`Email address`,name:`email`,pattern:/\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/g},{description:`Private IPv4 address (RFC1918)`,name:`private_ipv4`,pattern:/\b(?:10(?:\.\d{1,3}){3}|192\.168(?:\.\d{1,3}){2}|172\.(?:1[6-9]|2\d|3[01])(?:\.\d{1,3}){2})\b/g},{description:`URL pointing at internal/private hostname`,name:`internal_url`,pattern:/\bhttps?:\/\/(?:[a-z0-9-]+\.)*(?:internal|intranet|corp|local|lan)(?:[/:][^\s]*)?/gi}],$=(e,t=Q)=>{let{counts:n,text:r}=t.reduce((e,t)=>{let n=Array.from(e.text.matchAll(t.pattern)).length;return n===0?e:{counts:new Map(e.counts).set(t.name,n),text:e.text.replace(t.pattern,t.replacement??`[REDACTED]`)}},{counts:new Map,text:e}),i=Array.from(n.entries()).map(([e,t])=>({count:t,name:e}));return{matches:i,redacted:i.length>0,text:r}},ce=[`Submit a feedback report or issue to this server's maintainers.`,``,`IMPORTANT: Treat all input as potentially public.`,`- Do NOT include API keys, tokens, passwords, or credentials`,`- Do NOT include customer data, PII, or proprietary information`,`- Do NOT include internal URLs, hostnames, or system topology`,`- Describe the behavior and how to reproduce it, not the data involved`,``,`Common credential patterns are automatically redacted before submission,`,`but redaction is best-effort and is not a substitute for caution.`].join(`
59
- `),le=f.object({description:f.string().min(10,`Provide enough context to reproduce (>=10 chars)`).max(8e3).describe(`Detailed description. NO secrets, customer data, or internal URLs.`),severity:f.enum([`low`,`medium`,`high`]).optional().describe(`Severity hint (optional)`),title:f.string().min(5,`Title must be at least 5 characters`).max(200).describe(`Brief, public-safe summary`),type:f.enum([`bug`,`feature`,`feedback`,`question`]).default(`feedback`).describe(`What kind of report this is`)}),ue=(e,t)=>{if(!e.redacted&&!t.redacted)return;let n=new Map;for(let r of[...e.matches,...t.matches])n.set(r.name,(n.get(r.name)??0)+r.count);return[`⚠️ Automatic redactions applied:`,...Array.from(n.entries()).map(([e,t])=>`- ${e}: ${String(t)}`)].join(`
60
- `)},de=e=>{if(!(!e||Object.keys(e).length===0))return[`---`,`**Context (auto-collected):**`,"```json",JSON.stringify(e,null,2),"```"].join(`
61
- `)},fe=(e,t,n,r,i)=>{let a=[];return a.push(`**Type:** ${t}`),n&&a.push(`**Severity:** ${n}`),a.push(``),a.push(e),r&&(a.push(``),a.push(r)),i&&(a.push(``),a.push(i)),a.join(`
62
- `)},pe=e=>{let t=e.redactionPatterns??Q;return{annotations:{destructiveHint:!1,readOnlyHint:!1},description:e.description??ce,execute:async n=>{let r=$(n.title,t),i=$(n.description,t),a=e.enrichment?await e.enrichment({severity:n.severity,type:n.type}):void 0,o=ue(r,i),s=de(a),c=fe(i.text,n.type,n.severity,o,s),l=[n.type,...n.severity?[`severity:${n.severity}`]:[],...e.extraLabels??[]],u=await e.provider.submit({body:c,labels:l,title:r.text});return u.success?JSON.stringify({id:u.id,provider:e.provider.name,redacted:o!==void 0,redactionDetails:[...r.matches,...i.matches],success:!0,url:u.url},null,2):JSON.stringify({error:u.error,redacted:o!==void 0,success:!1},null,2)},name:e.name??`report_feedback`,parameters:le}},me=e=>{let t=e.baseUrl??`https://api.github.com`,n=e.fetchImpl??fetch;return{name:`github`,submit:async r=>{let i=e.getToken();if(!i)return{error:`No GitHub token configured`,success:!1};let a=[...e.defaultLabels??[],...r.labels],o=JSON.stringify({body:r.body,labels:Array.from(new Set(a)),title:r.title});try{let r=await n(`${t}/repos/${e.repo}/issues`,{body:o,headers:{Accept:`application/vnd.github+json`,Authorization:`Bearer ${i}`,"Content-Type":`application/json`,"X-GitHub-Api-Version":`2022-11-28`},method:`POST`}),a=await r.json().catch(()=>({}));return r.ok?{id:a.number===void 0?void 0:String(a.number),success:!0,url:a.html_url}:{error:`GitHub API ${String(r.status)}: ${a.message??r.statusText}`,success:!1}}catch(e){return{error:e instanceof Error?e.message:`Unknown error submitting to GitHub`,success:!1}}}}},he=e=>{let t=e.fetchImpl??fetch,n=e.transform??(e=>e);return{name:`webhook`,submit:async r=>{try{let i=await t(e.url,{body:JSON.stringify(n(r)),headers:{"Content-Type":`application/json`,...e.headers??{}},method:`POST`});if(!i.ok){let e=await i.text().catch(()=>``);return{error:`Webhook ${String(i.status)}: ${e||i.statusText}`,success:!1}}return{success:!0}}catch(e){return{error:e instanceof Error?e.message:`Unknown error posting to webhook`,success:!1}}}}};export{b as DEFAULT_HEALTH_DETAIL_PATH,y as DEFAULT_HEALTH_PATH,S as DEFAULT_INFO_PATH,Q as DEFAULT_REDACTION_PATTERNS,I as NoopTelemetry,q as UserError,re as audioContent,M as classifyError,ae as createCapabilitiesTool,k as createCompositeTelemetry,oe as createConnectionsTool,j as createConsoleTelemetry,g as createDashboardArtifact,ie as createDefaultLogger,P as createEnrichedError,e as createFastMCPBackend,pe as createFeedbackTool,D as createGateway,O as createGatewayManager,me as createGithubFeedback,ee as createHealthArtifact,x as createHealthDetailArtifact,se as createHealthTool,C as createInfoArtifact,G as createInfoTool,F as createJsonFileTelemetry,A as createLogLayerTelemetry,W as createProxiedTools,K as createServer,he as createWebhookFeedback,E as getRuntimeInfo,ne as imageContent,T as readBuildInfoFromEnv,$ as redact,h as registerArtifacts,te as resolveBuildInfo,H as wrapPrompt,V as wrapResource,B as wrapTool};
57
+ </html>`,b=e=>{let t=Math.floor(e/1e3),n=Math.floor(t/60),r=Math.floor(n/60),i=Math.floor(r/24);return i>0?`${String(i)}d ${String(r%24)}h`:r>0?`${String(r)}h ${String(n%60)}m`:n>0?`${String(n)}m ${String(t%60)}s`:`${String(t)}s`},x=`/health`,S=`/health/detail`,C=(e,t=x)=>({handler:()=>{let t=e(),n=t.status===`running`?200:503;return new Response(JSON.stringify({name:t.name,status:t.status}),{headers:{"Content-Type":`application/json`},status:n})},path:t,type:`dynamic`}),w=(e,t=S)=>({handler:()=>{let t=e(),n=t.status===`running`?200:503;return new Response(JSON.stringify(t),{headers:{"Content-Type":`application/json`},status:n})},path:t,protected:!0,type:`dynamic`}),T=`/info`,E=(e,t=T)=>({handler:()=>new Response(JSON.stringify(e()),{headers:{"Content-Type":`application/json`},status:200}),path:t,protected:!0,type:`dynamic`}),D=e=>n(process.env[e]).filter(e=>e.length>0),O=()=>({branch:D(`SOMAMCP_BUILD_BRANCH`).orUndefined(),commit:D(`SOMAMCP_BUILD_COMMIT`).orUndefined(),date:D(`SOMAMCP_BUILD_DATE`).orUndefined(),environment:D(`SOMAMCP_ENVIRONMENT`).orUndefined()}),k=e=>{let t=O();return{branch:e?.branch??t.branch,commit:e?.commit??t.commit,date:e?.date??t.date,environment:e?.environment??t.environment}},A=()=>({arch:process.arch,nodeVersion:process.version,platform:process.platform}),j=(e,t)=>{let i=r(n.none()),o=r(n.none()),l=r([]),u=r(`disconnected`),d=r(n.none()),f=e.name??e.id,p=()=>{let t=e.reconnectIntervalMs??5e3;d.set(n(setTimeout(()=>{m.connect()},t)))},m={get config(){return e},get info(){return{id:e.id,name:f,remoteTools:l.get().map(e=>({description:e.description,name:e.name})),status:u.get(),url:e.url}},get name(){return f},get status(){return u.get()},get tools(){return l.get()},async callTool(t,n={}){let r=i.get();if(r.isEmpty||u.get()!==`connected`)throw Error(`Gateway ${e.id} is not connected`);return r.orThrow(Error(`Gateway ${e.id} is not connected`)).callTool({arguments:n,name:t})},async connect(){if(u.get()===`connected`)return;u.set(`connecting`);let r=Date.now();(await a.fromPromise((async()=>{let t=new c(new URL(e.url));o.set(n(t));let r=new s({name:`soma-gateway-${e.id}`,version:`1.0.0`});i.set(n(r)),await r.connect(t);let a=await r.listTools();l.set(a.tools)})())).fold(n=>{u.set(`error`),t.recordEvent({data:{id:e.id,url:e.url},error:n instanceof Error?n.message:String(n),name:f,timestamp:r,type:`gateway.error`}),e.reconnect!==!1&&p()},()=>{u.set(`connected`),t.recordEvent({data:{id:e.id,remoteToolCount:l.get().length,url:e.url},durationMs:Date.now()-r,name:f,timestamp:r,type:`gateway.connect`})})},async disconnect(){d.get().match({None:()=>void 0,Some:e=>clearTimeout(e)}),d.set(n.none());let r=i.get();r.isSome()&&await a.fromPromise(r.value.close()),i.set(n.none()),o.set(n.none()),l.set([]),u.set(`disconnected`),t.recordEvent({data:{id:e.id},name:f,timestamp:Date.now(),type:`gateway.disconnect`})}};return m},te=e=>{let n=r(t.empty()),i=()=>[...n.get()].map(([,e])=>e);return{get connectedCount(){return i().filter(e=>e.status===`connected`).length},get totalCount(){return n.get().size},add(t){let r=j(t,e);return n.set(n.get().add(o([t.id,r]))),r},async connectAll(){await Promise.allSettled(i().map(e=>e.connect()))},async disconnectAll(){await Promise.allSettled(i().map(e=>e.disconnect()))},get(e){return n.get().get(e)},getAll(){return i()},getInfoAll(){return i().map(e=>e.info)}}},M=e=>({flush:async()=>{await Promise.all(e.map(e=>e.flush?e.flush():Promise.resolve()))},recordEvent:t=>{e.forEach(e=>e.recordEvent(t))}}),N=e=>({flush:()=>Promise.resolve(),recordEvent:t=>{let n={durationMs:t.durationMs,eventName:t.name,timestamp:new Date(t.timestamp).toISOString(),type:t.type,...t.sessionId&&{sessionId:t.sessionId},...t.requestId&&{requestId:t.requestId},...t.errorCategory&&{errorCategory:t.errorCategory},...t.data};t.error?e.withError(Error(t.error)).error(t.type,n):e.info(t.type,n)}}),P=(e=`[soma]`)=>N(l({prefix:e,stream:`stderr`})),F=e=>{if(e instanceof Error){let t=e.message.toLowerCase();if(t.includes(`validation`)||t.includes(`invalid`)||t.includes(`schema`))return`validation`;if(t.includes(`timeout`)||t.includes(`timed out`)||t.includes(`etimedout`))return`timeout`;if(t.includes(`gateway`)||t.includes(`not connected`)||t.includes(`econnrefused`)||t.includes(`connection refused`))return`gateway`;if(t.includes(`auth`)||t.includes(`unauthorized`)||t.includes(`forbidden`))return`auth`;if(t.includes(`not found`)||t.includes(`404`))return`not_found`}return typeof e==`object`&&e&&`name`in e&&e.name===`UserError`?`validation`:`internal`},I=(e,t)=>{switch(e){case`validation`:return[`Check the tool's parameter schema and provide valid input`];case`timeout`:return[`The operation timed out. Try again or reduce the scope of the request`];case`gateway`:return[`Gateway is ${t?.gatewayStatus??`unavailable`}. The remote service may be down`,`Try again later or check the remote service status`];case`auth`:return[`Authentication failed. Check credentials or permissions`];case`not_found`:return[`The requested resource was not found. Verify the identifier`];case`internal`:return[`An internal error occurred. The tool maintainer should investigate`]}},L=(e,t)=>{let n=F(e),r=e instanceof Error?e.message:String(e),i=I(n,t),a={...t?.gatewayStatus&&{gatewayStatus:t.gatewayStatus},...t?.toolName&&{toolName:t.toolName}};return{errorCategory:n,message:r,...Object.keys(a).length>0&&{relatedState:a},suggestions:i}},R=e=>{let t=r([]),i=r(n.none()),a=r(!1),o=async()=>{let n=t.getAndSet([]);if(n.length===0)return;a.get()||(await d(p(e.filePath),{recursive:!0}),a.set(!0));let r=`${n.map(e=>JSON.stringify(e)).join(`
58
+ `)}\n`;await u(e.filePath,r)},s=()=>{i.get().isSome()||i.set(n(setTimeout(()=>{i.set(n.none()),o()},e.flushIntervalMs??1e3)))};return{flush:async()=>{i.get().match({None:()=>void 0,Some:e=>clearTimeout(e)}),i.set(n.none()),await o()},recordEvent:e=>{t.update(t=>[...t,e]),s()}}},z={flush:()=>Promise.resolve(),recordEvent:()=>{}},B=(e,t)=>!t||t.length===0?e:Object.fromEntries(Object.entries(e).map(([e,n])=>[e,t.includes(e)?`[REDACTED]`:n])),V=(e,t=1e4)=>{let n=typeof e==`string`?e:JSON.stringify(e);return n&&n.length>t?`${n.slice(0,t)}...[truncated, ${n.length} total chars]`:e},H=e=>a.fromPromise(e),U=(e,t,n)=>({...e,execute:async(r,i)=>{let a=n?.captureLevel??`full`;if(a===`none`)return e.execute(r,i);let o=Date.now(),{requestId:s,sessionId:c}=i,l=a===`full`?B(r,n?.redactInputFields):void 0;return(await H(e.execute(r,i))).fold(n=>{let r=L(n,{toolName:e.name});return t.recordEvent({data:{name:e.name},durationMs:Date.now()-o,error:r.message,errorCategory:r.errorCategory,errorStack:n.stack,input:l,name:e.name,requestId:s,sessionId:c,timestamp:o,type:`tool.error`}),{content:[{text:JSON.stringify(r,null,2),type:`text`}],isError:!0}},r=>(t.recordEvent({data:{name:e.name},durationMs:Date.now()-o,input:l,name:e.name,output:a===`full`?V(r,n?.maxOutputSize):void 0,requestId:s,sessionId:c,timestamp:o,type:`tool.execute`}),r))}}),W=(e,t)=>({...e,load:async n=>{let r=Date.now();return(await H(e.load(n))).fold(n=>{let i=L(n);throw t.recordEvent({data:{name:e.name,uri:e.uri},durationMs:Date.now()-r,error:i.message,errorCategory:i.errorCategory,errorStack:n.stack,name:e.name,timestamp:r,type:`resource.error`}),n},n=>(t.recordEvent({data:{name:e.name,uri:e.uri},durationMs:Date.now()-r,name:e.name,timestamp:r,type:`resource.load`}),n))}}),G=(e,t)=>({...e,load:async(n,r)=>{let i=Date.now();return(await H(e.load(n,r))).fold(n=>{let r=L(n);throw t.recordEvent({data:{name:e.name},durationMs:Date.now()-i,error:r.message,errorCategory:r.errorCategory,errorStack:n.stack,name:e.name,timestamp:i,type:`prompt.error`}),n},n=>(t.recordEvent({data:{name:e.name},durationMs:Date.now()-i,name:e.name,timestamp:i,type:`prompt.load`}),n))}}),K=e=>a.fromPromise(e),q=(e,t)=>{let n=e.config.toolPrefix??`${e.config.id}_`;return e.tools.map(r=>({annotations:{openWorldHint:!0,readOnlyHint:!0},description:`[${e.name}] ${r.description??`Remote tool`}`,execute:async i=>{let a=Date.now(),o=`${n}${r.name}`;return(await K(e.callTool(r.name,i))).fold(n=>{let s=L(n,{gatewayStatus:e.status,toolName:r.name});return t?.recordEvent({data:{gateway:e.config.id,remoteTool:r.name},durationMs:Date.now()-a,error:s.message,errorCategory:s.errorCategory,errorStack:n.stack,input:i,name:o,timestamp:a,type:`tool.error`}),{content:[{text:JSON.stringify(s,null,2),type:`text`}],isError:!0}},n=>(t?.recordEvent({data:{gateway:e.config.id,remoteTool:r.name},durationMs:Date.now()-a,input:i,name:o,output:n,timestamp:a,type:`tool.execute`}),JSON.stringify(n,null,2)))},name:`${n}${r.name}`}))},J=(e,t=`info`)=>({annotations:{readOnlyHint:!0},description:`Returns identity and build information for this server (name, version, build commit, runtime, capability counts)`,execute:()=>Promise.resolve(JSON.stringify(e(),null,2)),name:t}),Y=t=>{let{artifacts:i,backendOptions:a,build:o,enableDashboard:s,enableHealthEndpoint:c,enableInfoEndpoint:l,enableIntrospection:u,gateways:d,healthDetailPath:f,healthPath:p,infoPath:m,introspectionPrefix:h,logLayer:g,telemetry:_,...y}=t,b=y.name,x=y.version,S=k(o),T=A(),D=h??``,O=_??(g?N(g):z),j=e(y,a),M=te(O),P=[],F=[],I=[],L=r(0);d?.forEach(e=>M.add(e));let R=()=>{let e=L.get(),t=e>0?Date.now()-e:0;return{activeSessions:j.sessions.length,gateways:{connected:M.connectedCount,total:M.totalCount},name:b,startedAt:e,status:j.serverState,uptime:t}},B=()=>({prompts:I,resources:F,tools:P}),V=()=>({build:S,capabilities:{prompts:I.length,resources:F.length,tools:P.length},name:b,runtime:T,version:x});u!==!1&&j.addTool(J(()=>V(),`${D}info`));let H=[...i??[]];c!==!1&&(H.push(C(()=>R(),p)),H.push(w(()=>R(),f))),l!==!1&&H.push(E(()=>V(),m)),s!==!1&&H.push(v(()=>R(),()=>B(),()=>M.getInfoAll())),H.length>0&&ee(j.getApp(),H,n(y.authenticate).orUndefined()),j.on(`connect`,({session:e})=>{O.recordEvent({data:{sessionId:e.sessionId},name:b,timestamp:Date.now(),type:`session.connect`})}),j.on(`disconnect`,({session:e})=>{O.recordEvent({data:{sessionId:e.sessionId},name:b,timestamp:Date.now(),type:`session.disconnect`})});let K=e=>{let t=U(e,O,`captureConfig`in e?e.captureConfig:void 0);j.addTool(t),P.push({description:e.description,name:e.name})},Y=e=>{let t=W(e,O);j.addResource(t),F.push({description:e.description,name:e.name,uri:e.uri})},X=e=>{let t=G(e,O);j.addPrompt(t),I.push({description:e.description,name:e.name})};return{get name(){return b},get serverState(){return j.serverState},get sessions(){return j.sessions},addPrompt:X,addPrompts:e=>{e.forEach(X)},addResource:Y,addResources:e=>{e.forEach(Y)},addResourceTemplate:(...e)=>{j.addResourceTemplate(...e)},addTool:K,addTools:e=>{e.forEach(e=>K(e))},getApp:()=>j.getApp(),getCapabilities:B,getGatewayManager:()=>M,getHealth:R,getInfo:V,removePrompt:e=>{j.removePrompt(e)},removeResource:e=>{j.removeResource(e)},removeTool:e=>{j.removeTool(e)},async start(e){L.set(Date.now()),O.recordEvent({name:b,timestamp:L.get(),type:`server.start`}),await j.start(e),await M.connectAll(),M.getAll().filter(e=>e.status===`connected`&&e.config.proxyTools!==!1).forEach(e=>{q(e,O).forEach(e=>j.addTool(e))})},async stop(){await M.disconnectAll(),await j.stop(),O.recordEvent({name:b,timestamp:Date.now(),type:`server.stop`}),O.flush&&await O.flush()}}};var X=class extends Error{constructor(e){super(e),this.name=`UserError`}};const ne={".avif":`image/avif`,".bmp":`image/bmp`,".gif":`image/gif`,".ico":`image/x-icon`,".jpeg":`image/jpeg`,".jpg":`image/jpeg`,".png":`image/png`,".svg":`image/svg+xml`,".tiff":`image/tiff`,".webp":`image/webp`},re={".aac":`audio/aac`,".flac":`audio/flac`,".m4a":`audio/mp4`,".mp3":`audio/mpeg`,".ogg":`audio/ogg`,".opus":`audio/opus`,".wav":`audio/wav`,".weba":`audio/webm`},Z=(e,t,n)=>t[m(new URL(e,`file:///`).pathname).toLowerCase()]??n,ie=async(e,t)=>{if(`url`in e){let n=await fetch(e.url);if(!n.ok)throw Error(`Failed to fetch ${t} from URL (${e.url}): ${n.status} ${n.statusText}`);return{data:Buffer.from(await n.arrayBuffer()),source:e.url}}return`path`in e?{data:await f(e.path),source:e.path}:{data:e.buffer}},ae=async e=>{let{data:t,source:n}=await ie(e,`image`),r=n?Z(n,ne,`image/png`):`image/png`;return{data:t.toString(`base64`),mimeType:r,type:`image`}},oe=async e=>{let{data:t,source:n}=await ie(e,`audio`),r=n?Z(n,re,`audio/mpeg`):`audio/mpeg`;return{data:t.toString(`base64`),mimeType:r,type:`audio`}},se=e=>l({prefix:`[${e}]`,stream:`stderr`}).withContext({cell:e}),ce=e=>({annotations:{readOnlyHint:!0},description:`Lists all tools, resources, and prompts registered on this server`,execute:()=>Promise.resolve(JSON.stringify(e(),null,2)),name:`soma_capabilities`}),le=e=>({annotations:{readOnlyHint:!0},description:`Lists all gateway connections to remote servers with their status and available tools`,execute:()=>Promise.resolve(JSON.stringify(e(),null,2)),name:`soma_connections`}),ue=e=>({annotations:{readOnlyHint:!0},description:`Returns health and status information for this server including uptime, sessions, and gateway status`,execute:()=>Promise.resolve(JSON.stringify(e(),null,2)),name:`soma_health`}),Q=[{description:`GitHub personal access token`,name:`github_pat`,pattern:/\b(?:ghp|gho|ghu|ghs|ghr|github_pat)_[A-Za-z0-9_]{20,}\b/g},{description:`AWS access key ID`,name:`aws_access_key`,pattern:/\bAKIA[0-9A-Z]{16}\b/g},{description:`AWS secret access key (heuristic)`,name:`aws_secret_key`,pattern:/(?<![A-Za-z0-9/+])[A-Za-z0-9/+]{40}(?![A-Za-z0-9/+])/g},{description:`Stripe secret/publishable key`,name:`stripe_key`,pattern:/\b(?:sk|pk|rk)_(?:live|test)_[A-Za-z0-9]{20,}\b/g},{description:`Slack token`,name:`slack_token`,pattern:/\bxox[abprs]-[A-Za-z0-9-]{10,}\b/g},{description:`JSON Web Token`,name:`jwt`,pattern:/\beyJ[A-Za-z0-9_-]{8,}\.eyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]+\b/g},{description:`OpenAI / Anthropic style API key`,name:`ai_api_key`,pattern:/\b(?:sk-ant-|sk-)[A-Za-z0-9_-]{20,}\b/g},{description:`Generic bearer-style secret prefix`,name:`bearer_authorization`,pattern:/\b[Bb]earer\s+[A-Za-z0-9._\-+/]{16,}\b/g},{description:`Email address`,name:`email`,pattern:/\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/g},{description:`Private IPv4 address (RFC1918)`,name:`private_ipv4`,pattern:/\b(?:10(?:\.\d{1,3}){3}|192\.168(?:\.\d{1,3}){2}|172\.(?:1[6-9]|2\d|3[01])(?:\.\d{1,3}){2})\b/g},{description:`URL pointing at internal/private hostname`,name:`internal_url`,pattern:/\bhttps?:\/\/(?:[a-z0-9-]+\.)*(?:internal|intranet|corp|local|lan)(?:[/:][^\s]*)?/gi}],$=(e,n=Q)=>{let{counts:r,text:i}=n.reduce((e,t)=>{let n=Array.from(e.text.matchAll(t.pattern)).length;return n===0?e:{counts:e.counts.add(o([t.name,n])),text:e.text.replace(t.pattern,t.replacement??`[REDACTED]`)}},{counts:t.empty(),text:e}),a=[...r].map(([e,t])=>({count:t,name:e}));return{matches:a,redacted:a.length>0,text:i}},de=[`Submit a feedback report or issue to this server's maintainers.`,``,`IMPORTANT: Treat all input as potentially public.`,`- Do NOT include API keys, tokens, passwords, or credentials`,`- Do NOT include customer data, PII, or proprietary information`,`- Do NOT include internal URLs, hostnames, or system topology`,`- Describe the behavior and how to reproduce it, not the data involved`,``,`Common credential patterns are automatically redacted before submission,`,`but redaction is best-effort and is not a substitute for caution.`].join(`
59
+ `),fe=h.object({description:h.string().min(10,`Provide enough context to reproduce (>=10 chars)`).max(8e3).describe(`Detailed description. NO secrets, customer data, or internal URLs.`),severity:h.enum([`low`,`medium`,`high`]).optional().describe(`Severity hint (optional)`),title:h.string().min(5,`Title must be at least 5 characters`).max(200).describe(`Brief, public-safe summary`),type:h.enum([`bug`,`feature`,`feedback`,`question`]).default(`feedback`).describe(`What kind of report this is`)}),pe=(e,r)=>!e.redacted&&!r.redacted?n.none():n([`⚠️ Automatic redactions applied:`,...[...[...e.matches,...r.matches].reduce((e,t)=>e.add(o([t.name,e.get(t.name).orElse(0)+t.count])),t.empty())].map(([e,t])=>`- ${e}: ${String(t)}`)].join(`
60
+ `)),me=e=>e.filter(e=>Object.keys(e).length>0).map(e=>[`---`,`**Context (auto-collected):**`,"```json",JSON.stringify(e,null,2),"```"].join(`
61
+ `)),he=(e,t,n,r,i)=>[`**Type:** ${t}`,...n.map(e=>`**Severity:** ${e}`).toArray(),``,e,...r.map(e=>[``,e]).toArray().flat(),...i.map(e=>[``,e]).toArray().flat()].join(`
62
+ `),ge=e=>{let t=e.redactionPatterns??Q;return{annotations:{destructiveHint:!1,readOnlyHint:!1},description:e.description??de,execute:async r=>{let i=$(r.title,t),a=$(r.description,t),o=e.enrichment?n(await e.enrichment({severity:r.severity,type:r.type})):n.none(),s=pe(i,a),c=me(o),l=he(a.text,r.type,n(r.severity),s,c),u=[r.type,...r.severity?[`severity:${r.severity}`]:[],...e.extraLabels??[]],d=await e.provider.submit({body:l,labels:u,title:i.text});return d.success?JSON.stringify({id:d.id,provider:e.provider.name,redacted:s.isSome(),redactionDetails:[...i.matches,...a.matches],success:!0,url:d.url},null,2):JSON.stringify({error:d.error,redacted:s.isSome(),success:!1},null,2)},name:e.name??`report_feedback`,parameters:fe}},_e=e=>{let t=e.baseUrl??`https://api.github.com`,r=e.fetchImpl??fetch;return{name:`github`,submit:async o=>{let s=e.getToken();if(s.isEmpty)return{error:`No GitHub token configured`,success:!1};let c=s.orThrow(Error(`unreachable`)),l=[...e.defaultLabels??[],...o.labels],u=JSON.stringify({body:o.body,labels:i(l).toArray(),title:o.title});return(await a.fromPromise(r(`${t}/repos/${e.repo}/issues`,{body:u,headers:{Accept:`application/vnd.github+json`,Authorization:`Bearer ${c}`,"Content-Type":`application/json`,"X-GitHub-Api-Version":`2022-11-28`},method:`POST`}))).foldAsync(e=>({error:e instanceof Error?e.message:`Unknown error submitting to GitHub`,success:!1}),async e=>{let t=await e.json().catch(()=>({}));return e.ok?{id:n(t.number).fold(()=>void 0,e=>String(e)),success:!0,url:t.html_url}:{error:`GitHub API ${String(e.status)}: ${t.message??e.statusText}`,success:!1}})}}},ve=e=>{let t=e.fetchImpl??fetch,n=e.transform??(e=>e);return{name:`webhook`,submit:async r=>(await a.fromPromise(t(e.url,{body:JSON.stringify(n(r)),headers:{"Content-Type":`application/json`,...e.headers??{}},method:`POST`}))).foldAsync(e=>({error:e instanceof Error?e.message:`Unknown error posting to webhook`,success:!1}),async e=>{if(!e.ok){let t=await e.text().catch(()=>``);return{error:`Webhook ${String(e.status)}: ${t||e.statusText}`,success:!1}}return{success:!0}})}};export{S as DEFAULT_HEALTH_DETAIL_PATH,x as DEFAULT_HEALTH_PATH,T as DEFAULT_INFO_PATH,Q as DEFAULT_REDACTION_PATTERNS,z as NoopTelemetry,X as UserError,oe as audioContent,F as classifyError,ce as createCapabilitiesTool,M as createCompositeTelemetry,le as createConnectionsTool,P as createConsoleTelemetry,v as createDashboardArtifact,se as createDefaultLogger,L as createEnrichedError,e as createFastMCPBackend,ge as createFeedbackTool,j as createGateway,te as createGatewayManager,_e as createGithubFeedback,C as createHealthArtifact,w as createHealthDetailArtifact,ue as createHealthTool,E as createInfoArtifact,J as createInfoTool,R as createJsonFileTelemetry,N as createLogLayerTelemetry,q as createProxiedTools,Y as createServer,ve as createWebhookFeedback,A as getRuntimeInfo,ae as imageContent,O as readBuildInfoFromEnv,$ as redact,ee as registerArtifacts,k as resolveBuildInfo,G as wrapPrompt,W as wrapResource,U as wrapTool};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "somamcp",
3
- "version": "1.0.13",
3
+ "version": "1.0.15",
4
4
  "description": "Framework for building MCP servers with telemetry, introspection, and backend abstraction",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -24,8 +24,8 @@
24
24
  "validate": "ts-builds validate",
25
25
  "format": "ts-builds format",
26
26
  "format:check": "ts-builds format:check",
27
- "lint": "ts-builds lint",
28
- "lint:check": "ts-builds lint:check",
27
+ "lint": "eslint ./src --fix --max-warnings=0",
28
+ "lint:check": "eslint ./src --max-warnings=0",
29
29
  "typecheck": "ts-builds typecheck",
30
30
  "test": "ts-builds test",
31
31
  "test:watch": "ts-builds test:watch",
@@ -54,18 +54,18 @@
54
54
  "homepage": "https://github.com/sapientsai/SomaMCP#readme",
55
55
  "dependencies": {
56
56
  "@modelcontextprotocol/sdk": "^1.29.0",
57
- "fastmcp": "^4.1.0",
58
- "functype": "^1.4.1",
59
- "functype-log": "^1.4.1",
60
- "hono": "^4.12.25",
57
+ "fastmcp": "^4.3.0",
58
+ "functype": "^1.4.4",
59
+ "functype-log": "^1.4.4",
60
+ "hono": "^4.12.26",
61
61
  "zod": "^4.4.3"
62
62
  },
63
63
  "prettier": "ts-builds/prettier",
64
64
  "devDependencies": {
65
65
  "@types/node": "^24.13.2",
66
66
  "get-port-please": "^3.2.0",
67
- "ts-builds": "^3.2.0",
68
- "tsdown": "^0.22.2"
67
+ "ts-builds": "^3.2.1",
68
+ "tsdown": "^0.22.3"
69
69
  },
70
- "packageManager": "pnpm@11.6.0+sha512.9a36518224080c6fe5165afdcfe79bfa118c29be703f3f462b1e32efe1e98e47e8750b148e08286250aad4113cc7993ca413c4e2cd447752708c2ee5751bc95f"
70
+ "packageManager": "pnpm@11.8.0+sha512.c1f5e7c4cb241c8f174b743851d82f42b802324afc8b0f116b96adb15aa06664948dde36960a3ba1079ba5b4b29dd0140135b94b5b5f5263592249d68e555f26"
71
71
  }