sample-aws-pricing-calculator-mcp 1.2.6 → 1.2.7

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.
@@ -125,7 +125,7 @@ If any service fails validation, returns a structured needs_field_grounding redi
125
125
 
126
126
  The estimate is kept in the in-memory store, so the returned aws_estimate_id can be passed to add_service/export_estimate to extend it.
127
127
 
128
- For large estimates (20+ services / line items), prefer create_estimate + multiple add_service calls + export_estimate. This avoids token-generation limits and allows incremental building.`+Tg;Un.IMPORT_ESTIMATE="Download an existing AWS Pricing Calculator estimate by URL or ID. Returns the estimate in JSON (raw, for modifications like region swaps) or Markdown (for LLM consumption, summaries, funding recommendations). Use JSON format when you need to modify and re-export the estimate; use Markdown format when summarizing or presenting costs to the user."});var ZO=b((Upe,tQ)=>{tQ.exports={name:"sample-aws-pricing-calculator-mcp",version:"1.2.6",bin:"dist/mcp-server.js",files:["dist/mcp-server.js","catalog/schema.json","catalog/services/*.json"],description:"MCP server for creating, reading, updating AWS Pricing Calculator estimates through natural language.",license:"MIT-0",main:"mcp-server.js",scripts:{test:"npm run validate-catalog && SKIP_NETWORK=1 node --test test/*.test.js","test:roundtrip":"node --test test/catalog-roundtrip.test.js",mcp:"node mcp-server.js","validate-catalog":"node scripts/validate-catalog.js","validate-catalog:cost":"node scripts/validate-verified-catalog.js",build:"esbuild mcp-server.js --bundle --platform=node --outfile=dist/mcp-server.js --format=cjs --minify --external:@aws-sdk/client-dynamodb --external:@aws-sdk/lib-dynamodb && node scripts/emit-bundle-contract.js && rm -f dist/aws-calculator.zip && zip dist/aws-calculator.zip mcp-server.js lib/aws-client.js lib/estimate-builder.js lib/ec2.js package.json"},dependencies:{"@modelcontextprotocol/sdk":"1.29.0",express:"5.2.1"},peerDependencies:{"@aws-sdk/client-dynamodb":">=3.700.0","@aws-sdk/lib-dynamodb":">=3.700.0"},peerDependenciesMeta:{"@aws-sdk/client-dynamodb":{optional:!0},"@aws-sdk/lib-dynamodb":{optional:!0}},devDependencies:{"@aws-sdk/client-dynamodb":"3.1046.0","@aws-sdk/lib-dynamodb":"3.1046.0",ajv:"8.20.0","ajv-formats":"3.0.1",esbuild:"0.28.1",playwright:"1.60.0"}}});var YO=b((Lpe,XO)=>{"use strict";var rQ=Object.create,vp=Object.defineProperty,nQ=Object.getOwnPropertyDescriptor,iQ=Object.getOwnPropertyNames,aQ=Object.getPrototypeOf,oQ=Object.prototype.hasOwnProperty,sQ=(e,t)=>{for(var r in t)vp(e,r,{get:t[r],enumerable:!0})},qO=(e,t,r,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of iQ(t))!oQ.call(e,n)&&n!==r&&vp(e,n,{get:()=>t[n],enumerable:!(i=nQ(t,n))||i.enumerable});return e},cQ=(e,t,r)=>(r=e!=null?rQ(aQ(e)):{},qO(t||!e||!e.__esModule?vp(r,"default",{value:e,enumerable:!0}):r,e)),uQ=e=>qO(vp({},"__esModule",{value:!0}),e),UO={};sQ(UO,{RequestError:()=>Zi,createAdaptorServer:()=>WO,getRequestListener:()=>KO,serve:()=>jQ});XO.exports=uQ(UO);var lQ=require("http"),Cg=require("http2"),Eg=require("http2"),zO=require("stream"),Zi=class extends Error{constructor(e,t){super(e,t),this.name="RequestError"}},dQ=e=>e instanceof Zi?e:new Zi(e.message,{cause:e}),pQ=global.Request,sc=class extends pQ{constructor(e,t){typeof e=="object"&&To in e&&(e=e[To]()),typeof t?.body?.getReader<"u"&&(t.duplex??="half"),super(e,t)}},fQ=e=>{let t=[],r=e.rawHeaders;for(let i=0;i<r.length;i+=2){let{[i]:n,[i+1]:a}=r;n.charCodeAt(0)!==58&&t.push([n,a])}return new Headers(t)},LO=Symbol("wrapBodyStream"),mQ=(e,t,r,i,n)=>{let a={method:e,headers:r,signal:n.signal};if(e==="TRACE"){a.method="GET";let o=new sc(t,a);return Object.defineProperty(o,"method",{get(){return"TRACE"}}),o}if(!(e==="GET"||e==="HEAD"))if("rawBody"in i&&i.rawBody instanceof Buffer)a.body=new ReadableStream({start(o){o.enqueue(i.rawBody),o.close()}});else if(i[LO]){let o;a.body=new ReadableStream({async pull(s){try{o||=zO.Readable.toWeb(i).getReader();let{done:c,value:u}=await o.read();c?s.close():s.enqueue(u)}catch(c){s.error(c)}}})}else a.body=zO.Readable.toWeb(i);return new sc(t,a)},To=Symbol("getRequestCache"),FO=Symbol("requestCache"),mp=Symbol("incomingKey"),hp=Symbol("urlKey"),hQ=Symbol("headersKey"),Io=Symbol("abortControllerKey"),vQ=Symbol("getAbortController"),cc={get method(){return this[mp].method||"GET"},get url(){return this[hp]},get headers(){return this[hQ]||=fQ(this[mp])},[vQ](){return this[To](),this[Io]},[To](){return this[Io]||=new AbortController,this[FO]||=mQ(this.method,this[hp],this.headers,this[mp],this[Io])}};["body","bodyUsed","cache","credentials","destination","integrity","mode","redirect","referrer","referrerPolicy","signal","keepalive"].forEach(e=>{Object.defineProperty(cc,e,{get(){return this[To]()[e]}})});["arrayBuffer","blob","clone","formData","json","text"].forEach(e=>{Object.defineProperty(cc,e,{value:function(){return this[To]()[e]()}})});Object.defineProperty(cc,Symbol.for("nodejs.util.inspect.custom"),{value:function(e,t,r){let i={method:this.method,url:this.url,headers:this.headers,nativeRequest:this[FO]};return`Request (lightweight) ${r(i,{...t,depth:e==null?null:e-1})}`}});Object.setPrototypeOf(cc,sc.prototype);var gQ=(e,t)=>{let r=Object.create(cc);r[mp]=e;let i=e.url||"";if(i[0]!=="/"&&(i.startsWith("http://")||i.startsWith("https://"))){if(e instanceof Eg.Http2ServerRequest)throw new Zi("Absolute URL for :path is not allowed in HTTP/2");try{let s=new URL(i);r[hp]=s.href}catch(s){throw new Zi("Invalid absolute URL",{cause:s})}return r}let n=(e instanceof Eg.Http2ServerRequest?e.authority:e.headers.host)||t;if(!n)throw new Zi("Missing host header");let a;if(e instanceof Eg.Http2ServerRequest){if(a=e.scheme,!(a==="http"||a==="https"))throw new Zi("Unsupported scheme")}else a=e.socket&&e.socket.encrypted?"https":"http";let o=new URL(`${a}://${n}${i}`);if(o.hostname.length!==n.length&&o.hostname!==n.replace(/:\d+$/,""))throw new Zi("Invalid host header");return r[hp]=o.href,r},Rg=Symbol("responseCache"),jo=Symbol("getResponseCache"),$a=Symbol("cache"),Ag=global.Response,Eo=class BO{#t;#e;[jo](){return delete this[$a],this[Rg]||=new Ag(this.#t,this.#e)}constructor(t,r){let i;if(this.#t=t,r instanceof BO){let n=r[Rg];if(n){this.#e=n,this[jo]();return}else this.#e=r.#e,i=new Headers(r.#e.headers)}else this.#e=r;(typeof t=="string"||typeof t?.getReader<"u"||t instanceof Blob||t instanceof Uint8Array)&&(this[$a]=[r?.status||200,t,i||r?.headers])}get headers(){let t=this[$a];return t?(t[2]instanceof Headers||(t[2]=new Headers(t[2]||{"content-type":"text/plain; charset=UTF-8"})),t[2]):this[jo]().headers}get status(){return this[$a]?.[0]??this[jo]().status}get ok(){let t=this.status;return t>=200&&t<300}};["body","bodyUsed","redirected","statusText","trailers","type","url"].forEach(e=>{Object.defineProperty(Eo.prototype,e,{get(){return this[jo]()[e]}})});["arrayBuffer","blob","clone","formData","json","text"].forEach(e=>{Object.defineProperty(Eo.prototype,e,{value:function(){return this[jo]()[e]()}})});Object.defineProperty(Eo.prototype,Symbol.for("nodejs.util.inspect.custom"),{value:function(e,t,r){let i={status:this.status,headers:this.headers,ok:this.ok,nativeResponse:this[Rg]};return`Response (lightweight) ${r(i,{...t,depth:e==null?null:e-1})}`}});Object.setPrototypeOf(Eo,Ag);Object.setPrototypeOf(Eo.prototype,Ag.prototype);async function yQ(e){return Promise.race([e,Promise.resolve().then(()=>Promise.resolve(void 0))])}function VO(e,t,r){let i=s=>{e.cancel(s).catch(()=>{})};return t.on("close",i),t.on("error",i),(r??e.read()).then(o,n),e.closed.finally(()=>{t.off("close",i),t.off("error",i)});function n(s){s&&t.destroy(s)}function a(){e.read().then(o,n)}function o({done:s,value:c}){try{if(s)t.end();else if(!t.write(c))t.once("drain",a);else return e.read().then(o,n)}catch(u){n(u)}}}function bQ(e,t){if(e.locked)throw new TypeError("ReadableStream is locked.");return t.destroyed?void 0:VO(e.getReader(),t)}var Mg=e=>{let t={};e instanceof Headers||(e=new Headers(e??void 0));let r=[];for(let[i,n]of e)i==="set-cookie"?r.push(n):t[i]=n;return r.length>0&&(t["set-cookie"]=r),t["content-type"]??="text/plain; charset=UTF-8",t},_Q="x-hono-already-sent",xQ=cQ(require("crypto"));typeof global.crypto>"u"&&(global.crypto=xQ.default);var Zg=Symbol("outgoingEnded"),NO=Symbol("incomingDraining"),wQ=500,SQ=64*1024*1024,kg=e=>{let t=e;if(e.destroyed||t[NO])return;if(t[NO]=!0,e instanceof Cg.Http2ServerRequest){try{e.stream?.close?.(Cg.constants.NGHTTP2_NO_ERROR)}catch{}return}let r=0,i=()=>{clearTimeout(a),e.off("data",o),e.off("end",i),e.off("error",i)},n=()=>{i();let s=e.socket;s&&!s.destroyed&&s.destroySoon()},a=setTimeout(n,wQ);a.unref?.();let o=s=>{r+=s.length,r>SQ&&n()};e.on("data",o),e.on("end",i),e.on("error",i),e.resume()},$Q=()=>new Response(null,{status:400}),HO=e=>new Response(null,{status:e instanceof Error&&(e.name==="TimeoutError"||e.constructor.name==="TimeoutError")?504:500}),Dg=(e,t)=>{let r=e instanceof Error?e:new Error("unknown error",{cause:e});r.code==="ERR_STREAM_PREMATURE_CLOSE"?console.info("The user aborted a request."):(console.error(e),t.headersSent||t.writeHead(500,{"Content-Type":"text/plain"}),t.end(`Error: ${r.message}`),t.destroy(r))},JO=e=>{"flushHeaders"in e&&e.writable&&e.flushHeaders()},GO=async(e,t)=>{let[r,i,n]=e[$a],a=!1;if(!n)n={"content-type":"text/plain; charset=UTF-8"};else if(n instanceof Headers)a=n.has("content-length"),n=Mg(n);else if(Array.isArray(n)){let o=new Headers(n);a=o.has("content-length"),n=Mg(o)}else for(let o in n)if(o.length===14&&o.toLowerCase()==="content-length"){a=!0;break}a||(typeof i=="string"?n["Content-Length"]=Buffer.byteLength(i):i instanceof Uint8Array?n["Content-Length"]=i.byteLength:i instanceof Blob&&(n["Content-Length"]=i.size)),t.writeHead(r,n),typeof i=="string"||i instanceof Uint8Array?t.end(i):i instanceof Blob?t.end(new Uint8Array(await i.arrayBuffer())):(JO(t),await bQ(i,t)?.catch(o=>Dg(o,t))),t[Zg]?.()},PQ=e=>typeof e.then=="function",OQ=async(e,t,r={})=>{if(PQ(e))if(r.errorHandler)try{e=await e}catch(n){let a=await r.errorHandler(n);if(!a)return;e=a}else e=await e.catch(HO);if($a in e)return GO(e,t);let i=Mg(e.headers);if(e.body){let n=e.body.getReader(),a=[],o=!1,s;if(i["transfer-encoding"]!=="chunked"){let c=2;for(let u=0;u<c;u++){s||=n.read();let l=await yQ(s).catch(d=>{console.error(d),o=!0});if(!l){if(u===1){await new Promise(d=>setTimeout(d)),c=3;continue}break}if(s=void 0,l.value&&a.push(l.value),l.done){o=!0;break}}o&&!("content-length"in i)&&(i["content-length"]=a.reduce((u,l)=>u+l.length,0))}t.writeHead(e.status,i),a.forEach(c=>{t.write(c)}),o?t.end():(a.length===0&&JO(t),await VO(n,t,s))}else i[_Q]||(t.writeHead(e.status,i),t.end());t[Zg]?.()},KO=(e,t={})=>{let r=t.autoCleanupIncoming??!0;return t.overrideGlobalObjects!==!1&&global.Request!==sc&&(Object.defineProperty(global,"Request",{value:sc}),Object.defineProperty(global,"Response",{value:Eo})),async(i,n)=>{let a,o;try{o=gQ(i,t.hostname);let s=!r||i.method==="GET"||i.method==="HEAD";if(s||(i[LO]=!0,i.on("end",()=>{s=!0}),i instanceof Cg.Http2ServerRequest&&(n[Zg]=()=>{s||setTimeout(()=>{s||setTimeout(()=>{kg(i)})})}),n.on("finish",()=>{s||kg(i)})),n.on("close",()=>{o[Io]&&(i.errored?o[Io].abort(i.errored.toString()):n.writableFinished||o[Io].abort("Client connection prematurely closed.")),s||setTimeout(()=>{s||setTimeout(()=>{kg(i)})})}),a=e(o,{incoming:i,outgoing:n}),$a in a)return GO(a,n)}catch(s){if(a)return Dg(s,n);if(t.errorHandler){if(a=await t.errorHandler(o?s:dQ(s)),!a)return}else o?a=HO(s):a=$Q()}try{return await OQ(a,n,t)}catch(s){return Dg(s,n)}}},WO=e=>{let t=e.fetch,r=KO(t,{hostname:e.hostname,overrideGlobalObjects:e.overrideGlobalObjects,autoCleanupIncoming:e.autoCleanupIncoming});return(e.createServer||lQ.createServer)(e.serverOptions||{},r)},jQ=(e,t)=>{let r=WO(e);return r.listen(e?.port??3e3,e.hostname,()=>{let i=r.address();t&&t(i)}),r}});var QO=b(gp=>{"use strict";Object.defineProperty(gp,"__esModule",{value:!0});gp.WebStandardStreamableHTTPServerTransport=void 0;var ct=ca(),zg=class{constructor(t={}){this._started=!1,this._hasHandledRequest=!1,this._streamMapping=new Map,this._requestToStreamMapping=new Map,this._requestResponseMap=new Map,this._initialized=!1,this._enableJsonResponse=!1,this._standaloneSseStreamId="_GET_stream",this.sessionIdGenerator=t.sessionIdGenerator,this._enableJsonResponse=t.enableJsonResponse??!1,this._eventStore=t.eventStore,this._onsessioninitialized=t.onsessioninitialized,this._onsessionclosed=t.onsessionclosed,this._allowedHosts=t.allowedHosts,this._allowedOrigins=t.allowedOrigins,this._enableDnsRebindingProtection=t.enableDnsRebindingProtection??!1,this._retryInterval=t.retryInterval}async start(){if(this._started)throw new Error("Transport already started");this._started=!0}createJsonErrorResponse(t,r,i,n){let a={code:r,message:i};return n?.data!==void 0&&(a.data=n.data),new Response(JSON.stringify({jsonrpc:"2.0",error:a,id:null}),{status:t,headers:{"Content-Type":"application/json",...n?.headers}})}validateRequestHeaders(t){if(this._enableDnsRebindingProtection){if(this._allowedHosts&&this._allowedHosts.length>0){let r=t.headers.get("host");if(!r||!this._allowedHosts.includes(r)){let i=`Invalid Host header: ${r}`;return this.onerror?.(new Error(i)),this.createJsonErrorResponse(403,-32e3,i)}}if(this._allowedOrigins&&this._allowedOrigins.length>0){let r=t.headers.get("origin");if(r&&!this._allowedOrigins.includes(r)){let i=`Invalid Origin header: ${r}`;return this.onerror?.(new Error(i)),this.createJsonErrorResponse(403,-32e3,i)}}}}async handleRequest(t,r){if(!this.sessionIdGenerator&&this._hasHandledRequest)throw new Error("Stateless transport cannot be reused across requests. Create a new transport per request.");this._hasHandledRequest=!0;let i=this.validateRequestHeaders(t);if(i)return i;switch(t.method){case"POST":return this.handlePostRequest(t,r);case"GET":return this.handleGetRequest(t);case"DELETE":return this.handleDeleteRequest(t);default:return this.handleUnsupportedRequest()}}async writePrimingEvent(t,r,i,n){if(!this._eventStore||n<"2025-11-25")return;let a=await this._eventStore.storeEvent(i,{}),o=`id: ${a}
128
+ For large estimates (20+ services / line items), prefer create_estimate + multiple add_service calls + export_estimate. This avoids token-generation limits and allows incremental building.`+Tg;Un.IMPORT_ESTIMATE="Download an existing AWS Pricing Calculator estimate by URL or ID. Returns the estimate in JSON (raw, for modifications like region swaps) or Markdown (for LLM consumption, summaries, funding recommendations). Use JSON format when you need to modify and re-export the estimate; use Markdown format when summarizing or presenting costs to the user."});var ZO=b((Upe,tQ)=>{tQ.exports={name:"sample-aws-pricing-calculator-mcp",version:"1.2.7",bin:"dist/mcp-server.js",files:["dist/mcp-server.js","catalog/schema.json","catalog/services/*.json"],description:"MCP server for creating, reading, updating AWS Pricing Calculator estimates through natural language.",license:"MIT-0",main:"mcp-server.js",scripts:{test:"npm run validate-catalog && SKIP_NETWORK=1 node --test test/*.test.js","test:roundtrip":"node --test test/catalog-roundtrip.test.js",mcp:"node mcp-server.js","validate-catalog":"node scripts/validate-catalog.js","validate-catalog:cost":"node scripts/validate-verified-catalog.js",build:"esbuild mcp-server.js --bundle --platform=node --outfile=dist/mcp-server.js --format=cjs --minify --external:@aws-sdk/client-dynamodb --external:@aws-sdk/lib-dynamodb && node scripts/emit-bundle-contract.js && rm -f dist/aws-calculator.zip && zip dist/aws-calculator.zip mcp-server.js lib/aws-client.js lib/estimate-builder.js lib/ec2.js package.json"},dependencies:{"@modelcontextprotocol/sdk":"1.29.0",express:"5.2.1"},peerDependencies:{"@aws-sdk/client-dynamodb":">=3.700.0","@aws-sdk/lib-dynamodb":">=3.700.0"},peerDependenciesMeta:{"@aws-sdk/client-dynamodb":{optional:!0},"@aws-sdk/lib-dynamodb":{optional:!0}},devDependencies:{"@aws-sdk/client-dynamodb":"3.1046.0","@aws-sdk/lib-dynamodb":"3.1046.0",ajv:"8.20.0","ajv-formats":"3.0.1",esbuild:"0.28.1",playwright:"1.60.0"}}});var YO=b((Lpe,XO)=>{"use strict";var rQ=Object.create,vp=Object.defineProperty,nQ=Object.getOwnPropertyDescriptor,iQ=Object.getOwnPropertyNames,aQ=Object.getPrototypeOf,oQ=Object.prototype.hasOwnProperty,sQ=(e,t)=>{for(var r in t)vp(e,r,{get:t[r],enumerable:!0})},qO=(e,t,r,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of iQ(t))!oQ.call(e,n)&&n!==r&&vp(e,n,{get:()=>t[n],enumerable:!(i=nQ(t,n))||i.enumerable});return e},cQ=(e,t,r)=>(r=e!=null?rQ(aQ(e)):{},qO(t||!e||!e.__esModule?vp(r,"default",{value:e,enumerable:!0}):r,e)),uQ=e=>qO(vp({},"__esModule",{value:!0}),e),UO={};sQ(UO,{RequestError:()=>Zi,createAdaptorServer:()=>WO,getRequestListener:()=>KO,serve:()=>jQ});XO.exports=uQ(UO);var lQ=require("http"),Cg=require("http2"),Eg=require("http2"),zO=require("stream"),Zi=class extends Error{constructor(e,t){super(e,t),this.name="RequestError"}},dQ=e=>e instanceof Zi?e:new Zi(e.message,{cause:e}),pQ=global.Request,sc=class extends pQ{constructor(e,t){typeof e=="object"&&To in e&&(e=e[To]()),typeof t?.body?.getReader<"u"&&(t.duplex??="half"),super(e,t)}},fQ=e=>{let t=[],r=e.rawHeaders;for(let i=0;i<r.length;i+=2){let{[i]:n,[i+1]:a}=r;n.charCodeAt(0)!==58&&t.push([n,a])}return new Headers(t)},LO=Symbol("wrapBodyStream"),mQ=(e,t,r,i,n)=>{let a={method:e,headers:r,signal:n.signal};if(e==="TRACE"){a.method="GET";let o=new sc(t,a);return Object.defineProperty(o,"method",{get(){return"TRACE"}}),o}if(!(e==="GET"||e==="HEAD"))if("rawBody"in i&&i.rawBody instanceof Buffer)a.body=new ReadableStream({start(o){o.enqueue(i.rawBody),o.close()}});else if(i[LO]){let o;a.body=new ReadableStream({async pull(s){try{o||=zO.Readable.toWeb(i).getReader();let{done:c,value:u}=await o.read();c?s.close():s.enqueue(u)}catch(c){s.error(c)}}})}else a.body=zO.Readable.toWeb(i);return new sc(t,a)},To=Symbol("getRequestCache"),FO=Symbol("requestCache"),mp=Symbol("incomingKey"),hp=Symbol("urlKey"),hQ=Symbol("headersKey"),Io=Symbol("abortControllerKey"),vQ=Symbol("getAbortController"),cc={get method(){return this[mp].method||"GET"},get url(){return this[hp]},get headers(){return this[hQ]||=fQ(this[mp])},[vQ](){return this[To](),this[Io]},[To](){return this[Io]||=new AbortController,this[FO]||=mQ(this.method,this[hp],this.headers,this[mp],this[Io])}};["body","bodyUsed","cache","credentials","destination","integrity","mode","redirect","referrer","referrerPolicy","signal","keepalive"].forEach(e=>{Object.defineProperty(cc,e,{get(){return this[To]()[e]}})});["arrayBuffer","blob","clone","formData","json","text"].forEach(e=>{Object.defineProperty(cc,e,{value:function(){return this[To]()[e]()}})});Object.defineProperty(cc,Symbol.for("nodejs.util.inspect.custom"),{value:function(e,t,r){let i={method:this.method,url:this.url,headers:this.headers,nativeRequest:this[FO]};return`Request (lightweight) ${r(i,{...t,depth:e==null?null:e-1})}`}});Object.setPrototypeOf(cc,sc.prototype);var gQ=(e,t)=>{let r=Object.create(cc);r[mp]=e;let i=e.url||"";if(i[0]!=="/"&&(i.startsWith("http://")||i.startsWith("https://"))){if(e instanceof Eg.Http2ServerRequest)throw new Zi("Absolute URL for :path is not allowed in HTTP/2");try{let s=new URL(i);r[hp]=s.href}catch(s){throw new Zi("Invalid absolute URL",{cause:s})}return r}let n=(e instanceof Eg.Http2ServerRequest?e.authority:e.headers.host)||t;if(!n)throw new Zi("Missing host header");let a;if(e instanceof Eg.Http2ServerRequest){if(a=e.scheme,!(a==="http"||a==="https"))throw new Zi("Unsupported scheme")}else a=e.socket&&e.socket.encrypted?"https":"http";let o=new URL(`${a}://${n}${i}`);if(o.hostname.length!==n.length&&o.hostname!==n.replace(/:\d+$/,""))throw new Zi("Invalid host header");return r[hp]=o.href,r},Rg=Symbol("responseCache"),jo=Symbol("getResponseCache"),$a=Symbol("cache"),Ag=global.Response,Eo=class BO{#t;#e;[jo](){return delete this[$a],this[Rg]||=new Ag(this.#t,this.#e)}constructor(t,r){let i;if(this.#t=t,r instanceof BO){let n=r[Rg];if(n){this.#e=n,this[jo]();return}else this.#e=r.#e,i=new Headers(r.#e.headers)}else this.#e=r;(typeof t=="string"||typeof t?.getReader<"u"||t instanceof Blob||t instanceof Uint8Array)&&(this[$a]=[r?.status||200,t,i||r?.headers])}get headers(){let t=this[$a];return t?(t[2]instanceof Headers||(t[2]=new Headers(t[2]||{"content-type":"text/plain; charset=UTF-8"})),t[2]):this[jo]().headers}get status(){return this[$a]?.[0]??this[jo]().status}get ok(){let t=this.status;return t>=200&&t<300}};["body","bodyUsed","redirected","statusText","trailers","type","url"].forEach(e=>{Object.defineProperty(Eo.prototype,e,{get(){return this[jo]()[e]}})});["arrayBuffer","blob","clone","formData","json","text"].forEach(e=>{Object.defineProperty(Eo.prototype,e,{value:function(){return this[jo]()[e]()}})});Object.defineProperty(Eo.prototype,Symbol.for("nodejs.util.inspect.custom"),{value:function(e,t,r){let i={status:this.status,headers:this.headers,ok:this.ok,nativeResponse:this[Rg]};return`Response (lightweight) ${r(i,{...t,depth:e==null?null:e-1})}`}});Object.setPrototypeOf(Eo,Ag);Object.setPrototypeOf(Eo.prototype,Ag.prototype);async function yQ(e){return Promise.race([e,Promise.resolve().then(()=>Promise.resolve(void 0))])}function VO(e,t,r){let i=s=>{e.cancel(s).catch(()=>{})};return t.on("close",i),t.on("error",i),(r??e.read()).then(o,n),e.closed.finally(()=>{t.off("close",i),t.off("error",i)});function n(s){s&&t.destroy(s)}function a(){e.read().then(o,n)}function o({done:s,value:c}){try{if(s)t.end();else if(!t.write(c))t.once("drain",a);else return e.read().then(o,n)}catch(u){n(u)}}}function bQ(e,t){if(e.locked)throw new TypeError("ReadableStream is locked.");return t.destroyed?void 0:VO(e.getReader(),t)}var Mg=e=>{let t={};e instanceof Headers||(e=new Headers(e??void 0));let r=[];for(let[i,n]of e)i==="set-cookie"?r.push(n):t[i]=n;return r.length>0&&(t["set-cookie"]=r),t["content-type"]??="text/plain; charset=UTF-8",t},_Q="x-hono-already-sent",xQ=cQ(require("crypto"));typeof global.crypto>"u"&&(global.crypto=xQ.default);var Zg=Symbol("outgoingEnded"),NO=Symbol("incomingDraining"),wQ=500,SQ=64*1024*1024,kg=e=>{let t=e;if(e.destroyed||t[NO])return;if(t[NO]=!0,e instanceof Cg.Http2ServerRequest){try{e.stream?.close?.(Cg.constants.NGHTTP2_NO_ERROR)}catch{}return}let r=0,i=()=>{clearTimeout(a),e.off("data",o),e.off("end",i),e.off("error",i)},n=()=>{i();let s=e.socket;s&&!s.destroyed&&s.destroySoon()},a=setTimeout(n,wQ);a.unref?.();let o=s=>{r+=s.length,r>SQ&&n()};e.on("data",o),e.on("end",i),e.on("error",i),e.resume()},$Q=()=>new Response(null,{status:400}),HO=e=>new Response(null,{status:e instanceof Error&&(e.name==="TimeoutError"||e.constructor.name==="TimeoutError")?504:500}),Dg=(e,t)=>{let r=e instanceof Error?e:new Error("unknown error",{cause:e});r.code==="ERR_STREAM_PREMATURE_CLOSE"?console.info("The user aborted a request."):(console.error(e),t.headersSent||t.writeHead(500,{"Content-Type":"text/plain"}),t.end(`Error: ${r.message}`),t.destroy(r))},JO=e=>{"flushHeaders"in e&&e.writable&&e.flushHeaders()},GO=async(e,t)=>{let[r,i,n]=e[$a],a=!1;if(!n)n={"content-type":"text/plain; charset=UTF-8"};else if(n instanceof Headers)a=n.has("content-length"),n=Mg(n);else if(Array.isArray(n)){let o=new Headers(n);a=o.has("content-length"),n=Mg(o)}else for(let o in n)if(o.length===14&&o.toLowerCase()==="content-length"){a=!0;break}a||(typeof i=="string"?n["Content-Length"]=Buffer.byteLength(i):i instanceof Uint8Array?n["Content-Length"]=i.byteLength:i instanceof Blob&&(n["Content-Length"]=i.size)),t.writeHead(r,n),typeof i=="string"||i instanceof Uint8Array?t.end(i):i instanceof Blob?t.end(new Uint8Array(await i.arrayBuffer())):(JO(t),await bQ(i,t)?.catch(o=>Dg(o,t))),t[Zg]?.()},PQ=e=>typeof e.then=="function",OQ=async(e,t,r={})=>{if(PQ(e))if(r.errorHandler)try{e=await e}catch(n){let a=await r.errorHandler(n);if(!a)return;e=a}else e=await e.catch(HO);if($a in e)return GO(e,t);let i=Mg(e.headers);if(e.body){let n=e.body.getReader(),a=[],o=!1,s;if(i["transfer-encoding"]!=="chunked"){let c=2;for(let u=0;u<c;u++){s||=n.read();let l=await yQ(s).catch(d=>{console.error(d),o=!0});if(!l){if(u===1){await new Promise(d=>setTimeout(d)),c=3;continue}break}if(s=void 0,l.value&&a.push(l.value),l.done){o=!0;break}}o&&!("content-length"in i)&&(i["content-length"]=a.reduce((u,l)=>u+l.length,0))}t.writeHead(e.status,i),a.forEach(c=>{t.write(c)}),o?t.end():(a.length===0&&JO(t),await VO(n,t,s))}else i[_Q]||(t.writeHead(e.status,i),t.end());t[Zg]?.()},KO=(e,t={})=>{let r=t.autoCleanupIncoming??!0;return t.overrideGlobalObjects!==!1&&global.Request!==sc&&(Object.defineProperty(global,"Request",{value:sc}),Object.defineProperty(global,"Response",{value:Eo})),async(i,n)=>{let a,o;try{o=gQ(i,t.hostname);let s=!r||i.method==="GET"||i.method==="HEAD";if(s||(i[LO]=!0,i.on("end",()=>{s=!0}),i instanceof Cg.Http2ServerRequest&&(n[Zg]=()=>{s||setTimeout(()=>{s||setTimeout(()=>{kg(i)})})}),n.on("finish",()=>{s||kg(i)})),n.on("close",()=>{o[Io]&&(i.errored?o[Io].abort(i.errored.toString()):n.writableFinished||o[Io].abort("Client connection prematurely closed.")),s||setTimeout(()=>{s||setTimeout(()=>{kg(i)})})}),a=e(o,{incoming:i,outgoing:n}),$a in a)return GO(a,n)}catch(s){if(a)return Dg(s,n);if(t.errorHandler){if(a=await t.errorHandler(o?s:dQ(s)),!a)return}else o?a=HO(s):a=$Q()}try{return await OQ(a,n,t)}catch(s){return Dg(s,n)}}},WO=e=>{let t=e.fetch,r=KO(t,{hostname:e.hostname,overrideGlobalObjects:e.overrideGlobalObjects,autoCleanupIncoming:e.autoCleanupIncoming});return(e.createServer||lQ.createServer)(e.serverOptions||{},r)},jQ=(e,t)=>{let r=WO(e);return r.listen(e?.port??3e3,e.hostname,()=>{let i=r.address();t&&t(i)}),r}});var QO=b(gp=>{"use strict";Object.defineProperty(gp,"__esModule",{value:!0});gp.WebStandardStreamableHTTPServerTransport=void 0;var ct=ca(),zg=class{constructor(t={}){this._started=!1,this._hasHandledRequest=!1,this._streamMapping=new Map,this._requestToStreamMapping=new Map,this._requestResponseMap=new Map,this._initialized=!1,this._enableJsonResponse=!1,this._standaloneSseStreamId="_GET_stream",this.sessionIdGenerator=t.sessionIdGenerator,this._enableJsonResponse=t.enableJsonResponse??!1,this._eventStore=t.eventStore,this._onsessioninitialized=t.onsessioninitialized,this._onsessionclosed=t.onsessionclosed,this._allowedHosts=t.allowedHosts,this._allowedOrigins=t.allowedOrigins,this._enableDnsRebindingProtection=t.enableDnsRebindingProtection??!1,this._retryInterval=t.retryInterval}async start(){if(this._started)throw new Error("Transport already started");this._started=!0}createJsonErrorResponse(t,r,i,n){let a={code:r,message:i};return n?.data!==void 0&&(a.data=n.data),new Response(JSON.stringify({jsonrpc:"2.0",error:a,id:null}),{status:t,headers:{"Content-Type":"application/json",...n?.headers}})}validateRequestHeaders(t){if(this._enableDnsRebindingProtection){if(this._allowedHosts&&this._allowedHosts.length>0){let r=t.headers.get("host");if(!r||!this._allowedHosts.includes(r)){let i=`Invalid Host header: ${r}`;return this.onerror?.(new Error(i)),this.createJsonErrorResponse(403,-32e3,i)}}if(this._allowedOrigins&&this._allowedOrigins.length>0){let r=t.headers.get("origin");if(r&&!this._allowedOrigins.includes(r)){let i=`Invalid Origin header: ${r}`;return this.onerror?.(new Error(i)),this.createJsonErrorResponse(403,-32e3,i)}}}}async handleRequest(t,r){if(!this.sessionIdGenerator&&this._hasHandledRequest)throw new Error("Stateless transport cannot be reused across requests. Create a new transport per request.");this._hasHandledRequest=!0;let i=this.validateRequestHeaders(t);if(i)return i;switch(t.method){case"POST":return this.handlePostRequest(t,r);case"GET":return this.handleGetRequest(t);case"DELETE":return this.handleDeleteRequest(t);default:return this.handleUnsupportedRequest()}}async writePrimingEvent(t,r,i,n){if(!this._eventStore||n<"2025-11-25")return;let a=await this._eventStore.storeEvent(i,{}),o=`id: ${a}
129
129
  data:
