somamcp 1.5.0 → 2.0.0

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/edge.js CHANGED
@@ -1,61 +1 @@
1
- import{EdgeFastMCP as e}from"fastmcp/edge";import{Map as t,Option as n,Ref as r,Set as i,Try as a,Tuple as o}from"functype";import{Hono as s}from"hono";import{Client as c}from"@modelcontextprotocol/sdk/client/index.js";import{StreamableHTTPClientTransport as l}from"@modelcontextprotocol/sdk/client/streamableHttp.js";import{createDirectConsoleLogger as u}from"functype-log";import{z as d}from"zod";const f=e=>e.json({error:`Unauthorized`},401),p=({authenticate:e,onUnauthorized:t})=>{let r=t??f;return async(t,i)=>{if(!e)return r(t);let o=n(t.env).flatMap(e=>n(e.incoming)).orElse(t.req.raw);if((await a.fromPromise(e(o))).isFailure())return r(t);await i()}},m=(e,t)=>typeof e.get==`function`?n(e.get(t)):n.none(),h=(e,t,r)=>{let i=e;return n(i[t]??i[r]).map(e=>Array.isArray(e)?e[0]??``:e)},g=(e,t,r)=>m(e,t).fold(()=>h(e,t,r),e=>n(e)),_=e=>n(e).flatMap(e=>n(e.headers)),v=(e,t)=>{let n=t.toLowerCase();return _(e).flatMap(e=>g(e,n,t)).orUndefined()},y=e=>typeof e==`string`?e:e===void 0?{content:[]}:`content`in e?e:{content:[e]},b=e=>e.content.map(e=>e.type===`text`?e.text:`[${e.type}]`).join(` `).trim()||`Tool execution failed`,x=e=>({client:{version:void 0},log:{debug:(t,n)=>e.forEach(e=>e.debug(t,n)),error:(t,n)=>e.forEach(e=>e.error(t,n)),info:(t,n)=>e.forEach(e=>e.info(t,n)),warn:(t,n)=>e.forEach(e=>e.warn(t,n))},reportProgress:async()=>{},session:void 0,streamContent:async()=>{}}),S=(t,r)=>{let{mcpPath:i}=r??{},a=i??`/mcp`,o=n(t.logger),c=new e({logger:o.orUndefined(),mcpPath:a,name:t.name,version:t.version}),l=new s;n(t.authenticate).forEach(e=>{l.use(a,p({authenticate:e}))}),l.notFound(e=>c.fetch(e.req.raw));let u=e=>o.forEach(t=>t.warn(`[somamcp/edge] ${e}`)),d=e=>u(`${e} is not supported by the edge backend; ignoring.`);return{get serverState(){return`running`},get sessions(){return[]},addPrompt:e=>{c.addPrompt({arguments:e.arguments?.map(e=>({description:e.description,name:e.name,required:e.required})),description:e.description,load:async t=>await e.load(t),name:e.name})},addResource:e=>{c.addResource({description:e.description,load:async()=>{let t=await e.load();return Array.isArray(t)?(t.length>1&&u(`resource "${e.name}" returned ${t.length} results; only the first is served.`),t[0]??{text:``}):t},mimeType:e.mimeType,name:e.name,uri:e.uri})},addResourceTemplate:()=>d(`addResourceTemplate`),addTool:e=>{let t=x(o);c.addTool({description:e.description??``,execute:async n=>{let r=y(await e.execute(n,t));if(typeof r!=`string`&&r.isError===!0)throw Error(b(r));return r},name:e.name,parameters:e.parameters})},fetch:async e=>l.fetch(e),getApp:()=>l,on:()=>{},removePrompt:()=>d(`removePrompt`),removeResource:()=>d(`removeResource`),removeTool:()=>d(`removeTool`),supportsRemoval:!1,start:async()=>{},stop:async()=>{}}},ee=(e,t,n)=>{t.forEach(t=>{switch(t.protected&&e.use(t.path,p({authenticate: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))}})},te=(e,t,n)=>({handler:()=>{let r=e(),i=t(),a=n(),o=ne(r,i,a);return new Response(o,{headers:{"Content-Type":`text/html; charset=utf-8`}})},path:`/dashboard`,protected:!0,type:`dynamic`}),ne=(e,t,n)=>`<!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>${e.name} - SomaMCP Dashboard</title>
7
- <style>
8
- * { margin: 0; padding: 0; box-sizing: border-box; }
9
- body { font-family: system-ui, -apple-system, sans-serif; background: #0a0a0a; color: #e0e0e0; padding: 2rem; }
10
- h1 { font-size: 1.5rem; margin-bottom: 1.5rem; color: #fff; }
11
- h2 { font-size: 1.1rem; margin-bottom: 0.75rem; color: #a0a0a0; text-transform: uppercase; letter-spacing: 0.05em; }
12
- .grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 1.5rem; }
13
- .card { background: #1a1a1a; border: 1px solid #2a2a2a; border-radius: 8px; padding: 1.25rem; }
14
- .status { display: inline-block; padding: 2px 8px; border-radius: 4px; font-size: 0.85rem; font-weight: 600; }
15
- .status.running { background: #0a3d0a; color: #4ade80; }
16
- .status.stopped { background: #3d0a0a; color: #f87171; }
17
- .status.error { background: #3d2a0a; color: #fbbf24; }
18
- .status.connected { background: #0a3d0a; color: #4ade80; }
19
- .status.disconnected { background: #3d0a0a; color: #f87171; }
20
- .metric { margin: 0.5rem 0; }
21
- .metric-label { color: #888; font-size: 0.85rem; }
22
- .metric-value { color: #fff; font-weight: 500; }
23
- ul { list-style: none; }
24
- li { padding: 0.35rem 0; border-bottom: 1px solid #222; font-size: 0.9rem; }
25
- li:last-child { border-bottom: none; }
26
- .desc { color: #888; font-size: 0.8rem; }
27
- </style>
28
- </head>
29
- <body>
30
- <h1>${e.name}</h1>
31
- <div class="grid">
32
- <div class="card">
33
- <h2>Health</h2>
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">${C(e.uptime)}</span></div>
36
- <div class="metric"><span class="metric-label">Sessions:</span> <span class="metric-value">${e.activeSessions}</span></div>
37
- <div class="metric"><span class="metric-label">Gateways:</span> <span class="metric-value">${e.gateways.connected}/${e.gateways.total}</span></div>
38
- </div>
39
- <div class="card">
40
- <h2>Tools (${t.tools.length})</h2>
41
- <ul>${t.tools.map(e=>`<li><strong>${e.name}</strong>${e.description?` <span class="desc">${e.description}</span>`:``}</li>`).join(``)}</ul>
42
- </div>
43
- <div class="card">
44
- <h2>Resources (${t.resources.length})</h2>
45
- <ul>${t.resources.map(e=>`<li><strong>${e.name}</strong> <span class="desc">${e.uri}</span></li>`).join(``)}</ul>
46
- </div>
47
- <div class="card">
48
- <h2>Prompts (${t.prompts.length})</h2>
49
- <ul>${t.prompts.map(e=>`<li><strong>${e.name}</strong>${e.description?` <span class="desc">${e.description}</span>`:``}</li>`).join(``)}</ul>
50
- </div>
51
- ${n.length>0?`<div class="card">
52
- <h2>Gateways (${n.length})</h2>
53
- <ul>${n.map(e=>`<li><strong>${e.name}</strong> <span class="status ${e.status}">${e.status}</span> <span class="desc">${e.url}</span></li>`).join(``)}</ul>
54
- </div>`:``}
55
- </div>
56
- </body>
57
- </html>`,C=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`},w=`/health`,T=`/health/detail`,E=(e,t=w)=>({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`}),D=(e,t=T)=>({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`}),O=`/info`,k=(e,t=O)=>({handler:()=>new Response(JSON.stringify(e()),{headers:{"Content-Type":`application/json`},status:200}),path:t,protected:!0,type:`dynamic`}),A=()=>n(globalThis.process),j=e=>n(globalThis[e]),M=()=>j(`navigator`).flatMap(e=>n(e.userAgent)),N=()=>M().contains(`Cloudflare-Workers`)||j(`Deno`).isEmpty===!1||j(`EdgeRuntime`).isEmpty===!1,P=()=>!N()&&A().flatMap(e=>n(e.versions?.node)).isEmpty===!1,F=e=>A().flatMap(t=>n(t.env?.[e])).filter(e=>e.length>0),I=()=>({branch:F(`SOMAMCP_BUILD_BRANCH`).orUndefined(),commit:F(`SOMAMCP_BUILD_COMMIT`).orUndefined(),date:F(`SOMAMCP_BUILD_DATE`).orUndefined(),environment:F(`SOMAMCP_ENVIRONMENT`).orUndefined()}),L=e=>{let t=I();return{branch:e?.branch??t.branch,commit:e?.commit??t.commit,date:e?.date??t.date,environment:e?.environment??t.environment}},R=`unknown`,z=()=>P()?{arch:A().flatMap(e=>n(e.arch)).orElse(R),nodeVersion:A().flatMap(e=>n(e.version)).orElse(R),platform:A().flatMap(e=>n(e.platform)).orElse(R),runtime:`node`}:{arch:R,nodeVersion:R,platform:M().orElse(R),runtime:`edge`},B=(e,t)=>{let i=r(n.none()),o=r(n.none()),s=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:s.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 s.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(/* @__PURE__ */ 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 l(new URL(e.url));o.set(n(t));let r=new c({name:`soma-gateway-${e.id}`,version:`1.0.0`});i.set(n(r)),await r.connect(t);let a=await r.listTools();s.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:s.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()),s.set([]),u.set(`disconnected`),t.recordEvent({data:{id:e.id},name:f,timestamp:Date.now(),type:`gateway.disconnect`})}};return m},V=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=B(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)}}},H=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`},U=(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`]}},W=(e,t)=>{let n=H(e),r=e instanceof Error?e.message:String(e),i=U(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}},G=e=>a.fromPromise(e),K=(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 G(e.callTool(r.name,i))).fold(n=>{let s=W(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}`}))},q=(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}),J=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)}}),Y={flush:()=>Promise.resolve(),recordEvent:()=>{}},re=(e,t)=>!t||t.length===0?e:Object.fromEntries(Object.entries(e).map(([e,n])=>[e,t.includes(e)?`[REDACTED]`:n])),ie=(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},X=e=>a.fromPromise(e),Z=(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`?re(r,n?.redactInputFields):void 0;return(await X(e.execute(r,i))).fold(n=>{let r=W(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`?ie(r,n?.maxOutputSize):void 0,requestId:s,sessionId:c,timestamp:o,type:`tool.execute`}),r))}}),ae=(e,t)=>({...e,load:async n=>{let r=Date.now();return(await X(e.load(n))).fold(n=>{let i=W(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))}}),oe=(e,t)=>({...e,load:async(n,r)=>{let i=Date.now();return(await X(e.load(n,r))).fold(n=>{let r=W(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))}}),se=e=>{let{artifacts:t,backend:i,backendOptions:a,build:o,enableDashboard:s,enableHealthEndpoint:c,enableInfoEndpoint:l,enableIntrospection:u,gateways:d,healthDetailPath:f,healthPath:m,infoPath:h,introspectionPrefix:g,logLayer:_,telemetry:v,...y}=e,b=y.name,x=y.version,S=L(o),ne=z(),C=g??``,w=v??(_?J(_):Y),T=i(y,a),O=V(w),A=[],j=[],M=[],N=r(0);d?.forEach(e=>O.add(e));let P=()=>{let e=N.get(),t=e>0?Date.now()-e:0;return{activeSessions:T.sessions.length,gateways:{connected:O.connectedCount,total:O.totalCount},name:b,startedAt:e,status:T.serverState,uptime:t}},F=()=>({prompts:M,resources:j,tools:A}),I=()=>({build:S,capabilities:{prompts:M.length,resources:j.length,tools:A.length},name:b,runtime:ne,version:x}),R=e=>{A.some(t=>t.name===e.name)||A.push({description:e.description,name:e.name})},B=(e,t)=>{if(T.supportsRemoval===!1)return;let n=e.findIndex(e=>e.name===t);n>=0&&e.splice(n,1)};if(u!==!1){let e=q(()=>I(),`${C}info`);T.addTool(e),R(e)}let H=[...t??[]];c!==!1&&(H.push(E(()=>P(),m)),H.push(D(()=>P(),f))),l!==!1&&H.push(k(()=>I(),h)),s!==!1&&H.push(te(()=>P(),()=>F(),()=>O.getInfoAll())),H.length>0&&ee(T.getApp(),H,n(y.authenticate).orUndefined()),T.on(`connect`,({session:e})=>{w.recordEvent({data:{sessionId:e.sessionId},name:b,timestamp:Date.now(),type:`session.connect`})}),T.on(`disconnect`,({session:e})=>{w.recordEvent({data:{sessionId:e.sessionId},name:b,timestamp:Date.now(),type:`session.disconnect`})});let U=e=>{let t=`captureConfig`in e?e.captureConfig:void 0,n=Z(e,w,t);T.addTool(n),R(e)},W=e=>{let t=ae(e,w);T.addResource(t),j.push({description:e.description,name:e.name,uri:e.uri})},G=e=>{let t=oe(e,w);T.addPrompt(t),M.push({description:e.description,name:e.name})};return{get name(){return b},get serverState(){return T.serverState},get sessions(){return T.sessions},addPrompt:G,addPrompts:e=>{e.forEach(G)},addResource:W,addResources:e=>{e.forEach(W)},addResourceTemplate:(...e)=>{T.addResourceTemplate(...e)},addRoute:e=>{let t=T.getApp(),r=Array.isArray(e.method)?[...e.method]:[e.method];if(e.protected){let r=n(y.authenticate).orUndefined();t.use(e.path,p({authenticate:r,onUnauthorized:e.onUnauthorized}))}t.on(r,e.path,t=>e.handler(t))},addTool:U,addTools:e=>{e.forEach(e=>U(e))},fetch:async e=>T.fetch?T.fetch(e):T.getApp().fetch(e),getApp:()=>T.getApp(),getCapabilities:F,getGatewayManager:()=>O,getHealth:P,getInfo:I,removePrompt:e=>{T.removePrompt(e),B(M,e)},removeResource:e=>{T.removeResource(e),B(j,e)},removeTool:e=>{T.removeTool(e),B(A,e)},async start(e){N.set(Date.now()),w.recordEvent({name:b,timestamp:N.get(),type:`server.start`}),await T.start(e),await O.connectAll(),O.getAll().filter(e=>e.status===`connected`&&e.config.proxyTools!==!1).forEach(e=>{K(e,w).forEach(e=>{T.addTool(e),R(e)})})},async stop(){await O.disconnectAll(),await T.stop(),w.recordEvent({name:b,timestamp:Date.now(),type:`server.stop`}),w.flush&&await w.flush()}}};var ce=class extends Error{constructor(e){super(e),this.name=`UserError`}};const le=e=>({flush:async()=>{await Promise.all(e.map(e=>e.flush?e.flush():Promise.resolve()))},recordEvent:t=>{e.forEach(e=>e.recordEvent(t))}}),ue=(e=`[soma]`)=>{let t=u({prefix:e,stream:`stderr`});return J(t)},de=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`}),fe=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`}),pe=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}},me=[`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(`
58
- `),he=d.object({description:d.string().min(10,`Provide enough context to reproduce (>=10 chars)`).max(8e3).describe(`Detailed description. NO secrets, customer data, or internal URLs.`),severity:d.enum([`low`,`medium`,`high`]).optional().describe(`Severity hint (optional)`),title:d.string().min(5,`Title must be at least 5 characters`).max(200).describe(`Brief, public-safe summary`),type:d.enum([`bug`,`feature`,`feedback`,`question`]).default(`feedback`).describe(`What kind of report this is`)}),ge=(e,r)=>{if(!e.redacted&&!r.redacted)return n.none();let i=[...[...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)}`);return n([`⚠️ Automatic redactions applied:`,...i].join(`
59
- `))},_e=e=>e.filter(e=>Object.keys(e).length>0).map(e=>[`---`,`**Context (auto-collected):**`,"```json",JSON.stringify(e,null,2),"```"].join(`
60
- `)),ve=(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(`
61
- `),ye=e=>{let t=e.redactionPatterns??Q;return{annotations:{destructiveHint:!1,readOnlyHint:!1},description:e.description??me,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=ge(i,a),c=_e(o),l=ve(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:he}},be=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(/* @__PURE__ */ 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}})}}},xe=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}})}},Se=e=>se({...e,backend:e.backend??S});export{T as DEFAULT_HEALTH_DETAIL_PATH,w as DEFAULT_HEALTH_PATH,O as DEFAULT_INFO_PATH,Q as DEFAULT_REDACTION_PATTERNS,Y as NoopTelemetry,ce as UserError,H as classifyError,p as createAuthMiddleware,de as createCapabilitiesTool,le as createCompositeTelemetry,fe as createConnectionsTool,ue as createConsoleTelemetry,te as createDashboardArtifact,S as createEdgeBackend,W as createEnrichedError,ye as createFeedbackTool,B as createGateway,V as createGatewayManager,be as createGithubFeedback,E as createHealthArtifact,D as createHealthDetailArtifact,pe as createHealthTool,k as createInfoArtifact,q as createInfoTool,K as createProxiedTools,Se as createServer,se as createServerCore,xe as createWebhookFeedback,v as getRequestHeader,z as getRuntimeInfo,I as readBuildInfoFromEnv,$ as redact,ee as registerArtifacts,L as resolveBuildInfo,oe as wrapPrompt,ae as wrapResource,Z as wrapTool};
1
+ import{n as e}from"./backend-DnC4_jJ7.js";import{A as t,B as n,C as r,D as i,E as a,F as o,H as s,I as c,L as l,M as u,N as d,O as f,P as p,R as m,S as h,T as g,V as _,_ as v,a as y,b,c as x,d as S,f as C,g as w,i as T,j as E,k as D,l as O,n as k,o as A,p as j,r as M,s as N,t as P,u as F,v as I,w as L,x as R,y as z,z as B}from"./src-C1b-whVb.js";export{o as DEFAULT_HEALTH_DETAIL_PATH,c as DEFAULT_HEALTH_PATH,d as DEFAULT_INFO_PATH,y as DEFAULT_REDACTION_PATTERNS,h as NoopTelemetry,v as UserError,j as audioContent,a as classifyError,s as createAuthMiddleware,O as createCapabilitiesTool,C as createCompositeTelemetry,x as createConnectionsTool,S as createConsoleTelemetry,B as createDashboardArtifact,F as createDefaultLogger,i as createEnrichedError,T as createFeedbackTool,D as createGateway,f as createGatewayManager,M as createGithubFeedback,l as createHealthArtifact,m as createHealthDetailArtifact,N as createHealthTool,p as createInfoArtifact,L as createInfoTool,r as createLogLayerTelemetry,g as createProxiedTools,e as createSdkBackend,P as createServer,I as createServerCore,k as createWebhookFeedback,_ as getRequestHeader,t as getRuntimeInfo,w as imageContent,E as readBuildInfoFromEnv,A as redact,n as registerArtifacts,u as resolveBuildInfo,z as wrapPrompt,b as wrapResource,R as wrapTool};
@@ -0,0 +1,421 @@
1
+ import { A as SessionAuth, E as ResourceTemplate, M as Tool$1, O as SchemaParams, S as Resource, a as BackendFactory, b as PromptArgument, d as AudioContent, g as ImageContent, k as ServerStatus, l as ServerConfig, o as BackendSession, u as TransportConfig, y as Prompt } from "./index-ololl9dI.js";
2
+ import { Option } from "functype";
3
+ import { Context, Hono, MiddlewareHandler } from "hono";
4
+ import { FetchLike, Tool } from "@modelcontextprotocol/client";
5
+ import { DirectLogger, DirectLogger as DirectLogger$1 } from "functype-log";
6
+ import { z } from "zod";
7
+ type ArtifactCommon = {
8
+ protected?: boolean;
9
+ };
10
+ type StaticArtifact = ArtifactCommon & {
11
+ contentType: string;
12
+ content: string;
13
+ path: string;
14
+ type: "static";
15
+ };
16
+ type DynamicArtifact = ArtifactCommon & {
17
+ handler: (c: Context) => Response | Promise<Response>;
18
+ path: string;
19
+ type: "dynamic";
20
+ };
21
+ type DirectoryArtifact = ArtifactCommon & {
22
+ directory: string;
23
+ path: string;
24
+ type: "directory";
25
+ };
26
+ type ArtifactConfig = DirectoryArtifact | DynamicArtifact | StaticArtifact;
27
+ type ArtifactAuthenticate = (request: Request) => Promise<unknown>;
28
+ type BuildInfo = {
29
+ branch?: string;
30
+ commit?: string;
31
+ date?: string;
32
+ environment?: string;
33
+ };
34
+ type RuntimeInfo = {
35
+ arch: string;
36
+ nodeVersion: string;
37
+ platform: string;
38
+ /** Which runtime family reported the fields above. Absent on pre-1.2 builds. */
39
+ runtime?: "edge" | "node";
40
+ };
41
+ declare const readBuildInfoFromEnv: () => BuildInfo;
42
+ declare const resolveBuildInfo: (override?: BuildInfo) => BuildInfo;
43
+ declare const getRuntimeInfo: () => RuntimeInfo;
44
+ type GatewayConfig = {
45
+ /**
46
+ * Replaces the global `fetch` for every request to the remote server, e.g. a
47
+ * Workers service binding's `fetch`, or one that adds credentials.
48
+ */
49
+ fetch?: FetchLike;
50
+ id: string;
51
+ name?: string;
52
+ proxyTools?: boolean;
53
+ reconnect?: boolean;
54
+ reconnectIntervalMs?: number;
55
+ toolPrefix?: string;
56
+ url: string;
57
+ /**
58
+ * How to pick the protocol revision. `"auto"` (the default) probes with
59
+ * `server/discover` and speaks `2026-07-28` when offered, falling back to the
60
+ * 2025 `initialize` handshake. A server that answers the probe with a 5xx fails
61
+ * to connect in that mode; `"legacy"` skips the probe and always uses the 2025
62
+ * handshake.
63
+ */
64
+ versionNegotiation?: "auto" | "legacy";
65
+ };
66
+ type GatewayStatus = "connected" | "connecting" | "disconnected" | "error";
67
+ type GatewayInfo = {
68
+ id: string;
69
+ name: string;
70
+ /** Protocol revision negotiated with the remote server; absent until connected. */
71
+ protocolVersion?: string;
72
+ remoteTools: ReadonlyArray<{
73
+ description?: string;
74
+ name: string;
75
+ }>;
76
+ status: GatewayStatus;
77
+ url: string;
78
+ };
79
+ type GatewayInstance = {
80
+ readonly config: GatewayConfig;
81
+ readonly info: GatewayInfo;
82
+ readonly name: string;
83
+ readonly status: GatewayStatus;
84
+ readonly tools: ReadonlyArray<Tool>;
85
+ callTool: (name: string, args?: Record<string, unknown>) => Promise<unknown>;
86
+ connect: () => Promise<void>;
87
+ disconnect: () => Promise<void>;
88
+ };
89
+ type GatewayManagerInstance = {
90
+ readonly connectedCount: number;
91
+ readonly totalCount: number;
92
+ add: (config: GatewayConfig) => GatewayInstance;
93
+ connectAll: () => Promise<void>;
94
+ disconnectAll: () => Promise<void>;
95
+ get: (id: string) => Option<GatewayInstance>;
96
+ getAll: () => ReadonlyArray<GatewayInstance>;
97
+ getInfoAll: () => ReadonlyArray<GatewayInfo>;
98
+ };
99
+ type TelemetryEventType = "server.start" | "server.stop" | "tool.execute" | "tool.error" | "resource.load" | "resource.error" | "prompt.load" | "prompt.error" | "gateway.connect" | "gateway.disconnect" | "gateway.error" | "session.connect" | "session.disconnect";
100
+ type ErrorCategory = "validation" | "timeout" | "gateway" | "internal" | "auth" | "not_found";
101
+ type CaptureLevel = "full" | "metadata" | "none";
102
+ type ToolCaptureConfig = {
103
+ captureLevel?: CaptureLevel;
104
+ maxOutputSize?: number;
105
+ redactInputFields?: ReadonlyArray<string>;
106
+ };
107
+ type TelemetryEvent = {
108
+ data?: Record<string, unknown>;
109
+ durationMs?: number;
110
+ error?: string;
111
+ errorCategory?: ErrorCategory;
112
+ errorStack?: string;
113
+ input?: Record<string, unknown>;
114
+ name: string;
115
+ output?: unknown;
116
+ requestId?: string;
117
+ sessionId?: string;
118
+ timestamp: number;
119
+ type: TelemetryEventType;
120
+ };
121
+ type TelemetryCollector = {
122
+ flush?: () => Promise<void>;
123
+ recordEvent: (event: TelemetryEvent) => void;
124
+ };
125
+ /** Callback invoked to authenticate an incoming request, as the web `Request`. */
126
+ type Authenticate = (request: Request) => Promise<unknown>;
127
+ /** Response builder invoked when auth is missing or fails. Defaults to `401 { error: "Unauthorized" }`. */
128
+ type OnUnauthorized = (c: Context) => Response | Promise<Response>;
129
+ type AuthMiddlewareConfig = {
130
+ authenticate?: Authenticate;
131
+ onUnauthorized?: OnUnauthorized;
132
+ };
133
+ declare const createAuthMiddleware: ({ authenticate, onUnauthorized }: AuthMiddlewareConfig) => MiddlewareHandler;
134
+ /**
135
+ * Read a header from a request, safely, whatever `authenticate` was given:
136
+ *
137
+ * - **a web `Request`** — what somamcp passes everywhere. Headers implement the
138
+ * WHATWG `Headers` interface (`.get(name)`).
139
+ * - **`undefined`** — stdio, which has no request. Returns `undefined`.
140
+ * - **`http.IncomingMessage`** — not passed by somamcp 2.x, but still read, for
141
+ * code that shares a callback with a plain Node server. Headers are a plain
142
+ * lowercased object; values may be `string | string[]`.
143
+ *
144
+ * Case-insensitive on the header name. Returns `undefined` when the header is
145
+ * absent or the request shape is not recognized — matches the `Headers.get`
146
+ * shape callers already write against.
147
+ */
148
+ declare const getRequestHeader: (request: unknown, name: string) => string | undefined;
149
+ type RouteMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
150
+ /**
151
+ * Config for a custom HTTP route registered on the server's Hono app via
152
+ * `SomaServerInstance.addRoute`.
153
+ *
154
+ * When `protected: true`, the server's `authenticate` callback runs first — a
155
+ * throw or rejection short-circuits to `onUnauthorized` (default `401`).
156
+ *
157
+ * ### Route ordering
158
+ *
159
+ * Hono dispatches by registration order. `addRoute` registers immediately, so
160
+ * routes added **before** `start()` land alongside artifacts and introspection
161
+ * routes in call order. For concrete non-overlapping paths this doesn't matter;
162
+ * for wildcards or overlapping prefixes, register earlier to take precedence.
163
+ */
164
+ type RouteConfig = {
165
+ method: RouteMethod | ReadonlyArray<RouteMethod>;
166
+ path: `/${string}`;
167
+ protected?: boolean;
168
+ handler: (c: Context) => Response | Promise<Response>;
169
+ onUnauthorized?: OnUnauthorized;
170
+ };
171
+ type SomaServerOptions<T extends SessionAuth = SessionAuth> = ServerConfig<T> & {
172
+ artifacts?: ArtifactConfig[];
173
+ /**
174
+ * Backend implementation. Defaults to the MCP SDK 2.x backend: `createSdkBackend`
175
+ * from `somamcp`, or `createNodeBackend` (the same, plus a port and stdio) from
176
+ * `somamcp/node`.
177
+ */
178
+ backend?: BackendFactory<T>;
179
+ /** Options for the backend; the SDK backends take `SdkBackendOptions`. */
180
+ backendOptions?: Record<string, unknown>;
181
+ build?: BuildInfo;
182
+ enableDashboard?: boolean;
183
+ enableHealthEndpoint?: boolean;
184
+ enableInfoEndpoint?: boolean;
185
+ enableIntrospection?: boolean;
186
+ gateways?: GatewayConfig[];
187
+ healthDetailPath?: string;
188
+ healthPath?: string;
189
+ infoPath?: string;
190
+ introspectionPrefix?: string;
191
+ logLayer?: DirectLogger;
192
+ telemetry?: TelemetryCollector;
193
+ };
194
+ type ServerHealth = {
195
+ activeSessions: number;
196
+ gateways: {
197
+ connected: number;
198
+ total: number;
199
+ };
200
+ name: string;
201
+ startedAt: number;
202
+ status: ServerStatus;
203
+ uptime: number;
204
+ };
205
+ type ServerCapabilities = {
206
+ prompts: ReadonlyArray<{
207
+ description?: string;
208
+ name: string;
209
+ }>;
210
+ resources: ReadonlyArray<{
211
+ description?: string;
212
+ name: string;
213
+ uri: string;
214
+ }>;
215
+ tools: ReadonlyArray<{
216
+ description?: string;
217
+ name: string;
218
+ }>;
219
+ };
220
+ type CapabilitiesSummary = {
221
+ prompts: number;
222
+ resources: number;
223
+ tools: number;
224
+ };
225
+ type ServerInfo = {
226
+ build: BuildInfo;
227
+ capabilities: CapabilitiesSummary;
228
+ name: string;
229
+ runtime: RuntimeInfo;
230
+ version: string;
231
+ };
232
+ type ToolOptions<T extends SessionAuth = SessionAuth, P extends SchemaParams = SchemaParams> = Tool$1<T, P> & {
233
+ captureConfig?: ToolCaptureConfig;
234
+ };
235
+ type SomaServerInstance<T extends SessionAuth = SessionAuth> = {
236
+ readonly name: string;
237
+ readonly serverState: ServerStatus;
238
+ readonly sessions: ReadonlyArray<BackendSession<T>>;
239
+ addPrompt: <Args extends PromptArgument<T>[]>(prompt: Prompt<T, Args>) => void;
240
+ addPrompts: <Args extends PromptArgument<T>[]>(prompts: Prompt<T, Args>[]) => void;
241
+ addResource: (resource: Resource<T>) => void;
242
+ addResources: (resources: Resource<T>[]) => void;
243
+ addResourceTemplate: (template: ResourceTemplate<T>) => void;
244
+ addRoute: (route: RouteConfig) => void;
245
+ addTool: <P extends SchemaParams>(tool: Tool$1<T, P>) => void;
246
+ addTools: <P extends SchemaParams>(tools: Tool$1<T, P>[]) => void;
247
+ /**
248
+ * Web-standard request handler covering both MCP calls and registered
249
+ * artifacts/routes. This is the entry point on Workers and other fetch runtimes:
250
+ * `export default { fetch: (req) => server.fetch(req) }`.
251
+ */
252
+ fetch: (request: Request) => Promise<Response>;
253
+ getApp: () => Hono;
254
+ getCapabilities: () => ServerCapabilities;
255
+ getGatewayManager: () => GatewayManagerInstance;
256
+ getHealth: () => ServerHealth;
257
+ getInfo: () => ServerInfo;
258
+ removePrompt: (name: string) => void;
259
+ removeResource: (name: string) => void;
260
+ removeTool: (name: string) => void;
261
+ start: (options?: TransportConfig) => Promise<void>;
262
+ stop: () => Promise<void>;
263
+ };
264
+ /**
265
+ * Backend-agnostic server core.
266
+ *
267
+ * `backend` is required here on purpose: each entry binds its own default.
268
+ * `somamcp` binds createSdkBackend, which serves through `fetch` only, and
269
+ * `somamcp/node` binds createNodeBackend, which can also listen. A default here
270
+ * would put the choice, and anything Node-only, in front of every entry.
271
+ */
272
+ declare const createServerCore: <T extends SessionAuth = SessionAuth>(options: SomaServerOptions<T> & {
273
+ backend: BackendFactory<T>;
274
+ }) => SomaServerInstance<T>;
275
+ /** Raw bytes (a Node `Buffer` is one), or a URL to fetch them from. */
276
+ type ContentInput = {
277
+ buffer: Uint8Array;
278
+ } | {
279
+ url: string;
280
+ };
281
+ declare const imageContent: (input: ContentInput) => Promise<ImageContent>;
282
+ declare const audioContent: (input: ContentInput) => Promise<AudioContent>;
283
+ declare const createCompositeTelemetry: (collectors: ReadonlyArray<TelemetryCollector>) => TelemetryCollector;
284
+ declare const createConsoleTelemetry: (prefix?: string) => TelemetryCollector;
285
+ type EnrichedErrorResponse = {
286
+ errorCategory: ErrorCategory;
287
+ message: string;
288
+ relatedState?: Record<string, unknown>;
289
+ suggestions?: ReadonlyArray<string>;
290
+ };
291
+ declare const classifyError: (error: unknown) => ErrorCategory;
292
+ declare const createEnrichedError: (error: unknown, context?: {
293
+ gatewayStatus?: string;
294
+ toolName?: string;
295
+ }) => EnrichedErrorResponse;
296
+ declare const createLogLayerTelemetry: (logger: DirectLogger) => TelemetryCollector;
297
+ declare const NoopTelemetry: TelemetryCollector;
298
+ /**
299
+ * Wrap a tool's `execute` in telemetry + error enrichment.
300
+ *
301
+ * The success path returns the tool's return value **unchanged**, so any of the
302
+ * supported shapes reach the backend intact: a plain string, a `ContentResult`
303
+ * (`{ content: [...], isError? }`), or a content-array with multimodal parts
304
+ * (`{ type: "image", data, mimeType }`, `audio`, `resource`, etc.). Use the
305
+ * exported `imageContent` / `audioContent` helpers to build parts without
306
+ * reaching into the backend.
307
+ *
308
+ * The failure path converts an error to a `ContentResult` with `isError: true`
309
+ * and the enriched error payload as the text content.
310
+ */
311
+ declare const wrapTool: <T extends SessionAuth, P extends SchemaParams>(tool: Tool$1<T, P>, telemetry: TelemetryCollector, captureConfig?: ToolCaptureConfig) => Tool$1<T, P>;
312
+ declare const wrapResource: <T extends SessionAuth>(resource: Resource<T>, telemetry: TelemetryCollector) => Resource<T>;
313
+ declare const wrapPrompt: <T extends SessionAuth, Args extends PromptArgument<T>[] = PromptArgument<T>[]>(prompt: Prompt<T, Args>, telemetry: TelemetryCollector) => Prompt<T, Args>;
314
+ declare const createDefaultLogger: (name: string) => DirectLogger;
315
+ declare const registerArtifacts: (app: Hono, artifacts: ReadonlyArray<ArtifactConfig>, authenticate?: ArtifactAuthenticate) => void;
316
+ declare const createDashboardArtifact: (getHealth: () => ServerHealth, getCapabilities: () => ServerCapabilities, getConnections: () => ReadonlyArray<GatewayInfo>) => ArtifactConfig;
317
+ declare const DEFAULT_HEALTH_PATH = "/health";
318
+ declare const DEFAULT_HEALTH_DETAIL_PATH = "/health/detail";
319
+ declare const createHealthArtifact: (getHealth: () => ServerHealth, path?: string) => ArtifactConfig;
320
+ declare const createHealthDetailArtifact: (getHealth: () => ServerHealth, path?: string) => ArtifactConfig;
321
+ declare const DEFAULT_INFO_PATH = "/info";
322
+ declare const createInfoArtifact: (getInfo: () => ServerInfo, path?: string) => ArtifactConfig;
323
+ declare const createCapabilitiesTool: <T extends SessionAuth>(getCapabilities: () => ServerCapabilities) => Tool$1<T>;
324
+ declare const createConnectionsTool: <T extends SessionAuth>(getConnections: () => ReadonlyArray<GatewayInfo>) => Tool$1<T>;
325
+ declare const createHealthTool: <T extends SessionAuth>(getHealth: () => ServerHealth) => Tool$1<T>;
326
+ declare const createInfoTool: <T extends SessionAuth>(getInfo: () => ServerInfo, name?: string) => Tool$1<T>;
327
+ type RedactionPattern = {
328
+ description: string;
329
+ name: string;
330
+ pattern: RegExp;
331
+ replacement?: string;
332
+ };
333
+ type RedactionResult = {
334
+ matches: ReadonlyArray<{
335
+ name: string;
336
+ count: number;
337
+ }>;
338
+ redacted: boolean;
339
+ text: string;
340
+ };
341
+ declare const DEFAULT_REDACTION_PATTERNS: ReadonlyArray<RedactionPattern>;
342
+ declare const redact: (input: string, patterns?: ReadonlyArray<RedactionPattern>) => RedactionResult;
343
+ type FeedbackType = "bug" | "feature" | "feedback" | "question";
344
+ type FeedbackSeverity = "high" | "low" | "medium";
345
+ type NormalizedFeedback = {
346
+ body: string;
347
+ labels: ReadonlyArray<string>;
348
+ title: string;
349
+ };
350
+ type FeedbackSubmitSuccess = {
351
+ id?: string;
352
+ success: true;
353
+ url?: string;
354
+ };
355
+ type FeedbackSubmitFailure = {
356
+ error: string;
357
+ success: false;
358
+ };
359
+ type FeedbackSubmitResult = FeedbackSubmitFailure | FeedbackSubmitSuccess;
360
+ type FeedbackProvider = {
361
+ readonly name: string;
362
+ submit: (payload: NormalizedFeedback) => Promise<FeedbackSubmitResult>;
363
+ };
364
+ type FeedbackEnrichmentContext = {
365
+ type: FeedbackType;
366
+ severity?: FeedbackSeverity;
367
+ };
368
+ type FeedbackToolOptions = {
369
+ description?: string;
370
+ enrichment?: (ctx: FeedbackEnrichmentContext) => Promise<Record<string, unknown>> | Record<string, unknown>;
371
+ extraLabels?: ReadonlyArray<string>;
372
+ name?: string;
373
+ provider: FeedbackProvider;
374
+ redactionPatterns?: ReadonlyArray<RedactionPattern>;
375
+ };
376
+ declare const PARAMETERS: z.ZodObject<{
377
+ description: z.ZodString;
378
+ severity: z.ZodOptional<z.ZodEnum<{
379
+ low: "low";
380
+ medium: "medium";
381
+ high: "high";
382
+ }>>;
383
+ title: z.ZodString;
384
+ type: z.ZodDefault<z.ZodEnum<{
385
+ bug: "bug";
386
+ feature: "feature";
387
+ feedback: "feedback";
388
+ question: "question";
389
+ }>>;
390
+ }, z.core.$strip>;
391
+ declare const createFeedbackTool: <T extends SessionAuth>(options: FeedbackToolOptions) => Tool$1<T, typeof PARAMETERS>;
392
+ type GithubFeedbackOptions = {
393
+ baseUrl?: string;
394
+ defaultLabels?: ReadonlyArray<string>;
395
+ fetchImpl?: typeof fetch;
396
+ getToken: () => Option<string>;
397
+ repo: `${string}/${string}`;
398
+ };
399
+ declare const createGithubFeedback: (options: GithubFeedbackOptions) => FeedbackProvider;
400
+ type WebhookFeedbackOptions = {
401
+ fetchImpl?: typeof fetch;
402
+ headers?: Record<string, string>;
403
+ transform?: (payload: NormalizedFeedback) => unknown;
404
+ url: string;
405
+ };
406
+ declare const createWebhookFeedback: (options: WebhookFeedbackOptions) => FeedbackProvider;
407
+ declare const createGateway: (config: GatewayConfig, telemetry: TelemetryCollector) => GatewayInstance;
408
+ declare const createGatewayManager: (telemetry: TelemetryCollector) => GatewayManagerInstance;
409
+ declare const createProxiedTools: <T extends SessionAuth>(gateway: GatewayInstance, telemetry?: TelemetryCollector) => ReadonlyArray<Tool$1<T>>;
410
+ /**
411
+ * Create a server on the MCP SDK 2.x backend. Serve it with `server.fetch`:
412
+ *
413
+ * ```ts
414
+ * const server = createServer({ name: "my-server", version: "1.0.0" })
415
+ * export default { fetch: (req: Request) => server.fetch(req) }
416
+ * ```
417
+ *
418
+ * To listen on a port or on stdio, import `createServer` from `somamcp/node` instead.
419
+ */
420
+ declare const createServer: <T extends SessionAuth = SessionAuth>(options: SomaServerOptions<T>) => SomaServerInstance<T>;
421
+ export { ServerHealth as $, DEFAULT_HEALTH_DETAIL_PATH as A, DynamicArtifact as At, NoopTelemetry as B, redact as C, RuntimeInfo as Ct, createCapabilitiesTool as D, ArtifactAuthenticate as Dt, createConnectionsTool as E, resolveBuildInfo as Et, registerArtifacts as F, createConsoleTelemetry as G, EnrichedErrorResponse as H, createDefaultLogger as I, audioContent as J, createCompositeTelemetry as K, wrapPrompt as L, createHealthArtifact as M, createHealthDetailArtifact as N, DEFAULT_INFO_PATH as O, ArtifactConfig as Ot, createDashboardArtifact as P, ServerCapabilities as Q, wrapResource as R, RedactionResult as S, BuildInfo as St, createHealthTool as T, readBuildInfoFromEnv as Tt, classifyError as U, createLogLayerTelemetry as V, createEnrichedError as W, createServerCore as X, imageContent as Y, CapabilitiesSummary as Z, FeedbackSubmitSuccess as _, GatewayConfig as _t, createGateway as a, RouteMethod as at, DEFAULT_REDACTION_PATTERNS as b, GatewayManagerInstance as bt, GithubFeedbackOptions as c, Authenticate as ct, FeedbackToolOptions as d, CaptureLevel as dt, ServerInfo as et, createFeedbackTool as f, ErrorCategory as ft, FeedbackSubmitResult as g, ToolCaptureConfig as gt, FeedbackSubmitFailure as h, TelemetryEventType as ht, createGatewayManager as i, RouteConfig as it, DEFAULT_HEALTH_PATH as j, StaticArtifact as jt, createInfoArtifact as k, DirectoryArtifact as kt, createGithubFeedback as l, OnUnauthorized as lt, FeedbackSeverity as m, TelemetryEvent as mt, createServer as n, SomaServerOptions as nt, WebhookFeedbackOptions as o, getRequestHeader as ot, FeedbackProvider as p, TelemetryCollector as pt, ContentInput as q, createProxiedTools as r, ToolOptions as rt, createWebhookFeedback as s, AuthMiddlewareConfig as st, DirectLogger$1 as t, SomaServerInstance as tt, FeedbackEnrichmentContext as u, createAuthMiddleware as ut, FeedbackType as v, GatewayInfo as vt, createInfoTool as w, getRuntimeInfo as wt, RedactionPattern as x, GatewayStatus as xt, NormalizedFeedback as y, GatewayInstance as yt, wrapTool as z };