@manifest-network/manifest-mcp-fred 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -4
- package/dist/index.js.map +1 -1
- package/dist/tools/deployApp.d.ts +20 -0
- package/dist/tools/deployApp.d.ts.map +1 -1
- package/dist/tools/deployApp.js +18 -2
- package/dist/tools/deployApp.js.map +1 -1
- package/package.json +3 -3
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;;;;;;;;;;;;;;;cA+Ia,aAAA;EAAA,QACH,SAAA;EAAA,QACA,aAAA;EAAA,QACA,cAAA;EAAA,QACA,UAAA;cAEI,OAAA,EAAS,0BAAA;EAAA,QA4Bb,aAAA;EAAA,QAu2BA,iBAAA;EAAA,QAgKA,eAAA;EAviCA;;;;;;;;;EAAA,QA2qCA,eAAA;EA0BR,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
|
@@ -14,7 +14,7 @@ import { getAppLogs } from "./tools/getLogs.js";
|
|
|
14
14
|
import { restartApp } from "./tools/restartApp.js";
|
|
15
15
|
import { updateApp } from "./tools/updateApp.js";
|
|
16
16
|
import { waitForAppReady } from "./tools/waitForAppReady.js";
|
|
17
|
-
import { CosmosClientManager, INFRASTRUCTURE_ERROR_CODES, LeaseState, MAX_PAGE_LIMIT, ManifestMCPError, ManifestMCPError as ManifestMCPError$1, ManifestMCPErrorCode, ManifestMCPErrorCode as ManifestMCPErrorCode$1, VERSION, bigIntReplacer, createMnemonicServer, createPagination, createValidatedConfig, jsonResponse, leaseStateToJSON, logger, manifestMeta, mutatingAnnotations, readOnlyAnnotations, structuredResponse, withErrorHandling } from "@manifest-network/manifest-mcp-core";
|
|
17
|
+
import { CosmosClientManager, DNS_LABEL_RE, INFRASTRUCTURE_ERROR_CODES, LeaseState, MAX_PAGE_LIMIT, ManifestMCPError, ManifestMCPError as ManifestMCPError$1, ManifestMCPErrorCode, ManifestMCPErrorCode as ManifestMCPErrorCode$1, VERSION, bigIntReplacer, createMnemonicServer, createPagination, createValidatedConfig, jsonResponse, leaseStateToJSON, logger, manifestMeta, mutatingAnnotations, readOnlyAnnotations, structuredResponse, withErrorHandling } from "@manifest-network/manifest-mcp-core";
|
|
18
18
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
19
19
|
import { z } from "zod";
|
|
20
20
|
//#region src/index.ts
|
|
@@ -254,7 +254,7 @@ var FredMCPServer = class {
|
|
|
254
254
|
}), bigIntReplacer);
|
|
255
255
|
}));
|
|
256
256
|
this.mcpServer.registerTool("deploy_app", {
|
|
257
|
-
description: "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.",
|
|
257
|
+
description: "Deploy a new containerized application. Requires funded credits (use fund_credit if needed). Creates a lease on-chain, optionally attaches a custom domain (FQDN) to the lease item, uploads the container manifest to a provider, and polls until ready. Use browse_catalog first to see available SKU sizes.",
|
|
258
258
|
inputSchema: {
|
|
259
259
|
image: z.string().optional().describe("Docker image to deploy. Required unless services is provided."),
|
|
260
260
|
port: z.number().int().min(1).max(65535).optional().describe("Container port to expose. Required unless services is provided."),
|
|
@@ -297,7 +297,9 @@ var FredMCPServer = class {
|
|
|
297
297
|
expose: z.array(z.string()).optional(),
|
|
298
298
|
labels: z.record(z.string(), z.string()).optional()
|
|
299
299
|
})).optional().describe("Multi-service stack. Mutually exclusive with image/port. Keys are service names (RFC 1123 DNS labels)."),
|
|
300
|
-
gas_multiplier: z.number().finite().min(1).optional().describe("Gas simulation multiplier override for this transaction. Defaults to the server-configured value (typically 1.5). Increase if a transaction fails with out-of-gas errors.")
|
|
300
|
+
gas_multiplier: z.number().finite().min(1).optional().describe("Gas simulation multiplier override for this transaction. Defaults to the server-configured value (typically 1.5). Increase if a transaction fails with out-of-gas errors."),
|
|
301
|
+
custom_domain: z.string().max(253).optional().describe("Optional FQDN to attach to the lease item once the create-lease tx confirms (e.g. \"app.example.com\"). Must be lowercase with a non-numeric TLD label and not match a reserved suffix; the chain validates the format. On a stack lease (`services`), pair with `service_name` to pick which item to attach the domain to."),
|
|
302
|
+
service_name: z.string().regex(DNS_LABEL_RE).optional().describe("Required when `custom_domain` is set on a stack lease (`services`). Must match one of the keys in `services` and be a valid RFC 1123 DNS label (1-63 lowercase alphanumeric chars + hyphens, no leading/trailing hyphen). Omit for image+port (single-item legacy) leases.")
|
|
301
303
|
},
|
|
302
304
|
outputSchema: {
|
|
303
305
|
lease_uuid: z.string(),
|
|
@@ -306,7 +308,9 @@ var FredMCPServer = class {
|
|
|
306
308
|
state: z.number(),
|
|
307
309
|
url: z.string().optional(),
|
|
308
310
|
connection: z.looseObject({}).optional(),
|
|
309
|
-
connectionError: z.string().optional()
|
|
311
|
+
connectionError: z.string().optional(),
|
|
312
|
+
custom_domain: z.string().optional(),
|
|
313
|
+
service_name: z.string().optional()
|
|
310
314
|
},
|
|
311
315
|
annotations: mutatingAnnotations("Deploy a containerized app", { destructive: false }),
|
|
312
316
|
_meta: manifestMeta({
|
|
@@ -333,6 +337,8 @@ var FredMCPServer = class {
|
|
|
333
337
|
depends_on: args.depends_on,
|
|
334
338
|
services: args.services,
|
|
335
339
|
gasMultiplier: args.gas_multiplier,
|
|
340
|
+
customDomain: args.custom_domain,
|
|
341
|
+
serviceName: args.service_name,
|
|
336
342
|
abortSignal: extra.signal,
|
|
337
343
|
onLeaseCreated: emit ? (leaseUuid, providerUrl) => {
|
|
338
344
|
emit(`Lease ${leaseUuid} created on chain at ${providerUrl}; uploading manifest`);
|
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 createPagination,\n createValidatedConfig,\n jsonResponse,\n LeaseState,\n leaseStateToJSON,\n logger,\n MAX_PAGE_LIMIT,\n ManifestMCPError,\n ManifestMCPErrorCode,\n type ManifestMCPServerOptions,\n type MnemonicServerConfig,\n manifestMeta,\n mutatingAnnotations,\n readOnlyAnnotations,\n structuredResponse,\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 type { RequestHandlerExtra } from '@modelcontextprotocol/sdk/shared/protocol.js';\nimport type {\n ServerNotification,\n ServerRequest,\n} from '@modelcontextprotocol/sdk/types.js';\nimport { z } from 'zod';\nimport { AuthTokenService } from './http/auth-token-service.js';\nimport { getLeaseProvision, getLeaseReleases, MAX_TAIL } from './http/fred.js';\nimport { appStatus } from './tools/appStatus.js';\nimport { browseCatalog } from './tools/browseCatalog.js';\nimport { buildManifestPreview } from './tools/buildManifestPreview.js';\nimport { checkDeploymentReadiness } from './tools/checkDeploymentReadiness.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';\nimport { waitForAppReady } from './tools/waitForAppReady.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 type TerminalChainLeaseState,\n type TerminalChainState,\n type TerminalChainStateContext,\n TerminalChainStateError,\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 type ManifestFormat,\n type ManifestValidationResult,\n mergeManifest,\n metaHashHex,\n normalizePorts,\n parseStackManifest,\n validateManifest,\n validateServiceName,\n} from './manifest.js';\nexport { appStatus } from './tools/appStatus.js';\nexport { browseCatalog, mapWithConcurrency } from './tools/browseCatalog.js';\nexport {\n type BuildManifestPreviewInput,\n type BuildManifestPreviewResult,\n buildManifestPreview,\n type ManifestPreviewServiceInput,\n} from './tools/buildManifestPreview.js';\nexport {\n type CheckDeploymentReadinessInput,\n type CheckDeploymentReadinessResult,\n checkDeploymentReadiness,\n type SkuSummary,\n} from './tools/checkDeploymentReadiness.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';\nexport {\n type WaitForAppReadyOptions,\n type WaitForAppReadyResult,\n waitForAppReady,\n} from './tools/waitForAppReady.js';\n\nexport class FredMCPServer {\n private mcpServer: McpServer;\n private clientManager: CosmosClientManager;\n private walletProvider: WalletProvider;\n private authTokens: AuthTokenService;\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 this.authTokens = new AuthTokenService(this.walletProvider);\n\n this.mcpServer = new McpServer(\n {\n name: '@manifest-network/manifest-mcp-fred',\n version: VERSION,\n },\n {\n capabilities: {\n tools: {},\n resources: {},\n prompts: {},\n },\n },\n );\n\n this.registerTools();\n this.registerResources();\n this.registerPrompts();\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 outputSchema: {\n providers: z.array(z.looseObject({})),\n tiers: z.record(z.string(), z.array(z.looseObject({}))),\n },\n annotations: readOnlyAnnotations('Browse providers and SKUs'),\n _meta: manifestMeta({\n broadcasts: false,\n estimable: false,\n }),\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 structuredResponse(\n result as unknown as Record<string, unknown>,\n bigIntReplacer,\n );\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 outputSchema: {\n lease_uuid: z.string(),\n chainState: z.looseObject({\n state: z.number(),\n providerUuid: z.string(),\n }),\n connection: z.looseObject({}).optional(),\n fredStatus: z.looseObject({}).optional(),\n providerError: z.string().optional(),\n connectionError: z.string().optional(),\n },\n annotations: readOnlyAnnotations('Get deployed app status'),\n _meta: manifestMeta({\n broadcasts: false,\n estimable: false,\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.authTokens.providerToken(addr, uuid),\n );\n return structuredResponse(\n result as unknown as Record<string, unknown>,\n bigIntReplacer,\n );\n }),\n );\n\n // -- wait_for_app_ready --\n this.mcpServer.registerTool(\n 'wait_for_app_ready',\n {\n description:\n 'Wait for a deployed app to reach the ACTIVE state on the provider, polling at the configured interval. Use this after deploy_app instead of looping app_status manually. Throws on timeout or terminal lease state.',\n inputSchema: {\n lease_uuid: z\n .string()\n .uuid()\n .describe('The lease UUID of the app to wait on'),\n timeout_seconds: z\n .number()\n .int()\n .min(1)\n .max(600)\n .optional()\n .describe(\n 'Maximum seconds to wait before throwing. Defaults to 120s.',\n ),\n interval_seconds: z\n .number()\n .int()\n .min(1)\n .max(60)\n .optional()\n .describe('Seconds between status polls. Defaults to 3s.'),\n },\n outputSchema: {\n lease_uuid: z.string().describe('The lease UUID that was waited on'),\n provider_uuid: z.string().describe('Provider hosting the lease'),\n provider_url: z.string().describe('Provider API URL'),\n state: z\n .string()\n .describe(\n 'Final lease state, JSON-encoded LeaseState (e.g. LEASE_STATE_ACTIVE)',\n ),\n status: z\n .looseObject({})\n .describe(\n 'Raw provider status payload (instances, endpoints, services, etc.)',\n ),\n },\n annotations: readOnlyAnnotations('Wait for deployed app readiness'),\n _meta: manifestMeta({\n broadcasts: false,\n estimable: false,\n }),\n },\n withErrorHandling(\n 'wait_for_app_ready',\n async (\n args,\n extra: RequestHandlerExtra<ServerRequest, ServerNotification>,\n ) => {\n const emit = this.progressEmitter('wait_for_app_ready', extra);\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 waitForAppReady(\n queryClient,\n address,\n leaseUuid,\n (addr, uuid) => this.authTokens.providerToken(addr, uuid),\n {\n timeoutMs:\n args.timeout_seconds !== undefined\n ? args.timeout_seconds * 1_000\n : undefined,\n intervalMs:\n args.interval_seconds !== undefined\n ? args.interval_seconds * 1_000\n : undefined,\n abortSignal: extra.signal,\n onProgress: emit\n ? (status) => {\n const state = leaseStateToJSON(status.state);\n const provision = status.provision_status\n ? `, provision=${status.provision_status}`\n : '';\n emit(`Polling lease: state=${state}${provision}`);\n }\n : undefined,\n },\n );\n return structuredResponse(\n result as unknown as Record<string, unknown>,\n bigIntReplacer,\n );\n },\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 annotations: readOnlyAnnotations('Get container logs'),\n _meta: manifestMeta({\n broadcasts: false,\n estimable: false,\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.authTokens.providerToken(addr, uuid),\n tail,\n );\n return jsonResponse(result, bigIntReplacer);\n }),\n );\n\n // -- check_deployment_readiness --\n this.mcpServer.registerTool(\n 'check_deployment_readiness',\n {\n description:\n \"Pre-flight check for deploy_app: surfaces the caller's wallet balances, credit account, requested SKU availability, and a human-readable list of missing steps. Use this before deploy_app to decide whether to fund credits, switch SKU, or top up the wallet. Note: the chain does not expose provider allowed_registries, so a `ready: true` does not guarantee the registry of `image` is allowed — that is checked at upload time.\",\n inputSchema: {\n size: z\n .string()\n .optional()\n .describe(\n 'SKU tier to verify availability for (e.g. \"docker-micro\"). Omit to skip the SKU check.',\n ),\n image: z\n .string()\n .optional()\n .describe(\n 'Image planned for deployment. Recorded on the result for downstream display; not validated.',\n ),\n },\n outputSchema: {\n tenant: z.string(),\n image: z.string().nullable(),\n size: z.string().nullable(),\n wallet_balances: z.array(\n z.object({ denom: z.string(), amount: z.string() }),\n ),\n credits: z.looseObject({}).nullable(),\n current_balance: z\n .array(z.object({ denom: z.string(), amount: z.string() }))\n .optional(),\n hours_remaining: z.string().optional(),\n sku: z\n .object({\n name: z.string(),\n uuid: z.string(),\n provider_uuid: z.string(),\n price: z\n .object({ amount: z.string(), denom: z.string() })\n .optional(),\n active: z.boolean(),\n })\n .nullable(),\n available_sku_names: z.array(z.string()),\n ready: z.boolean(),\n missing_steps: z.array(z.string()),\n },\n annotations: readOnlyAnnotations('Check deploy pre-flight readiness'),\n _meta: manifestMeta({\n broadcasts: false,\n estimable: false,\n }),\n },\n withErrorHandling('check_deployment_readiness', async (args) => {\n const address = await this.walletProvider.getAddress();\n await this.clientManager.acquireRateLimit();\n const queryClient = await this.clientManager.getQueryClient();\n const result = await checkDeploymentReadiness(queryClient, address, {\n size: args.size,\n image: args.image,\n });\n return structuredResponse(\n result as unknown as Record<string, unknown>,\n bigIntReplacer,\n );\n }),\n );\n\n // -- build_manifest_preview --\n this.mcpServer.registerTool(\n 'build_manifest_preview',\n {\n description:\n 'Build a deployment manifest, validate it against the documented Fred rules, and compute the SHA-256 meta_hash that would be recorded on-chain. Use this BEFORE deploy_app to catch invalid manifests without paying for a lease. Two modes: raw `manifest` JSON string, or structured fields (image+port, or services for stacks).',\n inputSchema: {\n manifest: z\n .string()\n .optional()\n .describe(\n 'Raw manifest JSON string. Mutually exclusive with structured fields below.',\n ),\n image: z\n .string()\n .optional()\n .describe(\n 'Single-service image. Required (with port) when not using manifest or services.',\n ),\n port: z\n .number()\n .int()\n .min(1)\n .max(65535)\n .optional()\n .describe('Container port to expose. Required with image.'),\n env: z\n .record(z.string(), z.string())\n .optional()\n .describe('Environment variables as key-value pairs.'),\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 init: z.boolean().optional(),\n expose: z.array(z.string()).optional(),\n labels: z.record(z.string(), z.string()).optional(),\n depends_on: z\n .record(z.string(), z.object({ condition: z.string() }))\n .optional(),\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 and manifest.',\n ),\n },\n outputSchema: {\n manifest_json: z\n .string()\n .describe('Canonical manifest JSON that would be uploaded'),\n manifest: z\n .looseObject({})\n .describe('Parsed manifest object (same content as manifest_json)'),\n format: z\n .enum(['single', 'stack'])\n .describe('Detected manifest format'),\n meta_hash_hex: z\n .string()\n .describe('SHA-256 of manifest_json, lowercase hex'),\n validation: z.object({\n valid: z.boolean(),\n errors: z.array(z.string()),\n }),\n },\n annotations: readOnlyAnnotations('Preview and validate a manifest'),\n _meta: manifestMeta({\n broadcasts: false,\n estimable: false,\n }),\n },\n withErrorHandling('build_manifest_preview', async (args) => {\n const result = await buildManifestPreview({\n manifest: args.manifest,\n image: args.image,\n port: args.port,\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 depends_on: args.depends_on,\n services: args.services,\n });\n return structuredResponse(\n result as unknown as Record<string, unknown>,\n bigIntReplacer,\n );\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 gas_multiplier: z\n .number()\n .finite()\n .min(1)\n .optional()\n .describe(\n 'Gas simulation multiplier override for this transaction. Defaults to the server-configured value (typically 1.5). Increase if a transaction fails with out-of-gas errors.',\n ),\n },\n outputSchema: {\n lease_uuid: z.string(),\n provider_uuid: z.string(),\n provider_url: z.string(),\n state: z.number(),\n url: z.string().optional(),\n connection: z.looseObject({}).optional(),\n connectionError: z.string().optional(),\n },\n // Additive: creates a new lease and uploads a manifest. Does not\n // replace any existing app's state.\n annotations: mutatingAnnotations('Deploy a containerized app', {\n destructive: false,\n }),\n _meta: manifestMeta({\n broadcasts: true,\n estimable: false,\n }),\n },\n withErrorHandling(\n 'deploy_app',\n async (\n args,\n extra: RequestHandlerExtra<ServerRequest, ServerNotification>,\n ) => {\n const emit = this.progressEmitter('deploy_app', extra);\n const result = await deployApp(\n this.clientManager,\n (addr, uuid) => this.authTokens.providerToken(addr, uuid),\n (addr, uuid, metaHashHex) =>\n this.authTokens.leaseDataToken(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 gasMultiplier: args.gas_multiplier,\n abortSignal: extra.signal,\n onLeaseCreated: emit\n ? (leaseUuid, providerUrl) => {\n emit(\n `Lease ${leaseUuid} created on chain at ${providerUrl}; uploading manifest`,\n );\n }\n : undefined,\n pollOptions: emit\n ? {\n onProgress: (status) => {\n const state = leaseStateToJSON(status.state);\n const provision = status.provision_status\n ? `, provision=${status.provision_status}`\n : '';\n emit(`Polling lease: state=${state}${provision}`);\n },\n }\n : undefined,\n },\n );\n return structuredResponse(\n result as unknown as Record<string, unknown>,\n bigIntReplacer,\n );\n },\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 // Additive: triggers a restart cycle without replacing config.\n // Not idempotent — each call triggers a fresh restart even when\n // the app is already running (relies on the helper's default).\n annotations: mutatingAnnotations('Restart a deployed app', {\n destructive: false,\n }),\n _meta: manifestMeta({\n broadcasts: true,\n estimable: false,\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.authTokens.providerToken(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 outputSchema: {\n lease_uuid: z.string(),\n status: z.string(),\n },\n // Destructive: replaces the running app's manifest. Even with the\n // merge mode, prior config can be overwritten.\n annotations: mutatingAnnotations('Update a deployed app manifest', {\n destructive: true,\n }),\n _meta: manifestMeta({\n broadcasts: true,\n estimable: false,\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.authTokens.providerToken(addr, uuid),\n manifest,\n args.existing_manifest,\n );\n return structuredResponse(\n result as unknown as Record<string, unknown>,\n bigIntReplacer,\n );\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 outputSchema: {\n lease_uuid: z.string(),\n provision_status: z.string(),\n fail_count: z.number(),\n // The provider omits last_error when there's no recent failure.\n // structuredResponse's JSON.stringify round-trip drops undefined\n // keys, so the parsed structuredContent has no `last_error` at\n // all in the success case — declare optional to match.\n last_error: z.string().optional(),\n },\n annotations: readOnlyAnnotations('Get app provision diagnostics'),\n _meta: manifestMeta({\n broadcasts: false,\n estimable: false,\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.authTokens.providerToken(\n address,\n leaseUuid,\n );\n const provision = await getLeaseProvision(\n providerUrl,\n leaseUuid,\n authToken,\n );\n\n return structuredResponse(\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 outputSchema: {\n lease_uuid: z.string(),\n releases: z.array(\n z.looseObject({\n version: z.number(),\n image: z.string(),\n status: z.string(),\n created_at: z.string(),\n }),\n ),\n },\n annotations: readOnlyAnnotations('Get app release history'),\n _meta: manifestMeta({\n broadcasts: false,\n estimable: false,\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.authTokens.providerToken(\n address,\n leaseUuid,\n );\n const result = await getLeaseReleases(\n providerUrl,\n leaseUuid,\n authToken,\n );\n\n return structuredResponse(\n {\n lease_uuid: leaseUuid,\n releases: result.releases,\n },\n bigIntReplacer,\n );\n }),\n );\n }\n\n private registerResources(): void {\n const fixedPagination = createPagination(MAX_PAGE_LIMIT);\n\n const resourceJson = (\n uri: URL,\n data: unknown,\n ): {\n contents: Array<{ uri: string; mimeType: string; text: string }>;\n } => ({\n contents: [\n {\n uri: uri.href,\n mimeType: 'application/json',\n text: JSON.stringify(data, bigIntReplacer, 2),\n },\n ],\n });\n\n // -- manifest://leases/active --\n this.mcpServer.registerResource(\n 'leases-active',\n 'manifest://leases/active',\n {\n title: \"Caller's active and pending leases\",\n description:\n \"Snapshot of the caller wallet's leases currently in ACTIVE or PENDING state. Useful as immutable context for an agent deciding which app to operate on.\",\n mimeType: 'application/json',\n },\n async (uri) => {\n await this.clientManager.acquireRateLimit();\n const queryClient = await this.clientManager.getQueryClient();\n const tenant = await this.walletProvider.getAddress();\n const billing = queryClient.liftedinit.billing.v1;\n\n const [active, pending] = await Promise.all([\n billing.leasesByTenant({\n tenant,\n stateFilter: LeaseState.LEASE_STATE_ACTIVE,\n pagination: fixedPagination,\n }),\n billing.leasesByTenant({\n tenant,\n stateFilter: LeaseState.LEASE_STATE_PENDING,\n pagination: fixedPagination,\n }),\n ]);\n\n const summarize = (l: {\n uuid: string;\n state: number;\n providerUuid: string;\n createdAt?: Date;\n metaHash?: Uint8Array;\n }) => ({\n uuid: l.uuid,\n state: leaseStateToJSON(l.state),\n provider_uuid: l.providerUuid,\n created_at: l.createdAt?.toISOString(),\n });\n\n return resourceJson(uri, {\n tenant,\n active: active.leases.map(summarize),\n pending: pending.leases.map(summarize),\n counts: {\n active: active.leases.length,\n pending: pending.leases.length,\n },\n });\n },\n );\n\n // -- manifest://leases/recent --\n this.mcpServer.registerResource(\n 'leases-recent',\n 'manifest://leases/recent',\n {\n title: \"Caller's most recent leases (any state)\",\n description:\n \"The caller's leases ordered by most recent first, up to 50, regardless of state. Useful for surfacing recently-closed or rejected leases the agent may want to act on.\",\n mimeType: 'application/json',\n },\n async (uri) => {\n await this.clientManager.acquireRateLimit();\n const queryClient = await this.clientManager.getQueryClient();\n const tenant = await this.walletProvider.getAddress();\n const result = await queryClient.liftedinit.billing.v1.leasesByTenant({\n tenant,\n stateFilter: LeaseState.LEASE_STATE_UNSPECIFIED,\n pagination: {\n key: new Uint8Array(),\n offset: 0n,\n limit: 50n,\n countTotal: true,\n reverse: true,\n },\n });\n\n return resourceJson(uri, {\n tenant,\n leases: result.leases.map((l) => ({\n uuid: l.uuid,\n state: leaseStateToJSON(l.state),\n provider_uuid: l.providerUuid,\n created_at: l.createdAt?.toISOString(),\n closed_at: l.closedAt?.toISOString(),\n })),\n total: result.pagination?.total?.toString(),\n });\n },\n );\n\n // -- manifest://providers --\n this.mcpServer.registerResource(\n 'providers',\n 'manifest://providers',\n {\n title: 'Provider catalog snapshot',\n description:\n 'All active providers and their available SKUs (chain-side data only — no live HTTP health check). Use browse_catalog when health is needed.',\n mimeType: 'application/json',\n },\n async (uri) => {\n await this.clientManager.acquireRateLimit();\n const queryClient = await this.clientManager.getQueryClient();\n const sku = queryClient.liftedinit.sku.v1;\n const [providersResult, skusResult] = await Promise.all([\n sku.providers({ activeOnly: true, pagination: fixedPagination }),\n sku.sKUs({ activeOnly: true, pagination: fixedPagination }),\n ]);\n\n const providers = providersResult.providers.map((p) => ({\n uuid: p.uuid,\n address: p.address,\n api_url: p.apiUrl,\n active: p.active,\n }));\n\n const skus = skusResult.skus.map((s) => ({\n uuid: s.uuid,\n name: s.name,\n provider_uuid: s.providerUuid,\n active: s.active,\n base_price: s.basePrice\n ? { amount: s.basePrice.amount, denom: s.basePrice.denom }\n : null,\n }));\n\n return resourceJson(uri, {\n providers,\n skus,\n counts: {\n providers: providers.length,\n skus: skus.length,\n },\n });\n },\n );\n }\n\n private registerPrompts(): void {\n // -- deploy-containerized-app --\n this.mcpServer.registerPrompt(\n 'deploy-containerized-app',\n {\n title: 'Deploy a containerized app to Manifest',\n description:\n 'Walks through the full deploy lifecycle for a single containerized app: pre-flight check, manifest preview, deploy_app, and wait_for_app_ready. Emits a user-facing plan that asks for confirmation before broadcasting any transaction.',\n argsSchema: {\n image: z\n .string()\n .describe('Public Docker image to deploy (e.g. nginx:1.25)'),\n port: z\n .string()\n .optional()\n .describe(\n 'TCP port the container exposes (e.g. \"80\"). Required for single-service deployments.',\n ),\n size: z\n .string()\n .optional()\n .describe(\n 'SKU tier name (e.g. \"docker-micro\"). Use browse_catalog or check_deployment_readiness to enumerate available sizes.',\n ),\n },\n },\n ({ image, port, size }) => ({\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: [\n `Deploy this containerized app to the Manifest network end-to-end. Use ONLY the manifest-mcp-fred tools listed below; never broadcast a transaction without explicit confirmation from the user.`,\n ``,\n `Inputs:`,\n `- image: ${image}`,\n `- port: ${port ?? '(unspecified — ask the user)'}`,\n `- size: ${size ?? '(unspecified — call browse_catalog to enumerate sizes and ask the user)'}`,\n ``,\n `Workflow:`,\n `1. Pre-flight: call \\`check_deployment_readiness\\` with { size, image }. If \\`ready: false\\`, surface the \\`missing_steps\\` list to the user and stop.`,\n `2. Build a manifest preview: call \\`build_manifest_preview\\` with the same structured inputs (image + port). Show the user the resulting \\`manifest_json\\`, \\`format\\`, and \\`meta_hash_hex\\`. If \\`validation.valid: false\\`, surface every \\`validation.errors\\` entry verbatim and stop.`,\n `3. Print a deployment plan: image, manifest summary, SKU, provider (from \\`check_deployment_readiness.sku\\`), and the meta_hash. Wait for an explicit \"yes\" before continuing.`,\n `4. Call \\`deploy_app\\` (this broadcasts a chain TX and incurs fees). Pass any progressToken the host provides so the user sees provisioning progress.`,\n `5. Call \\`wait_for_app_ready\\` with the returned \\`lease_uuid\\`. On success, print the lease UUID, provider URL, and any \\`status.endpoints\\`. On failure, surface diagnostics and offer \\`close_lease\\` to reclaim the orphaned lease.`,\n ``,\n `Never skip the confirmation step in (3). If anything in (1) or (2) fails, do NOT proceed to (4).`,\n ].join('\\n'),\n },\n },\n ],\n }),\n );\n\n // -- diagnose-failing-app --\n this.mcpServer.registerPrompt(\n 'diagnose-failing-app',\n {\n title: 'Diagnose a failing or stuck deployed app',\n description:\n 'Bundles app_status, app_diagnostics, and get_logs into a structured triage flow for a misbehaving lease.',\n argsSchema: {\n lease_uuid: z\n .string()\n .describe('Lease UUID of the app to diagnose (uuid format)'),\n },\n },\n ({ lease_uuid }) => ({\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: [\n `Diagnose lease ${lease_uuid} on Manifest. Surface a short triage report — do not propose fixes until the data is collected.`,\n ``,\n `1. \\`app_status({ lease_uuid })\\` — record the chainState and (if present) fredStatus.`,\n `2. \\`app_diagnostics({ lease_uuid })\\` — record provision_status, fail_count, and last_error.`,\n `3. \\`get_logs({ lease_uuid, tail: 200 })\\` — capture the most recent logs.`,\n ``,\n `Then summarize:`,\n `- Lease state on chain.`,\n `- Provider state (provision_status / phase / fail_count / last_error).`,\n `- Most relevant log lines (last error or repeated failures).`,\n `- One concrete next step (e.g. \"image pull is failing — try a public registry\", \"container is restarting — inspect crash trace\", \"lease is closed — open a new deployment\").`,\n ].join('\\n'),\n },\n },\n ],\n }),\n );\n\n // -- shutdown-all-leases --\n this.mcpServer.registerPrompt(\n 'shutdown-all-leases',\n {\n title: \"Close all of the caller's active leases\",\n description:\n \"Lists the caller's active and pending leases and walks through closing each one. Always confirms with the user before broadcasting close_lease transactions.\",\n },\n () => ({\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: [\n `Shut down every active or pending lease for the current wallet. Each \\`close_lease\\` is a chain transaction with fees, and is destructive — never call it without an explicit \"yes\" from the user.`,\n ``,\n `1. Read \\`manifest://leases/active\\` to list current leases. If the list is empty, report that and stop.`,\n `2. Print a numbered table: { uuid, state, provider_uuid, created_at }. Ask the user \"close all (N), some, or none?\".`,\n `3. For each UUID the user approves, call \\`close_lease({ lease_uuid })\\`.`,\n `4. After each close, print \\`{ lease_uuid, status }\\` so the user can confirm progress.`,\n `5. End with a summary: closed count, skipped count, any errors.`,\n ].join('\\n'),\n },\n },\n ],\n }),\n );\n }\n\n /**\n * Builds a fire-and-forget progress emitter for a long-running tool.\n * Returns `undefined` if the caller didn't request progress (no\n * `progressToken` in `extra._meta`); callers can branch on that to skip\n * notification work entirely.\n *\n * Notifications are best-effort: failures are logged but don't fail the\n * tool. Each call increments the progress counter.\n */\n private progressEmitter(\n toolName: string,\n extra: RequestHandlerExtra<ServerRequest, ServerNotification>,\n ): ((message: string) => void) | undefined {\n const token = extra._meta?.progressToken;\n if (token === undefined) return undefined;\n let counter = 0;\n return (message: string) => {\n counter += 1;\n void extra\n .sendNotification({\n method: 'notifications/progress',\n params: {\n progressToken: token,\n progress: counter,\n message,\n },\n })\n .catch((err: unknown) => {\n logger.warn(\n `[${toolName}] progress notification failed: ${err instanceof Error ? err.message : String(err)}`,\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 createPagination,\n createValidatedConfig,\n DNS_LABEL_RE,\n jsonResponse,\n LeaseState,\n leaseStateToJSON,\n logger,\n MAX_PAGE_LIMIT,\n ManifestMCPError,\n ManifestMCPErrorCode,\n type ManifestMCPServerOptions,\n type MnemonicServerConfig,\n manifestMeta,\n mutatingAnnotations,\n readOnlyAnnotations,\n structuredResponse,\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 type { RequestHandlerExtra } from '@modelcontextprotocol/sdk/shared/protocol.js';\nimport type {\n ServerNotification,\n ServerRequest,\n} from '@modelcontextprotocol/sdk/types.js';\nimport { z } from 'zod';\nimport { AuthTokenService } from './http/auth-token-service.js';\nimport { getLeaseProvision, getLeaseReleases, MAX_TAIL } from './http/fred.js';\nimport { appStatus } from './tools/appStatus.js';\nimport { browseCatalog } from './tools/browseCatalog.js';\nimport { buildManifestPreview } from './tools/buildManifestPreview.js';\nimport { checkDeploymentReadiness } from './tools/checkDeploymentReadiness.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';\nimport { waitForAppReady } from './tools/waitForAppReady.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 type TerminalChainLeaseState,\n type TerminalChainState,\n type TerminalChainStateContext,\n TerminalChainStateError,\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 type ManifestFormat,\n type ManifestValidationResult,\n mergeManifest,\n metaHashHex,\n normalizePorts,\n parseStackManifest,\n validateManifest,\n validateServiceName,\n} from './manifest.js';\nexport { appStatus } from './tools/appStatus.js';\nexport { browseCatalog, mapWithConcurrency } from './tools/browseCatalog.js';\nexport {\n type BuildManifestPreviewInput,\n type BuildManifestPreviewResult,\n buildManifestPreview,\n type ManifestPreviewServiceInput,\n} from './tools/buildManifestPreview.js';\nexport {\n type CheckDeploymentReadinessInput,\n type CheckDeploymentReadinessResult,\n checkDeploymentReadiness,\n type SkuSummary,\n} from './tools/checkDeploymentReadiness.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';\nexport {\n type WaitForAppReadyOptions,\n type WaitForAppReadyResult,\n waitForAppReady,\n} from './tools/waitForAppReady.js';\n\nexport class FredMCPServer {\n private mcpServer: McpServer;\n private clientManager: CosmosClientManager;\n private walletProvider: WalletProvider;\n private authTokens: AuthTokenService;\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 this.authTokens = new AuthTokenService(this.walletProvider);\n\n this.mcpServer = new McpServer(\n {\n name: '@manifest-network/manifest-mcp-fred',\n version: VERSION,\n },\n {\n capabilities: {\n tools: {},\n resources: {},\n prompts: {},\n },\n },\n );\n\n this.registerTools();\n this.registerResources();\n this.registerPrompts();\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 outputSchema: {\n providers: z.array(z.looseObject({})),\n tiers: z.record(z.string(), z.array(z.looseObject({}))),\n },\n annotations: readOnlyAnnotations('Browse providers and SKUs'),\n _meta: manifestMeta({\n broadcasts: false,\n estimable: false,\n }),\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 structuredResponse(\n result as unknown as Record<string, unknown>,\n bigIntReplacer,\n );\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 outputSchema: {\n lease_uuid: z.string(),\n chainState: z.looseObject({\n state: z.number(),\n providerUuid: z.string(),\n }),\n connection: z.looseObject({}).optional(),\n fredStatus: z.looseObject({}).optional(),\n providerError: z.string().optional(),\n connectionError: z.string().optional(),\n },\n annotations: readOnlyAnnotations('Get deployed app status'),\n _meta: manifestMeta({\n broadcasts: false,\n estimable: false,\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.authTokens.providerToken(addr, uuid),\n );\n return structuredResponse(\n result as unknown as Record<string, unknown>,\n bigIntReplacer,\n );\n }),\n );\n\n // -- wait_for_app_ready --\n this.mcpServer.registerTool(\n 'wait_for_app_ready',\n {\n description:\n 'Wait for a deployed app to reach the ACTIVE state on the provider, polling at the configured interval. Use this after deploy_app instead of looping app_status manually. Throws on timeout or terminal lease state.',\n inputSchema: {\n lease_uuid: z\n .string()\n .uuid()\n .describe('The lease UUID of the app to wait on'),\n timeout_seconds: z\n .number()\n .int()\n .min(1)\n .max(600)\n .optional()\n .describe(\n 'Maximum seconds to wait before throwing. Defaults to 120s.',\n ),\n interval_seconds: z\n .number()\n .int()\n .min(1)\n .max(60)\n .optional()\n .describe('Seconds between status polls. Defaults to 3s.'),\n },\n outputSchema: {\n lease_uuid: z.string().describe('The lease UUID that was waited on'),\n provider_uuid: z.string().describe('Provider hosting the lease'),\n provider_url: z.string().describe('Provider API URL'),\n state: z\n .string()\n .describe(\n 'Final lease state, JSON-encoded LeaseState (e.g. LEASE_STATE_ACTIVE)',\n ),\n status: z\n .looseObject({})\n .describe(\n 'Raw provider status payload (instances, endpoints, services, etc.)',\n ),\n },\n annotations: readOnlyAnnotations('Wait for deployed app readiness'),\n _meta: manifestMeta({\n broadcasts: false,\n estimable: false,\n }),\n },\n withErrorHandling(\n 'wait_for_app_ready',\n async (\n args,\n extra: RequestHandlerExtra<ServerRequest, ServerNotification>,\n ) => {\n const emit = this.progressEmitter('wait_for_app_ready', extra);\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 waitForAppReady(\n queryClient,\n address,\n leaseUuid,\n (addr, uuid) => this.authTokens.providerToken(addr, uuid),\n {\n timeoutMs:\n args.timeout_seconds !== undefined\n ? args.timeout_seconds * 1_000\n : undefined,\n intervalMs:\n args.interval_seconds !== undefined\n ? args.interval_seconds * 1_000\n : undefined,\n abortSignal: extra.signal,\n onProgress: emit\n ? (status) => {\n const state = leaseStateToJSON(status.state);\n const provision = status.provision_status\n ? `, provision=${status.provision_status}`\n : '';\n emit(`Polling lease: state=${state}${provision}`);\n }\n : undefined,\n },\n );\n return structuredResponse(\n result as unknown as Record<string, unknown>,\n bigIntReplacer,\n );\n },\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 annotations: readOnlyAnnotations('Get container logs'),\n _meta: manifestMeta({\n broadcasts: false,\n estimable: false,\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.authTokens.providerToken(addr, uuid),\n tail,\n );\n return jsonResponse(result, bigIntReplacer);\n }),\n );\n\n // -- check_deployment_readiness --\n this.mcpServer.registerTool(\n 'check_deployment_readiness',\n {\n description:\n \"Pre-flight check for deploy_app: surfaces the caller's wallet balances, credit account, requested SKU availability, and a human-readable list of missing steps. Use this before deploy_app to decide whether to fund credits, switch SKU, or top up the wallet. Note: the chain does not expose provider allowed_registries, so a `ready: true` does not guarantee the registry of `image` is allowed — that is checked at upload time.\",\n inputSchema: {\n size: z\n .string()\n .optional()\n .describe(\n 'SKU tier to verify availability for (e.g. \"docker-micro\"). Omit to skip the SKU check.',\n ),\n image: z\n .string()\n .optional()\n .describe(\n 'Image planned for deployment. Recorded on the result for downstream display; not validated.',\n ),\n },\n outputSchema: {\n tenant: z.string(),\n image: z.string().nullable(),\n size: z.string().nullable(),\n wallet_balances: z.array(\n z.object({ denom: z.string(), amount: z.string() }),\n ),\n credits: z.looseObject({}).nullable(),\n current_balance: z\n .array(z.object({ denom: z.string(), amount: z.string() }))\n .optional(),\n hours_remaining: z.string().optional(),\n sku: z\n .object({\n name: z.string(),\n uuid: z.string(),\n provider_uuid: z.string(),\n price: z\n .object({ amount: z.string(), denom: z.string() })\n .optional(),\n active: z.boolean(),\n })\n .nullable(),\n available_sku_names: z.array(z.string()),\n ready: z.boolean(),\n missing_steps: z.array(z.string()),\n },\n annotations: readOnlyAnnotations('Check deploy pre-flight readiness'),\n _meta: manifestMeta({\n broadcasts: false,\n estimable: false,\n }),\n },\n withErrorHandling('check_deployment_readiness', async (args) => {\n const address = await this.walletProvider.getAddress();\n await this.clientManager.acquireRateLimit();\n const queryClient = await this.clientManager.getQueryClient();\n const result = await checkDeploymentReadiness(queryClient, address, {\n size: args.size,\n image: args.image,\n });\n return structuredResponse(\n result as unknown as Record<string, unknown>,\n bigIntReplacer,\n );\n }),\n );\n\n // -- build_manifest_preview --\n this.mcpServer.registerTool(\n 'build_manifest_preview',\n {\n description:\n 'Build a deployment manifest, validate it against the documented Fred rules, and compute the SHA-256 meta_hash that would be recorded on-chain. Use this BEFORE deploy_app to catch invalid manifests without paying for a lease. Two modes: raw `manifest` JSON string, or structured fields (image+port, or services for stacks).',\n inputSchema: {\n manifest: z\n .string()\n .optional()\n .describe(\n 'Raw manifest JSON string. Mutually exclusive with structured fields below.',\n ),\n image: z\n .string()\n .optional()\n .describe(\n 'Single-service image. Required (with port) when not using manifest or services.',\n ),\n port: z\n .number()\n .int()\n .min(1)\n .max(65535)\n .optional()\n .describe('Container port to expose. Required with image.'),\n env: z\n .record(z.string(), z.string())\n .optional()\n .describe('Environment variables as key-value pairs.'),\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 init: z.boolean().optional(),\n expose: z.array(z.string()).optional(),\n labels: z.record(z.string(), z.string()).optional(),\n depends_on: z\n .record(z.string(), z.object({ condition: z.string() }))\n .optional(),\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 and manifest.',\n ),\n },\n outputSchema: {\n manifest_json: z\n .string()\n .describe('Canonical manifest JSON that would be uploaded'),\n manifest: z\n .looseObject({})\n .describe('Parsed manifest object (same content as manifest_json)'),\n format: z\n .enum(['single', 'stack'])\n .describe('Detected manifest format'),\n meta_hash_hex: z\n .string()\n .describe('SHA-256 of manifest_json, lowercase hex'),\n validation: z.object({\n valid: z.boolean(),\n errors: z.array(z.string()),\n }),\n },\n annotations: readOnlyAnnotations('Preview and validate a manifest'),\n _meta: manifestMeta({\n broadcasts: false,\n estimable: false,\n }),\n },\n withErrorHandling('build_manifest_preview', async (args) => {\n const result = await buildManifestPreview({\n manifest: args.manifest,\n image: args.image,\n port: args.port,\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 depends_on: args.depends_on,\n services: args.services,\n });\n return structuredResponse(\n result as unknown as Record<string, unknown>,\n bigIntReplacer,\n );\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, optionally attaches a custom domain (FQDN) to the lease item, 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 gas_multiplier: z\n .number()\n .finite()\n .min(1)\n .optional()\n .describe(\n 'Gas simulation multiplier override for this transaction. Defaults to the server-configured value (typically 1.5). Increase if a transaction fails with out-of-gas errors.',\n ),\n custom_domain: z\n .string()\n .max(253)\n .optional()\n .describe(\n 'Optional FQDN to attach to the lease item once the create-lease tx confirms (e.g. \"app.example.com\"). Must be lowercase with a non-numeric TLD label and not match a reserved suffix; the chain validates the format. On a stack lease (`services`), pair with `service_name` to pick which item to attach the domain to.',\n ),\n service_name: z\n .string()\n .regex(DNS_LABEL_RE)\n .optional()\n .describe(\n 'Required when `custom_domain` is set on a stack lease (`services`). Must match one of the keys in `services` and be a valid RFC 1123 DNS label (1-63 lowercase alphanumeric chars + hyphens, no leading/trailing hyphen). Omit for image+port (single-item legacy) leases.',\n ),\n },\n outputSchema: {\n lease_uuid: z.string(),\n provider_uuid: z.string(),\n provider_url: z.string(),\n state: z.number(),\n url: z.string().optional(),\n connection: z.looseObject({}).optional(),\n connectionError: z.string().optional(),\n custom_domain: z.string().optional(),\n service_name: z.string().optional(),\n },\n // Additive: creates a new lease and uploads a manifest. Does not\n // replace any existing app's state.\n annotations: mutatingAnnotations('Deploy a containerized app', {\n destructive: false,\n }),\n _meta: manifestMeta({\n broadcasts: true,\n estimable: false,\n }),\n },\n withErrorHandling(\n 'deploy_app',\n async (\n args,\n extra: RequestHandlerExtra<ServerRequest, ServerNotification>,\n ) => {\n const emit = this.progressEmitter('deploy_app', extra);\n const result = await deployApp(\n this.clientManager,\n (addr, uuid) => this.authTokens.providerToken(addr, uuid),\n (addr, uuid, metaHashHex) =>\n this.authTokens.leaseDataToken(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 gasMultiplier: args.gas_multiplier,\n customDomain: args.custom_domain,\n serviceName: args.service_name,\n abortSignal: extra.signal,\n onLeaseCreated: emit\n ? (leaseUuid, providerUrl) => {\n emit(\n `Lease ${leaseUuid} created on chain at ${providerUrl}; uploading manifest`,\n );\n }\n : undefined,\n pollOptions: emit\n ? {\n onProgress: (status) => {\n const state = leaseStateToJSON(status.state);\n const provision = status.provision_status\n ? `, provision=${status.provision_status}`\n : '';\n emit(`Polling lease: state=${state}${provision}`);\n },\n }\n : undefined,\n },\n );\n return structuredResponse(\n result as unknown as Record<string, unknown>,\n bigIntReplacer,\n );\n },\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 // Additive: triggers a restart cycle without replacing config.\n // Not idempotent — each call triggers a fresh restart even when\n // the app is already running (relies on the helper's default).\n annotations: mutatingAnnotations('Restart a deployed app', {\n destructive: false,\n }),\n _meta: manifestMeta({\n broadcasts: true,\n estimable: false,\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.authTokens.providerToken(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 outputSchema: {\n lease_uuid: z.string(),\n status: z.string(),\n },\n // Destructive: replaces the running app's manifest. Even with the\n // merge mode, prior config can be overwritten.\n annotations: mutatingAnnotations('Update a deployed app manifest', {\n destructive: true,\n }),\n _meta: manifestMeta({\n broadcasts: true,\n estimable: false,\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.authTokens.providerToken(addr, uuid),\n manifest,\n args.existing_manifest,\n );\n return structuredResponse(\n result as unknown as Record<string, unknown>,\n bigIntReplacer,\n );\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 outputSchema: {\n lease_uuid: z.string(),\n provision_status: z.string(),\n fail_count: z.number(),\n // The provider omits last_error when there's no recent failure.\n // structuredResponse's JSON.stringify round-trip drops undefined\n // keys, so the parsed structuredContent has no `last_error` at\n // all in the success case — declare optional to match.\n last_error: z.string().optional(),\n },\n annotations: readOnlyAnnotations('Get app provision diagnostics'),\n _meta: manifestMeta({\n broadcasts: false,\n estimable: false,\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.authTokens.providerToken(\n address,\n leaseUuid,\n );\n const provision = await getLeaseProvision(\n providerUrl,\n leaseUuid,\n authToken,\n );\n\n return structuredResponse(\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 outputSchema: {\n lease_uuid: z.string(),\n releases: z.array(\n z.looseObject({\n version: z.number(),\n image: z.string(),\n status: z.string(),\n created_at: z.string(),\n }),\n ),\n },\n annotations: readOnlyAnnotations('Get app release history'),\n _meta: manifestMeta({\n broadcasts: false,\n estimable: false,\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.authTokens.providerToken(\n address,\n leaseUuid,\n );\n const result = await getLeaseReleases(\n providerUrl,\n leaseUuid,\n authToken,\n );\n\n return structuredResponse(\n {\n lease_uuid: leaseUuid,\n releases: result.releases,\n },\n bigIntReplacer,\n );\n }),\n );\n }\n\n private registerResources(): void {\n const fixedPagination = createPagination(MAX_PAGE_LIMIT);\n\n const resourceJson = (\n uri: URL,\n data: unknown,\n ): {\n contents: Array<{ uri: string; mimeType: string; text: string }>;\n } => ({\n contents: [\n {\n uri: uri.href,\n mimeType: 'application/json',\n text: JSON.stringify(data, bigIntReplacer, 2),\n },\n ],\n });\n\n // -- manifest://leases/active --\n this.mcpServer.registerResource(\n 'leases-active',\n 'manifest://leases/active',\n {\n title: \"Caller's active and pending leases\",\n description:\n \"Snapshot of the caller wallet's leases currently in ACTIVE or PENDING state. Useful as immutable context for an agent deciding which app to operate on.\",\n mimeType: 'application/json',\n },\n async (uri) => {\n await this.clientManager.acquireRateLimit();\n const queryClient = await this.clientManager.getQueryClient();\n const tenant = await this.walletProvider.getAddress();\n const billing = queryClient.liftedinit.billing.v1;\n\n const [active, pending] = await Promise.all([\n billing.leasesByTenant({\n tenant,\n stateFilter: LeaseState.LEASE_STATE_ACTIVE,\n pagination: fixedPagination,\n }),\n billing.leasesByTenant({\n tenant,\n stateFilter: LeaseState.LEASE_STATE_PENDING,\n pagination: fixedPagination,\n }),\n ]);\n\n const summarize = (l: {\n uuid: string;\n state: number;\n providerUuid: string;\n createdAt?: Date;\n metaHash?: Uint8Array;\n }) => ({\n uuid: l.uuid,\n state: leaseStateToJSON(l.state),\n provider_uuid: l.providerUuid,\n created_at: l.createdAt?.toISOString(),\n });\n\n return resourceJson(uri, {\n tenant,\n active: active.leases.map(summarize),\n pending: pending.leases.map(summarize),\n counts: {\n active: active.leases.length,\n pending: pending.leases.length,\n },\n });\n },\n );\n\n // -- manifest://leases/recent --\n this.mcpServer.registerResource(\n 'leases-recent',\n 'manifest://leases/recent',\n {\n title: \"Caller's most recent leases (any state)\",\n description:\n \"The caller's leases ordered by most recent first, up to 50, regardless of state. Useful for surfacing recently-closed or rejected leases the agent may want to act on.\",\n mimeType: 'application/json',\n },\n async (uri) => {\n await this.clientManager.acquireRateLimit();\n const queryClient = await this.clientManager.getQueryClient();\n const tenant = await this.walletProvider.getAddress();\n const result = await queryClient.liftedinit.billing.v1.leasesByTenant({\n tenant,\n stateFilter: LeaseState.LEASE_STATE_UNSPECIFIED,\n pagination: {\n key: new Uint8Array(),\n offset: 0n,\n limit: 50n,\n countTotal: true,\n reverse: true,\n },\n });\n\n return resourceJson(uri, {\n tenant,\n leases: result.leases.map((l) => ({\n uuid: l.uuid,\n state: leaseStateToJSON(l.state),\n provider_uuid: l.providerUuid,\n created_at: l.createdAt?.toISOString(),\n closed_at: l.closedAt?.toISOString(),\n })),\n total: result.pagination?.total?.toString(),\n });\n },\n );\n\n // -- manifest://providers --\n this.mcpServer.registerResource(\n 'providers',\n 'manifest://providers',\n {\n title: 'Provider catalog snapshot',\n description:\n 'All active providers and their available SKUs (chain-side data only — no live HTTP health check). Use browse_catalog when health is needed.',\n mimeType: 'application/json',\n },\n async (uri) => {\n await this.clientManager.acquireRateLimit();\n const queryClient = await this.clientManager.getQueryClient();\n const sku = queryClient.liftedinit.sku.v1;\n const [providersResult, skusResult] = await Promise.all([\n sku.providers({ activeOnly: true, pagination: fixedPagination }),\n sku.sKUs({ activeOnly: true, pagination: fixedPagination }),\n ]);\n\n const providers = providersResult.providers.map((p) => ({\n uuid: p.uuid,\n address: p.address,\n api_url: p.apiUrl,\n active: p.active,\n }));\n\n const skus = skusResult.skus.map((s) => ({\n uuid: s.uuid,\n name: s.name,\n provider_uuid: s.providerUuid,\n active: s.active,\n base_price: s.basePrice\n ? { amount: s.basePrice.amount, denom: s.basePrice.denom }\n : null,\n }));\n\n return resourceJson(uri, {\n providers,\n skus,\n counts: {\n providers: providers.length,\n skus: skus.length,\n },\n });\n },\n );\n }\n\n private registerPrompts(): void {\n // -- deploy-containerized-app --\n this.mcpServer.registerPrompt(\n 'deploy-containerized-app',\n {\n title: 'Deploy a containerized app to Manifest',\n description:\n 'Walks through the full deploy lifecycle for a single containerized app: pre-flight check, manifest preview, deploy_app, and wait_for_app_ready. Emits a user-facing plan that asks for confirmation before broadcasting any transaction.',\n argsSchema: {\n image: z\n .string()\n .describe('Public Docker image to deploy (e.g. nginx:1.25)'),\n port: z\n .string()\n .optional()\n .describe(\n 'TCP port the container exposes (e.g. \"80\"). Required for single-service deployments.',\n ),\n size: z\n .string()\n .optional()\n .describe(\n 'SKU tier name (e.g. \"docker-micro\"). Use browse_catalog or check_deployment_readiness to enumerate available sizes.',\n ),\n },\n },\n ({ image, port, size }) => ({\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: [\n `Deploy this containerized app to the Manifest network end-to-end. Use ONLY the manifest-mcp-fred tools listed below; never broadcast a transaction without explicit confirmation from the user.`,\n ``,\n `Inputs:`,\n `- image: ${image}`,\n `- port: ${port ?? '(unspecified — ask the user)'}`,\n `- size: ${size ?? '(unspecified — call browse_catalog to enumerate sizes and ask the user)'}`,\n ``,\n `Workflow:`,\n `1. Pre-flight: call \\`check_deployment_readiness\\` with { size, image }. If \\`ready: false\\`, surface the \\`missing_steps\\` list to the user and stop.`,\n `2. Build a manifest preview: call \\`build_manifest_preview\\` with the same structured inputs (image + port). Show the user the resulting \\`manifest_json\\`, \\`format\\`, and \\`meta_hash_hex\\`. If \\`validation.valid: false\\`, surface every \\`validation.errors\\` entry verbatim and stop.`,\n `3. Print a deployment plan: image, manifest summary, SKU, provider (from \\`check_deployment_readiness.sku\\`), and the meta_hash. Wait for an explicit \"yes\" before continuing.`,\n `4. Call \\`deploy_app\\` (this broadcasts a chain TX and incurs fees). Pass any progressToken the host provides so the user sees provisioning progress.`,\n `5. Call \\`wait_for_app_ready\\` with the returned \\`lease_uuid\\`. On success, print the lease UUID, provider URL, and any \\`status.endpoints\\`. On failure, surface diagnostics and offer \\`close_lease\\` to reclaim the orphaned lease.`,\n ``,\n `Never skip the confirmation step in (3). If anything in (1) or (2) fails, do NOT proceed to (4).`,\n ].join('\\n'),\n },\n },\n ],\n }),\n );\n\n // -- diagnose-failing-app --\n this.mcpServer.registerPrompt(\n 'diagnose-failing-app',\n {\n title: 'Diagnose a failing or stuck deployed app',\n description:\n 'Bundles app_status, app_diagnostics, and get_logs into a structured triage flow for a misbehaving lease.',\n argsSchema: {\n lease_uuid: z\n .string()\n .describe('Lease UUID of the app to diagnose (uuid format)'),\n },\n },\n ({ lease_uuid }) => ({\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: [\n `Diagnose lease ${lease_uuid} on Manifest. Surface a short triage report — do not propose fixes until the data is collected.`,\n ``,\n `1. \\`app_status({ lease_uuid })\\` — record the chainState and (if present) fredStatus.`,\n `2. \\`app_diagnostics({ lease_uuid })\\` — record provision_status, fail_count, and last_error.`,\n `3. \\`get_logs({ lease_uuid, tail: 200 })\\` — capture the most recent logs.`,\n ``,\n `Then summarize:`,\n `- Lease state on chain.`,\n `- Provider state (provision_status / phase / fail_count / last_error).`,\n `- Most relevant log lines (last error or repeated failures).`,\n `- One concrete next step (e.g. \"image pull is failing — try a public registry\", \"container is restarting — inspect crash trace\", \"lease is closed — open a new deployment\").`,\n ].join('\\n'),\n },\n },\n ],\n }),\n );\n\n // -- shutdown-all-leases --\n this.mcpServer.registerPrompt(\n 'shutdown-all-leases',\n {\n title: \"Close all of the caller's active leases\",\n description:\n \"Lists the caller's active and pending leases and walks through closing each one. Always confirms with the user before broadcasting close_lease transactions.\",\n },\n () => ({\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: [\n `Shut down every active or pending lease for the current wallet. Each \\`close_lease\\` is a chain transaction with fees, and is destructive — never call it without an explicit \"yes\" from the user.`,\n ``,\n `1. Read \\`manifest://leases/active\\` to list current leases. If the list is empty, report that and stop.`,\n `2. Print a numbered table: { uuid, state, provider_uuid, created_at }. Ask the user \"close all (N), some, or none?\".`,\n `3. For each UUID the user approves, call \\`close_lease({ lease_uuid })\\`.`,\n `4. After each close, print \\`{ lease_uuid, status }\\` so the user can confirm progress.`,\n `5. End with a summary: closed count, skipped count, any errors.`,\n ].join('\\n'),\n },\n },\n ],\n }),\n );\n }\n\n /**\n * Builds a fire-and-forget progress emitter for a long-running tool.\n * Returns `undefined` if the caller didn't request progress (no\n * `progressToken` in `extra._meta`); callers can branch on that to skip\n * notification work entirely.\n *\n * Notifications are best-effort: failures are logged but don't fail the\n * tool. Each call increments the progress counter.\n */\n private progressEmitter(\n toolName: string,\n extra: RequestHandlerExtra<ServerRequest, ServerNotification>,\n ): ((message: string) => void) | undefined {\n const token = extra._meta?.progressToken;\n if (token === undefined) return undefined;\n let counter = 0;\n return (message: string) => {\n counter += 1;\n void extra\n .sendNotification({\n method: 'notifications/progress',\n params: {\n progressToken: token,\n progress: counter,\n message,\n },\n })\n .catch((err: unknown) => {\n logger.warn(\n `[${toolName}] progress notification failed: ${err instanceof Error ? err.message : String(err)}`,\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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"}
|
|
@@ -51,6 +51,22 @@ interface DeployAppInput {
|
|
|
51
51
|
}>;
|
|
52
52
|
services?: Record<string, ServiceConfig>;
|
|
53
53
|
gasMultiplier?: number;
|
|
54
|
+
/**
|
|
55
|
+
* Optional FQDN to attach to the lease item once the create-lease tx
|
|
56
|
+
* confirms. The set-domain tx is submitted after `onLeaseCreated` fires
|
|
57
|
+
* and before the manifest upload, so providerd has the domain available
|
|
58
|
+
* when it provisions the container. Failures here surface as the same
|
|
59
|
+
* "Deploy partially succeeded: lease X was created..." error shape as
|
|
60
|
+
* upload/poll failures — the caller can `close_lease` to clean up or
|
|
61
|
+
* retry `set_item_custom_domain` standalone.
|
|
62
|
+
*/
|
|
63
|
+
customDomain?: string;
|
|
64
|
+
/**
|
|
65
|
+
* Required when `customDomain` is set on a stack lease (i.e., `services`
|
|
66
|
+
* is provided). Must match one of the keys in `services`. Omit for an
|
|
67
|
+
* image+port single-item legacy lease.
|
|
68
|
+
*/
|
|
69
|
+
serviceName?: string;
|
|
54
70
|
/** Fires once after the create-lease TX confirms, before upload/poll. Awaited. Errors propagate. */
|
|
55
71
|
onLeaseCreated?: (leaseUuid: string, providerUrl: string) => void | Promise<void>;
|
|
56
72
|
/** Aborts upload and poll (not the already-submitted chain TX). */
|
|
@@ -66,6 +82,10 @@ interface DeployAppResult {
|
|
|
66
82
|
readonly url?: string;
|
|
67
83
|
readonly connection?: ConnectionDetails;
|
|
68
84
|
readonly connectionError?: string;
|
|
85
|
+
/** Set when a `customDomain` was supplied AND the set-domain tx succeeded. */
|
|
86
|
+
readonly custom_domain?: string;
|
|
87
|
+
/** Set when a `serviceName` was supplied alongside a successful `customDomain` set. */
|
|
88
|
+
readonly service_name?: string;
|
|
69
89
|
}
|
|
70
90
|
declare function deployApp(clientManager: CosmosClientManager, getAuthToken: (address: string, leaseUuid: string) => Promise<string>, getLeaseDataAuthToken: (address: string, leaseUuid: string, metaHashHex: string) => Promise<string>, input: DeployAppInput, fetchFn?: typeof globalThis.fetch): Promise<DeployAppResult>;
|
|
71
91
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deployApp.d.ts","names":[],"sources":["../../src/tools/deployApp.ts"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"deployApp.d.ts","names":[],"sources":["../../src/tools/deployApp.ts"],"mappings":";;;;;UAwFiB,aAAA;EACf,KAAA;EACA,KAAA,GAAQ,MAAA,SAAe,MAAA;EACvB,GAAA,GAAM,MAAA;EACN,OAAA;EACA,IAAA;EACA,IAAA;EACA,KAAA;EACA,YAAA;IACE,IAAA;IACA,QAAA;IACA,OAAA;IACA,OAAA;IACA,YAAA;EAAA;EAEF,iBAAA;EACA,UAAA,GAAa,MAAA;IAAiB,SAAA;EAAA;EAC9B,MAAA;EACA,MAAA,GAAS,MAAA;AAAA;AAAA,UAGM,cAAA;EACf,KAAA;EACA,IAAA;EACA,IAAA;EACA,GAAA,GAAM,MAAA;EACN,OAAA;EACA,IAAA;EACA,IAAA;EACA,KAAA;EACA,YAAA;IACE,IAAA;IACA,QAAA;IACA,OAAA;IACA,OAAA;IACA,YAAA;EAAA;EAEF,iBAAA;EACA,IAAA;EACA,MAAA;EACA,MAAA,GAAS,MAAA;EACT,OAAA;EACA,UAAA,GAAa,MAAA;IAAiB,SAAA;EAAA;EAC9B,QAAA,GAAW,MAAA,SAAe,aAAA;EAC1B,aAAA;EAyBc;;;;;;;;;EAfd,YAAA;EA1BA;;;;;EAgCA,WAAA;EA1BE;EA4BF,cAAA,IACE,SAAA,UACA,WAAA,oBACU,OAAA;EA5BZ;EA8BA,WAAA,GAAc,WAAA;EA5Bd;EA8BA,WAAA,GAAc,IAAA,CAAK,WAAA;AAAA;AAAA,UAGJ,eAAA;EAAA,SACN,UAAA;EAAA,SACA,aAAA;EAAA,SACA,YAAA;EAAA,SACA,KAAA,EAAO,UAAA;EAAA,SACP,GAAA;EAAA,SACA,UAAA,GAAa,iBAAA;EAAA,SACb,eAAA;EAzBT;EAAA,SA2BS,aAAA;EAnBT;EAAA,SAqBS,YAAA;AAAA;AAAA,iBAGW,SAAA,CACpB,aAAA,EAAe,mBAAA,EACf,YAAA,GAAe,OAAA,UAAiB,SAAA,aAAsB,OAAA,UACtD,qBAAA,GACE,OAAA,UACA,SAAA,UACA,WAAA,aACG,OAAA,UACL,KAAA,EAAO,cAAA,EACP,OAAA,UAAiB,UAAA,CAAW,KAAA,GAC3B,OAAA,CAAQ,eAAA"}
|
package/dist/tools/deployApp.js
CHANGED
|
@@ -2,7 +2,7 @@ import { getLeaseConnectionInfo, uploadLeaseData } from "../http/provider.js";
|
|
|
2
2
|
import { TerminalChainStateError, pollLeaseUntilReady } from "../http/fred.js";
|
|
3
3
|
import { resolveProviderUrl } from "./resolveLeaseProvider.js";
|
|
4
4
|
import { buildManifest, buildStackManifest, metaHashHex, validateServiceName } from "../manifest.js";
|
|
5
|
-
import { MAX_PAGE_LIMIT, ManifestMCPError, ManifestMCPErrorCode, cosmosTx, createPagination, logger, requireUuid, sanitizeForLogging } from "@manifest-network/manifest-mcp-core";
|
|
5
|
+
import { MAX_PAGE_LIMIT, ManifestMCPError, ManifestMCPErrorCode, cosmosTx, createPagination, logger, requireUuid, sanitizeForLogging, setItemCustomDomain } from "@manifest-network/manifest-mcp-core";
|
|
6
6
|
//#region src/tools/deployApp.ts
|
|
7
7
|
function extractLeaseUuid(txResult) {
|
|
8
8
|
if (!txResult.events) throw new ManifestMCPError(ManifestMCPErrorCode.TX_FAILED, "No events in transaction result; cannot extract lease UUID");
|
|
@@ -33,6 +33,19 @@ async function deployApp(clientManager, getAuthToken, getLeaseDataAuthToken, inp
|
|
|
33
33
|
if (input.image && input.services) throw new ManifestMCPError(ManifestMCPErrorCode.INVALID_CONFIG, "image and services are mutually exclusive");
|
|
34
34
|
if (!input.image && !input.services) throw new ManifestMCPError(ManifestMCPErrorCode.INVALID_CONFIG, "either image or services is required");
|
|
35
35
|
if (input.image && !input.port) throw new ManifestMCPError(ManifestMCPErrorCode.INVALID_CONFIG, "port is required when using image");
|
|
36
|
+
if (input.customDomain === void 0 && input.serviceName !== void 0) throw new ManifestMCPError(ManifestMCPErrorCode.INVALID_CONFIG, "serviceName is only meaningful when customDomain is set; pass customDomain or omit serviceName");
|
|
37
|
+
let normalizedCustomDomain;
|
|
38
|
+
if (input.customDomain !== void 0) {
|
|
39
|
+
normalizedCustomDomain = input.customDomain.trim();
|
|
40
|
+
if (normalizedCustomDomain === "") throw new ManifestMCPError(ManifestMCPErrorCode.INVALID_CONFIG, "customDomain cannot be empty or whitespace-only");
|
|
41
|
+
if (input.services) {
|
|
42
|
+
if (!input.serviceName) throw new ManifestMCPError(ManifestMCPErrorCode.INVALID_CONFIG, "serviceName is required when setting customDomain on a stack lease (services); pick one of the service keys");
|
|
43
|
+
if (!Object.keys(input.services).includes(input.serviceName)) {
|
|
44
|
+
const available = Object.keys(input.services).join(", ");
|
|
45
|
+
throw new ManifestMCPError(ManifestMCPErrorCode.INVALID_CONFIG, `serviceName "${input.serviceName}" does not match any service in the deployment. Available: ${available}`);
|
|
46
|
+
}
|
|
47
|
+
} else if (input.serviceName) throw new ManifestMCPError(ManifestMCPErrorCode.INVALID_CONFIG, "serviceName must not be set on an image+port (legacy 1-item) lease — omit it or switch to services mode");
|
|
48
|
+
}
|
|
36
49
|
const address = await clientManager.getAddress();
|
|
37
50
|
await clientManager.acquireRateLimit();
|
|
38
51
|
const queryClient = await clientManager.getQueryClient();
|
|
@@ -93,6 +106,7 @@ async function deployApp(clientManager, getAuthToken, getLeaseDataAuthToken, inp
|
|
|
93
106
|
let status;
|
|
94
107
|
try {
|
|
95
108
|
input.abortSignal?.throwIfAborted();
|
|
109
|
+
if (normalizedCustomDomain !== void 0) await setItemCustomDomain(clientManager, leaseUuid, normalizedCustomDomain, { serviceName: input.serviceName }, overrides);
|
|
96
110
|
const leaseDataToken = await getLeaseDataAuthToken(address, leaseUuid, manifestMetaHash);
|
|
97
111
|
await uploadLeaseData(providerUrl, leaseUuid, new TextEncoder().encode(manifestJson), leaseDataToken, fetchFn, input.abortSignal);
|
|
98
112
|
status = await pollLeaseUntilReady(providerUrl, leaseUuid, () => getAuthToken(address, leaseUuid), {
|
|
@@ -138,7 +152,9 @@ async function deployApp(clientManager, getAuthToken, getLeaseDataAuthToken, inp
|
|
|
138
152
|
state: status.state,
|
|
139
153
|
...url && { url },
|
|
140
154
|
...connection && { connection },
|
|
141
|
-
...connectionError && { connectionError }
|
|
155
|
+
...connectionError && { connectionError },
|
|
156
|
+
...normalizedCustomDomain && { custom_domain: normalizedCustomDomain },
|
|
157
|
+
...normalizedCustomDomain && input.serviceName && { service_name: input.serviceName }
|
|
142
158
|
};
|
|
143
159
|
}
|
|
144
160
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deployApp.js","names":[],"sources":["../../src/tools/deployApp.ts"],"sourcesContent":["import type {\n CosmosClientManager,\n CosmosTxResult,\n LeaseState,\n ManifestQueryClient,\n} from '@manifest-network/manifest-mcp-core';\nimport {\n cosmosTx,\n createPagination,\n logger,\n MAX_PAGE_LIMIT,\n ManifestMCPError,\n ManifestMCPErrorCode,\n requireUuid,\n sanitizeForLogging,\n} from '@manifest-network/manifest-mcp-core';\nimport type { FredLeaseStatus, PollOptions } from '../http/fred.js';\nimport { pollLeaseUntilReady, TerminalChainStateError } from '../http/fred.js';\nimport {\n type ConnectionDetails,\n getLeaseConnectionInfo,\n uploadLeaseData,\n} from '../http/provider.js';\nimport {\n type BuildManifestOptions,\n buildManifest,\n buildStackManifest,\n metaHashHex,\n validateServiceName,\n} from '../manifest.js';\nimport { resolveProviderUrl } from './resolveLeaseProvider.js';\n\nfunction extractLeaseUuid(txResult: CosmosTxResult): string {\n if (!txResult.events) {\n throw new ManifestMCPError(\n ManifestMCPErrorCode.TX_FAILED,\n 'No events in transaction result; cannot extract lease UUID',\n );\n }\n\n for (const event of txResult.events) {\n if (!event.type.includes('lease') && !event.type.includes('Lease'))\n continue;\n for (const attr of event.attributes) {\n if (attr.key === 'lease_uuid' || attr.key === 'uuid') {\n const raw = attr.value.replace(/^\"|\"$/g, '');\n // Validate the extracted value is a proper UUID\n requireUuid(\n { lease_uuid: raw },\n 'lease_uuid',\n ManifestMCPErrorCode.TX_FAILED,\n );\n return raw;\n }\n }\n }\n\n throw new ManifestMCPError(\n ManifestMCPErrorCode.TX_FAILED,\n 'Could not find lease UUID in transaction events',\n { events: txResult.events as unknown as Record<string, unknown>[] },\n );\n}\n\nasync function findSkuUuid(\n queryClient: ManifestQueryClient,\n size: string,\n): Promise<{ skuUuid: string; providerUuid: string }> {\n const pagination = createPagination(MAX_PAGE_LIMIT);\n const result = await queryClient.liftedinit.sku.v1.sKUs({\n activeOnly: true,\n pagination,\n });\n\n for (const sku of result.skus) {\n if (sku.name === size) {\n return { skuUuid: sku.uuid, providerUuid: sku.providerUuid };\n }\n }\n\n const available = result.skus.map((s) => s.name);\n throw new ManifestMCPError(\n ManifestMCPErrorCode.QUERY_FAILED,\n `SKU tier \"${size}\" not found. Available: ${available.join(', ')}`,\n );\n}\n\nexport interface ServiceConfig {\n image: string;\n ports?: Record<string, Record<string, never>>;\n env?: Record<string, string>;\n command?: string[];\n args?: string[];\n user?: string;\n tmpfs?: string[];\n health_check?: {\n test: string[];\n interval?: string;\n timeout?: string;\n retries?: number;\n start_period?: string;\n };\n stop_grace_period?: string;\n depends_on?: Record<string, { condition: string }>;\n expose?: string[];\n labels?: Record<string, string>;\n}\n\nexport interface DeployAppInput {\n image?: string;\n port?: number;\n size: string;\n env?: Record<string, string>;\n command?: string[];\n args?: string[];\n user?: string;\n tmpfs?: string[];\n health_check?: {\n test: string[];\n interval?: string;\n timeout?: string;\n retries?: number;\n start_period?: string;\n };\n stop_grace_period?: string;\n init?: boolean;\n expose?: string[];\n labels?: Record<string, string>;\n storage?: string;\n depends_on?: Record<string, { condition: string }>;\n services?: Record<string, ServiceConfig>;\n gasMultiplier?: number;\n /** Fires once after the create-lease TX confirms, before upload/poll. Awaited. Errors propagate. */\n onLeaseCreated?: (\n leaseUuid: string,\n providerUrl: string,\n ) => void | Promise<void>;\n /** Aborts upload and poll (not the already-submitted chain TX). */\n abortSignal?: AbortSignal;\n /** Forwarded to the internal pollLeaseUntilReady call. abortSignal is the top-level field above. */\n pollOptions?: Omit<PollOptions, 'abortSignal'>;\n}\n\nexport interface DeployAppResult {\n readonly lease_uuid: string;\n readonly provider_uuid: string;\n readonly provider_url: string;\n readonly state: LeaseState;\n readonly url?: string;\n readonly connection?: ConnectionDetails;\n readonly connectionError?: string;\n}\n\nexport async function deployApp(\n clientManager: CosmosClientManager,\n getAuthToken: (address: string, leaseUuid: string) => Promise<string>,\n getLeaseDataAuthToken: (\n address: string,\n leaseUuid: string,\n metaHashHex: string,\n ) => Promise<string>,\n input: DeployAppInput,\n fetchFn?: typeof globalThis.fetch,\n): Promise<DeployAppResult> {\n // Validate mutually exclusive inputs\n if (input.image && input.services) {\n throw new ManifestMCPError(\n ManifestMCPErrorCode.INVALID_CONFIG,\n 'image and services are mutually exclusive',\n );\n }\n if (!input.image && !input.services) {\n throw new ManifestMCPError(\n ManifestMCPErrorCode.INVALID_CONFIG,\n 'either image or services is required',\n );\n }\n if (input.image && !input.port) {\n throw new ManifestMCPError(\n ManifestMCPErrorCode.INVALID_CONFIG,\n 'port is required when using image',\n );\n }\n\n const address = await clientManager.getAddress();\n await clientManager.acquireRateLimit();\n const queryClient = await clientManager.getQueryClient();\n\n // 1. Build manifest\n let manifestJson: string;\n if (input.services) {\n for (const name of Object.keys(input.services)) {\n if (!validateServiceName(name)) {\n throw new ManifestMCPError(\n ManifestMCPErrorCode.INVALID_CONFIG,\n `Invalid service name: \"${name}\". Must be 1-63 chars, lowercase alphanumeric + hyphens, no leading/trailing hyphens.`,\n );\n }\n }\n\n const services: Record<string, BuildManifestOptions> = {};\n for (const [name, svc] of Object.entries(input.services)) {\n services[name] = {\n image: svc.image,\n ports: svc.ports ?? {},\n env: svc.env,\n command: svc.command,\n args: svc.args,\n user: svc.user,\n tmpfs: svc.tmpfs,\n health_check: svc.health_check,\n stop_grace_period: svc.stop_grace_period,\n depends_on: svc.depends_on,\n expose: svc.expose,\n labels: svc.labels,\n };\n }\n manifestJson = JSON.stringify(buildStackManifest({ services }));\n } else {\n // image is guaranteed defined here: the guard above ensures !image && !services is false,\n // and the if-branch handles the services case. TypeScript can't narrow across if/else.\n const image = input.image as string;\n manifestJson = JSON.stringify(\n buildManifest({\n image,\n ports: { [`${input.port}/tcp`]: {} },\n env: input.env,\n command: input.command,\n args: input.args,\n user: input.user,\n tmpfs: input.tmpfs,\n health_check: input.health_check,\n stop_grace_period: input.stop_grace_period,\n init: input.init,\n expose: input.expose,\n labels: input.labels,\n depends_on: input.depends_on,\n }),\n );\n }\n\n // 2. SHA-256 hash of manifest (must match `meta_hash` recorded on-chain).\n const manifestMetaHash = await metaHashHex(manifestJson);\n\n // 3. Find matching SKU(s)\n const { skuUuid, providerUuid } = await findSkuUuid(queryClient, input.size);\n\n let leaseItems: string[];\n if (input.services) {\n const serviceNames = Object.keys(input.services);\n leaseItems = serviceNames.map((name) => `${skuUuid}:1:${name}`);\n } else {\n leaseItems = [`${skuUuid}:1`];\n }\n\n if (input.storage) {\n const { skuUuid: storageSkuUuid } = await findSkuUuid(\n queryClient,\n input.storage,\n );\n leaseItems.push(`${storageSkuUuid}:1`);\n }\n\n // 4. Get provider URL\n const providerUrl = await resolveProviderUrl(queryClient, providerUuid);\n\n // 5. Create lease\n const overrides =\n input.gasMultiplier !== undefined\n ? { gasMultiplier: input.gasMultiplier }\n : undefined;\n const txResult = await cosmosTx(\n clientManager,\n 'billing',\n 'create-lease',\n ['--meta-hash', manifestMetaHash, ...leaseItems],\n true,\n overrides,\n );\n\n // 6. Extract lease UUID\n const leaseUuid = extractLeaseUuid(txResult);\n\n // Outside the partial-success try: callback errors surface raw, not wrapped.\n // The lease exists on-chain regardless of abortSignal state — always notify.\n await input.onLeaseCreated?.(leaseUuid, providerUrl);\n\n let status: FredLeaseStatus;\n try {\n input.abortSignal?.throwIfAborted();\n\n // 7. Upload manifest with lease-data auth token\n const leaseDataToken = await getLeaseDataAuthToken(\n address,\n leaseUuid,\n manifestMetaHash,\n );\n await uploadLeaseData(\n providerUrl,\n leaseUuid,\n new TextEncoder().encode(manifestJson),\n leaseDataToken,\n fetchFn,\n input.abortSignal,\n );\n\n // 8. Poll until ready\n status = await pollLeaseUntilReady(\n providerUrl,\n leaseUuid,\n () => getAuthToken(address, leaseUuid),\n { ...input.pollOptions, abortSignal: input.abortSignal },\n fetchFn,\n );\n } catch (err) {\n // Chain-terminal states are self-explanatory and need no \"close this lease\"\n // advice (the lease is already terminal on-chain). Let Barney & friends\n // observe the typed error directly via `instanceof` / `err.chainState`.\n // withContext preserves the original stack (debugging points at the poll,\n // not at this catch) while attaching deployApp's provider context so\n // callers don't need to re-query the chain to recover it.\n if (err instanceof TerminalChainStateError) {\n throw err.withContext({ providerUuid, providerUrl });\n }\n const code =\n err instanceof ManifestMCPError\n ? err.code\n : ManifestMCPErrorCode.QUERY_FAILED;\n const details =\n err instanceof ManifestMCPError\n ? {\n ...err.details,\n lease_uuid: leaseUuid,\n provider_uuid: providerUuid,\n provider_url: providerUrl,\n }\n : {\n lease_uuid: leaseUuid,\n provider_uuid: providerUuid,\n provider_url: providerUrl,\n };\n throw new ManifestMCPError(\n code,\n `Deploy partially succeeded: lease ${leaseUuid} was created but subsequent steps failed. ` +\n `Close this lease with close_lease if needed. Error: ${err instanceof Error ? err.message : String(err)}`,\n details,\n );\n }\n\n // 9. Get connection info (best-effort)\n let connection: ConnectionDetails | undefined;\n let url: string | undefined;\n let connectionError: string | undefined;\n try {\n const authToken = await getAuthToken(address, leaseUuid);\n const connResp = await getLeaseConnectionInfo(\n providerUrl,\n leaseUuid,\n authToken,\n fetchFn,\n );\n connection = connResp.connection;\n if (connection.host && connection.ports) {\n const firstPort = Object.values(connection.ports)[0];\n if (typeof firstPort === 'number' || typeof firstPort === 'string') {\n url = `${connection.host}:${firstPort}`;\n }\n }\n } catch (err) {\n const rawMsg = err instanceof Error ? err.message : String(err);\n // Log raw message to stderr for debugging; sanitize only the user-facing return value\n logger.error(\n `[deploy_app] Failed to fetch connection info for lease ${leaseUuid}: ${rawMsg}`,\n );\n connectionError = sanitizeForLogging(rawMsg) as string;\n }\n\n return {\n lease_uuid: leaseUuid,\n provider_uuid: providerUuid,\n provider_url: providerUrl,\n state: status.state,\n ...(url && { url }),\n ...(connection && { connection }),\n ...(connectionError && { connectionError }),\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"deployApp.js","names":[],"sources":["../../src/tools/deployApp.ts"],"sourcesContent":["import type {\n CosmosClientManager,\n CosmosTxResult,\n LeaseState,\n ManifestQueryClient,\n} from '@manifest-network/manifest-mcp-core';\nimport {\n cosmosTx,\n createPagination,\n logger,\n MAX_PAGE_LIMIT,\n ManifestMCPError,\n ManifestMCPErrorCode,\n requireUuid,\n sanitizeForLogging,\n setItemCustomDomain,\n} from '@manifest-network/manifest-mcp-core';\nimport type { FredLeaseStatus, PollOptions } from '../http/fred.js';\nimport { pollLeaseUntilReady, TerminalChainStateError } from '../http/fred.js';\nimport {\n type ConnectionDetails,\n getLeaseConnectionInfo,\n uploadLeaseData,\n} from '../http/provider.js';\nimport {\n type BuildManifestOptions,\n buildManifest,\n buildStackManifest,\n metaHashHex,\n validateServiceName,\n} from '../manifest.js';\nimport { resolveProviderUrl } from './resolveLeaseProvider.js';\n\nfunction extractLeaseUuid(txResult: CosmosTxResult): string {\n if (!txResult.events) {\n throw new ManifestMCPError(\n ManifestMCPErrorCode.TX_FAILED,\n 'No events in transaction result; cannot extract lease UUID',\n );\n }\n\n for (const event of txResult.events) {\n if (!event.type.includes('lease') && !event.type.includes('Lease'))\n continue;\n for (const attr of event.attributes) {\n if (attr.key === 'lease_uuid' || attr.key === 'uuid') {\n const raw = attr.value.replace(/^\"|\"$/g, '');\n // Validate the extracted value is a proper UUID\n requireUuid(\n { lease_uuid: raw },\n 'lease_uuid',\n ManifestMCPErrorCode.TX_FAILED,\n );\n return raw;\n }\n }\n }\n\n throw new ManifestMCPError(\n ManifestMCPErrorCode.TX_FAILED,\n 'Could not find lease UUID in transaction events',\n { events: txResult.events as unknown as Record<string, unknown>[] },\n );\n}\n\nasync function findSkuUuid(\n queryClient: ManifestQueryClient,\n size: string,\n): Promise<{ skuUuid: string; providerUuid: string }> {\n const pagination = createPagination(MAX_PAGE_LIMIT);\n const result = await queryClient.liftedinit.sku.v1.sKUs({\n activeOnly: true,\n pagination,\n });\n\n for (const sku of result.skus) {\n if (sku.name === size) {\n return { skuUuid: sku.uuid, providerUuid: sku.providerUuid };\n }\n }\n\n const available = result.skus.map((s) => s.name);\n throw new ManifestMCPError(\n ManifestMCPErrorCode.QUERY_FAILED,\n `SKU tier \"${size}\" not found. Available: ${available.join(', ')}`,\n );\n}\n\nexport interface ServiceConfig {\n image: string;\n ports?: Record<string, Record<string, never>>;\n env?: Record<string, string>;\n command?: string[];\n args?: string[];\n user?: string;\n tmpfs?: string[];\n health_check?: {\n test: string[];\n interval?: string;\n timeout?: string;\n retries?: number;\n start_period?: string;\n };\n stop_grace_period?: string;\n depends_on?: Record<string, { condition: string }>;\n expose?: string[];\n labels?: Record<string, string>;\n}\n\nexport interface DeployAppInput {\n image?: string;\n port?: number;\n size: string;\n env?: Record<string, string>;\n command?: string[];\n args?: string[];\n user?: string;\n tmpfs?: string[];\n health_check?: {\n test: string[];\n interval?: string;\n timeout?: string;\n retries?: number;\n start_period?: string;\n };\n stop_grace_period?: string;\n init?: boolean;\n expose?: string[];\n labels?: Record<string, string>;\n storage?: string;\n depends_on?: Record<string, { condition: string }>;\n services?: Record<string, ServiceConfig>;\n gasMultiplier?: number;\n /**\n * Optional FQDN to attach to the lease item once the create-lease tx\n * confirms. The set-domain tx is submitted after `onLeaseCreated` fires\n * and before the manifest upload, so providerd has the domain available\n * when it provisions the container. Failures here surface as the same\n * \"Deploy partially succeeded: lease X was created...\" error shape as\n * upload/poll failures — the caller can `close_lease` to clean up or\n * retry `set_item_custom_domain` standalone.\n */\n customDomain?: string;\n /**\n * Required when `customDomain` is set on a stack lease (i.e., `services`\n * is provided). Must match one of the keys in `services`. Omit for an\n * image+port single-item legacy lease.\n */\n serviceName?: string;\n /** Fires once after the create-lease TX confirms, before upload/poll. Awaited. Errors propagate. */\n onLeaseCreated?: (\n leaseUuid: string,\n providerUrl: string,\n ) => void | Promise<void>;\n /** Aborts upload and poll (not the already-submitted chain TX). */\n abortSignal?: AbortSignal;\n /** Forwarded to the internal pollLeaseUntilReady call. abortSignal is the top-level field above. */\n pollOptions?: Omit<PollOptions, 'abortSignal'>;\n}\n\nexport interface DeployAppResult {\n readonly lease_uuid: string;\n readonly provider_uuid: string;\n readonly provider_url: string;\n readonly state: LeaseState;\n readonly url?: string;\n readonly connection?: ConnectionDetails;\n readonly connectionError?: string;\n /** Set when a `customDomain` was supplied AND the set-domain tx succeeded. */\n readonly custom_domain?: string;\n /** Set when a `serviceName` was supplied alongside a successful `customDomain` set. */\n readonly service_name?: string;\n}\n\nexport async function deployApp(\n clientManager: CosmosClientManager,\n getAuthToken: (address: string, leaseUuid: string) => Promise<string>,\n getLeaseDataAuthToken: (\n address: string,\n leaseUuid: string,\n metaHashHex: string,\n ) => Promise<string>,\n input: DeployAppInput,\n fetchFn?: typeof globalThis.fetch,\n): Promise<DeployAppResult> {\n // Validate mutually exclusive inputs\n if (input.image && input.services) {\n throw new ManifestMCPError(\n ManifestMCPErrorCode.INVALID_CONFIG,\n 'image and services are mutually exclusive',\n );\n }\n if (!input.image && !input.services) {\n throw new ManifestMCPError(\n ManifestMCPErrorCode.INVALID_CONFIG,\n 'either image or services is required',\n );\n }\n if (input.image && !input.port) {\n throw new ManifestMCPError(\n ManifestMCPErrorCode.INVALID_CONFIG,\n 'port is required when using image',\n );\n }\n\n // Validate custom-domain inputs eagerly, before any chain tx, so a\n // misconfigured deploy doesn't leave a paid-for lease behind.\n // The chain still validates FQDN format and reserved-suffix rules\n // (`IsValidFQDN`, `MatchesReservedSuffix`) when the set-domain tx\n // arrives — we just catch the obvious shape mistakes up-front.\n //\n // The trimmed value is the canonical form used downstream (set-domain\n // tx + result echo). Forwarding the untrimmed string would let\n // surrounding whitespace survive to the chain, which `IsValidFQDN`\n // rejects — orphaning a paid-for lease behind a \"Deploy partially\n // succeeded\" wrap, exactly the failure mode this block is meant to\n // prevent.\n // `serviceName` is documented as only meaningful when `customDomain` is set.\n // Reject it eagerly when the caller forgot the domain, otherwise the input\n // is silently ignored — confusing for the caller and a foot-gun (a typo\n // turning `customDomain` into `customdomain` would skip the domain claim\n // and quietly drop the service routing intent on the floor).\n if (input.customDomain === undefined && input.serviceName !== undefined) {\n throw new ManifestMCPError(\n ManifestMCPErrorCode.INVALID_CONFIG,\n 'serviceName is only meaningful when customDomain is set; pass customDomain or omit serviceName',\n );\n }\n\n let normalizedCustomDomain: string | undefined;\n if (input.customDomain !== undefined) {\n normalizedCustomDomain = input.customDomain.trim();\n if (normalizedCustomDomain === '') {\n throw new ManifestMCPError(\n ManifestMCPErrorCode.INVALID_CONFIG,\n 'customDomain cannot be empty or whitespace-only',\n );\n }\n if (input.services) {\n if (!input.serviceName) {\n throw new ManifestMCPError(\n ManifestMCPErrorCode.INVALID_CONFIG,\n 'serviceName is required when setting customDomain on a stack lease (services); pick one of the service keys',\n );\n }\n // Use Object.keys+includes rather than `in`: `'constructor' in {}`\n // is true (prototype chain), so an attacker passing\n // `service_name: 'constructor'` (or any Object.prototype key) on\n // a stack lease that doesn't define a same-named service would\n // pass this check, sail through create-lease, and only fail at\n // the set-domain tx — leaving the paid-for lease behind. Avoids\n // ES2022's `Object.hasOwn` (base tsconfig targets ES2020) and\n // biome's `noPrototypeBuiltins` rule on `hasOwnProperty.call`.\n if (!Object.keys(input.services).includes(input.serviceName)) {\n const available = Object.keys(input.services).join(', ');\n throw new ManifestMCPError(\n ManifestMCPErrorCode.INVALID_CONFIG,\n `serviceName \"${input.serviceName}\" does not match any service in the deployment. Available: ${available}`,\n );\n }\n } else if (input.serviceName) {\n // image+port mode — the underlying lease has a single legacy item\n // with service_name=\"\". Passing a service_name here would address\n // a non-existent item on the chain.\n throw new ManifestMCPError(\n ManifestMCPErrorCode.INVALID_CONFIG,\n 'serviceName must not be set on an image+port (legacy 1-item) lease — omit it or switch to services mode',\n );\n }\n }\n\n const address = await clientManager.getAddress();\n await clientManager.acquireRateLimit();\n const queryClient = await clientManager.getQueryClient();\n\n // 1. Build manifest\n let manifestJson: string;\n if (input.services) {\n for (const name of Object.keys(input.services)) {\n if (!validateServiceName(name)) {\n throw new ManifestMCPError(\n ManifestMCPErrorCode.INVALID_CONFIG,\n `Invalid service name: \"${name}\". Must be 1-63 chars, lowercase alphanumeric + hyphens, no leading/trailing hyphens.`,\n );\n }\n }\n\n const services: Record<string, BuildManifestOptions> = {};\n for (const [name, svc] of Object.entries(input.services)) {\n services[name] = {\n image: svc.image,\n ports: svc.ports ?? {},\n env: svc.env,\n command: svc.command,\n args: svc.args,\n user: svc.user,\n tmpfs: svc.tmpfs,\n health_check: svc.health_check,\n stop_grace_period: svc.stop_grace_period,\n depends_on: svc.depends_on,\n expose: svc.expose,\n labels: svc.labels,\n };\n }\n manifestJson = JSON.stringify(buildStackManifest({ services }));\n } else {\n // image is guaranteed defined here: the guard above ensures !image && !services is false,\n // and the if-branch handles the services case. TypeScript can't narrow across if/else.\n const image = input.image as string;\n manifestJson = JSON.stringify(\n buildManifest({\n image,\n ports: { [`${input.port}/tcp`]: {} },\n env: input.env,\n command: input.command,\n args: input.args,\n user: input.user,\n tmpfs: input.tmpfs,\n health_check: input.health_check,\n stop_grace_period: input.stop_grace_period,\n init: input.init,\n expose: input.expose,\n labels: input.labels,\n depends_on: input.depends_on,\n }),\n );\n }\n\n // 2. SHA-256 hash of manifest (must match `meta_hash` recorded on-chain).\n const manifestMetaHash = await metaHashHex(manifestJson);\n\n // 3. Find matching SKU(s)\n const { skuUuid, providerUuid } = await findSkuUuid(queryClient, input.size);\n\n let leaseItems: string[];\n if (input.services) {\n const serviceNames = Object.keys(input.services);\n leaseItems = serviceNames.map((name) => `${skuUuid}:1:${name}`);\n } else {\n leaseItems = [`${skuUuid}:1`];\n }\n\n if (input.storage) {\n const { skuUuid: storageSkuUuid } = await findSkuUuid(\n queryClient,\n input.storage,\n );\n leaseItems.push(`${storageSkuUuid}:1`);\n }\n\n // 4. Get provider URL\n const providerUrl = await resolveProviderUrl(queryClient, providerUuid);\n\n // 5. Create lease\n const overrides =\n input.gasMultiplier !== undefined\n ? { gasMultiplier: input.gasMultiplier }\n : undefined;\n const txResult = await cosmosTx(\n clientManager,\n 'billing',\n 'create-lease',\n ['--meta-hash', manifestMetaHash, ...leaseItems],\n true,\n overrides,\n );\n\n // 6. Extract lease UUID\n const leaseUuid = extractLeaseUuid(txResult);\n\n // Outside the partial-success try: callback errors surface raw, not wrapped.\n // The lease exists on-chain regardless of abortSignal state — always notify.\n await input.onLeaseCreated?.(leaseUuid, providerUrl);\n\n let status: FredLeaseStatus;\n try {\n input.abortSignal?.throwIfAborted();\n\n // 7. Optionally attach custom_domain to the freshly-created lease.\n // Submitted before the manifest upload so providerd has the domain\n // available when it provisions. Failures here flow through the\n // same partial-success error wrap below as upload/poll failures.\n // The chain accepts MsgSetItemCustomDomain in PENDING or ACTIVE\n // state; if providerd races and rejects the lease before this\n // tx lands, the chain auto-clears the index entry so no stuck\n // state is left behind.\n if (normalizedCustomDomain !== undefined) {\n await setItemCustomDomain(\n clientManager,\n leaseUuid,\n normalizedCustomDomain,\n { serviceName: input.serviceName },\n overrides,\n );\n }\n\n // 8. Upload manifest with lease-data auth token\n const leaseDataToken = await getLeaseDataAuthToken(\n address,\n leaseUuid,\n manifestMetaHash,\n );\n await uploadLeaseData(\n providerUrl,\n leaseUuid,\n new TextEncoder().encode(manifestJson),\n leaseDataToken,\n fetchFn,\n input.abortSignal,\n );\n\n // 9. Poll until ready\n status = await pollLeaseUntilReady(\n providerUrl,\n leaseUuid,\n () => getAuthToken(address, leaseUuid),\n { ...input.pollOptions, abortSignal: input.abortSignal },\n fetchFn,\n );\n } catch (err) {\n // Chain-terminal states are self-explanatory and need no \"close this lease\"\n // advice (the lease is already terminal on-chain). Let Barney & friends\n // observe the typed error directly via `instanceof` / `err.chainState`.\n // withContext preserves the original stack (debugging points at the poll,\n // not at this catch) while attaching deployApp's provider context so\n // callers don't need to re-query the chain to recover it.\n if (err instanceof TerminalChainStateError) {\n throw err.withContext({ providerUuid, providerUrl });\n }\n const code =\n err instanceof ManifestMCPError\n ? err.code\n : ManifestMCPErrorCode.QUERY_FAILED;\n const details =\n err instanceof ManifestMCPError\n ? {\n ...err.details,\n lease_uuid: leaseUuid,\n provider_uuid: providerUuid,\n provider_url: providerUrl,\n }\n : {\n lease_uuid: leaseUuid,\n provider_uuid: providerUuid,\n provider_url: providerUrl,\n };\n throw new ManifestMCPError(\n code,\n `Deploy partially succeeded: lease ${leaseUuid} was created but subsequent steps failed. ` +\n `Close this lease with close_lease if needed. Error: ${err instanceof Error ? err.message : String(err)}`,\n details,\n );\n }\n\n // 10. Get connection info (best-effort)\n let connection: ConnectionDetails | undefined;\n let url: string | undefined;\n let connectionError: string | undefined;\n try {\n const authToken = await getAuthToken(address, leaseUuid);\n const connResp = await getLeaseConnectionInfo(\n providerUrl,\n leaseUuid,\n authToken,\n fetchFn,\n );\n connection = connResp.connection;\n if (connection.host && connection.ports) {\n const firstPort = Object.values(connection.ports)[0];\n if (typeof firstPort === 'number' || typeof firstPort === 'string') {\n url = `${connection.host}:${firstPort}`;\n }\n }\n } catch (err) {\n const rawMsg = err instanceof Error ? err.message : String(err);\n // Log raw message to stderr for debugging; sanitize only the user-facing return value\n logger.error(\n `[deploy_app] Failed to fetch connection info for lease ${leaseUuid}: ${rawMsg}`,\n );\n connectionError = sanitizeForLogging(rawMsg) as string;\n }\n\n return {\n lease_uuid: leaseUuid,\n provider_uuid: providerUuid,\n provider_url: providerUrl,\n state: status.state,\n ...(url && { url }),\n ...(connection && { connection }),\n ...(connectionError && { connectionError }),\n // Reaching this return implies the set-domain tx (if requested)\n // succeeded — failures earlier in the try block throw and never\n // get here. Echo the trimmed canonical form, matching what the\n // chain stored.\n ...(normalizedCustomDomain && { custom_domain: normalizedCustomDomain }),\n ...(normalizedCustomDomain &&\n input.serviceName && { service_name: input.serviceName }),\n };\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@manifest-network/manifest-mcp-fred",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
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,12 +46,12 @@
|
|
|
46
46
|
],
|
|
47
47
|
"dependencies": {
|
|
48
48
|
"@cosmjs/encoding": "0.32.4",
|
|
49
|
-
"@manifest-network/manifest-mcp-core": "^0.
|
|
49
|
+
"@manifest-network/manifest-mcp-core": "^0.8.0",
|
|
50
50
|
"@modelcontextprotocol/sdk": "1.27.1",
|
|
51
51
|
"zod": "^4.3.6"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
|
-
"@manifest-network/manifestjs": "2.
|
|
54
|
+
"@manifest-network/manifestjs": "2.4.1",
|
|
55
55
|
"@types/node": "22.15.29",
|
|
56
56
|
"typescript": "5.9.3",
|
|
57
57
|
"vitest": "4.1.0"
|