130
130
 
131
131
  `;this._retryInterval!==void 0&&(o=`id: ${a}
@@ -187,7 +187,7 @@ return fn.apply(this, arguments)
187
187
  </body>
188
188
  </html>
189
189
  `}function Bce(){return function(){this.error(404)}}function Vce(){return function(t){if(this.hasTrailingSlash()){this.error(404);return}var r=Xb.original(this.req);r.path=null,r.pathname=Lce(r.pathname+"/");var i=Ace(qce.format(r)),n=Fce("Redirecting","Redirecting to "+Zce(i));t.statusCode=301,t.setHeader("Content-Type","text/html; charset=UTF-8"),t.setHeader("Content-Length",Buffer.byteLength(n)),t.setHeader("Content-Security-Policy","default-src 'none'"),t.setHeader("X-Content-Type-Options","nosniff"),t.setHeader("Location",i),t.end(n)}}});var MC=b((Pr,RC)=>{"use strict";var Sf=lk(),Hce=require("node:events").EventEmitter,IC=pk(),TC=y4(),EC=Cb(),kC=J4(),CC=PC();Pr=RC.exports=Jce;function Jce(){var e=function(t,r,i){e.handle(t,r,i)};return IC(e,Hce.prototype,!1),IC(e,TC,!1),e.request=Object.create(kC,{app:{configurable:!0,enumerable:!0,writable:!0,value:e}}),e.response=Object.create(CC,{app:{configurable:!0,enumerable:!0,writable:!0,value:e}}),e.init(),e}Pr.application=TC;Pr.request=kC;Pr.response=CC;Pr.Route=EC.Route;Pr.Router=EC;Pr.json=Sf.json;Pr.raw=Sf.raw;Pr.static=jC();Pr.text=Sf.text;Pr.urlencoded=Sf.urlencoded});var AC=b((hhe,DC)=>{"use strict";DC.exports=MC()});var{McpServer:Gce}=AP(),{StdioServerTransport:Kce}=UP(),{z:Rt}=eg(),ZC=require("node:path"),{PARTITIONS:Wce,loadManifest:zC,findService:Xce,fetchServiceDefinition:Yce,extractInputFields:Qce,searchServices:eue,fetchEstimate:tue,estimateToMarkdown:rue}=Po(),NC=ic(),{createEstimateStore:nue}=sO(),{loadCatalog:iue}=cp(),{nextStepFor:aue}=dp(),{traceTool:hi}=lg(),qC=nc(),{runWithSession:oue}=ep(),{createHandlerHelpers:sue,mcpJsonOk:Gn,mcpTextErr:Da,checkPartition:$f,parseServicesArg:UC}=DO(),vi=AO(),cue=require("node:fs");function uue(){if(process.env.CALCMCP_CATALOG_DIR)return process.env.CALCMCP_CATALOG_DIR;let e=[ZC.join(__dirname,"catalog","services"),ZC.join(__dirname,"..","catalog","services")];for(let t of e)if(cue.existsSync(t))return t;return e[0]}var LC=uue();process.env.CALCMCP_CATALOG_DIR&&process.stderr.write(`NOTE: catalog override active \u2014 loading from ${LC}
