@agentwonderland/mcp 0.1.2 → 0.1.4

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.
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Check if a string looks like a local file path (not a URL).
3
+ */
4
+ export declare function isLocalFilePath(value: string): boolean;
5
+ /**
6
+ * Scan input object for local file paths, upload them to temporary storage,
7
+ * and replace with download URLs. Non-file values are left unchanged.
8
+ */
9
+ export declare function uploadLocalFiles(input: Record<string, unknown>): Promise<Record<string, unknown>>;
@@ -0,0 +1,101 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { basename, resolve } from "node:path";
3
+ import { homedir } from "node:os";
4
+ import { getApiUrl } from "./config.js";
5
+ const EXT_TO_MIME = {
6
+ pdf: "application/pdf",
7
+ png: "image/png",
8
+ jpg: "image/jpeg",
9
+ jpeg: "image/jpeg",
10
+ gif: "image/gif",
11
+ webp: "image/webp",
12
+ svg: "image/svg+xml",
13
+ mp3: "audio/mpeg",
14
+ mp4: "video/mp4",
15
+ wav: "audio/wav",
16
+ csv: "text/csv",
17
+ json: "application/json",
18
+ txt: "text/plain",
19
+ html: "text/html",
20
+ xml: "application/xml",
21
+ zip: "application/zip",
22
+ doc: "application/msword",
23
+ docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
24
+ xls: "application/vnd.ms-excel",
25
+ xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
26
+ };
27
+ const MAX_UPLOAD_SIZE = 50 * 1024 * 1024; // 50MB
28
+ /**
29
+ * Check if a string looks like a local file path (not a URL).
30
+ */
31
+ export function isLocalFilePath(value) {
32
+ if (value.startsWith("http://") || value.startsWith("https://") || value.startsWith("data:")) {
33
+ return false;
34
+ }
35
+ if (value.includes("\n"))
36
+ return false;
37
+ // Unix absolute path, home dir path, or Windows drive path
38
+ return value.startsWith("/") || value.startsWith("~/") || /^[A-Za-z]:\\/.test(value);
39
+ }
40
+ function resolvePath(filePath) {
41
+ if (filePath.startsWith("~/")) {
42
+ return resolve(homedir(), filePath.slice(2));
43
+ }
44
+ return resolve(filePath);
45
+ }
46
+ function getMimeType(filename) {
47
+ const ext = filename.split(".").pop()?.toLowerCase() ?? "";
48
+ return EXT_TO_MIME[ext] ?? "application/octet-stream";
49
+ }
50
+ /**
51
+ * Upload a local file to the gateway's temporary storage.
52
+ * Returns the presigned download URL.
53
+ */
54
+ async function uploadFile(filePath) {
55
+ const resolved = resolvePath(filePath);
56
+ const buffer = readFileSync(resolved);
57
+ if (buffer.length > MAX_UPLOAD_SIZE) {
58
+ throw new Error(`File ${basename(resolved)} exceeds 50MB upload limit (${(buffer.length / (1024 * 1024)).toFixed(1)}MB)`);
59
+ }
60
+ const filename = basename(resolved);
61
+ const contentType = getMimeType(filename);
62
+ const apiUrl = getApiUrl();
63
+ const res = await fetch(`${apiUrl}/uploads`, {
64
+ method: "POST",
65
+ headers: { "Content-Type": "application/json" },
66
+ body: JSON.stringify({
67
+ file: buffer.toString("base64"),
68
+ filename,
69
+ content_type: contentType,
70
+ }),
71
+ });
72
+ if (!res.ok) {
73
+ const body = await res.json().catch(() => ({}));
74
+ throw new Error(`Upload failed: ${body.error ?? res.statusText}`);
75
+ }
76
+ const result = await res.json();
77
+ return result.url;
78
+ }
79
+ /**
80
+ * Scan input object for local file paths, upload them to temporary storage,
81
+ * and replace with download URLs. Non-file values are left unchanged.
82
+ */
83
+ export async function uploadLocalFiles(input) {
84
+ const result = { ...input };
85
+ for (const [key, value] of Object.entries(result)) {
86
+ if (typeof value !== "string")
87
+ continue;
88
+ if (!isLocalFilePath(value))
89
+ continue;
90
+ const resolved = resolvePath(value);
91
+ if (!existsSync(resolved))
92
+ continue;
93
+ try {
94
+ result[key] = await uploadFile(value);
95
+ }
96
+ catch {
97
+ // Leave original value if upload fails
98
+ }
99
+ }
100
+ return result;
101
+ }
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Shared display formatters for human-readable MCP and CLI output.
2
+ * Shared display formatters for human-readable MCP output.
3
3
  * Plain text only — no ANSI color codes.
