@manifest-network/manifest-mcp-fred 0.3.5 → 0.4.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;;;;;;;;;;;;cAyGa,aAAA;EAAA,QACH,SAAA;EAAA,QACA,aAAA;EAAA,QACA,cAAA;cAEI,OAAA,EAAS,0BAAA;EAAA,QAuBb,oBAAA;EAAA,QAUA,cAAA;EAAA,QAEM,oBAAA;EAAA,QAiBA,qBAAA;EAAA,QAuBN,aAAA;EAoZR,SAAA,CAAA,GAAa,MAAA;EAIb,gBAAA,CAAA,GAAoB,mBAAA;EAIpB,UAAA,CAAA;AAAA;AAAA,iBAKc,wBAAA,CACd,MAAA,EAAQ,oBAAA,GACP,OAAA,CAAQ,aAAA"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;;;;;;;;;;;;cAyGa,aAAA;EAAA,QACH,SAAA;EAAA,QACA,aAAA;EAAA,QACA,cAAA;cAEI,OAAA,EAAS,0BAAA;EAAA,QAuBb,oBAAA;EAAA,QAUA,cAAA;EAAA,QAEM,oBAAA;EAAA,QAiBA,qBAAA;EAAA,QAuBN,aAAA;EA6ZR,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
@@ -112,7 +112,8 @@ var FredMCPServer = class {
112
112
  depends_on: z.record(z.string(), z.object({ condition: z.string() })).optional(),
113
113
  expose: z.array(z.string()).optional(),
114
114
  labels: z.record(z.string(), z.string()).optional()
115
- })).optional().describe("Multi-service stack. Mutually exclusive with image/port. Keys are service names (RFC 1123 DNS labels).")
115
+ })).optional().describe("Multi-service stack. Mutually exclusive with image/port. Keys are service names (RFC 1123 DNS labels)."),
116
+ 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.")
116
117
  }
117
118
  }, withErrorHandling("deploy_app", async (args) => {
118
119
  return jsonResponse(await deployApp(this.clientManager, (addr, uuid) => this.getProviderAuthToken(addr, uuid), (addr, uuid, metaHashHex) => this.getLeaseDataAuthToken(addr, uuid, metaHashHex), {
@@ -131,7 +132,8 @@ var FredMCPServer = class {
131
132
  labels: args.labels,
132
133
  storage: args.storage,
133
134
  depends_on: args.depends_on,
134
- services: args.services
135
+ services: args.services,
136
+ gasMultiplier: args.gas_multiplier
135
137
  }), bigIntReplacer);
136
138
  }));
