@manifest-network/manifest-mcp-fred 0.3.0 → 0.3.2

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.
@@ -1,4 +1,19 @@
1
1
  //#region src/http/auth.d.ts
2
+ /**
3
+ * Produces unix-second timestamps guaranteed unique across calls.
4
+ *
5
+ * ADR-036 signing is deterministic, so tokens sharing the same timestamp
6
+ * produce identical signatures. The provider's replay tracker rejects
7
+ * duplicate signatures on protected endpoints (connection, restart, update).
8
+ * We wait for the wall clock to advance rather than drifting into the future
9
+ * (the provider enforces a 30 s max token age and 10 s max-future-skew).
10
+ * A promise queue serializes concurrent callers.
11
+ */
12
+ declare class AuthTimestampTracker {
13
+ private last;
14
+ private queue;
15
+ next(): Promise<number>;
16
+ }
2
17
  declare function createSignMessage(tenant: string, leaseUuid: string, timestamp: number): string;
3
18
  declare function createLeaseDataSignMessage(leaseUuid: string, metaHashHex: string, timestamp: number): string;
4
19
  interface AuthTokenPayload {
@@ -11,5 +26,5 @@ interface AuthTokenPayload {
11
26
  }
12
27
  declare function createAuthToken(tenant: string, leaseUuid: string, timestamp: number, pubKey: string, signature: string, metaHashHex?: string): string;
13
28
  //#endregion
14
- export { AuthTokenPayload, createAuthToken, createLeaseDataSignMessage, createSignMessage };
29
+ export { AuthTimestampTracker, AuthTokenPayload, createAuthToken, createLeaseDataSignMessage, createSignMessage };
15
30
  //# sourceMappingURL=auth.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"auth.d.ts","names":[],"sources":["../../src/http/auth.ts"],"mappings":";iBAEgB,iBAAA,CACd,MAAA,UACA,SAAA,UACA,SAAA;AAAA,iBAKc,0BAAA,CACd,SAAA,UACA,WAAA,UACA,SAAA;AAAA,UAKe,gBAAA;EAAA,SACN,MAAA;EAAA,SACA,UAAA;EAAA,SACA,SAAA;EAAA,SACA,OAAA;EAAA,SACA,SAAA;EAAA,SACA,SAAA;AAAA;AAAA,iBAGK,eAAA,CACd,MAAA,UACA,SAAA,UACA,SAAA,UACA,MAAA,UACA,SAAA,UACA,WAAA"}
1
+ {"version":3,"file":"auth.d.ts","names":[],"sources":["../../src/http/auth.ts"],"mappings":";;AAYA;;;;;;;;;cAAa,oBAAA;EAAA,QACH,IAAA;EAAA,QACA,KAAA;EAER,IAAA,CAAA,GAAQ,OAAA;AAAA;AAAA,iBAkBM,iBAAA,CACd,MAAA,UACA,SAAA,UACA,SAAA;AAAA,iBAKc,0BAAA,CACd,SAAA,UACA,WAAA,UACA,SAAA;AAAA,UAKe,gBAAA;EAAA,SACN,MAAA;EAAA,SACA,UAAA;EAAA,SACA,SAAA;EAAA,SACA,OAAA;EAAA,SACA,SAAA;EAAA,SACA,SAAA;AAAA;AAAA,iBAGK,eAAA,CACd,MAAA,UACA,SAAA,UACA,SAAA,UACA,MAAA,UACA,SAAA,UACA,WAAA"}
package/dist/http/auth.js CHANGED
@@ -1,5 +1,35 @@
1
1
  import { toBase64 } from "@cosmjs/encoding";
2
2
  //#region src/http/auth.ts
3
+ /**
4
+ * Produces unix-second timestamps guaranteed unique across calls.
5
+ *
6
+ * ADR-036 signing is deterministic, so tokens sharing the same timestamp
7
+ * produce identical signatures. The provider's replay tracker rejects
8
+ * duplicate signatures on protected endpoints (connection, restart, update).
9
+ * We wait for the wall clock to advance rather than drifting into the future
10
+ * (the provider enforces a 30 s max token age and 10 s max-future-skew).
11
+ * A promise queue serializes concurrent callers.
12
+ */
13
+ var AuthTimestampTracker = class {
14
+ constructor() {
15
+ this.last = 0;
16
+ this.queue = Promise.resolve(0);
17
+ }
18
+ next() {
19
+ const result = this.queue.then(async () => {
20
+ let now = Math.floor(Date.now() / 1e3);
21
+ while (now <= this.last) {
22
+ const sleepMs = Math.min((this.last - now + 1) * 1e3, 1e3);
23
+ await new Promise((resolve) => setTimeout(resolve, sleepMs));
24
+ now = Math.floor(Date.now() / 1e3);
25
+ }
26
+ this.last = now;
27
+ return now;
28
+ });
29
+ this.queue = result.catch(() => this.last);
30
+ return result;
31
+ }
32
+ };
3
33
  function createSignMessage(tenant, leaseUuid, timestamp) {
4
34
  return `${tenant}:${leaseUuid}:${timestamp}`;
5
35
  }
@@ -18,6 +48,6 @@ function createAuthToken(tenant, leaseUuid, timestamp, pubKey, signature, metaHa
18
48
  return toBase64(new TextEncoder().encode(JSON.stringify(payload)));
19
49
  }
20
50
  //#endregion
21
- export { createAuthToken, createLeaseDataSignMessage, createSignMessage };
51
+ export { AuthTimestampTracker, createAuthToken, createLeaseDataSignMessage, createSignMessage };
22
52
 
23
53
  //# sourceMappingURL=auth.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"auth.js","names":[],"sources":["../../src/http/auth.ts"],"sourcesContent":["import { toBase64 } from '@cosmjs/encoding';\n\nexport function createSignMessage(\n tenant: string,\n leaseUuid: string,\n timestamp: number,\n): string {\n return `${tenant}:${leaseUuid}:${timestamp}`;\n}\n\nexport function createLeaseDataSignMessage(\n leaseUuid: string,\n metaHashHex: string,\n timestamp: number,\n): string {\n return `manifest lease data ${leaseUuid} ${metaHashHex} ${timestamp}`;\n}\n\nexport interface AuthTokenPayload {\n readonly tenant: string;\n readonly lease_uuid: string;\n readonly timestamp: number;\n readonly pub_key: string;\n readonly signature: string;\n readonly meta_hash?: string;\n}\n\nexport function createAuthToken(\n tenant: string,\n leaseUuid: string,\n timestamp: number,\n pubKey: string,\n signature: string,\n metaHashHex?: string,\n): string {\n const payload: AuthTokenPayload = {\n tenant,\n lease_uuid: leaseUuid,\n timestamp,\n pub_key: pubKey,\n signature,\n ...(metaHashHex !== undefined && { meta_hash: metaHashHex }),\n };\n return toBase64(new TextEncoder().encode(JSON.stringify(payload)));\n}\n"],"mappings":";;AAEA,SAAgB,kBACd,QACA,WACA,WACQ;AACR,QAAO,GAAG,OAAO,GAAG,UAAU,GAAG;;AAGnC,SAAgB,2BACd,WACA,aACA,WACQ;AACR,QAAO,uBAAuB,UAAU,GAAG,YAAY,GAAG;;AAY5D,SAAgB,gBACd,QACA,WACA,WACA,QACA,WACA,aACQ;CACR,MAAM,UAA4B;EAChC;EACA,YAAY;EACZ;EACA,SAAS;EACT;EACA,GAAI,gBAAgB,KAAA,KAAa,EAAE,WAAW,aAAa;EAC5D;AACD,QAAO,SAAS,IAAI,aAAa,CAAC,OAAO,KAAK,UAAU,QAAQ,CAAC,CAAC"}
1
+ {"version":3,"file":"auth.js","names":[],"sources":["../../src/http/auth.ts"],"sourcesContent":["import { toBase64 } from '@cosmjs/encoding';\n\n/**\n * Produces unix-second timestamps guaranteed unique across calls.\n *\n * ADR-036 signing is deterministic, so tokens sharing the same timestamp\n * produce identical signatures. The provider's replay tracker rejects\n * duplicate signatures on protected endpoints (connection, restart, update).\n * We wait for the wall clock to advance rather than drifting into the future\n * (the provider enforces a 30 s max token age and 10 s max-future-skew).\n * A promise queue serializes concurrent callers.\n */\nexport class AuthTimestampTracker {\n private last = 0;\n private queue: Promise<number> = Promise.resolve(0);\n\n next(): Promise<number> {\n const result = this.queue.then(async () => {\n let now = Math.floor(Date.now() / 1000);\n while (now <= this.last) {\n // Cap sleep at 1 s so forward clock jumps (e.g. NTP) are\n // picked up quickly instead of waiting the full precomputed delay.\n const sleepMs = Math.min((this.last - now + 1) * 1000, 1000);\n await new Promise((resolve) => setTimeout(resolve, sleepMs));\n now = Math.floor(Date.now() / 1000);\n }\n this.last = now;\n return now;\n });\n this.queue = result.catch(() => this.last);\n return result;\n }\n}\n\nexport function createSignMessage(\n tenant: string,\n leaseUuid: string,\n timestamp: number,\n): string {\n return `${tenant}:${leaseUuid}:${timestamp}`;\n}\n\nexport function createLeaseDataSignMessage(\n leaseUuid: string,\n metaHashHex: string,\n timestamp: number,\n): string {\n return `manifest lease data ${leaseUuid} ${metaHashHex} ${timestamp}`;\n}\n\nexport interface AuthTokenPayload {\n readonly tenant: string;\n readonly lease_uuid: string;\n readonly timestamp: number;\n readonly pub_key: string;\n readonly signature: string;\n readonly meta_hash?: string;\n}\n\nexport function createAuthToken(\n tenant: string,\n leaseUuid: string,\n timestamp: number,\n pubKey: string,\n signature: string,\n metaHashHex?: string,\n): string {\n const payload: AuthTokenPayload = {\n tenant,\n lease_uuid: leaseUuid,\n timestamp,\n pub_key: pubKey,\n signature,\n ...(metaHashHex !== undefined && { meta_hash: metaHashHex }),\n };\n return toBase64(new TextEncoder().encode(JSON.stringify(payload)));\n}\n"],"mappings":";;;;;;;;;;;;AAYA,IAAa,uBAAb,MAAkC;;AAChC,OAAQ,OAAO;AACf,OAAQ,QAAyB,QAAQ,QAAQ,EAAE;;CAEnD,OAAwB;EACtB,MAAM,SAAS,KAAK,MAAM,KAAK,YAAY;GACzC,IAAI,MAAM,KAAK,MAAM,KAAK,KAAK,GAAG,IAAK;AACvC,UAAO,OAAO,KAAK,MAAM;IAGvB,MAAM,UAAU,KAAK,KAAK,KAAK,OAAO,MAAM,KAAK,KAAM,IAAK;AAC5D,UAAM,IAAI,SAAS,YAAY,WAAW,SAAS,QAAQ,CAAC;AAC5D,UAAM,KAAK,MAAM,KAAK,KAAK,GAAG,IAAK;;AAErC,QAAK,OAAO;AACZ,UAAO;IACP;AACF,OAAK,QAAQ,OAAO,YAAY,KAAK,KAAK;AAC1C,SAAO;;;AAIX,SAAgB,kBACd,QACA,WACA,WACQ;AACR,QAAO,GAAG,OAAO,GAAG,UAAU,GAAG;;AAGnC,SAAgB,2BACd,WACA,aACA,WACQ;AACR,QAAO,uBAAuB,UAAU,GAAG,YAAY,GAAG;;AAY5D,SAAgB,gBACd,QACA,WACA,WACA,QACA,WACA,aACQ;CACR,MAAM,UAA4B;EAChC;EACA,YAAY;EACZ;EACA,SAAS;EACT;EACA,GAAI,gBAAgB,KAAA,KAAa,EAAE,WAAW,aAAa;EAC5D;AACD,QAAO,SAAS,IAAI,aAAa,CAAC,OAAO,KAAK,UAAU,QAAQ,CAAC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"fred.d.ts","names":[],"sources":["../../src/http/fred.ts"],"mappings":";;;cAYa,QAAA;AAAA,UAEI,gBAAA;EAAA,SACN,IAAA;EAAA,SACA,MAAA;EAAA,SACA,KAAA,GAAQ,MAAA;EAAA,SACR,IAAA;AAAA;AAAA,UAGM,iBAAA;EAAA,SACN,SAAA,WAAoB,gBAAA;AAAA;AAAA,UAGd,eAAA;EAAA,SACN,KAAA,EAAO,UAAA;EAAA,SACP,gBAAA;EAAA,SACA,KAAA;EAAA,SACA,KAAA,GAAQ,MAAA;EAAA,SACR,SAAA,YAAqB,gBAAA;EAAA,SACrB,SAAA,GAAY,MAAA;EAAA,SACZ,UAAA;EAAA,SACA,UAAA;EAAA,SACA,UAAA;EAAA,SACA,QAAA,GAAW,MAAA,SAAe,iBAAA;AAAA;AAAA,iBAQf,cAAA,CACpB,WAAA,UACA,SAAA,UACA,SAAA,UACA,OAAA,UAAiB,UAAA,CAAW,KAAA,GAC3B,OAAA,CAAQ,eAAA;AAAA,UAsBM,aAAA;EAAA,SACN,UAAA;EAAA,SACA,MAAA;EAAA,SACA,aAAA;EAAA,SACA,IAAA,EAAM,MAAA;AAAA;AAAA,iBAGK,YAAA,CACpB,WAAA,UACA,SAAA,UACA,SAAA,UACA,IAAA,WACA,OAAA,UAAiB,UAAA,CAAW,KAAA,GAC3B,OAAA,CAAQ,aAAA;AAAA,UAgBM,kBAAA;EAAA,SACN,MAAA;EAAA,SACA,UAAA;EAAA,SACA,UAAA;AAAA;AAAA,iBAGW,iBAAA,CACpB,WAAA,UACA,SAAA,UACA,SAAA,UACA,OAAA,UAAiB,UAAA,CAAW,KAAA,GAC3B,OAAA,CAAQ,kBAAA;AAAA,UAcM,kBAAA;EAAA,SACN,MAAA;AAAA;AAAA,iBAGW,YAAA,CACpB,WAAA,UACA,SAAA,UACA,SAAA,UACA,OAAA,UAAiB,UAAA,CAAW,KAAA,GAC3B,OAAA,CAAQ,kBAAA;AAAA,iBAeW,WAAA,CACpB,WAAA,UACA,SAAA,UACA,OAAA,EAAS,UAAA,EACT,SAAA,UACA,OAAA,UAAiB,UAAA,CAAW,KAAA,GAC3B,OAAA,CAAQ,kBAAA;AAAA,UAmBM,gBAAA;EAAA,SACN,OAAA;EAAA,SACA,KAAA;EAAA,SACA,MAAA;EAAA,SACA,UAAA;EAAA,SACA,KAAA;EAAA,SACA,QAAA;AAAA;AAAA,UAGM,iBAAA;EAAA,SACN,UAAA;EAAA,SACA,MAAA;EAAA,SACA,aAAA;EAAA,SACA,QAAA,WAAmB,gBAAA;AAAA;AAAA,iBAGR,gBAAA,CACpB,WAAA,UACA,SAAA,UACA,SAAA,UACA,OAAA,UAAiB,UAAA,CAAW,KAAA,GAC3B,OAAA,CAAQ,iBAAA;AAAA,UAcM,aAAA;EAAA,SACN,IAAA;EAAA,SACA,KAAA,GAAQ,MAAA;AAAA;AAAA,iBAGG,YAAA,CACpB,WAAA,UACA,SAAA,UACA,SAAA,UACA,OAAA,UAAiB,UAAA,CAAW,KAAA,GAC3B,OAAA,CAAQ,aAAA;AAAA,UAcM,WAAA;EAAA,SACN,UAAA;EAAA,SACA,SAAA;EAAA,SACA,WAAA,GAAc,WAAA;EAAA,SACd,UAAA,IAAc,MAAA,EAAQ,eAAA;AAAA;AAAA,iBA0BX,mBAAA,CACpB,WAAA,UACA,SAAA,UACA,SAAA,kBAA2B,OAAA,WAC3B,IAAA,GAAM,WAAA,EACN,OAAA,UAAiB,UAAA,CAAW,KAAA,GAC3B,OAAA,CAAQ,eAAA"}
1
+ {"version":3,"file":"fred.d.ts","names":[],"sources":["../../src/http/fred.ts"],"mappings":";;;cAaa,QAAA;AAAA,UAEI,gBAAA;EAAA,SACN,IAAA;EAAA,SACA,MAAA;EAAA,SACA,KAAA,GAAQ,MAAA;EAAA,SACR,IAAA;AAAA;AAAA,UAGM,iBAAA;EAAA,SACN,SAAA,WAAoB,gBAAA;AAAA;AAAA,UAGd,eAAA;EAAA,SACN,KAAA,EAAO,UAAA;EAAA,SACP,gBAAA;EAAA,SACA,KAAA;EAAA,SACA,KAAA,GAAQ,MAAA;EAAA,SACR,SAAA,YAAqB,gBAAA;EAAA,SACrB,SAAA,GAAY,MAAA;EAAA,SACZ,UAAA;EAAA,SACA,UAAA;EAAA,SACA,UAAA;EAAA,SACA,QAAA,GAAW,MAAA,SAAe,iBAAA;AAAA;AAAA,iBAQf,cAAA,CACpB,WAAA,UACA,SAAA,UACA,SAAA,UACA,OAAA,UAAiB,UAAA,CAAW,KAAA,GAC3B,OAAA,CAAQ,eAAA;AAAA,UAsBM,aAAA;EAAA,SACN,UAAA;EAAA,SACA,MAAA;EAAA,SACA,aAAA;EAAA,SACA,IAAA,EAAM,MAAA;AAAA;AAAA,iBAGK,YAAA,CACpB,WAAA,UACA,SAAA,UACA,SAAA,UACA,IAAA,WACA,OAAA,UAAiB,UAAA,CAAW,KAAA,GAC3B,OAAA,CAAQ,aAAA;AAAA,UAgBM,kBAAA;EAAA,SACN,MAAA;EAAA,SACA,UAAA;EAAA,SACA,UAAA;AAAA;AAAA,iBAGW,iBAAA,CACpB,WAAA,UACA,SAAA,UACA,SAAA,UACA,OAAA,UAAiB,UAAA,CAAW,KAAA,GAC3B,OAAA,CAAQ,kBAAA;AAAA,UAcM,kBAAA;EAAA,SACN,MAAA;AAAA;AAAA,iBAGW,YAAA,CACpB,WAAA,UACA,SAAA,UACA,SAAA,UACA,OAAA,UAAiB,UAAA,CAAW,KAAA,GAC3B,OAAA,CAAQ,kBAAA;AAAA,iBAeW,WAAA,CACpB,WAAA,UACA,SAAA,UACA,OAAA,EAAS,UAAA,EACT,SAAA,UACA,OAAA,UAAiB,UAAA,CAAW,KAAA,GAC3B,OAAA,CAAQ,kBAAA;AAAA,UAqBM,gBAAA;EAAA,SACN,OAAA;EAAA,SACA,KAAA;EAAA,SACA,MAAA;EAAA,SACA,UAAA;EAAA,SACA,KAAA;EAAA,SACA,QAAA;AAAA;AAAA,UAGM,iBAAA;EAAA,SACN,UAAA;EAAA,SACA,MAAA;EAAA,SACA,aAAA;EAAA,SACA,QAAA,WAAmB,gBAAA;AAAA;AAAA,iBAGR,gBAAA,CACpB,WAAA,UACA,SAAA,UACA,SAAA,UACA,OAAA,UAAiB,UAAA,CAAW,KAAA,GAC3B,OAAA,CAAQ,iBAAA;AAAA,UAcM,aAAA;EAAA,SACN,IAAA;EAAA,SACA,KAAA,GAAQ,MAAA;AAAA;AAAA,iBAGG,YAAA,CACpB,WAAA,UACA,SAAA,UACA,SAAA,UACA,OAAA,UAAiB,UAAA,CAAW,KAAA,GAC3B,OAAA,CAAQ,aAAA;AAAA,UAcM,WAAA;EAAA,SACN,UAAA;EAAA,SACA,SAAA;EAAA,SACA,WAAA,GAAc,WAAA;EAAA,SACd,UAAA,IAAc,MAAA,EAAQ,eAAA;AAAA;AAAA,iBA0BX,mBAAA,CACpB,WAAA,UACA,SAAA,UACA,SAAA,kBAA2B,OAAA,WAC3B,IAAA,GAAM,WAAA,EACN,OAAA,UAAiB,UAAA,CAAW,KAAA,GAC3B,OAAA,CAAQ,eAAA"}
package/dist/http/fred.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { ProviderApiError, checkedFetch, parseJsonResponse, validateProviderUrl } from "./provider.js";
2
2
  import { LeaseState, leaseStateFromJSON, logger } from "@manifest-network/manifest-mcp-core";
3
+ import { toBase64 } from "@cosmjs/encoding";
3
4
  //#region src/http/fred.ts
4
5
  const MAX_TAIL = 1e3;
5
6
  async function getLeaseStatus(providerUrl, leaseUuid, authToken, fetchFn) {
@@ -32,13 +33,14 @@ async function restartLease(providerUrl, leaseUuid, authToken, fetchFn) {
32
33
  }
33
34
  async function updateLease(providerUrl, leaseUuid, payload, authToken, fetchFn) {
34
35
  const url = `${validateProviderUrl(providerUrl)}/v1/leases/${encodeURIComponent(leaseUuid)}/update`;
36
+ const b64 = toBase64(payload);
35
37
  return await parseJsonResponse(await checkedFetch(url, {
36
38
  method: "POST",
37
39
  headers: {
38
40
  Authorization: `Bearer ${authToken}`,
39
- "Content-Type": "application/octet-stream"
41
+ "Content-Type": "application/json"
40
42
  },
41
- body: payload
43
+ body: JSON.stringify({ payload: b64 })
42
44
  }, void 0, fetchFn), url);
43
45
  }
44
46
  async function getLeaseReleases(providerUrl, leaseUuid, authToken, fetchFn) {
@@ -1 +1 @@
1
- {"version":3,"file":"fred.js","names":[],"sources":["../../src/http/fred.ts"],"sourcesContent":["import {\n LeaseState,\n leaseStateFromJSON,\n logger,\n} from '@manifest-network/manifest-mcp-core';\nimport {\n checkedFetch,\n ProviderApiError,\n parseJsonResponse,\n validateProviderUrl,\n} from './provider.js';\n\nexport const MAX_TAIL = 1000;\n\nexport interface FredInstanceInfo {\n readonly name: string;\n readonly status: string;\n readonly ports?: Record<string, number>;\n readonly fqdn?: string;\n}\n\nexport interface FredServiceStatus {\n readonly instances: readonly FredInstanceInfo[];\n}\n\nexport interface FredLeaseStatus {\n readonly state: LeaseState;\n readonly provision_status?: string;\n readonly phase?: string;\n readonly steps?: Record<string, string>;\n readonly instances?: readonly FredInstanceInfo[];\n readonly endpoints?: Record<string, string>;\n readonly last_error?: string;\n readonly fail_count?: number;\n readonly created_at?: string;\n readonly services?: Record<string, FredServiceStatus>;\n}\n\n/** Raw wire shape before LeaseState conversion */\ninterface RawLeaseStatus extends Omit<FredLeaseStatus, 'state'> {\n readonly state: string;\n}\n\nexport async function getLeaseStatus(\n providerUrl: string,\n leaseUuid: string,\n authToken: string,\n fetchFn?: typeof globalThis.fetch,\n): Promise<FredLeaseStatus> {\n const validated = validateProviderUrl(providerUrl);\n const url = `${validated}/v1/leases/${encodeURIComponent(leaseUuid)}/status`;\n const res = await checkedFetch(\n url,\n {\n headers: { Authorization: `Bearer ${authToken}` },\n },\n undefined,\n fetchFn,\n );\n const raw = await parseJsonResponse<RawLeaseStatus>(res, url);\n const state = leaseStateFromJSON(raw.state);\n if (state === LeaseState.UNRECOGNIZED) {\n logger.warn(\n `[getLeaseStatus] Unrecognized lease state \"${raw.state}\" for lease ${leaseUuid}. ` +\n 'The provider may be running a newer version than the client supports.',\n );\n }\n return { ...raw, state };\n}\n\nexport interface FredLeaseLogs {\n readonly lease_uuid: string;\n readonly tenant: string;\n readonly provider_uuid: string;\n readonly logs: Record<string, string>;\n}\n\nexport async function getLeaseLogs(\n providerUrl: string,\n leaseUuid: string,\n authToken: string,\n tail?: number,\n fetchFn?: typeof globalThis.fetch,\n): Promise<FredLeaseLogs> {\n const validated = validateProviderUrl(providerUrl);\n const cappedTail = tail !== undefined ? Math.min(tail, MAX_TAIL) : undefined;\n const qs = cappedTail !== undefined ? `?tail=${cappedTail}` : '';\n const url = `${validated}/v1/leases/${encodeURIComponent(leaseUuid)}/logs${qs}`;\n const res = await checkedFetch(\n url,\n {\n headers: { Authorization: `Bearer ${authToken}` },\n },\n undefined,\n fetchFn,\n );\n return await parseJsonResponse<FredLeaseLogs>(res, url);\n}\n\nexport interface FredLeaseProvision {\n readonly status: string;\n readonly fail_count: number;\n readonly last_error: string;\n}\n\nexport async function getLeaseProvision(\n providerUrl: string,\n leaseUuid: string,\n authToken: string,\n fetchFn?: typeof globalThis.fetch,\n): Promise<FredLeaseProvision> {\n const validated = validateProviderUrl(providerUrl);\n const url = `${validated}/v1/leases/${encodeURIComponent(leaseUuid)}/provision`;\n const res = await checkedFetch(\n url,\n {\n headers: { Authorization: `Bearer ${authToken}` },\n },\n undefined,\n fetchFn,\n );\n return await parseJsonResponse<FredLeaseProvision>(res, url);\n}\n\nexport interface FredActionResponse {\n readonly status: string;\n}\n\nexport async function restartLease(\n providerUrl: string,\n leaseUuid: string,\n authToken: string,\n fetchFn?: typeof globalThis.fetch,\n): Promise<FredActionResponse> {\n const validated = validateProviderUrl(providerUrl);\n const url = `${validated}/v1/leases/${encodeURIComponent(leaseUuid)}/restart`;\n const res = await checkedFetch(\n url,\n {\n method: 'POST',\n headers: { Authorization: `Bearer ${authToken}` },\n },\n undefined,\n fetchFn,\n );\n return await parseJsonResponse<FredActionResponse>(res, url);\n}\n\nexport async function updateLease(\n providerUrl: string,\n leaseUuid: string,\n payload: Uint8Array,\n authToken: string,\n fetchFn?: typeof globalThis.fetch,\n): Promise<FredActionResponse> {\n const validated = validateProviderUrl(providerUrl);\n const url = `${validated}/v1/leases/${encodeURIComponent(leaseUuid)}/update`;\n const res = await checkedFetch(\n url,\n {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${authToken}`,\n 'Content-Type': 'application/octet-stream',\n },\n body: payload,\n },\n undefined,\n fetchFn,\n );\n return await parseJsonResponse<FredActionResponse>(res, url);\n}\n\nexport interface FredLeaseRelease {\n readonly version: number;\n readonly image: string;\n readonly status: string;\n readonly created_at: string;\n readonly error?: string;\n readonly manifest?: string;\n}\n\nexport interface FredLeaseReleases {\n readonly lease_uuid: string;\n readonly tenant: string;\n readonly provider_uuid: string;\n readonly releases: readonly FredLeaseRelease[];\n}\n\nexport async function getLeaseReleases(\n providerUrl: string,\n leaseUuid: string,\n authToken: string,\n fetchFn?: typeof globalThis.fetch,\n): Promise<FredLeaseReleases> {\n const validated = validateProviderUrl(providerUrl);\n const url = `${validated}/v1/leases/${encodeURIComponent(leaseUuid)}/releases`;\n const res = await checkedFetch(\n url,\n {\n headers: { Authorization: `Bearer ${authToken}` },\n },\n undefined,\n fetchFn,\n );\n return await parseJsonResponse<FredLeaseReleases>(res, url);\n}\n\nexport interface FredLeaseInfo {\n readonly host: string;\n readonly ports?: Record<string, unknown>;\n}\n\nexport async function getLeaseInfo(\n providerUrl: string,\n leaseUuid: string,\n authToken: string,\n fetchFn?: typeof globalThis.fetch,\n): Promise<FredLeaseInfo> {\n const validated = validateProviderUrl(providerUrl);\n const url = `${validated}/v1/leases/${encodeURIComponent(leaseUuid)}/info`;\n const res = await checkedFetch(\n url,\n {\n headers: { Authorization: `Bearer ${authToken}` },\n },\n undefined,\n fetchFn,\n );\n return await parseJsonResponse<FredLeaseInfo>(res, url);\n}\n\nexport interface PollOptions {\n readonly intervalMs?: number;\n readonly timeoutMs?: number;\n readonly abortSignal?: AbortSignal;\n readonly onProgress?: (status: FredLeaseStatus) => void;\n}\n\nfunction leaseStateName(state: LeaseState): string {\n return LeaseState[state] ?? String(state);\n}\n\nfunction abortableSleep(ms: number, signal?: AbortSignal): Promise<void> {\n if (!signal) return new Promise((resolve) => setTimeout(resolve, ms));\n signal.throwIfAborted();\n return new Promise<void>((resolve, reject) => {\n const onAbort = () => {\n clearTimeout(timer);\n reject(\n signal.reason ??\n new DOMException('The operation was aborted', 'AbortError'),\n );\n };\n const timer = setTimeout(() => {\n signal.removeEventListener('abort', onAbort);\n resolve();\n }, ms);\n signal.addEventListener('abort', onAbort, { once: true });\n });\n}\n\nexport async function pollLeaseUntilReady(\n providerUrl: string,\n leaseUuid: string,\n authToken: string | (() => Promise<string>),\n opts: PollOptions = {},\n fetchFn?: typeof globalThis.fetch,\n): Promise<FredLeaseStatus> {\n const {\n intervalMs = 3_000,\n timeoutMs = 120_000,\n abortSignal,\n onProgress,\n } = opts;\n const deadline = Date.now() + timeoutMs;\n let lastState: LeaseState | undefined;\n\n while (Date.now() < deadline) {\n abortSignal?.throwIfAborted();\n const token =\n typeof authToken === 'function' ? await authToken() : authToken;\n const status = await getLeaseStatus(providerUrl, leaseUuid, token, fetchFn);\n lastState = status.state;\n onProgress?.(status);\n switch (status.state) {\n case LeaseState.LEASE_STATE_ACTIVE:\n return status;\n case LeaseState.LEASE_STATE_PENDING:\n break;\n case LeaseState.LEASE_STATE_CLOSED:\n case LeaseState.LEASE_STATE_REJECTED:\n case LeaseState.LEASE_STATE_EXPIRED:\n throw new ProviderApiError(\n 0,\n `Lease ${leaseUuid} entered terminal state ${leaseStateName(status.state)}`,\n );\n default:\n throw new ProviderApiError(\n 0,\n `Lease ${leaseUuid} returned unexpected state ${leaseStateName(status.state)}`,\n );\n }\n await abortableSleep(intervalMs, abortSignal);\n }\n\n throw new ProviderApiError(\n 0,\n `Lease ${leaseUuid} poll timed out after ${timeoutMs}ms (last state: ${lastState !== undefined ? leaseStateName(lastState) : 'unknown'})`,\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"fred.js","names":[],"sources":["../../src/http/fred.ts"],"sourcesContent":["import { toBase64 } from '@cosmjs/encoding';\nimport {\n LeaseState,\n leaseStateFromJSON,\n logger,\n} from '@manifest-network/manifest-mcp-core';\nimport {\n checkedFetch,\n ProviderApiError,\n parseJsonResponse,\n validateProviderUrl,\n} from './provider.js';\n\nexport const MAX_TAIL = 1000;\n\nexport interface FredInstanceInfo {\n readonly name: string;\n readonly status: string;\n readonly ports?: Record<string, number>;\n readonly fqdn?: string;\n}\n\nexport interface FredServiceStatus {\n readonly instances: readonly FredInstanceInfo[];\n}\n\nexport interface FredLeaseStatus {\n readonly state: LeaseState;\n readonly provision_status?: string;\n readonly phase?: string;\n readonly steps?: Record<string, string>;\n readonly instances?: readonly FredInstanceInfo[];\n readonly endpoints?: Record<string, string>;\n readonly last_error?: string;\n readonly fail_count?: number;\n readonly created_at?: string;\n readonly services?: Record<string, FredServiceStatus>;\n}\n\n/** Raw wire shape before LeaseState conversion */\ninterface RawLeaseStatus extends Omit<FredLeaseStatus, 'state'> {\n readonly state: string;\n}\n\nexport async function getLeaseStatus(\n providerUrl: string,\n leaseUuid: string,\n authToken: string,\n fetchFn?: typeof globalThis.fetch,\n): Promise<FredLeaseStatus> {\n const validated = validateProviderUrl(providerUrl);\n const url = `${validated}/v1/leases/${encodeURIComponent(leaseUuid)}/status`;\n const res = await checkedFetch(\n url,\n {\n headers: { Authorization: `Bearer ${authToken}` },\n },\n undefined,\n fetchFn,\n );\n const raw = await parseJsonResponse<RawLeaseStatus>(res, url);\n const state = leaseStateFromJSON(raw.state);\n if (state === LeaseState.UNRECOGNIZED) {\n logger.warn(\n `[getLeaseStatus] Unrecognized lease state \"${raw.state}\" for lease ${leaseUuid}. ` +\n 'The provider may be running a newer version than the client supports.',\n );\n }\n return { ...raw, state };\n}\n\nexport interface FredLeaseLogs {\n readonly lease_uuid: string;\n readonly tenant: string;\n readonly provider_uuid: string;\n readonly logs: Record<string, string>;\n}\n\nexport async function getLeaseLogs(\n providerUrl: string,\n leaseUuid: string,\n authToken: string,\n tail?: number,\n fetchFn?: typeof globalThis.fetch,\n): Promise<FredLeaseLogs> {\n const validated = validateProviderUrl(providerUrl);\n const cappedTail = tail !== undefined ? Math.min(tail, MAX_TAIL) : undefined;\n const qs = cappedTail !== undefined ? `?tail=${cappedTail}` : '';\n const url = `${validated}/v1/leases/${encodeURIComponent(leaseUuid)}/logs${qs}`;\n const res = await checkedFetch(\n url,\n {\n headers: { Authorization: `Bearer ${authToken}` },\n },\n undefined,\n fetchFn,\n );\n return await parseJsonResponse<FredLeaseLogs>(res, url);\n}\n\nexport interface FredLeaseProvision {\n readonly status: string;\n readonly fail_count: number;\n readonly last_error: string;\n}\n\nexport async function getLeaseProvision(\n providerUrl: string,\n leaseUuid: string,\n authToken: string,\n fetchFn?: typeof globalThis.fetch,\n): Promise<FredLeaseProvision> {\n const validated = validateProviderUrl(providerUrl);\n const url = `${validated}/v1/leases/${encodeURIComponent(leaseUuid)}/provision`;\n const res = await checkedFetch(\n url,\n {\n headers: { Authorization: `Bearer ${authToken}` },\n },\n undefined,\n fetchFn,\n );\n return await parseJsonResponse<FredLeaseProvision>(res, url);\n}\n\nexport interface FredActionResponse {\n readonly status: string;\n}\n\nexport async function restartLease(\n providerUrl: string,\n leaseUuid: string,\n authToken: string,\n fetchFn?: typeof globalThis.fetch,\n): Promise<FredActionResponse> {\n const validated = validateProviderUrl(providerUrl);\n const url = `${validated}/v1/leases/${encodeURIComponent(leaseUuid)}/restart`;\n const res = await checkedFetch(\n url,\n {\n method: 'POST',\n headers: { Authorization: `Bearer ${authToken}` },\n },\n undefined,\n fetchFn,\n );\n return await parseJsonResponse<FredActionResponse>(res, url);\n}\n\nexport async function updateLease(\n providerUrl: string,\n leaseUuid: string,\n payload: Uint8Array,\n authToken: string,\n fetchFn?: typeof globalThis.fetch,\n): Promise<FredActionResponse> {\n const validated = validateProviderUrl(providerUrl);\n const url = `${validated}/v1/leases/${encodeURIComponent(leaseUuid)}/update`;\n // The provider expects JSON with a base64-encoded payload (Go []byte field).\n const b64 = toBase64(payload);\n const res = await checkedFetch(\n url,\n {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${authToken}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ payload: b64 }),\n },\n undefined,\n fetchFn,\n );\n return await parseJsonResponse<FredActionResponse>(res, url);\n}\n\nexport interface FredLeaseRelease {\n readonly version: number;\n readonly image: string;\n readonly status: string;\n readonly created_at: string;\n readonly error?: string;\n readonly manifest?: string;\n}\n\nexport interface FredLeaseReleases {\n readonly lease_uuid: string;\n readonly tenant: string;\n readonly provider_uuid: string;\n readonly releases: readonly FredLeaseRelease[];\n}\n\nexport async function getLeaseReleases(\n providerUrl: string,\n leaseUuid: string,\n authToken: string,\n fetchFn?: typeof globalThis.fetch,\n): Promise<FredLeaseReleases> {\n const validated = validateProviderUrl(providerUrl);\n const url = `${validated}/v1/leases/${encodeURIComponent(leaseUuid)}/releases`;\n const res = await checkedFetch(\n url,\n {\n headers: { Authorization: `Bearer ${authToken}` },\n },\n undefined,\n fetchFn,\n );\n return await parseJsonResponse<FredLeaseReleases>(res, url);\n}\n\nexport interface FredLeaseInfo {\n readonly host: string;\n readonly ports?: Record<string, unknown>;\n}\n\nexport async function getLeaseInfo(\n providerUrl: string,\n leaseUuid: string,\n authToken: string,\n fetchFn?: typeof globalThis.fetch,\n): Promise<FredLeaseInfo> {\n const validated = validateProviderUrl(providerUrl);\n const url = `${validated}/v1/leases/${encodeURIComponent(leaseUuid)}/info`;\n const res = await checkedFetch(\n url,\n {\n headers: { Authorization: `Bearer ${authToken}` },\n },\n undefined,\n fetchFn,\n );\n return await parseJsonResponse<FredLeaseInfo>(res, url);\n}\n\nexport interface PollOptions {\n readonly intervalMs?: number;\n readonly timeoutMs?: number;\n readonly abortSignal?: AbortSignal;\n readonly onProgress?: (status: FredLeaseStatus) => void;\n}\n\nfunction leaseStateName(state: LeaseState): string {\n return LeaseState[state] ?? String(state);\n}\n\nfunction abortableSleep(ms: number, signal?: AbortSignal): Promise<void> {\n if (!signal) return new Promise((resolve) => setTimeout(resolve, ms));\n signal.throwIfAborted();\n return new Promise<void>((resolve, reject) => {\n const onAbort = () => {\n clearTimeout(timer);\n reject(\n signal.reason ??\n new DOMException('The operation was aborted', 'AbortError'),\n );\n };\n const timer = setTimeout(() => {\n signal.removeEventListener('abort', onAbort);\n resolve();\n }, ms);\n signal.addEventListener('abort', onAbort, { once: true });\n });\n}\n\nexport async function pollLeaseUntilReady(\n providerUrl: string,\n leaseUuid: string,\n authToken: string | (() => Promise<string>),\n opts: PollOptions = {},\n fetchFn?: typeof globalThis.fetch,\n): Promise<FredLeaseStatus> {\n const {\n intervalMs = 3_000,\n timeoutMs = 120_000,\n abortSignal,\n onProgress,\n } = opts;\n const deadline = Date.now() + timeoutMs;\n let lastState: LeaseState | undefined;\n\n while (Date.now() < deadline) {\n abortSignal?.throwIfAborted();\n const token =\n typeof authToken === 'function' ? await authToken() : authToken;\n const status = await getLeaseStatus(providerUrl, leaseUuid, token, fetchFn);\n lastState = status.state;\n onProgress?.(status);\n switch (status.state) {\n case LeaseState.LEASE_STATE_ACTIVE:\n return status;\n case LeaseState.LEASE_STATE_PENDING:\n break;\n case LeaseState.LEASE_STATE_CLOSED:\n case LeaseState.LEASE_STATE_REJECTED:\n case LeaseState.LEASE_STATE_EXPIRED:\n throw new ProviderApiError(\n 0,\n `Lease ${leaseUuid} entered terminal state ${leaseStateName(status.state)}`,\n );\n default:\n throw new ProviderApiError(\n 0,\n `Lease ${leaseUuid} returned unexpected state ${leaseStateName(status.state)}`,\n );\n }\n await abortableSleep(intervalMs, abortSignal);\n }\n\n throw new ProviderApiError(\n 0,\n `Lease ${leaseUuid} poll timed out after ${timeoutMs}ms (last state: ${lastState !== undefined ? leaseStateName(lastState) : 'unknown'})`,\n );\n}\n"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -20,6 +20,7 @@ declare class FredMCPServer {
20
20
  private walletProvider;
21
21
  constructor(options: ManifestMCPServerOptions$1);
22
22
  private requireSignArbitrary;
23
+ private authTimestamps;
23
24
  private getProviderAuthToken;
24
25
  private getLeaseDataAuthToken;
25
26
  private registerTools;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;;;;;;;;;;;;cAwGa,aAAA;EAAA,QACH,SAAA;EAAA,QACA,aAAA;EAAA,QACA,cAAA;cAEI,OAAA,EAAS,0BAAA;EAAA,QAuBb,oBAAA;EAAA,QAUM,oBAAA;EAAA,QAiBA,qBAAA;EAAA,QAuBN,aAAA;EAoZR,SAAA,CAAA,GAAa,MAAA;EAIb,gBAAA,CAAA,GAAoB,mBAAA;EAIpB,UAAA,CAAA;AAAA;AAAA,iBAKc,wBAAA,CACd,MAAA,EAAQ,oBAAA,GACP,OAAA,CAAQ,aAAA"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;;;;;;;;;;;;cAyGa,aAAA;EAAA,QACH,SAAA;EAAA,QACA,aAAA;EAAA,QACA,cAAA;cAEI,OAAA,EAAS,0BAAA;EAAA,QAuBb,oBAAA;EAAA,QAUA,cAAA;EAAA,QAEM,oBAAA;EAAA,QAiBA,qBAAA;EAAA,QAuBN,aAAA;EAoZR,SAAA,CAAA,GAAa,MAAA;EAIb,gBAAA,CAAA,GAAoB,mBAAA;EAIpB,UAAA,CAAA;AAAA;AAAA,iBAKc,wBAAA,CACd,MAAA,EAAQ,oBAAA,GACP,OAAA,CAAQ,aAAA"}
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { createAuthToken, createLeaseDataSignMessage, createSignMessage } from "./http/auth.js";
1
+ import { AuthTimestampTracker, createAuthToken, createLeaseDataSignMessage, createSignMessage } from "./http/auth.js";
2
2
  import { ProviderApiError, checkedFetch, getLeaseConnectionInfo, getProviderHealth, uploadLeaseData, validateProviderUrl } from "./http/provider.js";
3
3
  import { MAX_TAIL, getLeaseInfo, getLeaseLogs, getLeaseProvision, getLeaseReleases, getLeaseStatus, pollLeaseUntilReady, restartLease, updateLease } from "./http/fred.js";
4
4
  import { resolveProviderUrl } from "./tools/resolveLeaseProvider.js";
@@ -16,6 +16,7 @@ import { z } from "zod";
16
16
  //#region src/index.ts
17
17
  var FredMCPServer = class {
18
18
  constructor(options) {
19
+ this.authTimestamps = new AuthTimestampTracker();
19
20
  const config = createValidatedConfig(options.config);
20
21
  this.walletProvider = options.walletProvider;
21
22
  this.clientManager = CosmosClientManager.getInstance(config, this.walletProvider);
@@ -31,13 +32,13 @@ var FredMCPServer = class {
31
32
  }
32
33
  async getProviderAuthToken(address, leaseUuid) {
33
34
  const signArbitrary = this.requireSignArbitrary();
34
- const timestamp = Math.floor(Date.now() / 1e3);
35
+ const timestamp = await this.authTimestamps.next();
35
36
  const { pub_key, signature } = await signArbitrary(address, createSignMessage(address, leaseUuid, timestamp));
36
37
  return createAuthToken(address, leaseUuid, timestamp, pub_key.value, signature);
37
38
  }
38
39
  async getLeaseDataAuthToken(address, leaseUuid, metaHashHex) {
39
40
  const signArbitrary = this.requireSignArbitrary();
40
- const timestamp = Math.floor(Date.now() / 1e3);
41
+ const timestamp = await this.authTimestamps.next();
41
42
  const { pub_key, signature } = await signArbitrary(address, createLeaseDataSignMessage(leaseUuid, metaHashHex, timestamp));
42
43
  return createAuthToken(address, leaseUuid, timestamp, pub_key.value, signature, metaHashHex);
43
44
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["ManifestMCPError","ManifestMCPErrorCode"],"sources":["../src/index.ts"],"sourcesContent":["import type { WalletProvider } from '@manifest-network/manifest-mcp-core';\nimport {\n bigIntReplacer,\n CosmosClientManager,\n createMnemonicServer,\n createValidatedConfig,\n jsonResponse,\n ManifestMCPError,\n ManifestMCPErrorCode,\n type ManifestMCPServerOptions,\n type MnemonicServerConfig,\n VERSION,\n withErrorHandling,\n} from '@manifest-network/manifest-mcp-core';\nimport type { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { z } from 'zod';\nimport {\n createAuthToken,\n createLeaseDataSignMessage,\n createSignMessage,\n} from './http/auth.js';\nimport { getLeaseProvision, getLeaseReleases, MAX_TAIL } from './http/fred.js';\nimport { appStatus } from './tools/appStatus.js';\nimport { browseCatalog } from './tools/browseCatalog.js';\nimport { deployApp } from './tools/deployApp.js';\nimport { fetchActiveLease } from './tools/fetchActiveLease.js';\nimport { getAppLogs } from './tools/getLogs.js';\nimport { resolveProviderUrl } from './tools/resolveLeaseProvider.js';\nimport { restartApp } from './tools/restartApp.js';\nimport { updateApp } from './tools/updateApp.js';\n\nexport type { ManifestMCPServerOptions } from '@manifest-network/manifest-mcp-core';\nexport {\n INFRASTRUCTURE_ERROR_CODES,\n ManifestMCPError,\n ManifestMCPErrorCode,\n} from '@manifest-network/manifest-mcp-core';\nexport {\n type AuthTokenPayload,\n createAuthToken,\n createLeaseDataSignMessage,\n createSignMessage,\n} from './http/auth.js';\nexport {\n type FredActionResponse,\n type FredInstanceInfo,\n type FredLeaseInfo,\n type FredLeaseLogs,\n type FredLeaseProvision,\n type FredLeaseRelease,\n type FredLeaseReleases,\n type FredLeaseStatus,\n type FredServiceStatus,\n getLeaseInfo,\n getLeaseLogs,\n getLeaseProvision,\n getLeaseReleases,\n getLeaseStatus,\n MAX_TAIL,\n type PollOptions,\n pollLeaseUntilReady,\n restartLease,\n updateLease,\n} from './http/fred.js';\nexport {\n type ConnectionDetails,\n checkedFetch,\n getLeaseConnectionInfo,\n getProviderHealth,\n type InstanceInfo,\n type LeaseConnectionResponse,\n ProviderApiError,\n type ProviderHealthResponse,\n type ServiceConnectionDetails,\n uploadLeaseData,\n validateProviderUrl,\n} from './http/provider.js';\nexport {\n type BuildManifestOptions,\n buildManifest,\n buildStackManifest,\n deriveAppNameFromImage,\n getServiceNames,\n isStackManifest,\n mergeManifest,\n normalizePorts,\n parseStackManifest,\n validateServiceName,\n} from './manifest.js';\nexport { appStatus } from './tools/appStatus.js';\nexport { browseCatalog, mapWithConcurrency } from './tools/browseCatalog.js';\nexport {\n type DeployAppInput,\n type DeployAppResult,\n deployApp,\n type ServiceConfig,\n} from './tools/deployApp.js';\nexport { fetchActiveLease } from './tools/fetchActiveLease.js';\nexport { getAppLogs } from './tools/getLogs.js';\nexport { resolveProviderUrl } from './tools/resolveLeaseProvider.js';\nexport { restartApp } from './tools/restartApp.js';\nexport { updateApp } from './tools/updateApp.js';\n\nexport class FredMCPServer {\n private mcpServer: McpServer;\n private clientManager: CosmosClientManager;\n private walletProvider: WalletProvider;\n\n constructor(options: ManifestMCPServerOptions) {\n const config = createValidatedConfig(options.config);\n this.walletProvider = options.walletProvider;\n this.clientManager = CosmosClientManager.getInstance(\n config,\n this.walletProvider,\n );\n\n this.mcpServer = new McpServer(\n {\n name: '@manifest-network/manifest-mcp-fred',\n version: VERSION,\n },\n {\n capabilities: {\n tools: {},\n },\n },\n );\n\n this.registerTools();\n }\n\n private requireSignArbitrary(): NonNullable<WalletProvider['signArbitrary']> {\n if (!this.walletProvider.signArbitrary) {\n throw new ManifestMCPError(\n ManifestMCPErrorCode.INVALID_CONFIG,\n 'Wallet does not support signArbitrary (ADR-036). Required for provider authentication. Use a wallet provider that implements signArbitrary.',\n );\n }\n return this.walletProvider.signArbitrary.bind(this.walletProvider);\n }\n\n private async getProviderAuthToken(\n address: string,\n leaseUuid: string,\n ): Promise<string> {\n const signArbitrary = this.requireSignArbitrary();\n const timestamp = Math.floor(Date.now() / 1000);\n const message = createSignMessage(address, leaseUuid, timestamp);\n const { pub_key, signature } = await signArbitrary(address, message);\n return createAuthToken(\n address,\n leaseUuid,\n timestamp,\n pub_key.value,\n signature,\n );\n }\n\n private async getLeaseDataAuthToken(\n address: string,\n leaseUuid: string,\n metaHashHex: string,\n ): Promise<string> {\n const signArbitrary = this.requireSignArbitrary();\n const timestamp = Math.floor(Date.now() / 1000);\n const message = createLeaseDataSignMessage(\n leaseUuid,\n metaHashHex,\n timestamp,\n );\n const { pub_key, signature } = await signArbitrary(address, message);\n return createAuthToken(\n address,\n leaseUuid,\n timestamp,\n pub_key.value,\n signature,\n metaHashHex,\n );\n }\n\n private registerTools(): void {\n // -- browse_catalog --\n this.mcpServer.registerTool(\n 'browse_catalog',\n {\n description:\n 'Browse available cloud providers and service tiers with live health checks. Use this before deploy_app to see which providers are online and what SKU sizes (e.g. docker-micro, docker-small) are available with pricing.',\n },\n withErrorHandling('browse_catalog', async () => {\n await this.clientManager.acquireRateLimit();\n const queryClient = await this.clientManager.getQueryClient();\n const result = await browseCatalog(queryClient);\n return jsonResponse(result, bigIntReplacer);\n }),\n );\n\n // -- app_status --\n this.mcpServer.registerTool(\n 'app_status',\n {\n description:\n 'Get detailed status and connection info for a deployed app. Use this after deploy_app to check if an app is running and get its URL.',\n inputSchema: {\n lease_uuid: z\n .string()\n .uuid()\n .describe('The lease UUID of the app to check'),\n },\n },\n withErrorHandling('app_status', async (args) => {\n const leaseUuid = args.lease_uuid;\n const address = await this.walletProvider.getAddress();\n await this.clientManager.acquireRateLimit();\n const queryClient = await this.clientManager.getQueryClient();\n const result = await appStatus(\n queryClient,\n address,\n leaseUuid,\n (addr, uuid) => this.getProviderAuthToken(addr, uuid),\n );\n return jsonResponse(result, bigIntReplacer);\n }),\n );\n\n // -- get_logs --\n this.mcpServer.registerTool(\n 'get_logs',\n {\n description:\n 'Get recent container logs for a deployed app. Use this to debug apps that are failing or to verify an app started correctly after deploy_app.',\n inputSchema: {\n lease_uuid: z\n .string()\n .uuid()\n .describe('The lease UUID of the app to get logs for'),\n tail: z\n .number()\n .int()\n .min(1)\n .max(MAX_TAIL)\n .optional()\n .describe('Number of recent log lines to retrieve'),\n },\n },\n withErrorHandling('get_logs', async (args) => {\n const leaseUuid = args.lease_uuid;\n const tail = args.tail;\n const address = await this.walletProvider.getAddress();\n await this.clientManager.acquireRateLimit();\n const queryClient = await this.clientManager.getQueryClient();\n const result = await getAppLogs(\n queryClient,\n address,\n leaseUuid,\n (addr, uuid) => this.getProviderAuthToken(addr, uuid),\n tail,\n );\n return jsonResponse(result, bigIntReplacer);\n }),\n );\n\n // -- deploy_app --\n this.mcpServer.registerTool(\n 'deploy_app',\n {\n description:\n 'Deploy a new containerized application. Requires funded credits (use fund_credit if needed). Creates a lease on-chain, uploads the container manifest to a provider, and polls until ready. Use browse_catalog first to see available SKU sizes.',\n inputSchema: {\n image: z\n .string()\n .optional()\n .describe(\n 'Docker image to deploy. Required unless services is provided.',\n ),\n port: z\n .number()\n .int()\n .min(1)\n .max(65535)\n .optional()\n .describe(\n 'Container port to expose. Required unless services is provided.',\n ),\n size: z\n .string()\n .describe('SKU tier name (e.g. \"docker-micro\", \"docker-small\")'),\n env: z\n .record(z.string(), z.string())\n .optional()\n .describe('Environment variables as key-value pairs'),\n command: z\n .array(z.string())\n .optional()\n .describe('Override container command (entrypoint)'),\n args: z\n .array(z.string())\n .optional()\n .describe('Arguments to the container command'),\n user: z\n .string()\n .optional()\n .describe('User to run the container as (e.g. \"1000:1000\")'),\n tmpfs: z\n .array(z.string())\n .optional()\n .describe('tmpfs mounts (e.g. [\"/tmp:size=64M\"])'),\n health_check: z\n .object({\n test: z.array(z.string()),\n interval: z.string().optional(),\n timeout: z.string().optional(),\n retries: z.number().int().optional(),\n start_period: z.string().optional(),\n })\n .optional()\n .describe('Container health check configuration'),\n stop_grace_period: z\n .string()\n .optional()\n .describe('Grace period before force-killing (e.g. \"30s\")'),\n init: z\n .boolean()\n .optional()\n .describe('Run an init process inside the container'),\n expose: z\n .array(z.string())\n .optional()\n .describe('Expose ports without publishing (e.g. [\"8080/tcp\"])'),\n labels: z\n .record(z.string(), z.string())\n .optional()\n .describe('Container labels as key-value pairs'),\n storage: z\n .string()\n .optional()\n .describe(\n 'Storage SKU name for persistent disk (adds a second lease item)',\n ),\n depends_on: z\n .record(z.string(), z.object({ condition: z.string() }))\n .optional()\n .describe('Service dependencies'),\n services: z\n .record(\n z.string(),\n z.object({\n image: z.string(),\n ports: z.record(z.string(), z.object({})).optional(),\n env: z.record(z.string(), z.string()).optional(),\n command: z.array(z.string()).optional(),\n args: z.array(z.string()).optional(),\n user: z.string().optional(),\n tmpfs: z.array(z.string()).optional(),\n health_check: z\n .object({\n test: z.array(z.string()),\n interval: z.string().optional(),\n timeout: z.string().optional(),\n retries: z.number().int().optional(),\n start_period: z.string().optional(),\n })\n .optional(),\n stop_grace_period: z.string().optional(),\n depends_on: z\n .record(z.string(), z.object({ condition: z.string() }))\n .optional(),\n expose: z.array(z.string()).optional(),\n labels: z.record(z.string(), z.string()).optional(),\n }),\n )\n .optional()\n .describe(\n 'Multi-service stack. Mutually exclusive with image/port. Keys are service names (RFC 1123 DNS labels).',\n ),\n },\n },\n withErrorHandling('deploy_app', async (args) => {\n const result = await deployApp(\n this.clientManager,\n (addr, uuid) => this.getProviderAuthToken(addr, uuid),\n (addr, uuid, metaHashHex) =>\n this.getLeaseDataAuthToken(addr, uuid, metaHashHex),\n {\n image: args.image,\n port: args.port,\n size: args.size,\n env: args.env,\n command: args.command,\n args: args.args,\n user: args.user,\n tmpfs: args.tmpfs,\n health_check: args.health_check,\n stop_grace_period: args.stop_grace_period,\n init: args.init,\n expose: args.expose,\n labels: args.labels,\n storage: args.storage,\n depends_on: args.depends_on,\n services: args.services,\n },\n );\n return jsonResponse(result, bigIntReplacer);\n }),\n );\n\n // -- restart_app --\n this.mcpServer.registerTool(\n 'restart_app',\n {\n description:\n 'Restart a running app via the provider without closing its lease. Use this to apply configuration changes or recover from a crash.',\n inputSchema: {\n lease_uuid: z\n .string()\n .uuid()\n .describe('The lease UUID of the app to restart'),\n },\n },\n withErrorHandling('restart_app', async (args) => {\n const leaseUuid = args.lease_uuid;\n const address = await this.walletProvider.getAddress();\n await this.clientManager.acquireRateLimit();\n const queryClient = await this.clientManager.getQueryClient();\n const result = await restartApp(\n queryClient,\n address,\n leaseUuid,\n (addr, uuid) => this.getProviderAuthToken(addr, uuid),\n );\n return jsonResponse(result, bigIntReplacer);\n }),\n );\n\n // -- update_app --\n this.mcpServer.registerTool(\n 'update_app',\n {\n description:\n 'Update a deployed app with a new container manifest. Use this to change the Docker image, ports, or environment variables of a running app without closing the lease.',\n inputSchema: {\n lease_uuid: z\n .string()\n .uuid()\n .describe('The lease UUID of the app to update'),\n manifest: z\n .string()\n .describe('The full manifest JSON string to deploy'),\n existing_manifest: z\n .string()\n .optional()\n .describe(\n 'The current manifest JSON. When provided, the new manifest is merged over the existing one (env, ports, labels merged; other fields carried forward if not in new).',\n ),\n },\n },\n withErrorHandling('update_app', async (args) => {\n const manifest = args.manifest;\n\n try {\n const parsed = JSON.parse(manifest);\n if (\n parsed === null ||\n typeof parsed !== 'object' ||\n Array.isArray(parsed)\n ) {\n throw new Error('must be a JSON object');\n }\n } catch (err) {\n throw new ManifestMCPError(\n ManifestMCPErrorCode.INVALID_CONFIG,\n `Invalid manifest: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n\n const leaseUuid = args.lease_uuid;\n const address = await this.walletProvider.getAddress();\n await this.clientManager.acquireRateLimit();\n const queryClient = await this.clientManager.getQueryClient();\n\n const result = await updateApp(\n queryClient,\n address,\n leaseUuid,\n (addr, uuid) => this.getProviderAuthToken(addr, uuid),\n manifest,\n args.existing_manifest,\n );\n return jsonResponse(result, bigIntReplacer);\n }),\n );\n\n // -- app_diagnostics --\n this.mcpServer.registerTool(\n 'app_diagnostics',\n {\n description:\n 'Get provision diagnostics for a deployed app. Use this to debug apps stuck in provisioning or that failed to start. Returns provision status, failure count, and last error message.',\n inputSchema: {\n lease_uuid: z\n .string()\n .uuid()\n .describe('The lease UUID of the app to diagnose'),\n },\n },\n withErrorHandling('app_diagnostics', async (args) => {\n const leaseUuid = args.lease_uuid;\n const address = await this.walletProvider.getAddress();\n await this.clientManager.acquireRateLimit();\n const queryClient = await this.clientManager.getQueryClient();\n\n const lease = await fetchActiveLease(\n queryClient,\n leaseUuid,\n 'cannot be diagnosed',\n );\n const providerUrl = await resolveProviderUrl(\n queryClient,\n lease.providerUuid,\n );\n const authToken = await this.getProviderAuthToken(address, leaseUuid);\n const provision = await getLeaseProvision(\n providerUrl,\n leaseUuid,\n authToken,\n );\n\n return jsonResponse(\n {\n lease_uuid: leaseUuid,\n provision_status: provision.status,\n fail_count: provision.fail_count,\n last_error: provision.last_error,\n },\n bigIntReplacer,\n );\n }),\n );\n\n // -- app_releases --\n this.mcpServer.registerTool(\n 'app_releases',\n {\n description:\n 'Get release/version history for a deployed app. Use this to see what versions have been deployed, when they were created, and their status.',\n inputSchema: {\n lease_uuid: z\n .string()\n .uuid()\n .describe('The lease UUID of the app to get release history for'),\n },\n },\n withErrorHandling('app_releases', async (args) => {\n const leaseUuid = args.lease_uuid;\n const address = await this.walletProvider.getAddress();\n await this.clientManager.acquireRateLimit();\n const queryClient = await this.clientManager.getQueryClient();\n\n const lease = await fetchActiveLease(\n queryClient,\n leaseUuid,\n 'releases are not available',\n );\n const providerUrl = await resolveProviderUrl(\n queryClient,\n lease.providerUuid,\n );\n const authToken = await this.getProviderAuthToken(address, leaseUuid);\n const result = await getLeaseReleases(\n providerUrl,\n leaseUuid,\n authToken,\n );\n\n return jsonResponse(\n {\n lease_uuid: leaseUuid,\n releases: result.releases,\n },\n bigIntReplacer,\n );\n }),\n );\n }\n\n getServer(): Server {\n return this.mcpServer.server;\n }\n\n getClientManager(): CosmosClientManager {\n return this.clientManager;\n }\n\n disconnect(): void {\n this.clientManager.disconnect();\n }\n}\n\nexport function createMnemonicFredServer(\n config: MnemonicServerConfig,\n): Promise<FredMCPServer> {\n return createMnemonicServer(config, FredMCPServer);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["ManifestMCPError","ManifestMCPErrorCode"],"sources":["../src/index.ts"],"sourcesContent":["import type { WalletProvider } from '@manifest-network/manifest-mcp-core';\nimport {\n bigIntReplacer,\n CosmosClientManager,\n createMnemonicServer,\n createValidatedConfig,\n jsonResponse,\n ManifestMCPError,\n ManifestMCPErrorCode,\n type ManifestMCPServerOptions,\n type MnemonicServerConfig,\n VERSION,\n withErrorHandling,\n} from '@manifest-network/manifest-mcp-core';\nimport type { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { z } from 'zod';\nimport {\n AuthTimestampTracker,\n createAuthToken,\n createLeaseDataSignMessage,\n createSignMessage,\n} from './http/auth.js';\nimport { getLeaseProvision, getLeaseReleases, MAX_TAIL } from './http/fred.js';\nimport { appStatus } from './tools/appStatus.js';\nimport { browseCatalog } from './tools/browseCatalog.js';\nimport { deployApp } from './tools/deployApp.js';\nimport { fetchActiveLease } from './tools/fetchActiveLease.js';\nimport { getAppLogs } from './tools/getLogs.js';\nimport { resolveProviderUrl } from './tools/resolveLeaseProvider.js';\nimport { restartApp } from './tools/restartApp.js';\nimport { updateApp } from './tools/updateApp.js';\n\nexport type { ManifestMCPServerOptions } from '@manifest-network/manifest-mcp-core';\nexport {\n INFRASTRUCTURE_ERROR_CODES,\n ManifestMCPError,\n ManifestMCPErrorCode,\n} from '@manifest-network/manifest-mcp-core';\nexport {\n type AuthTokenPayload,\n createAuthToken,\n createLeaseDataSignMessage,\n createSignMessage,\n} from './http/auth.js';\nexport {\n type FredActionResponse,\n type FredInstanceInfo,\n type FredLeaseInfo,\n type FredLeaseLogs,\n type FredLeaseProvision,\n type FredLeaseRelease,\n type FredLeaseReleases,\n type FredLeaseStatus,\n type FredServiceStatus,\n getLeaseInfo,\n getLeaseLogs,\n getLeaseProvision,\n getLeaseReleases,\n getLeaseStatus,\n MAX_TAIL,\n type PollOptions,\n pollLeaseUntilReady,\n restartLease,\n updateLease,\n} from './http/fred.js';\nexport {\n type ConnectionDetails,\n checkedFetch,\n getLeaseConnectionInfo,\n getProviderHealth,\n type InstanceInfo,\n type LeaseConnectionResponse,\n ProviderApiError,\n type ProviderHealthResponse,\n type ServiceConnectionDetails,\n uploadLeaseData,\n validateProviderUrl,\n} from './http/provider.js';\nexport {\n type BuildManifestOptions,\n buildManifest,\n buildStackManifest,\n deriveAppNameFromImage,\n getServiceNames,\n isStackManifest,\n mergeManifest,\n normalizePorts,\n parseStackManifest,\n validateServiceName,\n} from './manifest.js';\nexport { appStatus } from './tools/appStatus.js';\nexport { browseCatalog, mapWithConcurrency } from './tools/browseCatalog.js';\nexport {\n type DeployAppInput,\n type DeployAppResult,\n deployApp,\n type ServiceConfig,\n} from './tools/deployApp.js';\nexport { fetchActiveLease } from './tools/fetchActiveLease.js';\nexport { getAppLogs } from './tools/getLogs.js';\nexport { resolveProviderUrl } from './tools/resolveLeaseProvider.js';\nexport { restartApp } from './tools/restartApp.js';\nexport { updateApp } from './tools/updateApp.js';\n\nexport class FredMCPServer {\n private mcpServer: McpServer;\n private clientManager: CosmosClientManager;\n private walletProvider: WalletProvider;\n\n constructor(options: ManifestMCPServerOptions) {\n const config = createValidatedConfig(options.config);\n this.walletProvider = options.walletProvider;\n this.clientManager = CosmosClientManager.getInstance(\n config,\n this.walletProvider,\n );\n\n this.mcpServer = new McpServer(\n {\n name: '@manifest-network/manifest-mcp-fred',\n version: VERSION,\n },\n {\n capabilities: {\n tools: {},\n },\n },\n );\n\n this.registerTools();\n }\n\n private requireSignArbitrary(): NonNullable<WalletProvider['signArbitrary']> {\n if (!this.walletProvider.signArbitrary) {\n throw new ManifestMCPError(\n ManifestMCPErrorCode.INVALID_CONFIG,\n 'Wallet does not support signArbitrary (ADR-036). Required for provider authentication. Use a wallet provider that implements signArbitrary.',\n );\n }\n return this.walletProvider.signArbitrary.bind(this.walletProvider);\n }\n\n private authTimestamps = new AuthTimestampTracker();\n\n private async getProviderAuthToken(\n address: string,\n leaseUuid: string,\n ): Promise<string> {\n const signArbitrary = this.requireSignArbitrary();\n const timestamp = await this.authTimestamps.next();\n const message = createSignMessage(address, leaseUuid, timestamp);\n const { pub_key, signature } = await signArbitrary(address, message);\n return createAuthToken(\n address,\n leaseUuid,\n timestamp,\n pub_key.value,\n signature,\n );\n }\n\n private async getLeaseDataAuthToken(\n address: string,\n leaseUuid: string,\n metaHashHex: string,\n ): Promise<string> {\n const signArbitrary = this.requireSignArbitrary();\n const timestamp = await this.authTimestamps.next();\n const message = createLeaseDataSignMessage(\n leaseUuid,\n metaHashHex,\n timestamp,\n );\n const { pub_key, signature } = await signArbitrary(address, message);\n return createAuthToken(\n address,\n leaseUuid,\n timestamp,\n pub_key.value,\n signature,\n metaHashHex,\n );\n }\n\n private registerTools(): void {\n // -- browse_catalog --\n this.mcpServer.registerTool(\n 'browse_catalog',\n {\n description:\n 'Browse available cloud providers and service tiers with live health checks. Use this before deploy_app to see which providers are online and what SKU sizes (e.g. docker-micro, docker-small) are available with pricing.',\n },\n withErrorHandling('browse_catalog', async () => {\n await this.clientManager.acquireRateLimit();\n const queryClient = await this.clientManager.getQueryClient();\n const result = await browseCatalog(queryClient);\n return jsonResponse(result, bigIntReplacer);\n }),\n );\n\n // -- app_status --\n this.mcpServer.registerTool(\n 'app_status',\n {\n description:\n 'Get detailed status and connection info for a deployed app. Use this after deploy_app to check if an app is running and get its URL.',\n inputSchema: {\n lease_uuid: z\n .string()\n .uuid()\n .describe('The lease UUID of the app to check'),\n },\n },\n withErrorHandling('app_status', async (args) => {\n const leaseUuid = args.lease_uuid;\n const address = await this.walletProvider.getAddress();\n await this.clientManager.acquireRateLimit();\n const queryClient = await this.clientManager.getQueryClient();\n const result = await appStatus(\n queryClient,\n address,\n leaseUuid,\n (addr, uuid) => this.getProviderAuthToken(addr, uuid),\n );\n return jsonResponse(result, bigIntReplacer);\n }),\n );\n\n // -- get_logs --\n this.mcpServer.registerTool(\n 'get_logs',\n {\n description:\n 'Get recent container logs for a deployed app. Use this to debug apps that are failing or to verify an app started correctly after deploy_app.',\n inputSchema: {\n lease_uuid: z\n .string()\n .uuid()\n .describe('The lease UUID of the app to get logs for'),\n tail: z\n .number()\n .int()\n .min(1)\n .max(MAX_TAIL)\n .optional()\n .describe('Number of recent log lines to retrieve'),\n },\n },\n withErrorHandling('get_logs', async (args) => {\n const leaseUuid = args.lease_uuid;\n const tail = args.tail;\n const address = await this.walletProvider.getAddress();\n await this.clientManager.acquireRateLimit();\n const queryClient = await this.clientManager.getQueryClient();\n const result = await getAppLogs(\n queryClient,\n address,\n leaseUuid,\n (addr, uuid) => this.getProviderAuthToken(addr, uuid),\n tail,\n );\n return jsonResponse(result, bigIntReplacer);\n }),\n );\n\n // -- deploy_app --\n this.mcpServer.registerTool(\n 'deploy_app',\n {\n description:\n 'Deploy a new containerized application. Requires funded credits (use fund_credit if needed). Creates a lease on-chain, uploads the container manifest to a provider, and polls until ready. Use browse_catalog first to see available SKU sizes.',\n inputSchema: {\n image: z\n .string()\n .optional()\n .describe(\n 'Docker image to deploy. Required unless services is provided.',\n ),\n port: z\n .number()\n .int()\n .min(1)\n .max(65535)\n .optional()\n .describe(\n 'Container port to expose. Required unless services is provided.',\n ),\n size: z\n .string()\n .describe('SKU tier name (e.g. \"docker-micro\", \"docker-small\")'),\n env: z\n .record(z.string(), z.string())\n .optional()\n .describe('Environment variables as key-value pairs'),\n command: z\n .array(z.string())\n .optional()\n .describe('Override container command (entrypoint)'),\n args: z\n .array(z.string())\n .optional()\n .describe('Arguments to the container command'),\n user: z\n .string()\n .optional()\n .describe('User to run the container as (e.g. \"1000:1000\")'),\n tmpfs: z\n .array(z.string())\n .optional()\n .describe('tmpfs mounts (e.g. [\"/tmp:size=64M\"])'),\n health_check: z\n .object({\n test: z.array(z.string()),\n interval: z.string().optional(),\n timeout: z.string().optional(),\n retries: z.number().int().optional(),\n start_period: z.string().optional(),\n })\n .optional()\n .describe('Container health check configuration'),\n stop_grace_period: z\n .string()\n .optional()\n .describe('Grace period before force-killing (e.g. \"30s\")'),\n init: z\n .boolean()\n .optional()\n .describe('Run an init process inside the container'),\n expose: z\n .array(z.string())\n .optional()\n .describe('Expose ports without publishing (e.g. [\"8080/tcp\"])'),\n labels: z\n .record(z.string(), z.string())\n .optional()\n .describe('Container labels as key-value pairs'),\n storage: z\n .string()\n .optional()\n .describe(\n 'Storage SKU name for persistent disk (adds a second lease item)',\n ),\n depends_on: z\n .record(z.string(), z.object({ condition: z.string() }))\n .optional()\n .describe('Service dependencies'),\n services: z\n .record(\n z.string(),\n z.object({\n image: z.string(),\n ports: z.record(z.string(), z.object({})).optional(),\n env: z.record(z.string(), z.string()).optional(),\n command: z.array(z.string()).optional(),\n args: z.array(z.string()).optional(),\n user: z.string().optional(),\n tmpfs: z.array(z.string()).optional(),\n health_check: z\n .object({\n test: z.array(z.string()),\n interval: z.string().optional(),\n timeout: z.string().optional(),\n retries: z.number().int().optional(),\n start_period: z.string().optional(),\n })\n .optional(),\n stop_grace_period: z.string().optional(),\n depends_on: z\n .record(z.string(), z.object({ condition: z.string() }))\n .optional(),\n expose: z.array(z.string()).optional(),\n labels: z.record(z.string(), z.string()).optional(),\n }),\n )\n .optional()\n .describe(\n 'Multi-service stack. Mutually exclusive with image/port. Keys are service names (RFC 1123 DNS labels).',\n ),\n },\n },\n withErrorHandling('deploy_app', async (args) => {\n const result = await deployApp(\n this.clientManager,\n (addr, uuid) => this.getProviderAuthToken(addr, uuid),\n (addr, uuid, metaHashHex) =>\n this.getLeaseDataAuthToken(addr, uuid, metaHashHex),\n {\n image: args.image,\n port: args.port,\n size: args.size,\n env: args.env,\n command: args.command,\n args: args.args,\n user: args.user,\n tmpfs: args.tmpfs,\n health_check: args.health_check,\n stop_grace_period: args.stop_grace_period,\n init: args.init,\n expose: args.expose,\n labels: args.labels,\n storage: args.storage,\n depends_on: args.depends_on,\n services: args.services,\n },\n );\n return jsonResponse(result, bigIntReplacer);\n }),\n );\n\n // -- restart_app --\n this.mcpServer.registerTool(\n 'restart_app',\n {\n description:\n 'Restart a running app via the provider without closing its lease. Use this to apply configuration changes or recover from a crash.',\n inputSchema: {\n lease_uuid: z\n .string()\n .uuid()\n .describe('The lease UUID of the app to restart'),\n },\n },\n withErrorHandling('restart_app', async (args) => {\n const leaseUuid = args.lease_uuid;\n const address = await this.walletProvider.getAddress();\n await this.clientManager.acquireRateLimit();\n const queryClient = await this.clientManager.getQueryClient();\n const result = await restartApp(\n queryClient,\n address,\n leaseUuid,\n (addr, uuid) => this.getProviderAuthToken(addr, uuid),\n );\n return jsonResponse(result, bigIntReplacer);\n }),\n );\n\n // -- update_app --\n this.mcpServer.registerTool(\n 'update_app',\n {\n description:\n 'Update a deployed app with a new container manifest. Use this to change the Docker image, ports, or environment variables of a running app without closing the lease.',\n inputSchema: {\n lease_uuid: z\n .string()\n .uuid()\n .describe('The lease UUID of the app to update'),\n manifest: z\n .string()\n .describe('The full manifest JSON string to deploy'),\n existing_manifest: z\n .string()\n .optional()\n .describe(\n 'The current manifest JSON. When provided, the new manifest is merged over the existing one (env, ports, labels merged; other fields carried forward if not in new).',\n ),\n },\n },\n withErrorHandling('update_app', async (args) => {\n const manifest = args.manifest;\n\n try {\n const parsed = JSON.parse(manifest);\n if (\n parsed === null ||\n typeof parsed !== 'object' ||\n Array.isArray(parsed)\n ) {\n throw new Error('must be a JSON object');\n }\n } catch (err) {\n throw new ManifestMCPError(\n ManifestMCPErrorCode.INVALID_CONFIG,\n `Invalid manifest: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n\n const leaseUuid = args.lease_uuid;\n const address = await this.walletProvider.getAddress();\n await this.clientManager.acquireRateLimit();\n const queryClient = await this.clientManager.getQueryClient();\n\n const result = await updateApp(\n queryClient,\n address,\n leaseUuid,\n (addr, uuid) => this.getProviderAuthToken(addr, uuid),\n manifest,\n args.existing_manifest,\n );\n return jsonResponse(result, bigIntReplacer);\n }),\n );\n\n // -- app_diagnostics --\n this.mcpServer.registerTool(\n 'app_diagnostics',\n {\n description:\n 'Get provision diagnostics for a deployed app. Use this to debug apps stuck in provisioning or that failed to start. Returns provision status, failure count, and last error message.',\n inputSchema: {\n lease_uuid: z\n .string()\n .uuid()\n .describe('The lease UUID of the app to diagnose'),\n },\n },\n withErrorHandling('app_diagnostics', async (args) => {\n const leaseUuid = args.lease_uuid;\n const address = await this.walletProvider.getAddress();\n await this.clientManager.acquireRateLimit();\n const queryClient = await this.clientManager.getQueryClient();\n\n const lease = await fetchActiveLease(\n queryClient,\n leaseUuid,\n 'cannot be diagnosed',\n );\n const providerUrl = await resolveProviderUrl(\n queryClient,\n lease.providerUuid,\n );\n const authToken = await this.getProviderAuthToken(address, leaseUuid);\n const provision = await getLeaseProvision(\n providerUrl,\n leaseUuid,\n authToken,\n );\n\n return jsonResponse(\n {\n lease_uuid: leaseUuid,\n provision_status: provision.status,\n fail_count: provision.fail_count,\n last_error: provision.last_error,\n },\n bigIntReplacer,\n );\n }),\n );\n\n // -- app_releases --\n this.mcpServer.registerTool(\n 'app_releases',\n {\n description:\n 'Get release/version history for a deployed app. Use this to see what versions have been deployed, when they were created, and their status.',\n inputSchema: {\n lease_uuid: z\n .string()\n .uuid()\n .describe('The lease UUID of the app to get release history for'),\n },\n },\n withErrorHandling('app_releases', async (args) => {\n const leaseUuid = args.lease_uuid;\n const address = await this.walletProvider.getAddress();\n await this.clientManager.acquireRateLimit();\n const queryClient = await this.clientManager.getQueryClient();\n\n const lease = await fetchActiveLease(\n queryClient,\n leaseUuid,\n 'releases are not available',\n );\n const providerUrl = await resolveProviderUrl(\n queryClient,\n lease.providerUuid,\n );\n const authToken = await this.getProviderAuthToken(address, leaseUuid);\n const result = await getLeaseReleases(\n providerUrl,\n leaseUuid,\n authToken,\n );\n\n return jsonResponse(\n {\n lease_uuid: leaseUuid,\n releases: result.releases,\n },\n bigIntReplacer,\n );\n }),\n );\n }\n\n getServer(): Server {\n return this.mcpServer.server;\n }\n\n getClientManager(): CosmosClientManager {\n return this.clientManager;\n }\n\n disconnect(): void {\n this.clientManager.disconnect();\n }\n}\n\nexport function createMnemonicFredServer(\n config: MnemonicServerConfig,\n): Promise<FredMCPServer> {\n return createMnemonicServer(config, FredMCPServer);\n}\n"],"mappings":"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"}
@@ -31,9 +31,11 @@ async function appStatus(queryClient, address, leaseUuid, getAuthToken, fetchFn)
31
31
  providerError: sanitizeForLogging(rawMsg)
32
32
  };
33
33
  }
34
- let authToken;
34
+ let statusToken;
35
+ let connToken;
35
36
  try {
36
- authToken = await getAuthToken(address, leaseUuid);
37
+ statusToken = await getAuthToken(address, leaseUuid);
38
+ connToken = await getAuthToken(address, leaseUuid);
37
39
  } catch (err) {
38
40
  if (err instanceof ManifestMCPError && INFRASTRUCTURE_ERROR_CODES.has(err.code)) throw err;
39
41
  const rawMsg = `Auth token error: ${err instanceof Error ? err.message : String(err)}`;
@@ -44,19 +46,16 @@ async function appStatus(queryClient, address, leaseUuid, getAuthToken, fetchFn)
44
46
  providerError: sanitizeForLogging(rawMsg)
45
47
  };
46
48
  }
47
- const [statusResult, connResult] = await Promise.allSettled([getLeaseStatus(providerUrl, leaseUuid, authToken, fetchFn), getLeaseConnectionInfo(providerUrl, leaseUuid, authToken, fetchFn)]);
48
- if (statusResult.status === "fulfilled") fredStatus = statusResult.value;
49
- else {
50
- const rawMsg = statusResult.reason instanceof Error ? statusResult.reason.message : String(statusResult.reason);
51
- logger.error(`[app_status] Failed to get lease status for ${leaseUuid}: ${rawMsg}`);
52
- providerError = sanitizeForLogging(rawMsg);
49
+ const [statusResult, connResult] = await Promise.allSettled([getLeaseStatus(providerUrl, leaseUuid, statusToken, fetchFn), getLeaseConnectionInfo(providerUrl, leaseUuid, connToken, fetchFn)]);
50
+ function handleRejection(label, reason) {
51
+ const rawMsg = reason instanceof Error ? reason.message : String(reason);
52
+ logger.error(`[app_status] Failed to get ${label} for ${leaseUuid}: ${rawMsg}`);
53
+ return sanitizeForLogging(rawMsg);
53
54
  }
55
+ if (statusResult.status === "fulfilled") fredStatus = statusResult.value;
56
+ else providerError = handleRejection("lease status", statusResult.reason);
54
57
  if (connResult.status === "fulfilled") connection = connResult.value.connection;
55
- else {
56
- const rawMsg = connResult.reason instanceof Error ? connResult.reason.message : String(connResult.reason);
57
- logger.error(`[app_status] Failed to get connection info for ${leaseUuid}: ${rawMsg}`);
58
- connectionError = sanitizeForLogging(rawMsg);
59
- }
58
+ else connectionError = handleRejection("connection info", connResult.reason);
60
59
  }
61
60
  return {
62
61
  lease_uuid: leaseUuid,
@@ -1 +1 @@
1
- {"version":3,"file":"appStatus.js","names":[],"sources":["../../src/tools/appStatus.ts"],"sourcesContent":["import {\n INFRASTRUCTURE_ERROR_CODES,\n LeaseState,\n logger,\n ManifestMCPError,\n ManifestMCPErrorCode,\n type ManifestQueryClient,\n sanitizeForLogging,\n} from '@manifest-network/manifest-mcp-core';\nimport { type FredLeaseStatus, getLeaseStatus } from '../http/fred.js';\nimport {\n type ConnectionDetails,\n getLeaseConnectionInfo,\n} from '../http/provider.js';\nimport { resolveProviderUrl } from './resolveLeaseProvider.js';\n\nexport async function appStatus(\n queryClient: ManifestQueryClient,\n address: string,\n leaseUuid: string,\n getAuthToken: (address: string, leaseUuid: string) => Promise<string>,\n fetchFn?: typeof globalThis.fetch,\n) {\n const leaseResult = await queryClient.liftedinit.billing.v1.lease({\n leaseUuid,\n });\n\n if (!leaseResult.lease) {\n throw new ManifestMCPError(\n ManifestMCPErrorCode.QUERY_FAILED,\n `Lease \"${leaseUuid}\" not found on chain`,\n );\n }\n\n const lease = leaseResult.lease;\n const chainState = {\n state: lease.state,\n providerUuid: lease.providerUuid,\n createdAt: lease.createdAt?.toISOString(),\n closedAt: lease.closedAt?.toISOString(),\n };\n\n let fredStatus: FredLeaseStatus | null = null;\n let connection: ConnectionDetails | null = null;\n let providerError: string | undefined;\n let connectionError: string | undefined;\n\n if (\n lease.state === LeaseState.LEASE_STATE_PENDING ||\n lease.state === LeaseState.LEASE_STATE_ACTIVE\n ) {\n let providerUrl: string;\n try {\n providerUrl = await resolveProviderUrl(queryClient, lease.providerUuid);\n } catch (err) {\n if (\n err instanceof ManifestMCPError &&\n INFRASTRUCTURE_ERROR_CODES.has(err.code)\n )\n throw err;\n const rawMsg = `Could not resolve provider: ${err instanceof Error ? err.message : String(err)}`;\n logger.error(`[app_status] ${rawMsg}`);\n return {\n lease_uuid: leaseUuid,\n chainState,\n providerError: sanitizeForLogging(rawMsg) as string,\n };\n }\n\n let authToken: string;\n try {\n authToken = await getAuthToken(address, leaseUuid);\n } catch (err) {\n if (\n err instanceof ManifestMCPError &&\n INFRASTRUCTURE_ERROR_CODES.has(err.code)\n )\n throw err;\n const rawMsg = `Auth token error: ${err instanceof Error ? err.message : String(err)}`;\n logger.error(`[app_status] ${rawMsg}`);\n return {\n lease_uuid: leaseUuid,\n chainState,\n providerError: sanitizeForLogging(rawMsg) as string,\n };\n }\n\n const [statusResult, connResult] = await Promise.allSettled([\n getLeaseStatus(providerUrl, leaseUuid, authToken, fetchFn),\n getLeaseConnectionInfo(providerUrl, leaseUuid, authToken, fetchFn),\n ]);\n\n if (statusResult.status === 'fulfilled') {\n fredStatus = statusResult.value;\n } else {\n const rawMsg =\n statusResult.reason instanceof Error\n ? statusResult.reason.message\n : String(statusResult.reason);\n logger.error(\n `[app_status] Failed to get lease status for ${leaseUuid}: ${rawMsg}`,\n );\n providerError = sanitizeForLogging(rawMsg) as string;\n }\n\n if (connResult.status === 'fulfilled') {\n connection = connResult.value.connection;\n } else {\n const rawMsg =\n connResult.reason instanceof Error\n ? connResult.reason.message\n : String(connResult.reason);\n logger.error(\n `[app_status] Failed to get connection info for ${leaseUuid}: ${rawMsg}`,\n );\n connectionError = sanitizeForLogging(rawMsg) as string;\n }\n }\n\n return {\n lease_uuid: leaseUuid,\n ...(connection && { connection }),\n chainState,\n ...(fredStatus && { fredStatus }),\n ...(providerError && { providerError }),\n ...(connectionError && { connectionError }),\n };\n}\n"],"mappings":";;;;;AAgBA,eAAsB,UACpB,aACA,SACA,WACA,cACA,SACA;CACA,MAAM,cAAc,MAAM,YAAY,WAAW,QAAQ,GAAG,MAAM,EAChE,WACD,CAAC;AAEF,KAAI,CAAC,YAAY,MACf,OAAM,IAAI,iBACR,qBAAqB,cACrB,UAAU,UAAU,sBACrB;CAGH,MAAM,QAAQ,YAAY;CAC1B,MAAM,aAAa;EACjB,OAAO,MAAM;EACb,cAAc,MAAM;EACpB,WAAW,MAAM,WAAW,aAAa;EACzC,UAAU,MAAM,UAAU,aAAa;EACxC;CAED,IAAI,aAAqC;CACzC,IAAI,aAAuC;CAC3C,IAAI;CACJ,IAAI;AAEJ,KACE,MAAM,UAAU,WAAW,uBAC3B,MAAM,UAAU,WAAW,oBAC3B;EACA,IAAI;AACJ,MAAI;AACF,iBAAc,MAAM,mBAAmB,aAAa,MAAM,aAAa;WAChE,KAAK;AACZ,OACE,eAAe,oBACf,2BAA2B,IAAI,IAAI,KAAK,CAExC,OAAM;GACR,MAAM,SAAS,+BAA+B,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;AAC9F,UAAO,MAAM,gBAAgB,SAAS;AACtC,UAAO;IACL,YAAY;IACZ;IACA,eAAe,mBAAmB,OAAO;IAC1C;;EAGH,IAAI;AACJ,MAAI;AACF,eAAY,MAAM,aAAa,SAAS,UAAU;WAC3C,KAAK;AACZ,OACE,eAAe,oBACf,2BAA2B,IAAI,IAAI,KAAK,CAExC,OAAM;GACR,MAAM,SAAS,qBAAqB,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;AACpF,UAAO,MAAM,gBAAgB,SAAS;AACtC,UAAO;IACL,YAAY;IACZ;IACA,eAAe,mBAAmB,OAAO;IAC1C;;EAGH,MAAM,CAAC,cAAc,cAAc,MAAM,QAAQ,WAAW,CAC1D,eAAe,aAAa,WAAW,WAAW,QAAQ,EAC1D,uBAAuB,aAAa,WAAW,WAAW,QAAQ,CACnE,CAAC;AAEF,MAAI,aAAa,WAAW,YAC1B,cAAa,aAAa;OACrB;GACL,MAAM,SACJ,aAAa,kBAAkB,QAC3B,aAAa,OAAO,UACpB,OAAO,aAAa,OAAO;AACjC,UAAO,MACL,+CAA+C,UAAU,IAAI,SAC9D;AACD,mBAAgB,mBAAmB,OAAO;;AAG5C,MAAI,WAAW,WAAW,YACxB,cAAa,WAAW,MAAM;OACzB;GACL,MAAM,SACJ,WAAW,kBAAkB,QACzB,WAAW,OAAO,UAClB,OAAO,WAAW,OAAO;AAC/B,UAAO,MACL,kDAAkD,UAAU,IAAI,SACjE;AACD,qBAAkB,mBAAmB,OAAO;;;AAIhD,QAAO;EACL,YAAY;EACZ,GAAI,cAAc,EAAE,YAAY;EAChC;EACA,GAAI,cAAc,EAAE,YAAY;EAChC,GAAI,iBAAiB,EAAE,eAAe;EACtC,GAAI,mBAAmB,EAAE,iBAAiB;EAC3C"}
1
+ {"version":3,"file":"appStatus.js","names":[],"sources":["../../src/tools/appStatus.ts"],"sourcesContent":["import {\n INFRASTRUCTURE_ERROR_CODES,\n LeaseState,\n logger,\n ManifestMCPError,\n ManifestMCPErrorCode,\n type ManifestQueryClient,\n sanitizeForLogging,\n} from '@manifest-network/manifest-mcp-core';\nimport { type FredLeaseStatus, getLeaseStatus } from '../http/fred.js';\nimport {\n type ConnectionDetails,\n getLeaseConnectionInfo,\n} from '../http/provider.js';\nimport { resolveProviderUrl } from './resolveLeaseProvider.js';\n\nexport async function appStatus(\n queryClient: ManifestQueryClient,\n address: string,\n leaseUuid: string,\n getAuthToken: (address: string, leaseUuid: string) => Promise<string>,\n fetchFn?: typeof globalThis.fetch,\n) {\n const leaseResult = await queryClient.liftedinit.billing.v1.lease({\n leaseUuid,\n });\n\n if (!leaseResult.lease) {\n throw new ManifestMCPError(\n ManifestMCPErrorCode.QUERY_FAILED,\n `Lease \"${leaseUuid}\" not found on chain`,\n );\n }\n\n const lease = leaseResult.lease;\n const chainState = {\n state: lease.state,\n providerUuid: lease.providerUuid,\n createdAt: lease.createdAt?.toISOString(),\n closedAt: lease.closedAt?.toISOString(),\n };\n\n let fredStatus: FredLeaseStatus | null = null;\n let connection: ConnectionDetails | null = null;\n let providerError: string | undefined;\n let connectionError: string | undefined;\n\n if (\n lease.state === LeaseState.LEASE_STATE_PENDING ||\n lease.state === LeaseState.LEASE_STATE_ACTIVE\n ) {\n let providerUrl: string;\n try {\n providerUrl = await resolveProviderUrl(queryClient, lease.providerUuid);\n } catch (err) {\n if (\n err instanceof ManifestMCPError &&\n INFRASTRUCTURE_ERROR_CODES.has(err.code)\n )\n throw err;\n const rawMsg = `Could not resolve provider: ${err instanceof Error ? err.message : String(err)}`;\n logger.error(`[app_status] ${rawMsg}`);\n return {\n lease_uuid: leaseUuid,\n chainState,\n providerError: sanitizeForLogging(rawMsg) as string,\n };\n }\n\n let statusToken: string;\n let connToken: string;\n try {\n // The connection endpoint enforces replay protection (status does not),\n // but we generate separate tokens for both to keep each request\n // independently authenticated.\n statusToken = await getAuthToken(address, leaseUuid);\n connToken = await getAuthToken(address, leaseUuid);\n } catch (err) {\n if (\n err instanceof ManifestMCPError &&\n INFRASTRUCTURE_ERROR_CODES.has(err.code)\n )\n throw err;\n const rawMsg = `Auth token error: ${err instanceof Error ? err.message : String(err)}`;\n logger.error(`[app_status] ${rawMsg}`);\n return {\n lease_uuid: leaseUuid,\n chainState,\n providerError: sanitizeForLogging(rawMsg) as string,\n };\n }\n\n const [statusResult, connResult] = await Promise.allSettled([\n getLeaseStatus(providerUrl, leaseUuid, statusToken, fetchFn),\n getLeaseConnectionInfo(providerUrl, leaseUuid, connToken, fetchFn),\n ]);\n\n function handleRejection(label: string, reason: unknown): string {\n const rawMsg = reason instanceof Error ? reason.message : String(reason);\n logger.error(\n `[app_status] Failed to get ${label} for ${leaseUuid}: ${rawMsg}`,\n );\n return sanitizeForLogging(rawMsg) as string;\n }\n\n if (statusResult.status === 'fulfilled') {\n fredStatus = statusResult.value;\n } else {\n providerError = handleRejection('lease status', statusResult.reason);\n }\n\n if (connResult.status === 'fulfilled') {\n connection = connResult.value.connection;\n } else {\n connectionError = handleRejection('connection info', connResult.reason);\n }\n }\n\n return {\n lease_uuid: leaseUuid,\n ...(connection && { connection }),\n chainState,\n ...(fredStatus && { fredStatus }),\n ...(providerError && { providerError }),\n ...(connectionError && { connectionError }),\n };\n}\n"],"mappings":";;;;;AAgBA,eAAsB,UACpB,aACA,SACA,WACA,cACA,SACA;CACA,MAAM,cAAc,MAAM,YAAY,WAAW,QAAQ,GAAG,MAAM,EAChE,WACD,CAAC;AAEF,KAAI,CAAC,YAAY,MACf,OAAM,IAAI,iBACR,qBAAqB,cACrB,UAAU,UAAU,sBACrB;CAGH,MAAM,QAAQ,YAAY;CAC1B,MAAM,aAAa;EACjB,OAAO,MAAM;EACb,cAAc,MAAM;EACpB,WAAW,MAAM,WAAW,aAAa;EACzC,UAAU,MAAM,UAAU,aAAa;EACxC;CAED,IAAI,aAAqC;CACzC,IAAI,aAAuC;CAC3C,IAAI;CACJ,IAAI;AAEJ,KACE,MAAM,UAAU,WAAW,uBAC3B,MAAM,UAAU,WAAW,oBAC3B;EACA,IAAI;AACJ,MAAI;AACF,iBAAc,MAAM,mBAAmB,aAAa,MAAM,aAAa;WAChE,KAAK;AACZ,OACE,eAAe,oBACf,2BAA2B,IAAI,IAAI,KAAK,CAExC,OAAM;GACR,MAAM,SAAS,+BAA+B,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;AAC9F,UAAO,MAAM,gBAAgB,SAAS;AACtC,UAAO;IACL,YAAY;IACZ;IACA,eAAe,mBAAmB,OAAO;IAC1C;;EAGH,IAAI;EACJ,IAAI;AACJ,MAAI;AAIF,iBAAc,MAAM,aAAa,SAAS,UAAU;AACpD,eAAY,MAAM,aAAa,SAAS,UAAU;WAC3C,KAAK;AACZ,OACE,eAAe,oBACf,2BAA2B,IAAI,IAAI,KAAK,CAExC,OAAM;GACR,MAAM,SAAS,qBAAqB,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;AACpF,UAAO,MAAM,gBAAgB,SAAS;AACtC,UAAO;IACL,YAAY;IACZ;IACA,eAAe,mBAAmB,OAAO;IAC1C;;EAGH,MAAM,CAAC,cAAc,cAAc,MAAM,QAAQ,WAAW,CAC1D,eAAe,aAAa,WAAW,aAAa,QAAQ,EAC5D,uBAAuB,aAAa,WAAW,WAAW,QAAQ,CACnE,CAAC;EAEF,SAAS,gBAAgB,OAAe,QAAyB;GAC/D,MAAM,SAAS,kBAAkB,QAAQ,OAAO,UAAU,OAAO,OAAO;AACxE,UAAO,MACL,8BAA8B,MAAM,OAAO,UAAU,IAAI,SAC1D;AACD,UAAO,mBAAmB,OAAO;;AAGnC,MAAI,aAAa,WAAW,YAC1B,cAAa,aAAa;MAE1B,iBAAgB,gBAAgB,gBAAgB,aAAa,OAAO;AAGtE,MAAI,WAAW,WAAW,YACxB,cAAa,WAAW,MAAM;MAE9B,mBAAkB,gBAAgB,mBAAmB,WAAW,OAAO;;AAI3E,QAAO;EACL,YAAY;EACZ,GAAI,cAAc,EAAE,YAAY;EAChC;EACA,GAAI,cAAc,EAAE,YAAY;EAChC,GAAI,iBAAiB,EAAE,eAAe;EACtC,GAAI,mBAAmB,EAAE,iBAAiB;EAC3C"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@manifest-network/manifest-mcp-fred",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "description": "MCP server for Manifest provider (Fred) operations (deploy, status, logs, restart, update)",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -46,7 +46,7 @@
46
46
  ],
47
47
  "dependencies": {
48
48
  "@cosmjs/encoding": "0.32.4",
49
- "@manifest-network/manifest-mcp-core": "^0.3.0",
49
+ "@manifest-network/manifest-mcp-core": "^0.3.2",
50
50
  "@modelcontextprotocol/sdk": "1.27.1",
51
51
  "zod": "^4.3.6"
52
52
  },