190
- `);var FC=iue(LC,{strict:!1}),Aa=nue(),Mc=ZO(),Or=new Gce({name:Mc.name,version:Mc.version}),lue=sue({catalog:FC}),{addEntries:Yb,lintEstimate:BC,estimateNotFoundResult:Qb,exportWithLint:e_,buildFieldsResult:due,maybeBuildRedirectResult:pue,maybeBuildProductRedirect:fue,annotateSearchResults:mue}=lue;Or.tool("get_server_info",vi.GET_SERVER_INFO,{},hi("get_server_info",async()=>Gn({name:Mc.name,version:Mc.version,description:Mc.description,tools:["search_services","get_service_fields","create_estimate","add_service","build_estimate","validate_estimate","export_estimate","import_estimate","get_server_info"],partitions:Object.keys(Wce)})));Or.tool("search_services",vi.SEARCH_SERVICES,{query:Rt.string().describe('One or more search terms, comma-separated (e.g. "Lambda, S3, Amazon Personalize, API Gateway, CloudWatch")'),partition:Rt.string().optional().describe('AWS partition to search in (default: "aws"). Valid values: "aws", "aws-iso", "aws-iso-b", "aws-eusc"')},hi("search_services",async({query:e,partition:t})=>{let r=t||"aws",i=$f(r);if(i)return i;let n=await zC(r);return Gn(mue(eue(n,e)))}));Or.tool("get_service_fields",vi.GET_SERVICE_FIELDS,{service:Rt.string().describe('One or more service keys, comma-separated (e.g. "aWSLambda, amazonS3, stepFunctionStandard, amazonApiGateway")'),partition:Rt.string().optional().describe('AWS partition to fetch from (default: "aws"). Valid values: "aws", "aws-iso", "aws-iso-b", "aws-eusc"')},hi("get_service_fields",async({service:e,partition:t})=>{let r=t||"aws",i=$f(r);if(i)return i;let n=await zC(r),a=e.split(",").map(u=>u.trim()).filter(Boolean),o=[],s=[];for(let u of a){let l=Xce(n,u);if(!l){s.push(`Service "${u}" not found.`);continue}let d=await fue({svc:l,partition:r});if(d){o.push(d);continue}let p=await Yce(n,l.key,r);if(!p){s.push(`Failed to fetch definition for "${l.key}".`);continue}let m=Qce(p),g=await pue({svc:l,fields:m,partition:r});if(g){o.push(g);continue}let _=await due(l,r);_&&o.push(_)}let c=s.length?{services:o,errors:s}:a.length===1?o[0]:o;return Gn(c)}));Or.tool("create_estimate",vi.CREATE_ESTIMATE,{name:Rt.string().optional().describe('Name for the estimate (default: "My Estimate")'),partition:Rt.string().optional().describe('AWS partition for this estimate (default: "aws"). Valid values: "aws", "aws-iso", "aws-iso-b", "aws-eusc"')},hi("create_estimate",async({name:e,partition:t})=>{let r=$f(t);if(r)return r;let i=new NC(e,t||void 0);return await Aa.put(i),qC.session.start({estimateId:i.id,partition:t||"aws",origin:"create_estimate"}),Gn({estimate_id:i.id,name:i.name})}));Or.tool("add_service",vi.ADD_SERVICE,{estimate_id:Rt.string().describe("Estimate ID from create_estimate"),services:Rt.string().describe('JSON array of service entries. Each entry: {"service":"serviceKey","instance":"optional","group":"optional","config":{...with region, description, and field values}}. Example: [{"service":"aWSLambda","group":"Prod","config":{"region":"eu-west-1","description":"Compute","numberOfRequests":{"value":"19","unit":"millionPerMonth"}}}]')},hi("add_service",async({estimate_id:e,services:t})=>{let r=await Aa.get(e);if(!r)return Qb(e);let i=UC(t);if(i.error)return i.error;let n=await Yb(r,i.entries);return n.some(a=>a.error)||await Aa.put(r),Gn(n)}));Or.tool("validate_estimate",vi.VALIDATE_ESTIMATE,{estimate_id:Rt.string().describe("Estimate ID from create_estimate or build_estimate")},hi("validate_estimate",async({estimate_id:e})=>{let t=await Aa.get(e);if(!t)return Qb(e);try{let{blob:r,lintResult:i}=await BC(t),n=aue(i,FC);return Gn({lint_verdict:i.status,next_step:n,lint_services:i.services,would_be_payload:r})}catch(r){return Da(`Validate failed: ${r.message}`)}}));Or.tool("export_estimate",vi.EXPORT_ESTIMATE,{estimate_id:Rt.string().describe("Estimate ID from create_estimate")},hi("export_estimate",async({estimate_id:e})=>{let t=await Aa.get(e);if(!t)return Qb(e);try{let r=await e_(t);return r.isError?Da(r.text):Gn({sharable_url:r.sharable_url,aws_estimate_id:r.aws_estimate_id})}catch(r){return Da(`Export failed: ${r.message}`)}}));async function VC({services:e,name:t,partition:r}){let i=$f(r);if(i)return i;let n=UC(e);if(n.error)return n.error;if(n.entries.length===0)return Da("No services provided.");let a=new NC(t,r||void 0),o=await Yb(a,n.entries),s=o.filter(c=>c.error);if(s.length>0){let c=[...new Set(s.map(u=>String(u.service||"").split(":")[0]).filter(Boolean))];try{qC.buildEstimate.needsGrounding({estimateId:a.id,servicesToInspect:c,failureCount:s.length})}catch{}return{...Gn({estimate_id:a.id,status:"needs_field_grounding",next_step:`Field IDs/values for ${c.join(", ")} did not match the schema. Call get_service_fields for those services to discover valid field IDs and value shapes, then retry build_estimate with the corrected payload.`,services_to_inspect:c,issues:o}),isError:!1}}await Aa.put(a);try{let c=await e_(a);return c.isError?Da(JSON.stringify({estimate_id:a.id,error:c.text})):Gn({estimate_id:a.id,sharable_url:c.sharable_url,aws_estimate_id:c.aws_estimate_id,services:o})}catch(c){return Da(JSON.stringify({estimate_id:a.id,error:`Build failed: ${c.message}`}))}}Or.tool("build_estimate",vi.BUILD_ESTIMATE,{services:Rt.string().describe('JSON array of service entries. Same shape as add_service. Each entry: {"service":"serviceKey","instance":"optional","group":"optional","config":{...with region, description, and field values}}.'),name:Rt.string().optional().describe('Estimate name (default: "My Estimate")'),partition:Rt.string().optional().describe('AWS partition (default: "aws"). Valid values: "aws", "aws-iso", "aws-iso-b", "aws-eusc", "aws-eusc"')},hi("build_estimate",VC));Or.tool("import_estimate",vi.IMPORT_ESTIMATE,{estimate_id:Rt.string().describe('Estimate ID or full calculator.aws URL (e.g. "bedb9a10..." or "https://calculator.aws/#/estimate?id=bedb9a10...")'),format:Rt.enum(["json","markdown"]).optional().describe('Output format: "json" for raw data (default), "markdown" for LLM-friendly summary')},hi("import_estimate",async({estimate_id:e,format:t})=>{let r=e,i,n=e.match(/[?&]id=([a-f0-9]+)/);n&&(r=n[1]),e.includes("pricing.calculator.aws.eu")&&(i="aws-eusc");try{let a=await tue(r,{partition:i});return{content:[{type:"text",text:t==="markdown"?rue(a):JSON.stringify(a,null,2)}]}}catch(a){return Da(`Import failed: ${a.message}`)}}));async function hue(){if(process.env.MCP_TRANSPORT==="http"){let{StreamableHTTPServerTransport:e}=tj(),t=AC(),r=t();r.use(t.json()),r.post("/mcp",async(a,o)=>{await Or.close();let s=new e({sessionIdGenerator:void 0});o.on("close",()=>s.close()),await Or.connect(s);let c=a.headers["mcp-session-id"]||null;await oue(c,()=>s.handleRequest(a,o,a.body))}),r.get("/mcp",(a,o)=>o.writeHead(405).end("Method Not Allowed")),r.delete("/mcp",(a,o)=>o.writeHead(405).end("Method Not Allowed"));let i=process.env.PORT||8e3,n=process.env.HOST||"127.0.0.1";r.listen(i,n,()=>console.error(`MCP server listening on ${n}:${i}`))}else{let e=new Kce;await Or.connect(e)}}module.exports={__test:{store:Aa,addEntries:Yb,exportWithLint:e_,lintEstimate:BC,buildEstimateHandler:VC}};(require.main===module||process.env.MCP_TRANSPORT==="http")&&hue().catch(e=>{console.error(e),process.exit(1)});
190
+ `);var FC=iue(LC,{strict:!1}),Aa=nue(),Mc=ZO(),Or=new Gce({name:Mc.name,version:Mc.version}),lue=sue({catalog:FC}),{addEntries:Yb,lintEstimate:BC,estimateNotFoundResult:Qb,exportWithLint:e_,buildFieldsResult:due,maybeBuildRedirectResult:pue,maybeBuildProductRedirect:fue,annotateSearchResults:mue}=lue;Or.tool("get_server_info",vi.GET_SERVER_INFO,{},{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},hi("get_server_info",async()=>Gn({name:Mc.name,version:Mc.version,description:Mc.description,tools:["search_services","get_service_fields","create_estimate","add_service","build_estimate","validate_estimate","export_estimate","import_estimate","get_server_info"],partitions:Object.keys(Wce)})));Or.tool("search_services",vi.SEARCH_SERVICES,{query:Rt.string().describe('One or more search terms, comma-separated (e.g. "Lambda, S3, Amazon Personalize, API Gateway, CloudWatch")'),partition:Rt.string().optional().describe('AWS partition to search in (default: "aws"). Valid values: "aws", "aws-iso", "aws-iso-b", "aws-eusc"')},{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},hi("search_services",async({query:e,partition:t})=>{let r=t||"aws",i=$f(r);if(i)return i;let n=await zC(r);return Gn(mue(eue(n,e)))}));Or.tool("get_service_fields",vi.GET_SERVICE_FIELDS,{service:Rt.string().describe('One or more service keys, comma-separated (e.g. "aWSLambda, amazonS3, stepFunctionStandard, amazonApiGateway")'),partition:Rt.string().optional().describe('AWS partition to fetch from (default: "aws"). Valid values: "aws", "aws-iso", "aws-iso-b", "aws-eusc"')},{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0},hi("get_service_fields",async({service:e,partition:t})=>{let r=t||"aws",i=$f(r);if(i)return i;let n=await zC(r),a=e.split(",").map(u=>u.trim()).filter(Boolean),o=[],s=[];for(let u of a){let l=Xce(n,u);if(!l){s.push(`Service "${u}" not found.`);continue}let d=await fue({svc:l,partition:r});if(d){o.push(d);continue}let p=await Yce(n,l.key,r);if(!p){s.push(`Failed to fetch definition for "${l.key}".`);continue}let m=Qce(p),g=await pue({svc:l,fields:m,partition:r});if(g){o.push(g);continue}let _=await due(l,r);_&&o.push(_)}let c=s.length?{services:o,errors:s}:a.length===1?o[0]:o;return Gn(c)}));Or.tool("create_estimate",vi.CREATE_ESTIMATE,{name:Rt.string().optional().describe('Name for the estimate (default: "My Estimate")'),partition:Rt.string().optional().describe('AWS partition for this estimate (default: "aws"). Valid values: "aws", "aws-iso", "aws-iso-b", "aws-eusc"')},{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!1,openWorldHint:!1},hi("create_estimate",async({name:e,partition:t})=>{let r=$f(t);if(r)return r;let i=new NC(e,t||void 0);return await Aa.put(i),qC.session.start({estimateId:i.id,partition:t||"aws",origin:"create_estimate"}),Gn({estimate_id:i.id,name:i.name})}));Or.tool("add_service",vi.ADD_SERVICE,{estimate_id:Rt.string().describe("Estimate ID from create_estimate"),services:Rt.string().describe('JSON array of service entries. Each entry: {"service":"serviceKey","instance":"optional","group":"optional","config":{...with region, description, and field values}}. Example: [{"service":"aWSLambda","group":"Prod","config":{"region":"eu-west-1","description":"Compute","numberOfRequests":{"value":"19","unit":"millionPerMonth"}}}]')},{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!1,openWorldHint:!1},hi("add_service",async({estimate_id:e,services:t})=>{let r=await Aa.get(e);if(!r)return Qb(e);let i=UC(t);if(i.error)return i.error;let n=await Yb(r,i.entries);return n.some(a=>a.error)||await Aa.put(r),Gn(n)}));Or.tool("validate_estimate",vi.VALIDATE_ESTIMATE,{estimate_id:Rt.string().describe("Estimate ID from create_estimate or build_estimate")},{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0},hi("validate_estimate",async({estimate_id:e})=>{let t=await Aa.get(e);if(!t)return Qb(e);try{let{blob:r,lintResult:i}=await BC(t),n=aue(i,FC);return Gn({lint_verdict:i.status,next_step:n,lint_services:i.services,would_be_payload:r})}catch(r){return Da(`Validate failed: ${r.message}`)}}));Or.tool("export_estimate",vi.EXPORT_ESTIMATE,{estimate_id:Rt.string().describe("Estimate ID from create_estimate")},{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!1,openWorldHint:!0},hi("export_estimate",async({estimate_id:e})=>{let t=await Aa.get(e);if(!t)return Qb(e);try{let r=await e_(t);return r.isError?Da(r.text):Gn({sharable_url:r.sharable_url,aws_estimate_id:r.aws_estimate_id})}catch(r){return Da(`Export failed: ${r.message}`)}}));async function VC({services:e,name:t,partition:r}){let i=$f(r);if(i)return i;let n=UC(e);if(n.error)return n.error;if(n.entries.length===0)return Da("No services provided.");let a=new NC(t,r||void 0),o=await Yb(a,n.entries),s=o.filter(c=>c.error);if(s.length>0){let c=[...new Set(s.map(u=>String(u.service||"").split(":")[0]).filter(Boolean))];try{qC.buildEstimate.needsGrounding({estimateId:a.id,servicesToInspect:c,failureCount:s.length})}catch{}return{...Gn({estimate_id:a.id,status:"needs_field_grounding",next_step:`Field IDs/values for ${c.join(", ")} did not match the schema. Call get_service_fields for those services to discover valid field IDs and value shapes, then retry build_estimate with the corrected payload.`,services_to_inspect:c,issues:o}),isError:!1}}await Aa.put(a);try{let c=await e_(a);return c.isError?Da(JSON.stringify({estimate_id:a.id,error:c.text})):Gn({estimate_id:a.id,sharable_url:c.sharable_url,aws_estimate_id:c.aws_estimate_id,services:o})}catch(c){return Da(JSON.stringify({estimate_id:a.id,error:`Build failed: ${c.message}`}))}}Or.tool("build_estimate",vi.BUILD_ESTIMATE,{services:Rt.string().describe('JSON array of service entries. Same shape as add_service. Each entry: {"service":"serviceKey","instance":"optional","group":"optional","config":{...with region, description, and field values}}.'),name:Rt.string().optional().describe('Estimate name (default: "My Estimate")'),partition:Rt.string().optional().describe('AWS partition (default: "aws"). Valid values: "aws", "aws-iso", "aws-iso-b", "aws-eusc", "aws-eusc"')},{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!1,openWorldHint:!0},hi("build_estimate",VC));Or.tool("import_estimate",vi.IMPORT_ESTIMATE,{estimate_id:Rt.string().describe('Estimate ID or full calculator.aws URL (e.g. "bedb9a10..." or "https://calculator.aws/#/estimate?id=bedb9a10...")'),format:Rt.enum(["json","markdown"]).optional().describe('Output format: "json" for raw data (default), "markdown" for LLM-friendly summary')},{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0},hi("import_estimate",async({estimate_id:e,format:t})=>{let r=e,i,n=e.match(/[?&]id=([a-f0-9]+)/);n&&(r=n[1]),e.includes("pricing.calculator.aws.eu")&&(i="aws-eusc");try{let a=await tue(r,{partition:i});return{content:[{type:"text",text:t==="markdown"?rue(a):JSON.stringify(a,null,2)}]}}catch(a){return Da(`Import failed: ${a.message}`)}}));async function hue(){if(process.env.MCP_TRANSPORT==="http"){let{StreamableHTTPServerTransport:e}=tj(),t=AC(),r=t();r.use(t.json({limit:"10mb"})),r.post("/mcp",async(a,o)=>{await Or.close();let s=new e({sessionIdGenerator:void 0});o.on("close",()=>s.close()),await Or.connect(s);let c=a.headers["mcp-session-id"]||null;await oue(c,()=>s.handleRequest(a,o,a.body))}),r.get("/mcp",(a,o)=>o.writeHead(405).end("Method Not Allowed")),r.delete("/mcp",(a,o)=>o.writeHead(405).end("Method Not Allowed"));let i=process.env.PORT||8e3,n=process.env.HOST||"127.0.0.1";r.listen(i,n,()=>console.error(`MCP server listening on ${n}:${i}`))}else{let e=new Kce;await Or.connect(e)}}module.exports={__test:{store:Aa,addEntries:Yb,exportWithLint:e_,lintEstimate:BC,buildEstimateHandler:VC}};(require.main===module||process.env.MCP_TRANSPORT==="http")&&hue().catch(e=>{console.error(e),process.exit(1)});
191
191
  /*! Bundled license information:
192
192
 
193
193
  depd/index.js:
package/mcp-server.js CHANGED
@@ -83,6 +83,7 @@ server.tool(
83
83
  'get_server_info',
84
84
  desc.GET_SERVER_INFO,
85
85
  {},
86
+ { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
86
87
  traceTool('get_server_info', async () => mcpJsonOk({
87
88
  name: pkg.name,
88
89
  version: pkg.version,
@@ -99,6 +100,7 @@ server.tool(
99
100
  query: z.string().describe('One or more search terms, comma-separated (e.g. "Lambda, S3, Amazon Personalize, API Gateway, CloudWatch")'),
100
101
  partition: z.string().optional().describe('AWS partition to search in (default: "aws"). Valid values: "aws", "aws-iso", "aws-iso-b", "aws-eusc"'),
101
102
  },
103
+ { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
102
104
  traceTool('search_services', async ({ query, partition }) => {
103
105
  const p = partition || 'aws';
104
106
  const partErr = checkPartition(p);
@@ -120,6 +122,7 @@ server.tool(
120
122
  service: z.string().describe('One or more service keys, comma-separated (e.g. "aWSLambda, amazonS3, stepFunctionStandard, amazonApiGateway")'),
121
123
  partition: z.string().optional().describe('AWS partition to fetch from (default: "aws"). Valid values: "aws", "aws-iso", "aws-iso-b", "aws-eusc"'),
122
124
  },
125
+ { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
123
126
  traceTool('get_service_fields', async ({ service, partition }) => {
124
127
  const p = partition || 'aws';
125
128
  const partErr = checkPartition(p);
@@ -169,6 +172,7 @@ server.tool(
169
172
  name: z.string().optional().describe('Name for the estimate (default: "My Estimate")'),
170
173
  partition: z.string().optional().describe('AWS partition for this estimate (default: "aws"). Valid values: "aws", "aws-iso", "aws-iso-b", "aws-eusc"'),
171
174
  },
175
+ { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false },
172
176
  traceTool('create_estimate', async ({ name, partition }) => {
173
177
  const partErr = checkPartition(partition);
174
178
  if (partErr) return partErr;
@@ -194,6 +198,7 @@ server.tool(
194
198
  estimate_id: z.string().describe('Estimate ID from create_estimate'),
195
199
  services: z.string().describe('JSON array of service entries. Each entry: {"service":"serviceKey","instance":"optional","group":"optional","config":{...with region, description, and field values}}. Example: [{"service":"aWSLambda","group":"Prod","config":{"region":"eu-west-1","description":"Compute","numberOfRequests":{"value":"19","unit":"millionPerMonth"}}}]'),
196
200
  },
201
+ { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false },
197
202
  traceTool('add_service', async ({ estimate_id, services: servicesStr }) => {
198
203
  const estimate = await estimates.get(estimate_id);
199
204
  if (!estimate) return estimateNotFoundResult(estimate_id);
@@ -217,6 +222,7 @@ server.tool(
217
222
  'validate_estimate',
218
223
  desc.VALIDATE_ESTIMATE,
219
224
  { estimate_id: z.string().describe('Estimate ID from create_estimate or build_estimate') },
225
+ { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
220
226
  traceTool('validate_estimate', async ({ estimate_id }) => {
221
227
  const estimate = await estimates.get(estimate_id);
222
228
  if (!estimate) return estimateNotFoundResult(estimate_id);
@@ -245,6 +251,7 @@ server.tool(
245
251
  'export_estimate',
246
252
  desc.EXPORT_ESTIMATE,
247
253
  { estimate_id: z.string().describe('Estimate ID from create_estimate') },
254
+ { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true },
248
255
  traceTool('export_estimate', async ({ estimate_id }) => {
249
256
  const estimate = await estimates.get(estimate_id);
250
257
  if (!estimate) return estimateNotFoundResult(estimate_id);
@@ -342,6 +349,7 @@ server.tool(
342
349
  name: z.string().optional().describe('Estimate name (default: "My Estimate")'),
343
350
  partition: z.string().optional().describe('AWS partition (default: "aws"). Valid values: "aws", "aws-iso", "aws-iso-b", "aws-eusc", "aws-eusc"'),
344
351
  },
352
+ { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true },
345
353
  traceTool('build_estimate', buildEstimateHandler)
346
354
  );
347
355
 
@@ -352,6 +360,7 @@ server.tool(
352
360
  estimate_id: z.string().describe('Estimate ID or full calculator.aws URL (e.g. "bedb9a10..." or "https://calculator.aws/#/estimate?id=bedb9a10...")'),
353
361
  format: z.enum(['json', 'markdown']).optional().describe('Output format: "json" for raw data (default), "markdown" for LLM-friendly summary'),
354
362
  },
363
+ { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
355
364
  traceTool('import_estimate', async ({ estimate_id, format }) => {
356
365
  // Extract ID from URL if needed
357
366
  let id = estimate_id;
@@ -382,7 +391,7 @@ async function main() {
382
391
  // nosemgrep: lazy-load-module
383
392
  const express = require('express');
384
393
  const app = express();
385
- app.use(express.json());
394
+ app.use(express.json({ limit: '10mb' }));
386
395
  // No CSRF middleware: this endpoint speaks JSON-RPC, not HTML forms.
387
396
  // It uses no cookies and relies on transport-level auth (bearer token /
388
397
  // SigV4 / network policy) configured by the deployment, not browser
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sample-aws-pricing-calculator-mcp",
3
- "version": "1.2.6",
3
+ "version": "1.2.7",
4
4
  "bin": "dist/mcp-server.js",
5
5
  "files": [
6
6
  "dist/mcp-server.js",