137
139
  this.mcpServer.registerTool("restart_app", {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["ManifestMCPError","ManifestMCPErrorCode"],"sources":["../src/index.ts"],"sourcesContent":["import type { WalletProvider } from '@manifest-network/manifest-mcp-core';\nimport {\n bigIntReplacer,\n CosmosClientManager,\n createMnemonicServer,\n createValidatedConfig,\n jsonResponse,\n ManifestMCPError,\n ManifestMCPErrorCode,\n type ManifestMCPServerOptions,\n type MnemonicServerConfig,\n VERSION,\n withErrorHandling,\n} from '@manifest-network/manifest-mcp-core';\nimport type { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { z } from 'zod';\nimport {\n AuthTimestampTracker,\n createAuthToken,\n createLeaseDataSignMessage,\n createSignMessage,\n} from './http/auth.js';\nimport { getLeaseProvision, getLeaseReleases, MAX_TAIL } from './http/fred.js';\nimport { appStatus } from './tools/appStatus.js';\nimport { browseCatalog } from './tools/browseCatalog.js';\nimport { deployApp } from './tools/deployApp.js';\nimport { fetchActiveLease } from './tools/fetchActiveLease.js';\nimport { getAppLogs } from './tools/getLogs.js';\nimport { resolveProviderUrl } from './tools/resolveLeaseProvider.js';\nimport { restartApp } from './tools/restartApp.js';\nimport { updateApp } from './tools/updateApp.js';\n\nexport type { ManifestMCPServerOptions } from '@manifest-network/manifest-mcp-core';\nexport {\n INFRASTRUCTURE_ERROR_CODES,\n ManifestMCPError,\n ManifestMCPErrorCode,\n} from '@manifest-network/manifest-mcp-core';\nexport {\n type AuthTokenPayload,\n createAuthToken,\n createLeaseDataSignMessage,\n createSignMessage,\n} from './http/auth.js';\nexport {\n type FredActionResponse,\n type FredInstanceInfo,\n type FredLeaseInfo,\n type FredLeaseLogs,\n type FredLeaseProvision,\n type FredLeaseRelease,\n type FredLeaseReleases,\n type FredLeaseStatus,\n type FredServiceStatus,\n getLeaseInfo,\n getLeaseLogs,\n getLeaseProvision,\n getLeaseReleases,\n getLeaseStatus,\n MAX_TAIL,\n type PollOptions,\n pollLeaseUntilReady,\n restartLease,\n updateLease,\n} from './http/fred.js';\nexport {\n type ConnectionDetails,\n checkedFetch,\n getLeaseConnectionInfo,\n getProviderHealth,\n type InstanceInfo,\n type LeaseConnectionResponse,\n ProviderApiError,\n type ProviderHealthResponse,\n type ServiceConnectionDetails,\n uploadLeaseData,\n validateProviderUrl,\n} from './http/provider.js';\nexport {\n type BuildManifestOptions,\n buildManifest,\n buildStackManifest,\n deriveAppNameFromImage,\n getServiceNames,\n isStackManifest,\n mergeManifest,\n normalizePorts,\n parseStackManifest,\n validateServiceName,\n} from './manifest.js';\nexport { appStatus } from './tools/appStatus.js';\nexport { browseCatalog, mapWithConcurrency } from './tools/browseCatalog.js';\nexport {\n type DeployAppInput,\n type DeployAppResult,\n deployApp,\n type ServiceConfig,\n} from './tools/deployApp.js';\nexport { fetchActiveLease } from './tools/fetchActiveLease.js';\nexport { getAppLogs } from './tools/getLogs.js';\nexport { resolveProviderUrl } from './tools/resolveLeaseProvider.js';\nexport { restartApp } from './tools/restartApp.js';\nexport { updateApp } from './tools/updateApp.js';\n\nexport class FredMCPServer {\n private mcpServer: McpServer;\n private clientManager: CosmosClientManager;\n private walletProvider: WalletProvider;\n\n constructor(options: ManifestMCPServerOptions) {\n const config = createValidatedConfig(options.config);\n this.walletProvider = options.walletProvider;\n this.clientManager = CosmosClientManager.getInstance(\n config,\n this.walletProvider,\n );\n\n this.mcpServer = new McpServer(\n {\n name: '@manifest-network/manifest-mcp-fred',\n version: VERSION,\n },\n {\n capabilities: {\n tools: {},\n },\n },\n );\n\n this.registerTools();\n }\n\n private requireSignArbitrary(): NonNullable<WalletProvider['signArbitrary']> {\n if (!this.walletProvider.signArbitrary) {\n throw new ManifestMCPError(\n ManifestMCPErrorCode.INVALID_CONFIG,\n 'Wallet does not support signArbitrary (ADR-036). Required for provider authentication. Use a wallet provider that implements signArbitrary.',\n );\n }\n return this.walletProvider.signArbitrary.bind(this.walletProvider);\n }\n\n private authTimestamps = new AuthTimestampTracker();\n\n private async getProviderAuthToken(\n address: string,\n leaseUuid: string,\n ): Promise<string> {\n const signArbitrary = this.requireSignArbitrary();\n const timestamp = await this.authTimestamps.next();\n const message = createSignMessage(address, leaseUuid, timestamp);\n const { pub_key, signature } = await signArbitrary(address, message);\n return createAuthToken(\n address,\n leaseUuid,\n timestamp,\n pub_key.value,\n signature,\n );\n }\n\n private async getLeaseDataAuthToken(\n address: string,\n leaseUuid: string,\n metaHashHex: string,\n ): Promise<string> {\n const signArbitrary = this.requireSignArbitrary();\n const timestamp = await this.authTimestamps.next();\n const message = createLeaseDataSignMessage(\n leaseUuid,\n metaHashHex,\n timestamp,\n );\n const { pub_key, signature } = await signArbitrary(address, message);\n return createAuthToken(\n address,\n leaseUuid,\n timestamp,\n pub_key.value,\n signature,\n metaHashHex,\n );\n }\n\n private registerTools(): void {\n // -- browse_catalog --\n this.mcpServer.registerTool(\n 'browse_catalog',\n {\n description:\n 'Browse available cloud providers and service tiers with live health checks. Use this before deploy_app to see which providers are online and what SKU sizes (e.g. docker-micro, docker-small) are available with pricing.',\n },\n withErrorHandling('browse_catalog', async () => {\n await this.clientManager.acquireRateLimit();\n const queryClient = await this.clientManager.getQueryClient();\n const result = await browseCatalog(queryClient);\n return jsonResponse(result, bigIntReplacer);\n }),\n );\n\n // -- app_status --\n this.mcpServer.registerTool(\n 'app_status',\n {\n description:\n 'Get detailed status and connection info for a deployed app. Use this after deploy_app to check if an app is running and get its URL.',\n inputSchema: {\n lease_uuid: z\n .string()\n .uuid()\n .describe('The lease UUID of the app to check'),\n },\n },\n withErrorHandling('app_status', async (args) => {\n const leaseUuid = args.lease_uuid;\n const address = await this.walletProvider.getAddress();\n await this.clientManager.acquireRateLimit();\n const queryClient = await this.clientManager.getQueryClient();\n const result = await appStatus(\n queryClient,\n address,\n leaseUuid,\n (addr, uuid) => this.getProviderAuthToken(addr, uuid),\n );\n return jsonResponse(result, bigIntReplacer);\n }),\n );\n\n // -- get_logs --\n this.mcpServer.registerTool(\n 'get_logs',\n {\n description:\n 'Get recent container logs for a deployed app. Use this to debug apps that are failing or to verify an app started correctly after deploy_app.',\n inputSchema: {\n lease_uuid: z\n .string()\n .uuid()\n .describe('The lease UUID of the app to get logs for'),\n tail: z\n .number()\n .int()\n .min(1)\n .max(MAX_TAIL)\n .optional()\n .describe('Number of recent log lines to retrieve'),\n },\n },\n withErrorHandling('get_logs', async (args) => {\n const leaseUuid = args.lease_uuid;\n const tail = args.tail;\n const address = await this.walletProvider.getAddress();\n await this.clientManager.acquireRateLimit();\n const queryClient = await this.clientManager.getQueryClient();\n const result = await getAppLogs(\n queryClient,\n address,\n leaseUuid,\n (addr, uuid) => this.getProviderAuthToken(addr, uuid),\n tail,\n );\n return jsonResponse(result, bigIntReplacer);\n }),\n );\n\n // -- deploy_app --\n this.mcpServer.registerTool(\n 'deploy_app',\n {\n description:\n 'Deploy a new containerized application. Requires funded credits (use fund_credit if needed). Creates a lease on-chain, uploads the container manifest to a provider, and polls until ready. Use browse_catalog first to see available SKU sizes.',\n inputSchema: {\n image: z\n .string()\n .optional()\n .describe(\n 'Docker image to deploy. Required unless services is provided.',\n ),\n port: z\n .number()\n .int()\n .min(1)\n .max(65535)\n .optional()\n .describe(\n 'Container port to expose. Required unless services is provided.',\n ),\n size: z\n .string()\n .describe('SKU tier name (e.g. \"docker-micro\", \"docker-small\")'),\n env: z\n .record(z.string(), z.string())\n .optional()\n .describe('Environment variables as key-value pairs'),\n command: z\n .array(z.string())\n .optional()\n .describe('Override container command (entrypoint)'),\n args: z\n .array(z.string())\n .optional()\n .describe('Arguments to the container command'),\n user: z\n .string()\n .optional()\n .describe('User to run the container as (e.g. \"1000:1000\")'),\n tmpfs: z\n .array(z.string())\n .optional()\n .describe('tmpfs mounts (e.g. [\"/tmp:size=64M\"])'),\n health_check: z\n .object({\n test: z.array(z.string()),\n interval: z.string().optional(),\n timeout: z.string().optional(),\n retries: z.number().int().optional(),\n start_period: z.string().optional(),\n })\n .optional()\n .describe('Container health check configuration'),\n stop_grace_period: z\n .string()\n .optional()\n .describe('Grace period before force-killing (e.g. \"30s\")'),\n init: z\n .boolean()\n .optional()\n .describe('Run an init process inside the container'),\n expose: z\n .array(z.string())\n .optional()\n .describe('Expose ports without publishing (e.g. [\"8080/tcp\"])'),\n labels: z\n .record(z.string(), z.string())\n .optional()\n .describe('Container labels as key-value pairs'),\n storage: z\n .string()\n .optional()\n .describe(\n 'Storage SKU name for persistent disk (adds a second lease item)',\n ),\n depends_on: z\n .record(z.string(), z.object({ condition: z.string() }))\n .optional()\n .describe('Service dependencies'),\n services: z\n .record(\n z.string(),\n z.object({\n image: z.string(),\n ports: z.record(z.string(), z.object({})).optional(),\n env: z.record(z.string(), z.string()).optional(),\n command: z.array(z.string()).optional(),\n args: z.array(z.string()).optional(),\n user: z.string().optional(),\n tmpfs: z.array(z.string()).optional(),\n health_check: z\n .object({\n test: z.array(z.string()),\n interval: z.string().optional(),\n timeout: z.string().optional(),\n retries: z.number().int().optional(),\n start_period: z.string().optional(),\n })\n .optional(),\n stop_grace_period: z.string().optional(),\n depends_on: z\n .record(z.string(), z.object({ condition: z.string() }))\n .optional(),\n expose: z.array(z.string()).optional(),\n labels: z.record(z.string(), z.string()).optional(),\n }),\n )\n .optional()\n .describe(\n 'Multi-service stack. Mutually exclusive with image/port. Keys are service names (RFC 1123 DNS labels).',\n ),\n },\n },\n withErrorHandling('deploy_app', async (args) => {\n const result = await deployApp(\n this.clientManager,\n (addr, uuid) => this.getProviderAuthToken(addr, uuid),\n (addr, uuid, metaHashHex) =>\n this.getLeaseDataAuthToken(addr, uuid, metaHashHex),\n {\n image: args.image,\n port: args.port,\n size: args.size,\n env: args.env,\n command: args.command,\n args: args.args,\n user: args.user,\n tmpfs: args.tmpfs,\n health_check: args.health_check,\n stop_grace_period: args.stop_grace_period,\n init: args.init,\n expose: args.expose,\n labels: args.labels,\n storage: args.storage,\n depends_on: args.depends_on,\n services: args.services,\n },\n );\n return jsonResponse(result, bigIntReplacer);\n }),\n );\n\n // -- restart_app --\n this.mcpServer.registerTool(\n 'restart_app',\n {\n description:\n 'Restart a running app via the provider without closing its lease. Use this to apply configuration changes or recover from a crash.',\n inputSchema: {\n lease_uuid: z\n .string()\n .uuid()\n .describe('The lease UUID of the app to restart'),\n },\n },\n withErrorHandling('restart_app', async (args) => {\n const leaseUuid = args.lease_uuid;\n const address = await this.walletProvider.getAddress();\n await this.clientManager.acquireRateLimit();\n const queryClient = await this.clientManager.getQueryClient();\n const result = await restartApp(\n queryClient,\n address,\n leaseUuid,\n (addr, uuid) => this.getProviderAuthToken(addr, uuid),\n );\n return jsonResponse(result, bigIntReplacer);\n }),\n );\n\n // -- update_app --\n this.mcpServer.registerTool(\n 'update_app',\n {\n description:\n 'Update a deployed app with a new container manifest. Use this to change the Docker image, ports, or environment variables of a running app without closing the lease.',\n inputSchema: {\n lease_uuid: z\n .string()\n .uuid()\n .describe('The lease UUID of the app to update'),\n manifest: z\n .string()\n .describe('The full manifest JSON string to deploy'),\n existing_manifest: z\n .string()\n .optional()\n .describe(\n 'The current manifest JSON. When provided, the new manifest is merged over the existing one (env, ports, labels merged; other fields carried forward if not in new).',\n ),\n },\n },\n withErrorHandling('update_app', async (args) => {\n const manifest = args.manifest;\n\n try {\n const parsed = JSON.parse(manifest);\n if (\n parsed === null ||\n typeof parsed !== 'object' ||\n Array.isArray(parsed)\n ) {\n throw new Error('must be a JSON object');\n }\n } catch (err) {\n throw new ManifestMCPError(\n ManifestMCPErrorCode.INVALID_CONFIG,\n `Invalid manifest: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n\n const leaseUuid = args.lease_uuid;\n const address = await this.walletProvider.getAddress();\n await this.clientManager.acquireRateLimit();\n const queryClient = await this.clientManager.getQueryClient();\n\n const result = await updateApp(\n queryClient,\n address,\n leaseUuid,\n (addr, uuid) => this.getProviderAuthToken(addr, uuid),\n manifest,\n args.existing_manifest,\n );\n return jsonResponse(result, bigIntReplacer);\n }),\n );\n\n // -- app_diagnostics --\n this.mcpServer.registerTool(\n 'app_diagnostics',\n {\n description:\n 'Get provision diagnostics for a deployed app. Use this to debug apps stuck in provisioning or that failed to start. Returns provision status, failure count, and last error message.',\n inputSchema: {\n lease_uuid: z\n .string()\n .uuid()\n .describe('The lease UUID of the app to diagnose'),\n },\n },\n withErrorHandling('app_diagnostics', async (args) => {\n const leaseUuid = args.lease_uuid;\n const address = await this.walletProvider.getAddress();\n await this.clientManager.acquireRateLimit();\n const queryClient = await this.clientManager.getQueryClient();\n\n const lease = await fetchActiveLease(\n queryClient,\n leaseUuid,\n 'cannot be diagnosed',\n );\n const providerUrl = await resolveProviderUrl(\n queryClient,\n lease.providerUuid,\n );\n const authToken = await this.getProviderAuthToken(address, leaseUuid);\n const provision = await getLeaseProvision(\n providerUrl,\n leaseUuid,\n authToken,\n );\n\n return jsonResponse(\n {\n lease_uuid: leaseUuid,\n provision_status: provision.status,\n fail_count: provision.fail_count,\n last_error: provision.last_error,\n },\n bigIntReplacer,\n );\n }),\n );\n\n // -- app_releases --\n this.mcpServer.registerTool(\n 'app_releases',\n {\n description:\n 'Get release/version history for a deployed app. Use this to see what versions have been deployed, when they were created, and their status.',\n inputSchema: {\n lease_uuid: z\n .string()\n .uuid()\n .describe('The lease UUID of the app to get release history for'),\n },\n },\n withErrorHandling('app_releases', async (args) => {\n const leaseUuid = args.lease_uuid;\n const address = await this.walletProvider.getAddress();\n await this.clientManager.acquireRateLimit();\n const queryClient = await this.clientManager.getQueryClient();\n\n const lease = await fetchActiveLease(\n queryClient,\n leaseUuid,\n 'releases are not available',\n );\n const providerUrl = await resolveProviderUrl(\n queryClient,\n lease.providerUuid,\n );\n const authToken = await this.getProviderAuthToken(address, leaseUuid);\n const result = await getLeaseReleases(\n providerUrl,\n leaseUuid,\n authToken,\n );\n\n return jsonResponse(\n {\n lease_uuid: leaseUuid,\n releases: result.releases,\n },\n bigIntReplacer,\n );\n }),\n );\n }\n\n getServer(): Server {\n return this.mcpServer.server;\n }\n\n getClientManager(): CosmosClientManager {\n return this.clientManager;\n }\n\n disconnect(): void {\n this.clientManager.disconnect();\n }\n}\n\nexport function createMnemonicFredServer(\n config: MnemonicServerConfig,\n): Promise<FredMCPServer> {\n return createMnemonicServer(config, FredMCPServer);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["ManifestMCPError","ManifestMCPErrorCode"],"sources":["../src/index.ts"],"sourcesContent":["import type { WalletProvider } from '@manifest-network/manifest-mcp-core';\nimport {\n bigIntReplacer,\n CosmosClientManager,\n createMnemonicServer,\n createValidatedConfig,\n jsonResponse,\n ManifestMCPError,\n ManifestMCPErrorCode,\n type ManifestMCPServerOptions,\n type MnemonicServerConfig,\n VERSION,\n withErrorHandling,\n} from '@manifest-network/manifest-mcp-core';\nimport type { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { z } from 'zod';\nimport {\n AuthTimestampTracker,\n createAuthToken,\n createLeaseDataSignMessage,\n createSignMessage,\n} from './http/auth.js';\nimport { getLeaseProvision, getLeaseReleases, MAX_TAIL } from './http/fred.js';\nimport { appStatus } from './tools/appStatus.js';\nimport { browseCatalog } from './tools/browseCatalog.js';\nimport { deployApp } from './tools/deployApp.js';\nimport { fetchActiveLease } from './tools/fetchActiveLease.js';\nimport { getAppLogs } from './tools/getLogs.js';\nimport { resolveProviderUrl } from './tools/resolveLeaseProvider.js';\nimport { restartApp } from './tools/restartApp.js';\nimport { updateApp } from './tools/updateApp.js';\n\nexport type { ManifestMCPServerOptions } from '@manifest-network/manifest-mcp-core';\nexport {\n INFRASTRUCTURE_ERROR_CODES,\n ManifestMCPError,\n ManifestMCPErrorCode,\n} from '@manifest-network/manifest-mcp-core';\nexport {\n type AuthTokenPayload,\n createAuthToken,\n createLeaseDataSignMessage,\n createSignMessage,\n} from './http/auth.js';\nexport {\n type FredActionResponse,\n type FredInstanceInfo,\n type FredLeaseInfo,\n type FredLeaseLogs,\n type FredLeaseProvision,\n type FredLeaseRelease,\n type FredLeaseReleases,\n type FredLeaseStatus,\n type FredServiceStatus,\n getLeaseInfo,\n getLeaseLogs,\n getLeaseProvision,\n getLeaseReleases,\n getLeaseStatus,\n MAX_TAIL,\n type PollOptions,\n pollLeaseUntilReady,\n restartLease,\n updateLease,\n} from './http/fred.js';\nexport {\n type ConnectionDetails,\n checkedFetch,\n getLeaseConnectionInfo,\n getProviderHealth,\n type InstanceInfo,\n type LeaseConnectionResponse,\n ProviderApiError,\n type ProviderHealthResponse,\n type ServiceConnectionDetails,\n uploadLeaseData,\n validateProviderUrl,\n} from './http/provider.js';\nexport {\n type BuildManifestOptions,\n buildManifest,\n buildStackManifest,\n deriveAppNameFromImage,\n getServiceNames,\n isStackManifest,\n mergeManifest,\n normalizePorts,\n parseStackManifest,\n validateServiceName,\n} from './manifest.js';\nexport { appStatus } from './tools/appStatus.js';\nexport { browseCatalog, mapWithConcurrency } from './tools/browseCatalog.js';\nexport {\n type DeployAppInput,\n type DeployAppResult,\n deployApp,\n type ServiceConfig,\n} from './tools/deployApp.js';\nexport { fetchActiveLease } from './tools/fetchActiveLease.js';\nexport { getAppLogs } from './tools/getLogs.js';\nexport { resolveProviderUrl } from './tools/resolveLeaseProvider.js';\nexport { restartApp } from './tools/restartApp.js';\nexport { updateApp } from './tools/updateApp.js';\n\nexport class FredMCPServer {\n private mcpServer: McpServer;\n private clientManager: CosmosClientManager;\n private walletProvider: WalletProvider;\n\n constructor(options: ManifestMCPServerOptions) {\n const config = createValidatedConfig(options.config);\n this.walletProvider = options.walletProvider;\n this.clientManager = CosmosClientManager.getInstance(\n config,\n this.walletProvider,\n );\n\n this.mcpServer = new McpServer(\n {\n name: '@manifest-network/manifest-mcp-fred',\n version: VERSION,\n },\n {\n capabilities: {\n tools: {},\n },\n },\n );\n\n this.registerTools();\n }\n\n private requireSignArbitrary(): NonNullable<WalletProvider['signArbitrary']> {\n if (!this.walletProvider.signArbitrary) {\n throw new ManifestMCPError(\n ManifestMCPErrorCode.INVALID_CONFIG,\n 'Wallet does not support signArbitrary (ADR-036). Required for provider authentication. Use a wallet provider that implements signArbitrary.',\n );\n }\n return this.walletProvider.signArbitrary.bind(this.walletProvider);\n }\n\n private authTimestamps = new AuthTimestampTracker();\n\n private async getProviderAuthToken(\n address: string,\n leaseUuid: string,\n ): Promise<string> {\n const signArbitrary = this.requireSignArbitrary();\n const timestamp = await this.authTimestamps.next();\n const message = createSignMessage(address, leaseUuid, timestamp);\n const { pub_key, signature } = await signArbitrary(address, message);\n return createAuthToken(\n address,\n leaseUuid,\n timestamp,\n pub_key.value,\n signature,\n );\n }\n\n private async getLeaseDataAuthToken(\n address: string,\n leaseUuid: string,\n metaHashHex: string,\n ): Promise<string> {\n const signArbitrary = this.requireSignArbitrary();\n const timestamp = await this.authTimestamps.next();\n const message = createLeaseDataSignMessage(\n leaseUuid,\n metaHashHex,\n timestamp,\n );\n const { pub_key, signature } = await signArbitrary(address, message);\n return createAuthToken(\n address,\n leaseUuid,\n timestamp,\n pub_key.value,\n signature,\n metaHashHex,\n );\n }\n\n private registerTools(): void {\n // -- browse_catalog --\n this.mcpServer.registerTool(\n 'browse_catalog',\n {\n description:\n 'Browse available cloud providers and service tiers with live health checks. Use this before deploy_app to see which providers are online and what SKU sizes (e.g. docker-micro, docker-small) are available with pricing.',\n },\n withErrorHandling('browse_catalog', async () => {\n await this.clientManager.acquireRateLimit();\n const queryClient = await this.clientManager.getQueryClient();\n const result = await browseCatalog(queryClient);\n return jsonResponse(result, bigIntReplacer);\n }),\n );\n\n // -- app_status --\n this.mcpServer.registerTool(\n 'app_status',\n {\n description:\n 'Get detailed status and connection info for a deployed app. Use this after deploy_app to check if an app is running and get its URL.',\n inputSchema: {\n lease_uuid: z\n .string()\n .uuid()\n .describe('The lease UUID of the app to check'),\n },\n },\n withErrorHandling('app_status', async (args) => {\n const leaseUuid = args.lease_uuid;\n const address = await this.walletProvider.getAddress();\n await this.clientManager.acquireRateLimit();\n const queryClient = await this.clientManager.getQueryClient();\n const result = await appStatus(\n queryClient,\n address,\n leaseUuid,\n (addr, uuid) => this.getProviderAuthToken(addr, uuid),\n );\n return jsonResponse(result, bigIntReplacer);\n }),\n );\n\n // -- get_logs --\n this.mcpServer.registerTool(\n 'get_logs',\n {\n description:\n 'Get recent container logs for a deployed app. Use this to debug apps that are failing or to verify an app started correctly after deploy_app.',\n inputSchema: {\n lease_uuid: z\n .string()\n .uuid()\n .describe('The lease UUID of the app to get logs for'),\n tail: z\n .number()\n .int()\n .min(1)\n .max(MAX_TAIL)\n .optional()\n .describe('Number of recent log lines to retrieve'),\n },\n },\n withErrorHandling('get_logs', async (args) => {\n const leaseUuid = args.lease_uuid;\n const tail = args.tail;\n const address = await this.walletProvider.getAddress();\n await this.clientManager.acquireRateLimit();\n const queryClient = await this.clientManager.getQueryClient();\n const result = await getAppLogs(\n queryClient,\n address,\n leaseUuid,\n (addr, uuid) => this.getProviderAuthToken(addr, uuid),\n tail,\n );\n return jsonResponse(result, bigIntReplacer);\n }),\n );\n\n // -- deploy_app --\n this.mcpServer.registerTool(\n 'deploy_app',\n {\n description:\n 'Deploy a new containerized application. Requires funded credits (use fund_credit if needed). Creates a lease on-chain, uploads the container manifest to a provider, and polls until ready. Use browse_catalog first to see available SKU sizes.',\n inputSchema: {\n image: z\n .string()\n .optional()\n .describe(\n 'Docker image to deploy. Required unless services is provided.',\n ),\n port: z\n .number()\n .int()\n .min(1)\n .max(65535)\n .optional()\n .describe(\n 'Container port to expose. Required unless services is provided.',\n ),\n size: z\n .string()\n .describe('SKU tier name (e.g. \"docker-micro\", \"docker-small\")'),\n env: z\n .record(z.string(), z.string())\n .optional()\n .describe('Environment variables as key-value pairs'),\n command: z\n .array(z.string())\n .optional()\n .describe('Override container command (entrypoint)'),\n args: z\n .array(z.string())\n .optional()\n .describe('Arguments to the container command'),\n user: z\n .string()\n .optional()\n .describe('User to run the container as (e.g. \"1000:1000\")'),\n tmpfs: z\n .array(z.string())\n .optional()\n .describe('tmpfs mounts (e.g. [\"/tmp:size=64M\"])'),\n health_check: z\n .object({\n test: z.array(z.string()),\n interval: z.string().optional(),\n timeout: z.string().optional(),\n retries: z.number().int().optional(),\n start_period: z.string().optional(),\n })\n .optional()\n .describe('Container health check configuration'),\n stop_grace_period: z\n .string()\n .optional()\n .describe('Grace period before force-killing (e.g. \"30s\")'),\n init: z\n .boolean()\n .optional()\n .describe('Run an init process inside the container'),\n expose: z\n .array(z.string())\n .optional()\n .describe('Expose ports without publishing (e.g. [\"8080/tcp\"])'),\n labels: z\n .record(z.string(), z.string())\n .optional()\n .describe('Container labels as key-value pairs'),\n storage: z\n .string()\n .optional()\n .describe(\n 'Storage SKU name for persistent disk (adds a second lease item)',\n ),\n depends_on: z\n .record(z.string(), z.object({ condition: z.string() }))\n .optional()\n .describe('Service dependencies'),\n services: z\n .record(\n z.string(),\n z.object({\n image: z.string(),\n ports: z.record(z.string(), z.object({})).optional(),\n env: z.record(z.string(), z.string()).optional(),\n command: z.array(z.string()).optional(),\n args: z.array(z.string()).optional(),\n user: z.string().optional(),\n tmpfs: z.array(z.string()).optional(),\n health_check: z\n .object({\n test: z.array(z.string()),\n interval: z.string().optional(),\n timeout: z.string().optional(),\n retries: z.number().int().optional(),\n start_period: z.string().optional(),\n })\n .optional(),\n stop_grace_period: z.string().optional(),\n depends_on: z\n .record(z.string(), z.object({ condition: z.string() }))\n .optional(),\n expose: z.array(z.string()).optional(),\n labels: z.record(z.string(), z.string()).optional(),\n }),\n )\n .optional()\n .describe(\n 'Multi-service stack. Mutually exclusive with image/port. Keys are service names (RFC 1123 DNS labels).',\n ),\n 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 },\n withErrorHandling('deploy_app', async (args) => {\n const result = await deployApp(\n this.clientManager,\n (addr, uuid) => this.getProviderAuthToken(addr, uuid),\n (addr, uuid, metaHashHex) =>\n this.getLeaseDataAuthToken(addr, uuid, metaHashHex),\n {\n image: args.image,\n port: args.port,\n size: args.size,\n env: args.env,\n command: args.command,\n args: args.args,\n user: args.user,\n tmpfs: args.tmpfs,\n health_check: args.health_check,\n stop_grace_period: args.stop_grace_period,\n init: args.init,\n expose: args.expose,\n labels: args.labels,\n storage: args.storage,\n depends_on: args.depends_on,\n services: args.services,\n gasMultiplier: args.gas_multiplier,\n },\n );\n return jsonResponse(result, bigIntReplacer);\n }),\n );\n\n // -- restart_app --\n this.mcpServer.registerTool(\n 'restart_app',\n {\n description:\n 'Restart a running app via the provider without closing its lease. Use this to apply configuration changes or recover from a crash.',\n inputSchema: {\n lease_uuid: z\n .string()\n .uuid()\n .describe('The lease UUID of the app to restart'),\n },\n },\n withErrorHandling('restart_app', async (args) => {\n const leaseUuid = args.lease_uuid;\n const address = await this.walletProvider.getAddress();\n await this.clientManager.acquireRateLimit();\n const queryClient = await this.clientManager.getQueryClient();\n const result = await restartApp(\n queryClient,\n address,\n leaseUuid,\n (addr, uuid) => this.getProviderAuthToken(addr, uuid),\n );\n return jsonResponse(result, bigIntReplacer);\n }),\n );\n\n // -- update_app --\n this.mcpServer.registerTool(\n 'update_app',\n {\n description:\n 'Update a deployed app with a new container manifest. Use this to change the Docker image, ports, or environment variables of a running app without closing the lease.',\n inputSchema: {\n lease_uuid: z\n .string()\n .uuid()\n .describe('The lease UUID of the app to update'),\n manifest: z\n .string()\n .describe('The full manifest JSON string to deploy'),\n existing_manifest: z\n .string()\n .optional()\n .describe(\n 'The current manifest JSON. When provided, the new manifest is merged over the existing one (env, ports, labels merged; other fields carried forward if not in new).',\n ),\n },\n },\n withErrorHandling('update_app', async (args) => {\n const manifest = args.manifest;\n\n try {\n const parsed = JSON.parse(manifest);\n if (\n parsed === null ||\n typeof parsed !== 'object' ||\n Array.isArray(parsed)\n ) {\n throw new Error('must be a JSON object');\n }\n } catch (err) {\n throw new ManifestMCPError(\n ManifestMCPErrorCode.INVALID_CONFIG,\n `Invalid manifest: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n\n const leaseUuid = args.lease_uuid;\n const address = await this.walletProvider.getAddress();\n await this.clientManager.acquireRateLimit();\n const queryClient = await this.clientManager.getQueryClient();\n\n const result = await updateApp(\n queryClient,\n address,\n leaseUuid,\n (addr, uuid) => this.getProviderAuthToken(addr, uuid),\n manifest,\n args.existing_manifest,\n );\n return jsonResponse(result, bigIntReplacer);\n }),\n );\n\n // -- app_diagnostics --\n this.mcpServer.registerTool(\n 'app_diagnostics',\n {\n description:\n 'Get provision diagnostics for a deployed app. Use this to debug apps stuck in provisioning or that failed to start. Returns provision status, failure count, and last error message.',\n inputSchema: {\n lease_uuid: z\n .string()\n .uuid()\n .describe('The lease UUID of the app to diagnose'),\n },\n },\n withErrorHandling('app_diagnostics', async (args) => {\n const leaseUuid = args.lease_uuid;\n const address = await this.walletProvider.getAddress();\n await this.clientManager.acquireRateLimit();\n const queryClient = await this.clientManager.getQueryClient();\n\n const lease = await fetchActiveLease(\n queryClient,\n leaseUuid,\n 'cannot be diagnosed',\n );\n const providerUrl = await resolveProviderUrl(\n queryClient,\n lease.providerUuid,\n );\n const authToken = await this.getProviderAuthToken(address, leaseUuid);\n const provision = await getLeaseProvision(\n providerUrl,\n leaseUuid,\n authToken,\n );\n\n return jsonResponse(\n {\n lease_uuid: leaseUuid,\n provision_status: provision.status,\n fail_count: provision.fail_count,\n last_error: provision.last_error,\n },\n bigIntReplacer,\n );\n }),\n );\n\n // -- app_releases --\n this.mcpServer.registerTool(\n 'app_releases',\n {\n description:\n 'Get release/version history for a deployed app. Use this to see what versions have been deployed, when they were created, and their status.',\n inputSchema: {\n lease_uuid: z\n .string()\n .uuid()\n .describe('The lease UUID of the app to get release history for'),\n },\n },\n withErrorHandling('app_releases', async (args) => {\n const leaseUuid = args.lease_uuid;\n const address = await this.walletProvider.getAddress();\n await this.clientManager.acquireRateLimit();\n const queryClient = await this.clientManager.getQueryClient();\n\n const lease = await fetchActiveLease(\n queryClient,\n leaseUuid,\n 'releases are not available',\n );\n const providerUrl = await resolveProviderUrl(\n queryClient,\n lease.providerUuid,\n );\n const authToken = await this.getProviderAuthToken(address, leaseUuid);\n const result = await getLeaseReleases(\n providerUrl,\n leaseUuid,\n authToken,\n );\n\n return jsonResponse(\n {\n lease_uuid: leaseUuid,\n releases: result.releases,\n },\n bigIntReplacer,\n );\n }),\n );\n }\n\n getServer(): Server {\n return this.mcpServer.server;\n }\n\n getClientManager(): CosmosClientManager {\n return this.clientManager;\n }\n\n disconnect(): void {\n this.clientManager.disconnect();\n }\n}\n\nexport function createMnemonicFredServer(\n config: MnemonicServerConfig,\n): Promise<FredMCPServer> {\n return createMnemonicServer(config, FredMCPServer);\n}\n"],"mappings":"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"}
@@ -49,6 +49,7 @@ interface DeployAppInput {
49
49
  condition: string;
50
50
  }>;
51
51
  services?: Record<string, ServiceConfig>;
52
+ gasMultiplier?: number;
52
53
  }
53
54
  interface DeployAppResult {
54
55
  readonly lease_uuid: string;
@@ -1 +1 @@
1
- {"version":3,"file":"deployApp.d.ts","names":[],"sources":["../../src/tools/deployApp.ts"],"mappings":";;;;UA6FiB,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;AAAA;AAAA,UAGX,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;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"}
1
+ {"version":3,"file":"deployApp.d.ts","names":[],"sources":["../../src/tools/deployApp.ts"],"mappings":";;;;UA6FiB,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;AAAA;AAAA,UAGe,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;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"}
@@ -89,11 +89,12 @@ async function deployApp(clientManager, getAuthToken, getLeaseDataAuthToken, inp
89
89
  leaseItems.push(`${storageSkuUuid}:1`);
90
90
  }
91
91
  const providerUrl = await resolveProviderUrl(queryClient, providerUuid);
92
+ const overrides = input.gasMultiplier !== void 0 ? { gasMultiplier: input.gasMultiplier } : void 0;
92
93
  const leaseUuid = extractLeaseUuid(await cosmosTx(clientManager, "billing", "create-lease", [
93
94
  "--meta-hash",
94
95
  metaHashHex,
95
96
  ...leaseItems
96
- ], true));
97
+ ], true, overrides));
97
98
  let status;
98
99
  try {
99
100
  const leaseDataToken = await getLeaseDataAuthToken(address, leaseUuid, metaHashHex);
@@ -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 } from '../http/fred.js';\nimport { pollLeaseUntilReady } 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 validateServiceName,\n} from '../manifest.js';\nimport { resolveProviderUrl } from './resolveLeaseProvider.js';\n\nasync function sha256(data: string): Promise<string> {\n const encoded = new TextEncoder().encode(data);\n const hashBuffer = await crypto.subtle.digest('SHA-256', encoded);\n const bytes = new Uint8Array(hashBuffer);\n return Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('');\n}\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}\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\n const metaHashHex = await sha256(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 txResult = await cosmosTx(\n clientManager,\n 'billing',\n 'create-lease',\n ['--meta-hash', metaHashHex, ...leaseItems],\n true,\n );\n\n // 6. Extract lease UUID\n const leaseUuid = extractLeaseUuid(txResult);\n\n let status: FredLeaseStatus;\n try {\n // 7. Upload manifest with lease-data auth token\n const leaseDataToken = await getLeaseDataAuthToken(\n address,\n leaseUuid,\n metaHashHex,\n );\n await uploadLeaseData(\n providerUrl,\n leaseUuid,\n new TextEncoder().encode(manifestJson),\n leaseDataToken,\n fetchFn,\n );\n\n // 8. Poll until ready\n status = await pollLeaseUntilReady(\n providerUrl,\n leaseUuid,\n () => getAuthToken(address, leaseUuid),\n undefined,\n fetchFn,\n );\n } catch (err) {\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} from '@manifest-network/manifest-mcp-core';\nimport type { FredLeaseStatus } from '../http/fred.js';\nimport { pollLeaseUntilReady } 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 validateServiceName,\n} from '../manifest.js';\nimport { resolveProviderUrl } from './resolveLeaseProvider.js';\n\nasync function sha256(data: string): Promise<string> {\n const encoded = new TextEncoder().encode(data);\n const hashBuffer = await crypto.subtle.digest('SHA-256', encoded);\n const bytes = new Uint8Array(hashBuffer);\n return Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('');\n}\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\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\n const metaHashHex = await sha256(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', metaHashHex, ...leaseItems],\n true,\n overrides,\n );\n\n // 6. Extract lease UUID\n const leaseUuid = extractLeaseUuid(txResult);\n\n let status: FredLeaseStatus;\n try {\n // 7. Upload manifest with lease-data auth token\n const leaseDataToken = await getLeaseDataAuthToken(\n address,\n leaseUuid,\n metaHashHex,\n );\n await uploadLeaseData(\n providerUrl,\n leaseUuid,\n new TextEncoder().encode(manifestJson),\n leaseDataToken,\n fetchFn,\n );\n\n // 8. Poll until ready\n status = await pollLeaseUntilReady(\n providerUrl,\n leaseUuid,\n () => getAuthToken(address, leaseUuid),\n undefined,\n fetchFn,\n );\n } catch (err) {\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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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@manifest-network/manifest-mcp-fred",
3
- "version": "0.3.5",
3
+ "version": "0.4.5",
4
4
  "description": "MCP server for Manifest provider (Fred) operations (deploy, status, logs, restart, update)",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -46,7 +46,7 @@
46
46
  ],
47
47
  "dependencies": {
48
48
  "@cosmjs/encoding": "0.32.4",
49
- "@manifest-network/manifest-mcp-core": "^0.3.5",
49
+ "@manifest-network/manifest-mcp-core": "^0.4.4",
50
50
  "@modelcontextprotocol/sdk": "1.27.1",
51
51
  "zod": "^4.3.6"
52
52
  },