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.
- package/dist/mcp-server.js +2 -2
- package/mcp-server.js +10 -1
- package/package.json +1 -1
package/dist/mcp-server.js
CHANGED
|
@@ -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
|