nosana-mcp 0.2.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.
Files changed (56) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +128 -0
  3. package/dist/cli/commands/account.d.ts +7 -0
  4. package/dist/cli/commands/account.js +108 -0
  5. package/dist/cli/commands/account.js.map +1 -0
  6. package/dist/cli/commands/deploy.d.ts +3 -0
  7. package/dist/cli/commands/deploy.js +311 -0
  8. package/dist/cli/commands/deploy.js.map +1 -0
  9. package/dist/cli/commands/gpus.d.ts +3 -0
  10. package/dist/cli/commands/gpus.js +38 -0
  11. package/dist/cli/commands/gpus.js.map +1 -0
  12. package/dist/cli/commands/job.d.ts +3 -0
  13. package/dist/cli/commands/job.js +31 -0
  14. package/dist/cli/commands/job.js.map +1 -0
  15. package/dist/cli/commands/run.d.ts +33 -0
  16. package/dist/cli/commands/run.js +365 -0
  17. package/dist/cli/commands/run.js.map +1 -0
  18. package/dist/cli/commands/templates.d.ts +3 -0
  19. package/dist/cli/commands/templates.js +115 -0
  20. package/dist/cli/commands/templates.js.map +1 -0
  21. package/dist/cli/index.d.ts +2 -0
  22. package/dist/cli/index.js +45 -0
  23. package/dist/cli/index.js.map +1 -0
  24. package/dist/core/client.d.ts +23 -0
  25. package/dist/core/client.js +38 -0
  26. package/dist/core/client.js.map +1 -0
  27. package/dist/core/config.d.ts +18 -0
  28. package/dist/core/config.js +52 -0
  29. package/dist/core/config.js.map +1 -0
  30. package/dist/core/credits.d.ts +9 -0
  31. package/dist/core/credits.js +9 -0
  32. package/dist/core/credits.js.map +1 -0
  33. package/dist/core/deploy.d.ts +146 -0
  34. package/dist/core/deploy.js +400 -0
  35. package/dist/core/deploy.js.map +1 -0
  36. package/dist/core/format.d.ts +25 -0
  37. package/dist/core/format.js +144 -0
  38. package/dist/core/format.js.map +1 -0
  39. package/dist/core/markets.d.ts +74 -0
  40. package/dist/core/markets.js +146 -0
  41. package/dist/core/markets.js.map +1 -0
  42. package/dist/core/templates.d.ts +61 -0
  43. package/dist/core/templates.js +190 -0
  44. package/dist/core/templates.js.map +1 -0
  45. package/dist/mcp/index.d.ts +2 -0
  46. package/dist/mcp/index.js +73 -0
  47. package/dist/mcp/index.js.map +1 -0
  48. package/dist/mcp/tools.d.ts +52 -0
  49. package/dist/mcp/tools.js +994 -0
  50. package/dist/mcp/tools.js.map +1 -0
  51. package/docs/CLI.md +144 -0
  52. package/docs/COST.md +32 -0
  53. package/docs/MINIMAX-H3.md +79 -0
  54. package/examples/hello-world.json +18 -0
  55. package/examples/minimax-h3-i2v-32gb.json +56 -0
  56. package/package.json +66 -0