4
4
  */
5
5
  export declare function stars(rating: number | null | undefined): string;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Shared display formatters for human-readable MCP and CLI output.
2
+ * Shared display formatters for human-readable MCP output.
3
3
  * Plain text only — no ANSI color codes.
4
4
  */
5
5
  // ── Stars ────────────────────────────────────────────────────────
@@ -180,7 +180,7 @@ export function formatFeedbackSummary(stats) {
180
180
  }
181
181
  export function formatWalletStatus(info) {
182
182
  if (info.wallets.length === 0 && !info.card) {
183
- return "No payment methods configured.\nRun: aw wallet setup";
183
+ return "No payment methods configured.\nUse the wallet_setup tool to create or import a wallet.";
184
184
  }
185
185
  const lines = ["Payment methods:"];
186
186
  for (const w of info.wallets) {
@@ -4,3 +4,4 @@ export * from "./payments.js";
4
4
  export * from "./ows-adapter.js";
5
5
  export * from "./formatters.js";
6
6
  export * from "./types.js";
7
+ export * from "./file-upload.js";
@@ -4,3 +4,4 @@ export * from "./payments.js";
4
4
  export * from "./ows-adapter.js";
5
5
  export * from "./formatters.js";
6
6
  export * from "./types.js";
7
+ export * from "./file-upload.js";
@@ -5,7 +5,7 @@
5
5
  * any other viem-based flow can use OWS-managed keys transparently.
6
6
  *
7
7
  * The OWS SDK (`@open-wallet-standard/core`) is a NAPI native module.
8
- * ALL imports are dynamic so the CLI works without OWS installed.
8
+ * ALL imports are dynamic so the MCP server works without OWS installed.
9
9
  */
10
10
  import type { LocalAccount } from "viem/accounts";
11
11
  /**
@@ -5,17 +5,29 @@
5
5
  * any other viem-based flow can use OWS-managed keys transparently.
6
6
  *
7
7
  * The OWS SDK (`@open-wallet-standard/core`) is a NAPI native module.
8
- * ALL imports are dynamic so the CLI works without OWS installed.
8
+ * ALL imports are dynamic so the MCP server works without OWS installed.
9
9
  */
10
10
  // ── Helpers ──────────────────────────────────────────────────────
11
11
  const OWS_INSTALL_HINT = "OWS is not installed. Install with: npm install -g @open-wallet-standard/core";
12
12
  async function loadOws() {
13
+ // Try local/project resolution first
13
14
  try {
14
15
  // @ts-ignore — optional peer dep, dynamically imported
15
16
  return (await import("@open-wallet-standard/core"));
16
17
  }
17
18
  catch {
18
- throw new Error(OWS_INSTALL_HINT);
19
+ // Fallback: resolve from global npm prefix using createRequire
20
+ // (npx runs in an isolated context that can't see globally-installed native modules)
21
+ try {
22
+ const { execSync } = await import("node:child_process");
23
+ const { createRequire } = await import("node:module");
24
+ const globalRoot = execSync("npm root -g", { encoding: "utf-8" }).trim();
25
+ const globalRequire = createRequire(globalRoot + "/");
26
+ return globalRequire("@open-wallet-standard/core");
27
+ }
28
+ catch {
29
+ throw new Error(OWS_INSTALL_HINT);
30
+ }
19
31
  }
20
32
  }
21
33
  function findEvmAccount(wallet) {
@@ -32,8 +44,7 @@ function findEvmAccount(wallet) {
32
44
  */
33
45
  export async function isOwsAvailable() {
34
46
  try {
35
- // @ts-ignore — optional peer dep, dynamically imported
36
- await import("@open-wallet-standard/core");
47
+ await loadOws();
37
48
  return true;
38
49
  }
39
50
  catch {
@@ -27,7 +27,7 @@ export declare function getConfiguredMethods(): string[];
27
27
  export declare function paymentMethodDisplayName(method: string): string;
28
28
  /**
29
29
  * Return the consumer's configured payment methods in registry API format.
30
- * Maps CLI method names (tempo, base, card) to registry identifiers
30
+ * Maps method names (tempo, base, card) to registry identifiers
31
31
  * (tempo_usdc, base_usdc, stripe_card).
32
32
  */
33
33
  export declare function getAcceptedPaymentMethods(): string[];
@@ -102,13 +102,13 @@ export async function getPaymentFetch(method) {
102
102
  fetchCache.set(ck, pf);
103
103
  return pf;
104
104
  }
105
- throw new Error('Payment method "card" is not configured. Run: aw wallet setup');
105
+ throw new Error('Payment method "card" is not configured. Use the wallet_setup tool to configure a wallet');
106
106
  }
107
107
  // Explicit method requested (wallet ID or chain name)
108
108
  if (method) {
109
109
  const resolved = resolveWalletAndChain(method);
110
110
  if (!resolved) {
111
- throw new Error(`Payment method "${method}" is not configured. Run: aw wallet setup`);
111
+ throw new Error(`Payment method "${method}" is not configured. Use the wallet_setup tool to configure a wallet`);
112
112
  }
113
113
  const ck = cacheKey(resolved.wallet.id, resolved.chain);
114
114
  if (fetchCache.has(ck))
@@ -118,7 +118,7 @@ export async function getPaymentFetch(method) {
118
118
  fetchCache.set(ck, pf);
119
119
  return pf;
120
120
  }
121
- throw new Error(`Payment method "${method}" is not configured. Run: aw wallet setup`);
121
+ throw new Error(`Payment method "${method}" is not configured. Use the wallet_setup tool to configure a wallet`);
122
122
  }
123
123
  // Auto-detect: try default wallet, then card
124
124
  const configured = getConfiguredMethods();
@@ -197,7 +197,7 @@ export function paymentMethodDisplayName(method) {
197
197
  }
198
198
  /**
199
199
  * Return the consumer's configured payment methods in registry API format.
200
- * Maps CLI method names (tempo, base, card) to registry identifiers
200
+ * Maps method names (tempo, base, card) to registry identifiers
201
201
  * (tempo_usdc, base_usdc, stripe_card).
202
202
  */
203
203
  export function getAcceptedPaymentMethods() {
package/dist/tools/run.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { z } from "zod";
2
2
  import { apiGet, apiPostWithPayment } from "../core/api-client.js";
3
+ import { uploadLocalFiles } from "../core/file-upload.js";
3
4
  import { getConfiguredMethods, hasWalletConfigured } from "../core/payments.js";
4
5
  import { formatRunResult } from "../core/formatters.js";
5
6
  import { storeFeedbackToken } from "./_token-cache.js";
@@ -30,9 +31,10 @@ export function registerRunTools(server) {
30
31
  }
31
32
  }
32
33
  const method = pay_with;
34
+ const processedInput = await uploadLocalFiles(input);
33
35
  let result;
34
36
  try {
35
- result = await apiPostWithPayment(`/agents/${resolvedId}/run`, { input }, method);
37
+ result = await apiPostWithPayment(`/agents/${resolvedId}/run`, { input: processedInput }, method);
36
38
  }
37
39
  catch (err) {
38
40
  const apiErr = err;
@@ -2,6 +2,7 @@ import { z } from "zod";
2
2
  import { apiGet, apiPost, apiPostWithPayment } from "../core/api-client.js";
3
3
  import { hasWalletConfigured, getConfiguredMethods, getAcceptedPaymentMethods, } from "../core/payments.js";
4
4
  import { agentList, formatRunResult } from "../core/formatters.js";
5
+ import { uploadLocalFiles } from "../core/file-upload.js";
5
6
  import { storeFeedbackToken } from "./_token-cache.js";
6
7
  function text(t) {
7
8
  return { content: [{ type: "text", text: t }] };
@@ -46,9 +47,10 @@ export function registerSolveTools(server) {
46
47
  const method = pay_with ?? getConfiguredMethods()[0];
47
48
  // Path 1: If authenticated, use the platform /solve route
48
49
  try {
50
+ const processedInput = await uploadLocalFiles(input);
49
51
  const result = await apiPost("/solve", {
50
52
  intent,
51
- input,
53
+ input: processedInput,
52
54
  budget,
53
55
  });
54
56
  const jobId = result.job_id ?? "";
@@ -91,8 +93,9 @@ export function registerSolveTools(server) {
91
93
  ? selectedPrice
92
94
  : (inputTokens / 1000) * selectedPrice;
93
95
  let result;
96
+ const processedInput2 = await uploadLocalFiles(input);
94
97
  try {
95
- result = await apiPostWithPayment(`/agents/${selected.id}/run`, { input }, method);
98
+ result = await apiPostWithPayment(`/agents/${selected.id}/run`, { input: processedInput2 }, method);
96
99
  }
97
100
  catch (err) {
98
101
  const apiErr = err;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentwonderland/mcp",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "type": "module",
5
5
  "description": "MCP server for the Agent Wonderland AI agent marketplace",
6
6
  "bin": {
@@ -0,0 +1,114 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { basename, resolve } from "node:path";
3
+ import { homedir } from "node:os";
4
+ import { getApiUrl } from "./config.js";
5
+
6
+ const EXT_TO_MIME: Record<string, string> = {
7
+ pdf: "application/pdf",
8
+ png: "image/png",
9
+ jpg: "image/jpeg",
10
+ jpeg: "image/jpeg",
11
+ gif: "image/gif",
12
+ webp: "image/webp",
13
+ svg: "image/svg+xml",
14
+ mp3: "audio/mpeg",
15
+ mp4: "video/mp4",
16
+ wav: "audio/wav",
17
+ csv: "text/csv",
18
+ json: "application/json",
19
+ txt: "text/plain",
20
+ html: "text/html",
21
+ xml: "application/xml",
22
+ zip: "application/zip",
23
+ doc: "application/msword",
24
+ docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
25
+ xls: "application/vnd.ms-excel",
26
+ xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
27
+ };
28
+
29
+ const MAX_UPLOAD_SIZE = 50 * 1024 * 1024; // 50MB
30
+
31
+ /**
32
+ * Check if a string looks like a local file path (not a URL).
33
+ */
34
+ export function isLocalFilePath(value: string): boolean {
35
+ if (value.startsWith("http://") || value.startsWith("https://") || value.startsWith("data:")) {
36
+ return false;
37
+ }
38
+ if (value.includes("\n")) return false;
39
+ // Unix absolute path, home dir path, or Windows drive path
40
+ return value.startsWith("/") || value.startsWith("~/") || /^[A-Za-z]:\\/.test(value);
41
+ }
42
+
43
+ function resolvePath(filePath: string): string {
44
+ if (filePath.startsWith("~/")) {
45
+ return resolve(homedir(), filePath.slice(2));
46
+ }
47
+ return resolve(filePath);
48
+ }
49
+
50
+ function getMimeType(filename: string): string {
51
+ const ext = filename.split(".").pop()?.toLowerCase() ?? "";
52
+ return EXT_TO_MIME[ext] ?? "application/octet-stream";
53
+ }
54
+
55
+ /**
56
+ * Upload a local file to the gateway's temporary storage.
57
+ * Returns the presigned download URL.
58
+ */
59
+ async function uploadFile(filePath: string): Promise<string> {
60
+ const resolved = resolvePath(filePath);
61
+ const buffer = readFileSync(resolved);
62
+
63
+ if (buffer.length > MAX_UPLOAD_SIZE) {
64
+ throw new Error(`File ${basename(resolved)} exceeds 50MB upload limit (${(buffer.length / (1024 * 1024)).toFixed(1)}MB)`);
65
+ }
66
+
67
+ const filename = basename(resolved);
68
+ const contentType = getMimeType(filename);
69
+ const apiUrl = getApiUrl();
70
+
71
+ const res = await fetch(`${apiUrl}/uploads`, {
72
+ method: "POST",
73
+ headers: { "Content-Type": "application/json" },
74
+ body: JSON.stringify({
75
+ file: buffer.toString("base64"),
76
+ filename,
77
+ content_type: contentType,
78
+ }),
79
+ });
80
+
81
+ if (!res.ok) {
82
+ const body = await res.json().catch(() => ({})) as Record<string, unknown>;
83
+ throw new Error(`Upload failed: ${body.error ?? res.statusText}`);
84
+ }
85
+
86
+ const result = await res.json() as { url: string };
87
+ return result.url;
88
+ }
89
+
90
+ /**
91
+ * Scan input object for local file paths, upload them to temporary storage,
92
+ * and replace with download URLs. Non-file values are left unchanged.
93
+ */
94
+ export async function uploadLocalFiles(
95
+ input: Record<string, unknown>,
96
+ ): Promise<Record<string, unknown>> {
97
+ const result = { ...input };
98
+
99
+ for (const [key, value] of Object.entries(result)) {
100
+ if (typeof value !== "string") continue;
101
+ if (!isLocalFilePath(value)) continue;
102
+
103
+ const resolved = resolvePath(value);
104
+ if (!existsSync(resolved)) continue;
105
+
106
+ try {
107
+ result[key] = await uploadFile(value);
108
+ } catch {
109
+ // Leave original value if upload fails
110
+ }
111
+ }
112
+
113
+ return result;
114
+ }
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Shared display formatters for human-readable MCP and CLI output.
2
+ * Shared display formatters for human-readable MCP output.
3
3
  * Plain text only — no ANSI color codes.
4
4
  */
5
5
 
@@ -244,7 +244,7 @@ interface WalletInfo {
244
244
 
245
245
  export function formatWalletStatus(info: WalletInfo): string {
246
246
  if (info.wallets.length === 0 && !info.card) {
247
- return "No payment methods configured.\nRun: aw wallet setup";
247
+ return "No payment methods configured.\nUse the wallet_setup tool to create or import a wallet.";
248
248
  }
249
249
 
250
250
  const lines = ["Payment methods:"];
package/src/core/index.ts CHANGED
@@ -4,3 +4,4 @@ export * from "./payments.js";
4
4
  export * from "./ows-adapter.js";
5
5
  export * from "./formatters.js";
6
6
  export * from "./types.js";
7
+ export * from "./file-upload.js";
@@ -5,7 +5,7 @@
5
5
  * any other viem-based flow can use OWS-managed keys transparently.
6
6
  *
7
7
  * The OWS SDK (`@open-wallet-standard/core`) is a NAPI native module.
8
- * ALL imports are dynamic so the CLI works without OWS installed.
8
+ * ALL imports are dynamic so the MCP server works without OWS installed.
9
9
  */
10
10
 
11
11
  import type { LocalAccount } from "viem/accounts";
@@ -93,11 +93,22 @@ const OWS_INSTALL_HINT =
93
93
  "OWS is not installed. Install with: npm install -g @open-wallet-standard/core";
94
94
 
95
95
  async function loadOws(): Promise<OwsSdk> {
96
+ // Try local/project resolution first
96
97
  try {
97
98
  // @ts-ignore — optional peer dep, dynamically imported
98
99
  return (await import("@open-wallet-standard/core")) as unknown as OwsSdk;
99
100
  } catch {
100
- throw new Error(OWS_INSTALL_HINT);
101
+ // Fallback: resolve from global npm prefix using createRequire
102
+ // (npx runs in an isolated context that can't see globally-installed native modules)
103
+ try {
104
+ const { execSync } = await import("node:child_process");
105
+ const { createRequire } = await import("node:module");
106
+ const globalRoot = execSync("npm root -g", { encoding: "utf-8" }).trim();
107
+ const globalRequire = createRequire(globalRoot + "/");
108
+ return globalRequire("@open-wallet-standard/core") as unknown as OwsSdk;
109
+ } catch {
110
+ throw new Error(OWS_INSTALL_HINT);
111
+ }
101
112
  }
102
113
  }
103
114
 
@@ -123,8 +134,7 @@ function findEvmAccount(
123
134
  */
124
135
  export async function isOwsAvailable(): Promise<boolean> {
125
136
  try {
126
- // @ts-ignore — optional peer dep, dynamically imported
127
- await import("@open-wallet-standard/core");
137
+ await loadOws();
128
138
  return true;
129
139
  } catch {
130
140
  return false;
@@ -121,14 +121,14 @@ export async function getPaymentFetch(method?: string): Promise<typeof fetch> {
121
121
  fetchCache.set(ck, pf);
122
122
  return pf;
123
123
  }
124
- throw new Error('Payment method "card" is not configured. Run: aw wallet setup');
124
+ throw new Error('Payment method "card" is not configured. Use the wallet_setup tool to configure a wallet');
125
125
  }
126
126
 
127
127
  // Explicit method requested (wallet ID or chain name)
128
128
  if (method) {
129
129
  const resolved = resolveWalletAndChain(method);
130
130
  if (!resolved) {
131
- throw new Error(`Payment method "${method}" is not configured. Run: aw wallet setup`);
131
+ throw new Error(`Payment method "${method}" is not configured. Use the wallet_setup tool to configure a wallet`);
132
132
  }
133
133
  const ck = cacheKey(resolved.wallet.id, resolved.chain);
134
134
  if (fetchCache.has(ck)) return fetchCache.get(ck)!;
@@ -137,7 +137,7 @@ export async function getPaymentFetch(method?: string): Promise<typeof fetch> {
137
137
  fetchCache.set(ck, pf);
138
138
  return pf;
139
139
  }
140
- throw new Error(`Payment method "${method}" is not configured. Run: aw wallet setup`);
140
+ throw new Error(`Payment method "${method}" is not configured. Use the wallet_setup tool to configure a wallet`);
141
141
  }
142
142
 
143
143
  // Auto-detect: try default wallet, then card
@@ -219,7 +219,7 @@ export function paymentMethodDisplayName(method: string): string {
219
219
 
220
220
  /**
221
221
  * Return the consumer's configured payment methods in registry API format.
222
- * Maps CLI method names (tempo, base, card) to registry identifiers
222
+ * Maps method names (tempo, base, card) to registry identifiers
223
223
  * (tempo_usdc, base_usdc, stripe_card).
224
224
  */
225
225
  export function getAcceptedPaymentMethods(): string[] {
package/src/tools/run.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
2
  import { z } from "zod";
3
3
  import { apiGet, apiPostWithPayment } from "../core/api-client.js";
4
+ import { uploadLocalFiles } from "../core/file-upload.js";
4
5
  import { getConfiguredMethods, hasWalletConfigured } from "../core/payments.js";
5
6
  import { formatRunResult } from "../core/formatters.js";
6
7
  import { storeFeedbackToken } from "./_token-cache.js";
@@ -40,11 +41,12 @@ export function registerRunTools(server: McpServer): void {
40
41
  }
41
42
 
42
43
  const method = pay_with;
44
+ const processedInput = await uploadLocalFiles(input);
43
45
  let result: Record<string, unknown>;
44
46
  try {
45
47
  result = await apiPostWithPayment<Record<string, unknown>>(
46
48
  `/agents/${resolvedId}/run`,
47
- { input },
49
+ { input: processedInput },
48
50
  method,
49
51
  );
50
52
  } catch (err: unknown) {
@@ -7,6 +7,7 @@ import {
7
7
  getAcceptedPaymentMethods,
8
8
  } from "../core/payments.js";
9
9
  import { agentList, formatRunResult } from "../core/formatters.js";
10
+ import { uploadLocalFiles } from "../core/file-upload.js";
10
11
  import type { AgentRecord } from "../core/types.js";
11
12
  import { storeFeedbackToken } from "./_token-cache.js";
12
13
 
@@ -65,9 +66,10 @@ export function registerSolveTools(server: McpServer): void {
65
66
 
66
67
  // Path 1: If authenticated, use the platform /solve route
67
68
  try {
69
+ const processedInput = await uploadLocalFiles(input);
68
70
  const result = await apiPost<Record<string, unknown>>("/solve", {
69
71
  intent,
70
- input,
72
+ input: processedInput,
71
73
  budget,
72
74
  });
73
75
  const jobId = (result as Record<string, unknown>).job_id as string ?? "";
@@ -119,10 +121,11 @@ export function registerSolveTools(server: McpServer): void {
119
121
  : (inputTokens / 1000) * selectedPrice;
120
122
 
121
123
  let result: Record<string, unknown>;
124
+ const processedInput2 = await uploadLocalFiles(input);
122
125
  try {
123
126
  result = await apiPostWithPayment<Record<string, unknown>>(
124
127
  `/agents/${selected.id}/run`,
125
- { input },
128
+ { input: processedInput2 },
126
129
  method,
127
130
  );
128
131
  } catch (err: unknown) {