@runapi.ai/mcp 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/LICENSE +201 -0
- package/README.md +367 -0
- package/data/contract.json +3493 -0
- package/data/pricing.json +1263 -0
- package/dist/bin/runapi-mcp.d.ts +2 -0
- package/dist/bin/runapi-mcp.js +10 -0
- package/dist/bin/runapi-mcp.js.map +1 -0
- package/dist/scripts/sync-data.d.ts +2 -0
- package/dist/scripts/sync-data.js +22 -0
- package/dist/scripts/sync-data.js.map +1 -0
- package/dist/src/config.d.ts +7 -0
- package/dist/src/config.js +32 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/constants.d.ts +5 -0
- package/dist/src/constants.js +6 -0
- package/dist/src/constants.js.map +1 -0
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.js +6 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/init.d.ts +1 -0
- package/dist/src/init.js +52 -0
- package/dist/src/init.js.map +1 -0
- package/dist/src/lib/contract.d.ts +21 -0
- package/dist/src/lib/contract.js +81 -0
- package/dist/src/lib/contract.js.map +1 -0
- package/dist/src/lib/data.d.ts +3 -0
- package/dist/src/lib/data.js +22 -0
- package/dist/src/lib/data.js.map +1 -0
- package/dist/src/lib/errors.d.ts +10 -0
- package/dist/src/lib/errors.js +88 -0
- package/dist/src/lib/errors.js.map +1 -0
- package/dist/src/lib/input-rules.d.ts +9 -0
- package/dist/src/lib/input-rules.js +61 -0
- package/dist/src/lib/input-rules.js.map +1 -0
- package/dist/src/lib/pricing.d.ts +7 -0
- package/dist/src/lib/pricing.js +42 -0
- package/dist/src/lib/pricing.js.map +1 -0
- package/dist/src/lib/runapi-client.d.ts +22 -0
- package/dist/src/lib/runapi-client.js +119 -0
- package/dist/src/lib/runapi-client.js.map +1 -0
- package/dist/src/lib/schema.d.ts +3 -0
- package/dist/src/lib/schema.js +44 -0
- package/dist/src/lib/schema.js.map +1 -0
- package/dist/src/lib/text.d.ts +5 -0
- package/dist/src/lib/text.js +27 -0
- package/dist/src/lib/text.js.map +1 -0
- package/dist/src/lib/tool-response.d.ts +6 -0
- package/dist/src/lib/tool-response.js +11 -0
- package/dist/src/lib/tool-response.js.map +1 -0
- package/dist/src/server-instructions.d.ts +1 -0
- package/dist/src/server-instructions.js +66 -0
- package/dist/src/server-instructions.js.map +1 -0
- package/dist/src/server.d.ts +2 -0
- package/dist/src/server.js +20 -0
- package/dist/src/server.js.map +1 -0
- package/dist/src/tools/authenticated-handlers.d.ts +77 -0
- package/dist/src/tools/authenticated-handlers.js +144 -0
- package/dist/src/tools/authenticated-handlers.js.map +1 -0
- package/dist/src/tools/authenticated.d.ts +3 -0
- package/dist/src/tools/authenticated.js +53 -0
- package/dist/src/tools/authenticated.js.map +1 -0
- package/dist/src/tools/catalog-handlers.d.ts +88 -0
- package/dist/src/tools/catalog-handlers.js +104 -0
- package/dist/src/tools/catalog-handlers.js.map +1 -0
- package/dist/src/tools/catalog.d.ts +3 -0
- package/dist/src/tools/catalog.js +29 -0
- package/dist/src/tools/catalog.js.map +1 -0
- package/dist/src/types.d.ts +75 -0
- package/dist/src/types.js +2 -0
- package/dist/src/types.js.map +1 -0
- package/package.json +66 -0
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { USER_AGENT } from "../constants.js";
|
|
2
|
+
import { loadConfig, requireApiKey } from "../config.js";
|
|
3
|
+
import { errorFromResponse, PollTimeoutError } from "./errors.js";
|
|
4
|
+
const COMPLETED_STATUSES = new Set(["completed", "complete", "succeeded", "success", "finished"]);
|
|
5
|
+
const FAILED_STATUSES = new Set(["failed", "error", "canceled", "cancelled", "timeout"]);
|
|
6
|
+
export class RunApiClient {
|
|
7
|
+
config;
|
|
8
|
+
fetchImpl;
|
|
9
|
+
constructor(config = loadConfig(), fetchImpl = fetch) {
|
|
10
|
+
this.config = config;
|
|
11
|
+
this.fetchImpl = fetchImpl;
|
|
12
|
+
}
|
|
13
|
+
async listModels() {
|
|
14
|
+
return this.request("GET", "/v1/models", { auth: false });
|
|
15
|
+
}
|
|
16
|
+
async balance() {
|
|
17
|
+
return this.request("GET", "/api/v1/me/balance", { auth: true });
|
|
18
|
+
}
|
|
19
|
+
async createTask(service, action, params) {
|
|
20
|
+
return this.request("POST", `/api/v1/${routeServiceSlug(service)}/${action}`, {
|
|
21
|
+
auth: true,
|
|
22
|
+
body: params
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
async getTask(service, taskId, action) {
|
|
26
|
+
const routeService = routeServiceSlug(service);
|
|
27
|
+
const path = action ? `/api/v1/${routeService}/${action}/${taskId}` : `/api/v1/${routeService}/${taskId}`;
|
|
28
|
+
return this.request("GET", path, {
|
|
29
|
+
auth: true
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
async pollTask(service, taskId, action, options = {}) {
|
|
33
|
+
const timeoutMs = options.timeoutMs ?? 120_000;
|
|
34
|
+
const intervalMs = options.intervalMs ?? 5_000;
|
|
35
|
+
const startedAt = Date.now();
|
|
36
|
+
let lastTask;
|
|
37
|
+
while (Date.now() - startedAt < timeoutMs) {
|
|
38
|
+
const task = await this.getTask(service, taskId, action);
|
|
39
|
+
lastTask = task;
|
|
40
|
+
await options.onProgress?.(task);
|
|
41
|
+
const status = taskStatus(task);
|
|
42
|
+
if (COMPLETED_STATUSES.has(status) || FAILED_STATUSES.has(status)) {
|
|
43
|
+
return task;
|
|
44
|
+
}
|
|
45
|
+
await new Promise((resolve) => setTimeout(resolve, intervalMs));
|
|
46
|
+
}
|
|
47
|
+
throw new PollTimeoutError(`Timed out waiting for RunAPI task ${taskId}. Last status: ${taskStatus(lastTask)}.`);
|
|
48
|
+
}
|
|
49
|
+
async chat(params) {
|
|
50
|
+
if (params.api === "chat_completions") {
|
|
51
|
+
return this.request("POST", "/v1/chat/completions", {
|
|
52
|
+
auth: true,
|
|
53
|
+
body: {
|
|
54
|
+
model: params.model,
|
|
55
|
+
messages: params.messages,
|
|
56
|
+
max_tokens: params.max_tokens,
|
|
57
|
+
temperature: params.temperature
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
const system = params.messages.find((message) => message.role === "system")?.content;
|
|
62
|
+
const messages = params.messages.filter((message) => message.role !== "system");
|
|
63
|
+
return this.request("POST", "/v1/messages", {
|
|
64
|
+
auth: true,
|
|
65
|
+
body: {
|
|
66
|
+
model: params.model,
|
|
67
|
+
system,
|
|
68
|
+
messages,
|
|
69
|
+
max_tokens: params.max_tokens ?? 1024,
|
|
70
|
+
temperature: params.temperature
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
async request(method, requestPath, options = {}) {
|
|
75
|
+
const url = new URL(requestPath, this.config.baseUrl.replace(/\/+$/, ""));
|
|
76
|
+
const headers = {
|
|
77
|
+
accept: "application/json",
|
|
78
|
+
"user-agent": USER_AGENT,
|
|
79
|
+
...options.headers
|
|
80
|
+
};
|
|
81
|
+
if (options.body !== undefined) {
|
|
82
|
+
headers["content-type"] = "application/json";
|
|
83
|
+
}
|
|
84
|
+
if (options.auth !== false) {
|
|
85
|
+
headers.authorization = `Bearer ${requireApiKey(this.config)}`;
|
|
86
|
+
}
|
|
87
|
+
const response = await this.fetchImpl(url, {
|
|
88
|
+
method,
|
|
89
|
+
headers,
|
|
90
|
+
body: options.body === undefined ? undefined : JSON.stringify(options.body)
|
|
91
|
+
});
|
|
92
|
+
if (!response.ok) {
|
|
93
|
+
throw await errorFromResponse(response);
|
|
94
|
+
}
|
|
95
|
+
if (response.status === 204) {
|
|
96
|
+
return undefined;
|
|
97
|
+
}
|
|
98
|
+
return await response.json();
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
export function taskStatus(task) {
|
|
102
|
+
const status = task?.status || task?.state || nestedString(task?.data, "status");
|
|
103
|
+
return typeof status === "string" ? status.toLowerCase() : "unknown";
|
|
104
|
+
}
|
|
105
|
+
export function taskIdFromResponse(task) {
|
|
106
|
+
const id = task.id || task.task_id || nestedString(task.data, "id") || nestedString(task.data, "task_id");
|
|
107
|
+
return typeof id === "string" && id.length > 0 ? id : undefined;
|
|
108
|
+
}
|
|
109
|
+
function nestedString(value, key) {
|
|
110
|
+
if (!value || typeof value !== "object") {
|
|
111
|
+
return undefined;
|
|
112
|
+
}
|
|
113
|
+
const nested = value[key];
|
|
114
|
+
return typeof nested === "string" ? nested : undefined;
|
|
115
|
+
}
|
|
116
|
+
function routeServiceSlug(service) {
|
|
117
|
+
return service.replace(/-/g, "_");
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=runapi-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runapi-client.js","sourceRoot":"","sources":["../../../src/lib/runapi-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export function validateParams(fields, params) {
|
|
3
|
+
return z.object(schemaShape(fields)).passthrough().parse(params);
|
|
4
|
+
}
|
|
5
|
+
// The contract stores constraints, not complete JSON Schema. This keeps strict
|
|
6
|
+
// checks for required/enums/ranges while allowing API-specific params to pass through.
|
|
7
|
+
function schemaShape(fields) {
|
|
8
|
+
return Object.fromEntries(Object.entries(fields).map(([name, field]) => [name, zodForField(field)]));
|
|
9
|
+
}
|
|
10
|
+
function zodForField(field) {
|
|
11
|
+
let schema;
|
|
12
|
+
if (field.enum?.length) {
|
|
13
|
+
schema = z.union(field.enum.map((value) => literalFor(value)));
|
|
14
|
+
}
|
|
15
|
+
else if (field.type === "number" || field.type === "integer" || field.min !== undefined || field.max !== undefined || field.minimum !== undefined || field.maximum !== undefined) {
|
|
16
|
+
let numberSchema = z.number();
|
|
17
|
+
const min = field.min ?? field.minimum;
|
|
18
|
+
const max = field.max ?? field.maximum;
|
|
19
|
+
if (min !== undefined) {
|
|
20
|
+
numberSchema = numberSchema.min(min);
|
|
21
|
+
}
|
|
22
|
+
if (max !== undefined) {
|
|
23
|
+
numberSchema = numberSchema.max(max);
|
|
24
|
+
}
|
|
25
|
+
schema = numberSchema;
|
|
26
|
+
}
|
|
27
|
+
else if (field.type === "boolean") {
|
|
28
|
+
schema = z.boolean();
|
|
29
|
+
}
|
|
30
|
+
else if (field.type === "array") {
|
|
31
|
+
schema = z.array(z.unknown());
|
|
32
|
+
}
|
|
33
|
+
else if (field.type === "object") {
|
|
34
|
+
schema = z.record(z.unknown());
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
schema = z.unknown();
|
|
38
|
+
}
|
|
39
|
+
return field.required ? schema : schema.optional();
|
|
40
|
+
}
|
|
41
|
+
function literalFor(value) {
|
|
42
|
+
return z.literal(value);
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../src/lib/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,MAAM,UAAU,cAAc,CAAC,MAAqC,EAAE,MAA+B;IACnG,OAAO,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;AACnE,CAAC;AAED,+EAA+E;AAC/E,uFAAuF;AACvF,SAAS,WAAW,CAAC,MAAqC;IACxD,OAAO,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AACvG,CAAC;AAED,SAAS,WAAW,CAAC,KAAoB;IACvC,IAAI,MAAoB,CAAC;IAEzB,IAAI,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC;QACvB,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,CAA+E,CAAC,CAAC;IAC/I,CAAC;SAAM,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,IAAI,KAAK,CAAC,GAAG,KAAK,SAAS,IAAI,KAAK,CAAC,GAAG,KAAK,SAAS,IAAI,KAAK,CAAC,OAAO,KAAK,SAAS,IAAI,KAAK,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QACnL,IAAI,YAAY,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC;QAC9B,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,IAAI,KAAK,CAAC,OAAO,CAAC;QACvC,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,IAAI,KAAK,CAAC,OAAO,CAAC;QACvC,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;YACtB,YAAY,GAAG,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACvC,CAAC;QACD,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;YACtB,YAAY,GAAG,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACvC,CAAC;QACD,MAAM,GAAG,YAAY,CAAC;IACxB,CAAC;SAAM,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QACpC,MAAM,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC;IACvB,CAAC;SAAM,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;QAClC,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;IAChC,CAAC;SAAM,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QACnC,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;IACjC,CAAC;SAAM,CAAC;QACN,MAAM,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC;IACvB,CAAC;IAED,OAAO,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;AACrD,CAAC;AAED,SAAS,UAAU,CAAC,KAAc;IAChC,OAAO,CAAC,CAAC,OAAO,CAAC,KAAc,CAAC,CAAC;AACnC,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare function humanize(value: string): string;
|
|
2
|
+
export declare function modalityForAction(action: string): "image" | "video" | "audio" | "utility";
|
|
3
|
+
export declare function contractKey(service: string, action: string): string;
|
|
4
|
+
export declare function routeAction(action: string): string;
|
|
5
|
+
export declare function publicModelUrl(model: string): string;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export function humanize(value) {
|
|
2
|
+
return value
|
|
3
|
+
.replace(/[_-]+/g, " ")
|
|
4
|
+
.replace(/\b\w/g, (char) => char.toUpperCase());
|
|
5
|
+
}
|
|
6
|
+
export function modalityForAction(action) {
|
|
7
|
+
if (action.includes("video") || action === "ai_avatar" || action === "motion_control" || action === "animate") {
|
|
8
|
+
return "video";
|
|
9
|
+
}
|
|
10
|
+
if (action.includes("image") || action.includes("background") || action === "create_character") {
|
|
11
|
+
return "image";
|
|
12
|
+
}
|
|
13
|
+
if (action.includes("audio") || action.includes("music") || action.includes("speech") || action.includes("sound") || action.includes("voice") || action.includes("dialogue")) {
|
|
14
|
+
return "audio";
|
|
15
|
+
}
|
|
16
|
+
return "utility";
|
|
17
|
+
}
|
|
18
|
+
export function contractKey(service, action) {
|
|
19
|
+
return `${service}/${action.replaceAll("_", "-")}`;
|
|
20
|
+
}
|
|
21
|
+
export function routeAction(action) {
|
|
22
|
+
return action.replaceAll("-", "_");
|
|
23
|
+
}
|
|
24
|
+
export function publicModelUrl(model) {
|
|
25
|
+
return `https://runapi.ai/pricing?model=${encodeURIComponent(model)}`;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=text.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text.js","sourceRoot":"","sources":["../../../src/lib/text.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,QAAQ,CAAC,KAAa;IACpC,OAAO,KAAK;SACT,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC;SACtB,OAAO,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;AACpD,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,MAAc;IAC9C,IAAI,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,MAAM,KAAK,WAAW,IAAI,MAAM,KAAK,gBAAgB,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QAC9G,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,IAAI,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,MAAM,KAAK,kBAAkB,EAAE,CAAC;QAC/F,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,IAAI,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;QAC7K,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,OAAe,EAAE,MAAc;IACzD,OAAO,GAAG,OAAO,IAAI,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC;AACrD,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,MAAc;IACxC,OAAO,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;AACrC,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,KAAa;IAC1C,OAAO,mCAAmC,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC;AACxE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-response.js","sourceRoot":"","sources":["../../../src/lib/tool-response.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,QAAQ,CAAC,KAAc;IACrC,OAAO;QACL,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,MAAe;gBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;aACrC;SACF;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const SERVER_INSTRUCTIONS: string;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
export const SERVER_INSTRUCTIONS = `
|
|
2
|
+
RunAPI gives this host model discovery, pricing lookup, task creation, task polling, balance checks, and LLM chat.
|
|
3
|
+
|
|
4
|
+
Available tools:
|
|
5
|
+
- list_models: browse models by modality, service, or action. Free, no API key required.
|
|
6
|
+
- list_actions: list endpoint action names grouped by modality. Free, no API key required.
|
|
7
|
+
- get_model_info: inspect params, constraints, and pricing snapshot for a model slug. Pass service and action when known to disambiguate models that support multiple endpoints. Free, no API key required.
|
|
8
|
+
- check_pricing: inspect pricing snapshot for service + action + model. Free, no API key required.
|
|
9
|
+
- check_balance: check account balance and spending. Requires API key.
|
|
10
|
+
- create_task: create a media task and optionally poll for completion. Requires API key.
|
|
11
|
+
- get_task: fetch current status and latest payload for an existing task. Requires API key.
|
|
12
|
+
- chat: send messages to a RunAPI LLM endpoint. Requires API key.
|
|
13
|
+
|
|
14
|
+
Global behavior:
|
|
15
|
+
1. Use the user's language.
|
|
16
|
+
2. Be concise. Do not narrate tool internals unless the user asks.
|
|
17
|
+
3. Do not batch-ask. Ask at most one necessary follow-up before tool use.
|
|
18
|
+
4. Do not mention infrastructure providers, hidden vendors, or implementation partners.
|
|
19
|
+
5. Do not hardcode or guess model slugs. Use list_models and get_model_info.
|
|
20
|
+
6. Do not quote memorized prices. Use check_pricing or link to https://runapi.ai/pricing.
|
|
21
|
+
7. Present task results as task ID, status, output URLs, and cost fields when available.
|
|
22
|
+
8. Do not describe generated media as if you inspected it.
|
|
23
|
+
9. Do not paste raw JSON unless the user asks.
|
|
24
|
+
|
|
25
|
+
Phase 0: API key check
|
|
26
|
+
- Use free catalog tools even when no API key is configured.
|
|
27
|
+
- Before authenticated tools, guide setup with RUNAPI_API_KEY or ~/.config/runapi/config.json.
|
|
28
|
+
- If an authenticated tool returns an API key error, explain the setup and do not retry until the user has fixed configuration.
|
|
29
|
+
|
|
30
|
+
Phase 1: Intent assessment
|
|
31
|
+
- If the user is exploring, call list_models, list_actions, get_model_info, or check_pricing.
|
|
32
|
+
- If the user asks to generate media, identify modality, service, action, model, and params from catalog tools.
|
|
33
|
+
- If the user asks about an existing task, call get_task with service, action when known, and task_id.
|
|
34
|
+
- If the user asks for LLM inference through RunAPI, use chat instead of create_task.
|
|
35
|
+
|
|
36
|
+
Phase 2: Model selection
|
|
37
|
+
- When the user names a model slug, use it after verifying with get_model_info.
|
|
38
|
+
- If get_model_info returns ambiguous matches, call it again with the selected service and action before choosing params.
|
|
39
|
+
- When the user does not name a model, call list_models with a modality/action filter.
|
|
40
|
+
- Compare returned candidates by modality, supported inputs, likely quality/speed tradeoffs, and check_pricing results.
|
|
41
|
+
- Ask one clarifying question only when required to choose a compatible model or required input.
|
|
42
|
+
|
|
43
|
+
Phase 3: Task creation
|
|
44
|
+
- Always verify params with get_model_info before create_task. Include service and action in get_model_info when they are known.
|
|
45
|
+
- If get_model_info returns input_rules, follow them exactly before create_task.
|
|
46
|
+
- Include model in create_task when the selected action requires or supports a model slug.
|
|
47
|
+
- Confirm before expensive, long-running, or batch media requests.
|
|
48
|
+
- For ordinary image requests, wait for completion unless the user wants submit-only behavior.
|
|
49
|
+
- For long-running audio/video/batch work, consider wait=false when the host timeout is likely to interrupt the response, then tell the user to call get_task later.
|
|
50
|
+
- Never retry create_task automatically after a timeout because the original task may still be processing.
|
|
51
|
+
|
|
52
|
+
Phase 4: Result presentation
|
|
53
|
+
- Show task ID, final status, output URLs, and cost fields when available.
|
|
54
|
+
- If task output has multiple URLs, list them all.
|
|
55
|
+
- If task is still processing, show the task ID and how to check it later.
|
|
56
|
+
- Do not describe generated media content as if you inspected it.
|
|
57
|
+
|
|
58
|
+
Phase 5: Error recovery
|
|
59
|
+
- Missing or invalid key: explain RUNAPI_API_KEY and ~/.config/runapi/config.json setup.
|
|
60
|
+
- Insufficient balance: tell the user to add balance in the RunAPI dashboard.
|
|
61
|
+
- Rate limit: wait briefly before one retry only if the user confirms.
|
|
62
|
+
- Service unavailable: use list_models to suggest another compatible RunAPI model.
|
|
63
|
+
- Invalid params: call get_model_info, show valid fields, constraints, and input_rules, and ask for the corrected input.
|
|
64
|
+
- Timeout: do not recreate the task automatically; tell the user to check status with get_task.
|
|
65
|
+
`.trim();
|
|
66
|
+
//# sourceMappingURL=server-instructions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-instructions.js","sourceRoot":"","sources":["../../src/server-instructions.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,mBAAmB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgElC,CAAC,IAAI,EAAE,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { PACKAGE_NAME, PACKAGE_VERSION } from "./constants.js";
|
|
3
|
+
import { SERVER_INSTRUCTIONS } from "./server-instructions.js";
|
|
4
|
+
import { registerAuthenticatedTools } from "./tools/authenticated.js";
|
|
5
|
+
import { registerCatalogTools } from "./tools/catalog.js";
|
|
6
|
+
export function createServer() {
|
|
7
|
+
const server = new McpServer({
|
|
8
|
+
name: PACKAGE_NAME,
|
|
9
|
+
version: PACKAGE_VERSION
|
|
10
|
+
}, {
|
|
11
|
+
instructions: SERVER_INSTRUCTIONS,
|
|
12
|
+
capabilities: {
|
|
13
|
+
tools: {}
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
registerCatalogTools(server);
|
|
17
|
+
registerAuthenticatedTools(server);
|
|
18
|
+
return server;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAC/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAE1D,MAAM,UAAU,YAAY;IAC1B,MAAM,MAAM,GAAG,IAAI,SAAS,CAC1B;QACE,IAAI,EAAE,YAAY;QAClB,OAAO,EAAE,eAAe;KACzB,EACD;QACE,YAAY,EAAE,mBAAmB;QACjC,YAAY,EAAE;YACZ,KAAK,EAAE,EAAE;SACV;KACF,CACF,CAAC;IAEF,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAC7B,0BAA0B,CAAC,MAAM,CAAC,CAAC;IAEnC,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { type RunApiClient } from "../lib/runapi-client.js";
|
|
2
|
+
import type { ChatMessage, RunApiTaskResponse } from "../types.js";
|
|
3
|
+
export type ProgressSender = (message: {
|
|
4
|
+
progressToken: string | number;
|
|
5
|
+
progress: number;
|
|
6
|
+
total: number;
|
|
7
|
+
message: string;
|
|
8
|
+
}) => Promise<void> | void;
|
|
9
|
+
export declare function checkBalanceHandler(client: Pick<RunApiClient, "balance">): Promise<unknown>;
|
|
10
|
+
export declare function createTaskHandler(input: {
|
|
11
|
+
service: string;
|
|
12
|
+
action: string;
|
|
13
|
+
model?: string;
|
|
14
|
+
params?: Record<string, unknown>;
|
|
15
|
+
wait?: boolean;
|
|
16
|
+
timeout_ms?: number;
|
|
17
|
+
poll_interval_ms?: number;
|
|
18
|
+
}, client: Pick<RunApiClient, "createTask" | "pollTask">, sendProgress?: ProgressSender, progressToken?: string | number): Promise<{
|
|
19
|
+
error: string;
|
|
20
|
+
hint: string;
|
|
21
|
+
created?: undefined;
|
|
22
|
+
task_id?: undefined;
|
|
23
|
+
status?: undefined;
|
|
24
|
+
result?: undefined;
|
|
25
|
+
} | {
|
|
26
|
+
created: RunApiTaskResponse;
|
|
27
|
+
task_id: string | undefined;
|
|
28
|
+
status: string;
|
|
29
|
+
error?: undefined;
|
|
30
|
+
hint?: undefined;
|
|
31
|
+
result?: undefined;
|
|
32
|
+
} | {
|
|
33
|
+
task_id: string;
|
|
34
|
+
status: string;
|
|
35
|
+
result: RunApiTaskResponse;
|
|
36
|
+
error?: undefined;
|
|
37
|
+
hint?: undefined;
|
|
38
|
+
created?: undefined;
|
|
39
|
+
} | {
|
|
40
|
+
error: string;
|
|
41
|
+
hint?: undefined;
|
|
42
|
+
created?: undefined;
|
|
43
|
+
task_id?: undefined;
|
|
44
|
+
status?: undefined;
|
|
45
|
+
result?: undefined;
|
|
46
|
+
}>;
|
|
47
|
+
export declare function getTaskHandler(input: {
|
|
48
|
+
service: string;
|
|
49
|
+
action?: string;
|
|
50
|
+
task_id: string;
|
|
51
|
+
}, client: Pick<RunApiClient, "getTask">): Promise<{
|
|
52
|
+
task_id: string;
|
|
53
|
+
status: string;
|
|
54
|
+
task: RunApiTaskResponse;
|
|
55
|
+
error?: undefined;
|
|
56
|
+
} | {
|
|
57
|
+
error: string;
|
|
58
|
+
task_id?: undefined;
|
|
59
|
+
status?: undefined;
|
|
60
|
+
task?: undefined;
|
|
61
|
+
}>;
|
|
62
|
+
export declare function chatHandler(input: {
|
|
63
|
+
model: string;
|
|
64
|
+
messages: ChatMessage[];
|
|
65
|
+
max_tokens?: number;
|
|
66
|
+
temperature?: number;
|
|
67
|
+
api?: "messages" | "chat_completions";
|
|
68
|
+
}, client: Pick<RunApiClient, "chat">): Promise<{
|
|
69
|
+
text: string | undefined;
|
|
70
|
+
response: unknown;
|
|
71
|
+
error?: undefined;
|
|
72
|
+
} | {
|
|
73
|
+
error: string;
|
|
74
|
+
text?: undefined;
|
|
75
|
+
response?: undefined;
|
|
76
|
+
}>;
|
|
77
|
+
export declare function defaultTimeout(action: string): number;
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { findModelForAction } from "../lib/contract.js";
|
|
2
|
+
import { friendlyError } from "../lib/errors.js";
|
|
3
|
+
import { validateInputRules } from "../lib/input-rules.js";
|
|
4
|
+
import { taskIdFromResponse, taskStatus } from "../lib/runapi-client.js";
|
|
5
|
+
import { validateParams } from "../lib/schema.js";
|
|
6
|
+
export async function checkBalanceHandler(client) {
|
|
7
|
+
try {
|
|
8
|
+
return await client.balance();
|
|
9
|
+
}
|
|
10
|
+
catch (error) {
|
|
11
|
+
return { error: friendlyError(error) };
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export async function createTaskHandler(input, client, sendProgress, progressToken) {
|
|
15
|
+
try {
|
|
16
|
+
const info = findModelForAction(input.service, input.action, input.model);
|
|
17
|
+
if (!info) {
|
|
18
|
+
return {
|
|
19
|
+
error: "Unsupported RunAPI service/action/model combination.",
|
|
20
|
+
hint: "Call list_models first to choose a supported model."
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
const body = validateParams(info.fields, {
|
|
24
|
+
...(input.params || {}),
|
|
25
|
+
...(input.model ? { model: input.model } : {})
|
|
26
|
+
});
|
|
27
|
+
const ruleError = validateInputRules(info, body);
|
|
28
|
+
if (ruleError) {
|
|
29
|
+
return {
|
|
30
|
+
error: `Invalid RunAPI parameters: ${ruleError}`,
|
|
31
|
+
hint: "Call get_model_info with service and action to inspect input_rules before create_task."
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
const created = await client.createTask(input.service, input.action, body);
|
|
35
|
+
const taskId = taskIdFromResponse(created);
|
|
36
|
+
if (!input.wait || !taskId) {
|
|
37
|
+
return {
|
|
38
|
+
created,
|
|
39
|
+
task_id: taskId,
|
|
40
|
+
status: taskStatus(created)
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
const timeout = input.timeout_ms ?? defaultTimeout(input.action);
|
|
44
|
+
const startedAt = Date.now();
|
|
45
|
+
const completed = await client.pollTask(input.service, taskId, input.action, {
|
|
46
|
+
timeoutMs: timeout,
|
|
47
|
+
intervalMs: input.poll_interval_ms ?? 5_000,
|
|
48
|
+
onProgress: async (task) => {
|
|
49
|
+
const elapsed = Date.now() - startedAt;
|
|
50
|
+
await sendProgress?.({
|
|
51
|
+
progressToken: progressToken || taskId,
|
|
52
|
+
progress: Math.min(elapsed, timeout),
|
|
53
|
+
total: timeout,
|
|
54
|
+
message: `RunAPI task ${taskId}: ${taskStatus(task)}`
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
return {
|
|
59
|
+
task_id: taskId,
|
|
60
|
+
status: taskStatus(completed),
|
|
61
|
+
result: completed
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
return { error: friendlyError(error) };
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
export async function getTaskHandler(input, client) {
|
|
69
|
+
try {
|
|
70
|
+
const task = await client.getTask(input.service, input.task_id, input.action);
|
|
71
|
+
return {
|
|
72
|
+
task_id: input.task_id,
|
|
73
|
+
status: taskStatus(task),
|
|
74
|
+
task
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
return { error: friendlyError(error) };
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
export async function chatHandler(input, client) {
|
|
82
|
+
try {
|
|
83
|
+
const response = await client.chat(input);
|
|
84
|
+
return {
|
|
85
|
+
text: extractChatText(response),
|
|
86
|
+
response
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
return { error: friendlyError(error) };
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
export function defaultTimeout(action) {
|
|
94
|
+
if (action.includes("video")) {
|
|
95
|
+
return 300_000;
|
|
96
|
+
}
|
|
97
|
+
if (["music", "audio", "speech", "sound", "voice"].some((term) => action.includes(term))) {
|
|
98
|
+
return 300_000;
|
|
99
|
+
}
|
|
100
|
+
if (action.includes("image")) {
|
|
101
|
+
return 120_000;
|
|
102
|
+
}
|
|
103
|
+
return 30_000;
|
|
104
|
+
}
|
|
105
|
+
function extractChatText(response) {
|
|
106
|
+
if (!response || typeof response !== "object") {
|
|
107
|
+
return undefined;
|
|
108
|
+
}
|
|
109
|
+
const record = response;
|
|
110
|
+
const content = record.content;
|
|
111
|
+
if (Array.isArray(content)) {
|
|
112
|
+
const text = content.map((item) => {
|
|
113
|
+
if (!item || typeof item !== "object") {
|
|
114
|
+
return undefined;
|
|
115
|
+
}
|
|
116
|
+
const value = item.text;
|
|
117
|
+
return typeof value === "string" ? value : undefined;
|
|
118
|
+
}).filter((value) => Boolean(value)).join("");
|
|
119
|
+
if (text.length > 0) {
|
|
120
|
+
return text;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
const choices = record.choices;
|
|
124
|
+
if (Array.isArray(choices)) {
|
|
125
|
+
const text = choices.map((choice) => {
|
|
126
|
+
if (!choice || typeof choice !== "object") {
|
|
127
|
+
return undefined;
|
|
128
|
+
}
|
|
129
|
+
const choiceRecord = choice;
|
|
130
|
+
const message = choiceRecord.message;
|
|
131
|
+
if (message && typeof message === "object") {
|
|
132
|
+
const value = message.content;
|
|
133
|
+
return typeof value === "string" ? value : undefined;
|
|
134
|
+
}
|
|
135
|
+
const value = choiceRecord.text;
|
|
136
|
+
return typeof value === "string" ? value : undefined;
|
|
137
|
+
}).filter((value) => Boolean(value)).join("");
|
|
138
|
+
if (text.length > 0) {
|
|
139
|
+
return text;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return undefined;
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=authenticated-handlers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authenticated-handlers.js","sourceRoot":"","sources":["../../../src/tools/authenticated-handlers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { RunApiClient } from "../lib/runapi-client.js";
|
|
3
|
+
import { jsonText } from "../lib/tool-response.js";
|
|
4
|
+
import { chatHandler, checkBalanceHandler, createTaskHandler, getTaskHandler } from "./authenticated-handlers.js";
|
|
5
|
+
export function registerAuthenticatedTools(server, client = new RunApiClient()) {
|
|
6
|
+
server.tool("check_balance", "Return the authenticated RunAPI account balance and spending metrics.", {}, async () => {
|
|
7
|
+
return jsonText(await checkBalanceHandler(client));
|
|
8
|
+
});
|
|
9
|
+
server.tool("create_task", "Create a RunAPI media task and optionally poll until completion.", {
|
|
10
|
+
service: z.string().describe("RunAPI service slug returned by list_models"),
|
|
11
|
+
action: z.string().describe("RunAPI endpoint name, for example text_to_image"),
|
|
12
|
+
model: z.string().optional().describe("RunAPI model slug"),
|
|
13
|
+
params: z.record(z.unknown()).default({}).describe("Endpoint parameters validated against data/contract.json where constrained."),
|
|
14
|
+
wait: z.boolean().default(true).describe("Poll until the task reaches a terminal status."),
|
|
15
|
+
timeout_ms: z.number().int().positive().optional(),
|
|
16
|
+
poll_interval_ms: z.number().int().positive().optional()
|
|
17
|
+
}, async ({ service, action, model, params, wait, timeout_ms, poll_interval_ms }, extra) => {
|
|
18
|
+
const progressToken = extra._meta?.progressToken;
|
|
19
|
+
const result = await createTaskHandler({ service, action, model, params, wait, timeout_ms, poll_interval_ms }, client, async (progress) => {
|
|
20
|
+
await extra.sendNotification?.({
|
|
21
|
+
method: "notifications/progress",
|
|
22
|
+
params: progress
|
|
23
|
+
});
|
|
24
|
+
}, progressToken);
|
|
25
|
+
return jsonText(result);
|
|
26
|
+
});
|
|
27
|
+
server.tool("get_task", "Fetch the current status and latest payload for an existing RunAPI task.", {
|
|
28
|
+
service: z.string(),
|
|
29
|
+
action: z.string().optional().describe("RunAPI endpoint name. Provide this when using media task routes."),
|
|
30
|
+
task_id: z.string()
|
|
31
|
+
}, async ({ service, action, task_id }) => {
|
|
32
|
+
return jsonText(await getTaskHandler({ service, action, task_id }, client));
|
|
33
|
+
});
|
|
34
|
+
server.tool("chat", "Send a prompt to a RunAPI LLM endpoint and return the response with usage metadata when available.", {
|
|
35
|
+
model: z.string().describe("RunAPI LLM model slug"),
|
|
36
|
+
messages: z.array(z.object({
|
|
37
|
+
role: z.enum(["system", "user", "assistant"]),
|
|
38
|
+
content: z.string()
|
|
39
|
+
})),
|
|
40
|
+
max_tokens: z.number().int().positive().optional(),
|
|
41
|
+
temperature: z.number().min(0).max(2).optional(),
|
|
42
|
+
api: z.enum(["messages", "chat_completions"]).default("messages")
|
|
43
|
+
}, async ({ model, messages, max_tokens, temperature, api }) => {
|
|
44
|
+
return jsonText(await chatHandler({
|
|
45
|
+
model,
|
|
46
|
+
messages: messages,
|
|
47
|
+
max_tokens,
|
|
48
|
+
temperature,
|
|
49
|
+
api
|
|
50
|
+
}, client));
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=authenticated.js.map
|