@@ -0,0 +1,74 @@
1
+ import type { NosanaClient } from '@nosana/kit';
2
+ export interface GpuMarket {
3
+ slug: string;
4
+ name: string;
5
+ address: string;
6
+ type: string;
7
+ vramGb: number | null;
8
+ basePricePerHour: number;
9
+ feePercent: number;
10
+ /** Price shown on deploy.nosana.com: base reward plus the network fee. */
11
+ pricePerHour: number;
12
+ /** Idle hosts waiting in this market's queue (the dashboard's "Available" number). */
13
+ availableNodes: number;
14
+ /** Jobs waiting for a host (only when the on-chain read is requested). */
15
+ queuedJobs: number | null;
16
+ }
17
+ interface RawMarket {
18
+ address: string;
19
+ slug: string;
20
+ name: string;
21
+ type: string;
22
+ usd_reward_per_hour: number | null;
23
+ network_fee_percentage: number | null;
24
+ metadata?: {
25
+ key: string;
26
+ value: string;
27
+ }[] | null;
28
+ }
29
+ export declare function parseVramGb(metadata: RawMarket['metadata']): number | null;
30
+ export interface CatalogOptions {
31
+ /** Include COMMUNITY and OTHER markets, not only the PREMIUM ones the dashboard shows. */
32
+ includeAll?: boolean;
33
+ /** Also read the on-chain market accounts to count jobs waiting for a host. */
34
+ onchain?: boolean;
35
+ }
36
+ export declare function loadGpuCatalog(client: NosanaClient, options?: CatalogOptions): Promise<GpuMarket[]>;
37
+ /** Accepts a market address, slug ("nvidia-5090"), short form ("5090") or display name ("NVIDIA 5090"). */
38
+ export declare function resolveGpu(catalog: GpuMarket[], query: string): GpuMarket | undefined;
39
+ export declare function fitsVram(market: GpuMarket, minVramGb?: number | null): boolean;
40
+ export interface GpuTableOptions {
41
+ minVramGb?: number | null;
42
+ /** Extra hardware check, e.g. "needs a Blackwell card". */
43
+ recommend?: (market: GpuMarket) => boolean;
44
+ showQueue?: boolean;
45
+ }
46
+ export declare function fitLabel(market: GpuMarket, options: GpuTableOptions): string;
47
+ export declare function gpuTable(catalog: GpuMarket[], options?: GpuTableOptions): string;
48
+ export type GpuBucketName = 'ready_now' | 'fits_but_queued' | 'idle_with_risk' | 'unsupported' | 'too_small';
49
+ export interface GpuFitRequirements {
50
+ minVramGb?: number | null;
51
+ /** The workload only runs on Blackwell cards (RTX 5090, RTX PRO 6000). */
52
+ blackwellOnly?: boolean;
53
+ isBlackwell?: (market: GpuMarket) => boolean;
54
+ }
55
+ export interface BucketedGpu {
56
+ market: GpuMarket;
57
+ bucket: GpuBucketName;
58
+ risks: string[];
59
+ }
60
+ export interface GpuBuckets {
61
+ ready_now: BucketedGpu[];
62
+ fits_but_queued: BucketedGpu[];
63
+ idle_with_risk: BucketedGpu[];
64
+ unsupported: BucketedGpu[];
65
+ too_small: BucketedGpu[];
66
+ }
67
+ /**
68
+ * Sort GPUs the way a careful buyer would: fits and idle first, then fits but queued, then idle with a caveat.
69
+ * Hard incompatibilities (wrong architecture, too little VRAM) are kept apart so nobody "forces" them by accident.
70
+ */
71
+ export declare function bucketGpus(catalog: GpuMarket[], req?: GpuFitRequirements): GpuBuckets;
72
+ /** Cheapest GPU that fits and has an idle host, or null when nothing is ready right now. */
73
+ export declare function autoPickGpu(buckets: GpuBuckets): GpuMarket | null;
74
+ export {};
@@ -0,0 +1,146 @@
1
+ import pc from 'picocolors';
2
+ import { table, usd, withRetry, withTimeout } from './format.js';
3
+ export function parseVramGb(metadata) {
4
+ const entry = metadata?.find((m) => String(m.key).toLowerCase() === 'vram');
5
+ if (!entry)
6
+ return null;
7
+ const match = /([\d.]+)\s*(GB|MB)?/i.exec(String(entry.value));
8
+ if (!match)
9
+ return null;
10
+ const n = Number(match[1]);
11
+ if (!Number.isFinite(n))
12
+ return null;
13
+ return (match[2] ?? 'GB').toUpperCase() === 'MB' ? Math.round(n / 1024) : n;
14
+ }
15
+ export async function loadGpuCatalog(client, options = {}) {
16
+ const [rawMarkets, rawQueued] = await Promise.all([
17
+ withRetry(() => client.api.markets.list()),
18
+ withRetry(() => client.api.hosts.getQueuedNodes()).catch(() => []),
19
+ ]);
20
+ const markets = (Array.isArray(rawMarkets) ? rawMarkets : []);
21
+ const queuedNodes = (Array.isArray(rawQueued) ? rawQueued : []);
22
+ const availability = new Map();
23
+ for (const node of queuedNodes) {
24
+ if (node.state && node.state !== 'QUEUED')
25
+ continue;
26
+ availability.set(node.marketAddress, (availability.get(node.marketAddress) ?? 0) + 1);
27
+ }
28
+ let queuedJobs;
29
+ if (options.onchain) {
30
+ try {
31
+ const chain = await withTimeout(client.jobs.markets(), 20_000, 'on-chain market read');
32
+ queuedJobs = new Map();
33
+ for (const market of chain) {
34
+ const queue = Array.isArray(market.queue) ? market.queue.length : 0;
35
+ queuedJobs.set(String(market.address), Number(market.queueType) === 0 ? queue : 0);
36
+ }
37
+ }
38
+ catch {
39
+ queuedJobs = undefined;
40
+ }
41
+ }
42
+ return markets
43
+ .filter((m) => options.includeAll || m.type === 'PREMIUM')
44
+ .filter((m) => typeof m.usd_reward_per_hour === 'number')
45
+ .map((m) => {
46
+ const base = m.usd_reward_per_hour ?? 0;
47
+ const fee = m.network_fee_percentage ?? 0;
48
+ return {
49
+ slug: m.slug,
50
+ name: m.name,
51
+ address: m.address,
52
+ type: m.type,
53
+ vramGb: parseVramGb(m.metadata),
54
+ basePricePerHour: base,
55
+ feePercent: fee,
56
+ pricePerHour: base * (1 + fee / 100),
57
+ availableNodes: availability.get(m.address) ?? 0,
58
+ queuedJobs: queuedJobs ? (queuedJobs.get(m.address) ?? 0) : null,
59
+ };
60
+ })
61
+ .sort((a, b) => a.pricePerHour - b.pricePerHour || a.name.localeCompare(b.name));
62
+ }
63
+ /** Accepts a market address, slug ("nvidia-5090"), short form ("5090") or display name ("NVIDIA 5090"). */
64
+ export function resolveGpu(catalog, query) {
65
+ const q = query.trim().toLowerCase();
66
+ const squash = (s) => s.toLowerCase().replace(/[\s_-]+/g, '');
67
+ return (catalog.find((m) => m.address === query.trim()) ??
68
+ catalog.find((m) => m.slug.toLowerCase() === q) ??
69
+ catalog.find((m) => m.name.toLowerCase() === q) ??
70
+ catalog.find((m) => m.slug.toLowerCase() === `nvidia-${q}`) ??
71
+ catalog.find((m) => squash(m.name) === squash(q)) ??
72
+ catalog.find((m) => squash(m.name) === `nvidia${squash(q)}`) ??
73
+ catalog.find((m) => m.slug.toLowerCase().includes(q) || m.name.toLowerCase().includes(q)));
74
+ }
75
+ export function fitsVram(market, minVramGb) {
76
+ if (!minVramGb)
77
+ return true;
78
+ return market.vramGb !== null && market.vramGb >= minVramGb;
79
+ }
80
+ export function fitLabel(market, options) {
81
+ if (!fitsVram(market, options.minVramGb))
82
+ return pc.red('too little VRAM');
83
+ if (options.recommend && !options.recommend(market))
84
+ return pc.yellow('check hardware');
85
+ return options.minVramGb || options.recommend ? pc.green('fits') : '';
86
+ }
87
+ export function gpuTable(catalog, options = {}) {
88
+ const headers = ['GPU', 'Slug', 'VRAM', 'Price/h', 'Available'];
89
+ if (options.showQueue)
90
+ headers.push('Jobs waiting');
91
+ const showFit = Boolean(options.minVramGb || options.recommend);
92
+ if (showFit)
93
+ headers.push('Fit');
94
+ const rows = catalog.map((m) => {
95
+ const row = [
96
+ m.name,
97
+ m.slug,
98
+ m.vramGb ? `${m.vramGb} GB` : pc.dim('?'),
99
+ usd(m.pricePerHour),
100
+ m.availableNodes > 0 ? pc.green(String(m.availableNodes)) : pc.dim('0'),
101
+ ];
102
+ if (options.showQueue)
103
+ row.push(m.queuedJobs === null ? pc.dim('?') : String(m.queuedJobs));
104
+ if (showFit)
105
+ row.push(fitLabel(m, options));
106
+ return row;
107
+ });
108
+ return table(headers, rows);
109
+ }
110
+ /**
111
+ * Sort GPUs the way a careful buyer would: fits and idle first, then fits but queued, then idle with a caveat.
112
+ * Hard incompatibilities (wrong architecture, too little VRAM) are kept apart so nobody "forces" them by accident.
113
+ */
114
+ export function bucketGpus(catalog, req = {}) {
115
+ const buckets = { ready_now: [], fits_but_queued: [], idle_with_risk: [], unsupported: [], too_small: [] };
116
+ for (const market of catalog) {
117
+ const risks = [];
118
+ if (req.minVramGb && market.vramGb !== null && market.vramGb < req.minVramGb) {
119
+ buckets.too_small.push({ market, bucket: 'too_small', risks: [`${market.vramGb} GB VRAM, workload needs ${req.minVramGb} GB`] });
120
+ continue;
121
+ }
122
+ if (req.blackwellOnly && req.isBlackwell && !req.isBlackwell(market)) {
123
+ buckets.unsupported.push({ market, bucket: 'unsupported', risks: ['not a Blackwell GPU; this workload will not run here'] });
124
+ continue;
125
+ }
126
+ if (req.minVramGb && market.vramGb === null)
127
+ risks.push('VRAM not published for this market');
128
+ const idle = market.availableNodes > 0;
129
+ if (risks.length) {
130
+ if (idle)
131
+ buckets.idle_with_risk.push({ market, bucket: 'idle_with_risk', risks });
132
+ else
133
+ buckets.fits_but_queued.push({ market, bucket: 'fits_but_queued', risks });
134
+ }
135
+ else if (idle)
136
+ buckets.ready_now.push({ market, bucket: 'ready_now', risks });
137
+ else
138
+ buckets.fits_but_queued.push({ market, bucket: 'fits_but_queued', risks });
139
+ }
140
+ return buckets;
141
+ }
142
+ /** Cheapest GPU that fits and has an idle host, or null when nothing is ready right now. */
143
+ export function autoPickGpu(buckets) {
144
+ return buckets.ready_now[0]?.market ?? null;
145
+ }
146
+ //# sourceMappingURL=markets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markets.js","sourceRoot":"","sources":["../../src/core/markets.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAkCjE,MAAM,UAAU,WAAW,CAAC,QAA+B;IACzD,MAAM,KAAK,GAAG,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,KAAK,MAAM,CAAC,CAAC;IAC5E,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,MAAM,KAAK,GAAG,sBAAsB,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;IAC/D,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,MAAM,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3B,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACrC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,WAAW,EAAE,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9E,CAAC;AASD,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,MAAoB,EAAE,UAA0B,EAAE;IACrF,MAAM,CAAC,UAAU,EAAE,SAAS,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QAChD,SAAS,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAqB;QAC7D,SAAS,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,cAAc,EAAE,CAAsB,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC;KACzF,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAgB,CAAC;IAC7E,MAAM,WAAW,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAoB,CAAC;IAEnF,MAAM,YAAY,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC/C,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;QAC/B,IAAI,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,KAAK,QAAQ;YAAE,SAAS;QACpD,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IACxF,CAAC;IAED,IAAI,UAA2C,CAAC;IAChD,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;QACpB,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,sBAAsB,CAAC,CAAC;YACvF,UAAU,GAAG,IAAI,GAAG,EAAE,CAAC;YACvB,KAAK,MAAM,MAAM,IAAI,KAAK,EAAE,CAAC;gBAC3B,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;gBACpE,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACrF,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,UAAU,GAAG,SAAS,CAAC;QACzB,CAAC;IACH,CAAC;IAED,OAAO,OAAO;SACX,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,UAAU,IAAI,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC;SACzD,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,mBAAmB,KAAK,QAAQ,CAAC;SACxD,GAAG,CAAC,CAAC,CAAC,EAAa,EAAE;QACpB,MAAM,IAAI,GAAG,CAAC,CAAC,mBAAmB,IAAI,CAAC,CAAC;QACxC,MAAM,GAAG,GAAG,CAAC,CAAC,sBAAsB,IAAI,CAAC,CAAC;QAC1C,OAAO;YACL,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,OAAO,EAAE,CAAC,CAAC,OAAO;YAClB,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC;YAC/B,gBAAgB,EAAE,IAAI;YACtB,UAAU,EAAE,GAAG;YACf,YAAY,EAAE,IAAI,GAAG,CAAC,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC;YACpC,cAAc,EAAE,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC;YAChD,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI;SACjE,CAAC;IACJ,CAAC,CAAC;SACD,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,GAAG,CAAC,CAAC,YAAY,IAAI,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AACrF,CAAC;AAED,2GAA2G;AAC3G,MAAM,UAAU,UAAU,CAAC,OAAoB,EAAE,KAAa;IAC5D,MAAM,CAAC,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACrC,MAAM,MAAM,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IACtE,OAAO,CACL,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,KAAK,CAAC,IAAI,EAAE,CAAC;QAC/C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;QAC/C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;QAC/C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,UAAU,CAAC,EAAE,CAAC;QAC3D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC;QACjD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,SAAS,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;QAC5D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAC1F,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,MAAiB,EAAE,SAAyB;IACnE,IAAI,CAAC,SAAS;QAAE,OAAO,IAAI,CAAC;IAC5B,OAAO,MAAM,CAAC,MAAM,KAAK,IAAI,IAAI,MAAM,CAAC,MAAM,IAAI,SAAS,CAAC;AAC9D,CAAC;AASD,MAAM,UAAU,QAAQ,CAAC,MAAiB,EAAE,OAAwB;IAClE,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,SAAS,CAAC;QAAE,OAAO,EAAE,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;IAC3E,IAAI,OAAO,CAAC,SAAS,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC;QAAE,OAAO,EAAE,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC;IACxF,OAAO,OAAO,CAAC,SAAS,IAAI,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACxE,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,OAAoB,EAAE,UAA2B,EAAE;IAC1E,MAAM,OAAO,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC;IAChE,IAAI,OAAO,CAAC,SAAS;QAAE,OAAO,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IACpD,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,SAAS,IAAI,OAAO,CAAC,SAAS,CAAC,CAAC;IAChE,IAAI,OAAO;QAAE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACjC,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QAC7B,MAAM,GAAG,GAAG;YACV,CAAC,CAAC,IAAI;YACN,CAAC,CAAC,IAAI;YACN,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC;YACzC,GAAG,CAAC,CAAC,CAAC,YAAY,CAAC;YACnB,CAAC,CAAC,cAAc,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC;SACxE,CAAC;QACF,IAAI,OAAO,CAAC,SAAS;YAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;QAC5F,IAAI,OAAO;YAAE,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;QAC5C,OAAO,GAAG,CAAC;IACb,CAAC,CAAC,CAAC;IACH,OAAO,KAAK,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;AAC9B,CAAC;AAyBD;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,OAAoB,EAAE,MAA0B,EAAE;IAC3E,MAAM,OAAO,GAAe,EAAE,SAAS,EAAE,EAAE,EAAE,eAAe,EAAE,EAAE,EAAE,cAAc,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;IACvH,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,IAAI,GAAG,CAAC,SAAS,IAAI,MAAM,CAAC,MAAM,KAAK,IAAI,IAAI,MAAM,CAAC,MAAM,GAAG,GAAG,CAAC,SAAS,EAAE,CAAC;YAC7E,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAAC,SAAS,KAAK,CAAC,EAAE,CAAC,CAAC;YACjI,SAAS;QACX,CAAC;QACD,IAAI,GAAG,CAAC,aAAa,IAAI,GAAG,CAAC,WAAW,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC;YACrE,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC,sDAAsD,CAAC,EAAE,CAAC,CAAC;YAC7H,SAAS;QACX,CAAC;QACD,IAAI,GAAG,CAAC,SAAS,IAAI,MAAM,CAAC,MAAM,KAAK,IAAI;YAAE,KAAK,CAAC,IAAI,CAAC,oCAAoC,CAAC,CAAC;QAC9F,MAAM,IAAI,GAAG,MAAM,CAAC,cAAc,GAAG,CAAC,CAAC;QACvC,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;YACjB,IAAI,IAAI;gBAAE,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,gBAAgB,EAAE,KAAK,EAAE,CAAC,CAAC;;gBAC9E,OAAO,CAAC,eAAe,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,iBAAiB,EAAE,KAAK,EAAE,CAAC,CAAC;QAClF,CAAC;aAAM,IAAI,IAAI;YAAE,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,CAAC;;YAC3E,OAAO,CAAC,eAAe,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,iBAAiB,EAAE,KAAK,EAAE,CAAC,CAAC;IAClF,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,4FAA4F;AAC5F,MAAM,UAAU,WAAW,CAAC,OAAmB;IAC7C,OAAO,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,IAAI,IAAI,CAAC;AAC9C,CAAC"}
@@ -0,0 +1,61 @@
1
+ import type { JobDefinition, NosanaClient } from '@nosana/kit';
2
+ import { CliError } from './client.js';
3
+ export interface TemplateVariant {
4
+ id: string;
5
+ name: string;
6
+ description?: string;
7
+ }
8
+ export interface TemplateInfo {
9
+ id: string;
10
+ name: string;
11
+ description?: string;
12
+ category: string[];
13
+ icon?: string;
14
+ readme: string;
15
+ jobDefinition: JobDefinition | null;
16
+ vramRequirementGb: number | null;
17
+ cudaRequirement: string | null;
18
+ isVariant: boolean;
19
+ parentId: string | null;
20
+ variants: TemplateVariant[];
21
+ }
22
+ export declare function listTemplates(client: NosanaClient): Promise<TemplateInfo[]>;
23
+ export declare const topLevelTemplates: (all: TemplateInfo[]) => TemplateInfo[];
24
+ export interface ResolvedTemplate {
25
+ parent: TemplateInfo;
26
+ variant: TemplateVariant | null;
27
+ template: TemplateInfo;
28
+ jobDefinition: JobDefinition;
29
+ /** Identifier used for names and logs, e.g. "minimax-h3-i2v-32gb". */
30
+ id: string;
31
+ }
32
+ export declare class NeedsVariantError extends CliError {
33
+ readonly template: TemplateInfo;
34
+ constructor(template: TemplateInfo);
35
+ }
36
+ export declare function findTemplate(all: TemplateInfo[], query: string): TemplateInfo | undefined;
37
+ export declare function findVariant(template: TemplateInfo, variantId: string): TemplateVariant | undefined;
38
+ export declare function resolveVariant(all: TemplateInfo[], parent: TemplateInfo, variant: TemplateVariant): ResolvedTemplate;
39
+ export declare function resolveTemplate(all: TemplateInfo[], query: string, variantId?: string): ResolvedTemplate;
40
+ /** Copy the template definition and mark it as submitted from the CLI. */
41
+ export declare function prepareJobDefinition(definition: JobDefinition, trigger?: 'cli' | 'mcp'): JobDefinition;
42
+ export interface HardwareHints {
43
+ blackwellOnly: boolean;
44
+ minDriver: string | null;
45
+ notes: string[];
46
+ }
47
+ export declare function hardwareHints(template: TemplateInfo): HardwareHints;
48
+ export declare const isBlackwell: (name: string, slug: string) => boolean;
49
+ export declare function exposesPorts(definition: JobDefinition): boolean;
50
+ export declare function vramFromDefinition(definition: JobDefinition): number | null;
51
+ export type WorkloadKind = 'comfyui' | 'llm' | 'notebook' | 'ide' | 'asr' | 'webui' | 'custom';
52
+ export type LlmFlavor = 'ollama' | 'vllm' | 'other';
53
+ export declare function kindOfDefinition(definition: JobDefinition, category?: string[]): WorkloadKind;
54
+ export declare function llmFlavor(definition: JobDefinition): LlmFlavor;
55
+ /** Ports a job definition exposes, from `expose: 8188`, `expose: { port }` or an array of either. */
56
+ export declare function exposedPorts(definition: JobDefinition): number[];
57
+ export declare const primaryOpId: (definition: JobDefinition) => string | null;
58
+ /** URL path that proves the service itself (not just the tunnel) answers. */
59
+ export declare function readinessPath(kind: WorkloadKind, flavor?: LlmFlavor): string;
60
+ /** Rough time from "host assigned" to "service answers", driven by what has to be downloaded first. */
61
+ export declare function typicalBootMinutes(definition: JobDefinition, kind: WorkloadKind): number;
@@ -0,0 +1,190 @@
1
+ import { CliError } from './client.js';
2
+ import { withRetry } from './format.js';
3
+ function vramFrom(raw, definition) {
4
+ const mb = definition?.meta?.system_requirements?.vram_total_mb;
5
+ if (typeof mb === 'number' && mb > 0)
6
+ return Math.ceil(mb / 1024);
7
+ if (raw.vram_requirement !== null && raw.vram_requirement !== undefined) {
8
+ const n = Number(String(raw.vram_requirement).replace(/[^\d.]/g, ''));
9
+ if (Number.isFinite(n) && n > 0)
10
+ return n > 512 ? Math.ceil(n / 1024) : n;
11
+ }
12
+ return null;
13
+ }
14
+ function normalize(raw) {
15
+ const jobDefinition = raw.jobDefinition && typeof raw.jobDefinition === 'object' ? raw.jobDefinition : null;
16
+ const category = Array.isArray(raw.category)
17
+ ? raw.category
18
+ : String(raw.category ?? '')
19
+ .split('|')
20
+ .map((s) => s.trim())
21
+ .filter(Boolean);
22
+ return {
23
+ id: raw.id,
24
+ name: raw.name,
25
+ description: raw.description,
26
+ category,
27
+ icon: raw.icon,
28
+ readme: raw.readme ?? '',
29
+ jobDefinition,
30
+ vramRequirementGb: vramFrom(raw, jobDefinition),
31
+ cudaRequirement: raw.cuda_requirement ?? null,
32
+ isVariant: Boolean(raw.is_variant_template),
33
+ parentId: raw.parent_template_id ?? null,
34
+ variants: Array.isArray(raw.variants)
35
+ ? raw.variants.map((v) => ({ id: v.id, name: v.name, description: v.description }))
36
+ : [],
37
+ };
38
+ }
39
+ export async function listTemplates(client) {
40
+ const raw = (await withRetry(() => client.api.templates.list()));
41
+ return (Array.isArray(raw) ? raw : []).map(normalize);
42
+ }
43
+ export const topLevelTemplates = (all) => all.filter((t) => !t.isVariant);
44
+ export class NeedsVariantError extends CliError {
45
+ template;
46
+ constructor(template) {
47
+ super([
48
+ `Template "${template.id}" has ${template.variants.length} variants. Pick one with --variant <id>:`,
49
+ ...template.variants.map((v) => ` ${v.id.padEnd(14)} ${v.name}${v.description ? ` (${v.description})` : ''}`),
50
+ ].join('\n'), 2);
51
+ this.template = template;
52
+ this.name = 'NeedsVariantError';
53
+ }
54
+ }
55
+ export function findTemplate(all, query) {
56
+ const q = query.trim().toLowerCase();
57
+ return (all.find((t) => t.id.toLowerCase() === q) ??
58
+ all.find((t) => t.name.toLowerCase() === q) ??
59
+ topLevelTemplates(all).find((t) => t.id.toLowerCase().includes(q) || t.name.toLowerCase().includes(q)));
60
+ }
61
+ export function findVariant(template, variantId) {
62
+ const vq = variantId.trim().toLowerCase();
63
+ return (template.variants.find((v) => v.id.toLowerCase() === vq) ??
64
+ template.variants.find((v) => v.name.toLowerCase() === vq) ??
65
+ template.variants.find((v) => `${template.id}-${v.id}`.toLowerCase() === vq));
66
+ }
67
+ function finish(parent, variant, template) {
68
+ if (!template.jobDefinition) {
69
+ throw new CliError(`Template "${template.id}" has no job definition to deploy.`);
70
+ }
71
+ return { parent, variant, template, jobDefinition: template.jobDefinition, id: template.id };
72
+ }
73
+ export function resolveVariant(all, parent, variant) {
74
+ const variantTemplate = all.find((t) => t.id === `${parent.id}-${variant.id}`);
75
+ if (!variantTemplate) {
76
+ throw new CliError(`Variant template "${parent.id}-${variant.id}" was not returned by the templates API.`);
77
+ }
78
+ return finish(parent, variant, variantTemplate);
79
+ }
80
+ export function resolveTemplate(all, query, variantId) {
81
+ const found = findTemplate(all, query);
82
+ if (!found) {
83
+ throw new CliError(`Unknown template "${query}". Run \`nosana-deploy templates list\` to see what is available.`);
84
+ }
85
+ if (found.isVariant) {
86
+ const parent = all.find((t) => t.id === found.parentId) ?? found;
87
+ const variant = parent.variants.find((v) => `${parent.id}-${v.id}` === found.id) ?? null;
88
+ return finish(parent, variant, found);
89
+ }
90
+ if (found.variants.length > 0) {
91
+ if (variantId) {
92
+ const variant = findVariant(found, variantId);
93
+ if (!variant) {
94
+ throw new CliError(`Template "${found.id}" has no variant "${variantId}". Available: ${found.variants.map((v) => v.id).join(', ')}`, 2);
95
+ }
96
+ return resolveVariant(all, found, variant);
97
+ }
98
+ if (found.variants.length === 1)
99
+ return resolveVariant(all, found, found.variants[0]);
100
+ throw new NeedsVariantError(found);
101
+ }
102
+ if (variantId)
103
+ throw new CliError(`Template "${found.id}" has no variants; drop --variant.`, 2);
104
+ return finish(found, null, found);
105
+ }
106
+ /** Copy the template definition and mark it as submitted from the CLI. */
107
+ export function prepareJobDefinition(definition, trigger = 'cli') {
108
+ const clone = JSON.parse(JSON.stringify(definition));
109
+ clone.meta = { ...(clone.meta ?? {}), trigger };
110
+ return clone;
111
+ }
112
+ export function hardwareHints(template) {
113
+ const text = `${template.readme}\n${template.description ?? ''}`;
114
+ const blackwellOnly = /blackwell/i.test(text);
115
+ const driver = /r(\d{3})\+?\s*driver/i.exec(text);
116
+ const weights = /(\d+)\s*[-–]\s*(\d+)\s*GB of weights/i.exec(text);
117
+ const notes = [];
118
+ if (blackwellOnly)
119
+ notes.push('Needs a Blackwell GPU (RTX 5090 or RTX PRO 6000); older cards cannot run the nvfp4 weights.');
120
+ if (driver)
121
+ notes.push(`The host needs NVIDIA driver r${driver[1]} or newer.`);
122
+ if (weights)
123
+ notes.push(`First start downloads ${weights[1]} to ${weights[2]} GB of weights, so expect a long startup.`);
124
+ return { blackwellOnly, minDriver: driver ? `r${driver[1]}` : null, notes };
125
+ }
126
+ export const isBlackwell = (name, slug) => /\b50\d0\b|pro.?6000|rtx.?pro|b200|b100|gb200/i.test(`${name} ${slug}`);
127
+ export function exposesPorts(definition) {
128
+ const ops = definition.ops ?? [];
129
+ return ops.some((op) => op.args?.expose !== undefined && op.args.expose !== null);
130
+ }
131
+ export function vramFromDefinition(definition) {
132
+ const mb = definition.meta?.system_requirements?.vram_total_mb;
133
+ return typeof mb === 'number' && mb > 0 ? Math.ceil(mb / 1024) : null;
134
+ }
135
+ const opsOf = (definition) => (definition.ops ?? []);
136
+ export function kindOfDefinition(definition, category = []) {
137
+ const images = opsOf(definition).map((op) => op.args?.image ?? '').join(' ').toLowerCase();
138
+ if (/comfyui/.test(images))
139
+ return 'comfyui';
140
+ if (/ollama|vllm|text-generation|sglang|llama\.cpp|lmdeploy/.test(images) || category.includes('LLM'))
141
+ return 'llm';
142
+ if (/jupyter/.test(images))
143
+ return 'notebook';
144
+ if (/vscode|code-server|rstudio/.test(images))
145
+ return 'ide';
146
+ if (/whisper/.test(images) || category.includes('ASR'))
147
+ return 'asr';
148
+ if (category.includes('Web UI'))
149
+ return 'webui';
150
+ return 'custom';
151
+ }
152
+ export function llmFlavor(definition) {
153
+ const images = opsOf(definition).map((op) => op.args?.image ?? '').join(' ').toLowerCase();
154
+ if (/ollama/.test(images))
155
+ return 'ollama';
156
+ if (/vllm/.test(images))
157
+ return 'vllm';
158
+ return 'other';
159
+ }
160
+ /** Ports a job definition exposes, from `expose: 8188`, `expose: { port }` or an array of either. */
161
+ export function exposedPorts(definition) {
162
+ const ports = [];
163
+ for (const op of opsOf(definition)) {
164
+ const raw = op.args?.expose;
165
+ const items = Array.isArray(raw) ? raw : raw === undefined || raw === null ? [] : [raw];
166
+ for (const item of items) {
167
+ const port = typeof item === 'number' ? item : typeof item === 'string' ? Number(item) : Number(item?.port);
168
+ if (Number.isFinite(port) && port > 0)
169
+ ports.push(port);
170
+ }
171
+ }
172
+ return [...new Set(ports)];
173
+ }
174
+ export const primaryOpId = (definition) => opsOf(definition)[0]?.id ?? null;
175
+ /** URL path that proves the service itself (not just the tunnel) answers. */
176
+ export function readinessPath(kind, flavor = 'other') {
177
+ if (kind === 'llm')
178
+ return flavor === 'ollama' ? '/api/tags' : '/v1/models';
179
+ return '/';
180
+ }
181
+ /** Rough time from "host assigned" to "service answers", driven by what has to be downloaded first. */
182
+ export function typicalBootMinutes(definition, kind) {
183
+ const resources = opsOf(definition).flatMap((op) => op.args?.resources ?? []);
184
+ if (resources.some((r) => r.type === 'HF' || r.type === 'S3'))
185
+ return 10;
186
+ if (resources.some((r) => r.type === 'Ollama') || kind === 'llm')
187
+ return 5;
188
+ return 2;
189
+ }
190
+ //# sourceMappingURL=templates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"templates.js","sourceRoot":"","sources":["../../src/core/templates.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,73 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire } from 'node:module';
3
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
4
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
5
+ import { z } from 'zod';
6
+ import { formatError, stripAnsi } from '../core/format.js';
7
+ import { CliError } from '../core/client.js';
8
+ import { gpusResource, prompts, templatesResource, ToolContext, tools, WAIT_MAX_SECONDS } from './tools.js';
9
+ const { version } = createRequire(import.meta.url)('../../package.json');
10
+ const network = process.env.NOSANA_NETWORK === 'devnet' ? 'devnet' : 'mainnet';
11
+ const ctx = new ToolContext(network);
12
+ const server = new McpServer({ name: 'nosana', version }, {
13
+ instructions: [
14
+ 'Nosana MCP rents GPUs on the Nosana network and deploys ready-to-run templates (MiniMax H3 video, Qwen/Gemma/GPT-OSS LLMs, DeepSeek, ComfyUI, Jupyter, VS Code) or custom job definitions, paid with the account credits behind the API key. 1 credit is priced like 1 USD.',
15
+ 'Start with recommend_plan(workload). Prefer GPUs in ready_now (fits, idle host). Queue on a fits_but_queued GPU only if the user accepts waiting (accept_queue=true). Use an idle_with_risk GPU only if the user accepts the caveat (force=true). Never use an unsupported GPU.',
16
+ 'Always show the user the estimated credits and USD per hour before create_deployment, and pass confirm=true only after they agree. Check running_similar first; do not stack a second copy of the same workload without asking.',
17
+ `Nosana refuses timeouts under 60 minutes. Poll wait_for_deployment with max_seconds <= ${WAIT_MAX_SECONDS} and relay the phase to the user; big templates take 5 to 15 minutes to download weights. outcome "stopped" means the user or the timeout stopped it, not a failure.`,
18
+ 'Every response is a JSON object with ok, message, and next_tool/next_args suggesting the next call. When the workload is online, call get_endpoint_usage and hand the user the URL plus how to use it. Idle deployments burn credits: remind the user to stop_deployment when done.',
19
+ ].join(' '),
20
+ });
21
+ const envelopeShape = {
22
+ ok: z.boolean().describe('false only when the tool itself failed (bad input, missing key, API error).'),
23
+ message: z.string().describe('Human-readable summary to relay to the user.'),
24
+ next_tool: z.string().nullable().optional().describe('Suggested next tool, or null when nothing else is needed.'),
25
+ next_args: z.record(z.string(), z.unknown()).optional().describe('Suggested arguments for next_tool.'),
26
+ };
27
+ // Loose: every tool adds its own fields on top of the envelope, and clients validate structuredContent strictly.
28
+ const envelopeSchema = z.looseObject(envelopeShape);
29
+ const toResult = (envelope, isError = false) => ({
30
+ isError,
31
+ content: [{ type: 'text', text: stripAnsi(JSON.stringify(envelope, null, 2)) }],
32
+ structuredContent: envelope,
33
+ });
34
+ for (const definition of tools) {
35
+ server.registerTool(definition.name, {
36
+ title: definition.title,
37
+ description: `${definition.description} Returns JSON: {ok, message, next_tool, next_args, ...tool-specific fields}.`,
38
+ inputSchema: definition.shape,
39
+ outputSchema: envelopeSchema,
40
+ annotations: definition.annotations,
41
+ }, async (args) => {
42
+ try {
43
+ return toResult(await definition.run(ctx, args));
44
+ }
45
+ catch (error) {
46
+ const message = stripAnsi(formatError(error));
47
+ const hint = error instanceof CliError && error.exitCode === 2
48
+ ? 'Fix the arguments and call again.'
49
+ : /No Nosana API key/.test(message)
50
+ ? 'Call doctor for the exact configuration fix.'
51
+ : /fetch failed|ENOTFOUND|timed out|50[234]/.test(message)
52
+ ? 'Transient network problem talking to Nosana; retry in a few seconds.'
53
+ : undefined;
54
+ return toResult({ ok: false, message, error: message, hint, next_tool: /No Nosana API key/.test(message) ? 'doctor' : null }, true);
55
+ }
56
+ });
57
+ }
58
+ server.registerResource('templates', 'nosana://templates', { title: 'Nosana templates', description: 'Ready-to-run template catalog with kinds, variants and VRAM needs.', mimeType: 'application/json' }, async (uri) => ({ contents: [{ uri: uri.href, mimeType: 'application/json', text: await templatesResource(ctx) }] }));
59
+ server.registerResource('gpus', 'nosana://gpus', { title: 'Nosana GPU markets', description: 'GPU markets bucketed by idle availability with price per hour.', mimeType: 'application/json' }, async (uri) => ({ contents: [{ uri: uri.href, mimeType: 'application/json', text: await gpusResource(ctx) }] }));
60
+ const message = (text) => ({ messages: [{ role: 'user', content: { type: 'text', text } }] });
61
+ server.registerPrompt('deploy_template', {
62
+ title: 'Deploy any Nosana template',
63
+ description: 'Generic flow: recommend_plan, confirm cost, create, poll, hand back the URL and usage, remind to stop.',
64
+ argsSchema: { workload: z.string().describe('Template id, "id/variant", or a loose name like "qwen 27b"'), gpu: z.string().optional(), timeout_minutes: z.string().optional() },
65
+ }, ({ workload, gpu, timeout_minutes }) => message(prompts.deploy_template(workload, gpu, timeout_minutes)));
66
+ server.registerPrompt('deploy_llm', { title: 'Deploy an LLM with an OpenAI-compatible endpoint', description: 'Qwen, Gemma, GPT-OSS or DeepSeek on the cheapest GPU that fits; returns OPENAI_BASE_URL.', argsSchema: { model: z.string().optional().describe('e.g. qwen3-6-27b, gemma3-12b, gpt-oss-20b') } }, ({ model }) => message(prompts.deploy_llm(model)));
67
+ server.registerPrompt('deploy_comfy', { title: 'Deploy ComfyUI', description: 'Generic ComfyUI or MiniMax H3 with the right GPU class.', argsSchema: { workflow: z.string().optional().describe('e.g. comfyui/sdxl or minimax-h3/i2v-32gb') } }, ({ workflow }) => message(prompts.deploy_comfy(workflow)));
68
+ server.registerPrompt('deploy_minimax_h3', { title: 'Deploy MiniMax H3 on Nosana', description: 'MiniMax H3 video generation in ComfyUI on a Blackwell GPU.', argsSchema: { variant: z.string().optional().describe('i2v-32gb, i2v-80gb, ref2v-32gb or ref2v-80gb'), gpu: z.string().optional() } }, ({ variant, gpu }) => message(prompts.deploy_minimax_h3(variant, gpu)));
69
+ server.registerPrompt('stop_when_done', { title: 'Stop running deployments', description: 'List what is running and stop it so billing ends.', argsSchema: {} }, () => message(prompts.stop_when_done()));
70
+ const transport = new StdioServerTransport();
71
+ await server.connect(transport);
72
+ process.stderr.write(`[nosana-mcp] v${version} ready on stdio (${network}); ${tools.length} tools\n`);
73
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":"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"}