@fluxpool/mcp-server 0.1.0 → 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.
- package/README.md +57 -7
- package/dist/bridge.d.ts +3 -0
- package/dist/bridge.js +24 -0
- package/dist/bridge.js.map +1 -1
- package/dist/localInputs.d.ts +70 -0
- package/dist/localInputs.js +200 -0
- package/dist/localInputs.js.map +1 -0
- package/package.json +59 -50
package/README.md
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
# @fluxpool/mcp-server
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/@fluxpool/mcp-server)
|
|
4
|
+
[](LICENSE)
|
|
5
|
+
|
|
3
6
|
Generate images and videos with [Fluxpool.ai](https://fluxpool.ai) from Claude,
|
|
4
7
|
Cursor, or any MCP client — across Flux, Seedream, Seedance, Runway and more,
|
|
5
8
|
billed against a single pool of Fluxpool credits.
|
|
@@ -19,6 +22,46 @@ Generation is **asynchronous**: `create_generation` returns an ID, then
|
|
|
19
22
|
`check_generation` is polled until the status is `completed`. Output URLs are
|
|
20
23
|
presigned and **expire after one hour** — download promptly.
|
|
21
24
|
|
|
25
|
+
## Reference inputs (image / video / audio)
|
|
26
|
+
|
|
27
|
+
`create_generation` accepts an `inputs` array for image-to-image, video-to-video
|
|
28
|
+
and other reference-conditioned models. Every entry has the same shape:
|
|
29
|
+
|
|
30
|
+
```json
|
|
31
|
+
{ "type": "image", "source": "url", "value": "https://..." }
|
|
32
|
+
{ "type": "image", "source": "data", "value": "data:image/png;base64,..." }
|
|
33
|
+
{ "type": "image", "source": "local", "value": "./pic.png" }
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
- **`type`** — `image`, `video`, or `audio`.
|
|
37
|
+
- **`source`** — how `value` should be interpreted:
|
|
38
|
+
- `url` — an https:// URL, passed through untouched.
|
|
39
|
+
- `data` — a base64 data-URI; the backend uploads it to S3 for you.
|
|
40
|
+
- `local` — a path on the machine running this bridge. Resolved locally
|
|
41
|
+
(see below) before being forwarded to the server.
|
|
42
|
+
|
|
43
|
+
### Local file paths
|
|
44
|
+
|
|
45
|
+
`source: "local"` is a bridge convenience: the file is read on your machine,
|
|
46
|
+
base64-encoded, and sent to the server as a `data` entry. **The hosted
|
|
47
|
+
endpoint never sees a `local` from this bridge**, so `local` works only when
|
|
48
|
+
you connect via this package (not via the direct HTTP endpoint).
|
|
49
|
+
|
|
50
|
+
**Auto-compression for oversize images.** The backend caps inline data-URIs
|
|
51
|
+
at ~4.5 MB decoded. Images larger than 4 MB are automatically resized to
|
|
52
|
+
2048px and re-encoded as webp. That path uses the optional
|
|
53
|
+
[`sharp`](https://sharp.pixelplumbing.com/) dependency:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
# From your MCP client machine — installs prebuilt binaries for your platform.
|
|
57
|
+
npm install -g sharp
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
If `sharp` is not installed, oversize images are rejected with a message
|
|
61
|
+
pointing you here. Video and audio files above 4 MB are never auto-compressed
|
|
62
|
+
— use the two-step [`POST /v1/uploads`](https://api.fluxpool.ai) flow and pass
|
|
63
|
+
the returned URL with `source: "url"`.
|
|
64
|
+
|
|
22
65
|
## Get an API key
|
|
23
66
|
|
|
24
67
|
Create one at **<https://app.fluxpool.ai/api>**. Keys look like `fp_live_…`.
|
|
@@ -200,19 +243,26 @@ Tests stub `fetch` and use a dummy key — they never touch the network.
|
|
|
200
243
|
|
|
201
244
|
### Releasing
|
|
202
245
|
|
|
246
|
+
See [PUBLISHING.md](PUBLISHING.md) for the full release process. Short
|
|
247
|
+
version:
|
|
248
|
+
|
|
203
249
|
```bash
|
|
204
|
-
npm
|
|
250
|
+
npm publish --dry-run --access public # check the file list and warnings
|
|
251
|
+
npm version patch
|
|
252
|
+
npm publish --access public --otp=<code>
|
|
253
|
+
git push --follow-tags
|
|
205
254
|
```
|
|
206
255
|
|
|
207
|
-
|
|
208
|
-
npm Trusted Publishing (OIDC) — no npm token is stored in this repo.
|
|
209
|
-
|
|
210
|
-
## Contributing
|
|
256
|
+
## Support
|
|
211
257
|
|
|
212
|
-
|
|
258
|
+
Questions, bugs, or a tool you wish existed: email
|
|
259
|
+
<dev@fluxpool.ai>, open an issue at
|
|
260
|
+
<https://github.com/ZKcandy/fluxpool-mcp-server/issues>, or reach us through
|
|
261
|
+
<https://fluxpool.ai>.
|
|
213
262
|
|
|
214
263
|
Because tools are defined server-side, adding or changing one is a backend
|
|
215
|
-
change rather than a change
|
|
264
|
+
change rather than a change to this package — new tools reach you without
|
|
265
|
+
upgrading anything.
|
|
216
266
|
|
|
217
267
|
## License
|
|
218
268
|
|
package/dist/bridge.d.ts
CHANGED
|
@@ -14,12 +14,15 @@
|
|
|
14
14
|
*/
|
|
15
15
|
import type { Readable, Writable } from 'node:stream';
|
|
16
16
|
import { type FluxpoolClient } from './client.js';
|
|
17
|
+
import { type ResolveOptions } from './localInputs.js';
|
|
17
18
|
export interface BridgeOptions {
|
|
18
19
|
client: FluxpoolClient;
|
|
19
20
|
input?: Readable;
|
|
20
21
|
output?: Writable;
|
|
21
22
|
/** Defaults to stderr. Never stdout — that channel is the protocol. */
|
|
22
23
|
log?: (message: string) => void;
|
|
24
|
+
/** Injection seams for local-input resolution — tests only. */
|
|
25
|
+
resolveOptions?: ResolveOptions;
|
|
23
26
|
}
|
|
24
27
|
export declare class Bridge {
|
|
25
28
|
#private;
|
package/dist/bridge.js
CHANGED
|
@@ -14,17 +14,20 @@
|
|
|
14
14
|
*/
|
|
15
15
|
import { createInterface } from 'node:readline';
|
|
16
16
|
import { errorResponse } from './client.js';
|
|
17
|
+
import { needsLocalResolution, resolveLocalInputs } from './localInputs.js';
|
|
17
18
|
import { JSON_RPC } from './types.js';
|
|
18
19
|
export class Bridge {
|
|
19
20
|
#client;
|
|
20
21
|
#input;
|
|
21
22
|
#output;
|
|
22
23
|
#log;
|
|
24
|
+
#resolveOptions;
|
|
23
25
|
constructor(options) {
|
|
24
26
|
this.#client = options.client;
|
|
25
27
|
this.#input = options.input ?? process.stdin;
|
|
26
28
|
this.#output = options.output ?? process.stdout;
|
|
27
29
|
this.#log = options.log ?? ((message) => process.stderr.write(`${message}\n`));
|
|
30
|
+
this.#resolveOptions = options.resolveOptions;
|
|
28
31
|
}
|
|
29
32
|
/** Pump stdin until it closes. Resolves when the stream ends. */
|
|
30
33
|
async run() {
|
|
@@ -55,6 +58,27 @@ export class Bridge {
|
|
|
55
58
|
return;
|
|
56
59
|
}
|
|
57
60
|
const id = extractId(message);
|
|
61
|
+
// Local-file resolution runs BEFORE forwarding. It only fires when the
|
|
62
|
+
// message is a `tools/call` for `create_generation` and its arguments
|
|
63
|
+
// carry at least one `source: 'local'` entry — every other message
|
|
64
|
+
// (initialize, tools/list, check_generation, url/data inputs) skips
|
|
65
|
+
// straight through. Failures here become an INVALID_PARAMS response
|
|
66
|
+
// so the model on the other end gets a specific "your file didn't
|
|
67
|
+
// work" hint rather than a generic transport error.
|
|
68
|
+
if (needsLocalResolution(message)) {
|
|
69
|
+
try {
|
|
70
|
+
const params = message.params;
|
|
71
|
+
if (params && typeof params === 'object') {
|
|
72
|
+
params.arguments = await resolveLocalInputs(params.arguments, this.#resolveOptions);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
catch (cause) {
|
|
76
|
+
if (id === null)
|
|
77
|
+
return;
|
|
78
|
+
this.write(errorResponse(id, JSON_RPC.INVALID_PARAMS, describe(cause)));
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
58
82
|
let response;
|
|
59
83
|
try {
|
|
60
84
|
response = await this.#client.send(message, id);
|
package/dist/bridge.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bridge.js","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEhD,OAAO,EAAE,aAAa,EAAuB,MAAM,aAAa,CAAC;AACjE,OAAO,EAAE,QAAQ,EAAiD,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"bridge.js","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local-path resolution for `create_generation` inputs.
|
|
3
|
+
*
|
|
4
|
+
* The backend contract (project_api_image_input_unification) accepts three
|
|
5
|
+
* input sources:
|
|
6
|
+
* - `url` — https:// pass-through
|
|
7
|
+
* - `data` — base64 data-URI, backend inline-uploads to S3
|
|
8
|
+
* - `local` — client-side ONLY; the Lambda has no way to reach a caller's
|
|
9
|
+
* disk, so it rejects source=local with a 400.
|
|
10
|
+
*
|
|
11
|
+
* This module fills that gap for stdio MCP callers: when a `tools/call`
|
|
12
|
+
* message names a local file in `inputs[]`, we read it here, base64-encode
|
|
13
|
+
* (with optional sharp compression for oversize images), and rewrite the
|
|
14
|
+
* item to `source: 'data'` BEFORE the bridge forwards the request. The
|
|
15
|
+
* server never sees a `local` from this client.
|
|
16
|
+
*
|
|
17
|
+
* `sharp` is an optional dependency. If it is installed and an image
|
|
18
|
+
* exceeds the 4 MB data-URI target, we auto-resize + re-encode as webp
|
|
19
|
+
* so it fits. If not installed, oversize images get a clear error telling
|
|
20
|
+
* the user how to enable auto-compression. Non-image types (video/audio)
|
|
21
|
+
* never touch sharp regardless.
|
|
22
|
+
*/
|
|
23
|
+
export interface InputItem {
|
|
24
|
+
type?: string;
|
|
25
|
+
source?: string;
|
|
26
|
+
value?: string;
|
|
27
|
+
[k: string]: unknown;
|
|
28
|
+
}
|
|
29
|
+
export interface ResolveOptions {
|
|
30
|
+
/** Injection seam for tests — defaults to Node's fs.readFile. */
|
|
31
|
+
readFile?: (path: string) => Promise<Buffer>;
|
|
32
|
+
/** Injection seam for tests — defaults to dynamic import('sharp'). */
|
|
33
|
+
loadSharp?: () => Promise<SharpModule | null>;
|
|
34
|
+
}
|
|
35
|
+
interface SharpModule {
|
|
36
|
+
default: SharpFactory;
|
|
37
|
+
}
|
|
38
|
+
interface SharpFactory {
|
|
39
|
+
(input: Buffer): SharpInstance;
|
|
40
|
+
}
|
|
41
|
+
interface SharpInstance {
|
|
42
|
+
rotate(): SharpInstance;
|
|
43
|
+
resize(options: {
|
|
44
|
+
width?: number;
|
|
45
|
+
height?: number;
|
|
46
|
+
fit?: 'inside' | 'cover' | 'contain';
|
|
47
|
+
withoutEnlargement?: boolean;
|
|
48
|
+
}): SharpInstance;
|
|
49
|
+
webp(options: {
|
|
50
|
+
quality: number;
|
|
51
|
+
}): SharpInstance;
|
|
52
|
+
toBuffer(): Promise<Buffer>;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Walk a params object, rewriting every {source:'local'} entry inside
|
|
56
|
+
* `inputs[]` to {source:'data'}. Mutates in place and returns it so
|
|
57
|
+
* callers can chain.
|
|
58
|
+
*
|
|
59
|
+
* Throws with a plain Error whose message the bridge relays back to the
|
|
60
|
+
* MCP client as a JSON-RPC error. The message is written for the human
|
|
61
|
+
* on the other end of the client, not for a machine.
|
|
62
|
+
*/
|
|
63
|
+
export declare function resolveLocalInputs(params: unknown, options?: ResolveOptions): Promise<unknown>;
|
|
64
|
+
/**
|
|
65
|
+
* True when the message is a `tools/call` for `create_generation` that
|
|
66
|
+
* has `inputs[]` with at least one `source: 'local'` entry. Cheap check
|
|
67
|
+
* used by the bridge to decide whether to run the resolver.
|
|
68
|
+
*/
|
|
69
|
+
export declare function needsLocalResolution(message: unknown): boolean;
|
|
70
|
+
export {};
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local-path resolution for `create_generation` inputs.
|
|
3
|
+
*
|
|
4
|
+
* The backend contract (project_api_image_input_unification) accepts three
|
|
5
|
+
* input sources:
|
|
6
|
+
* - `url` — https:// pass-through
|
|
7
|
+
* - `data` — base64 data-URI, backend inline-uploads to S3
|
|
8
|
+
* - `local` — client-side ONLY; the Lambda has no way to reach a caller's
|
|
9
|
+
* disk, so it rejects source=local with a 400.
|
|
10
|
+
*
|
|
11
|
+
* This module fills that gap for stdio MCP callers: when a `tools/call`
|
|
12
|
+
* message names a local file in `inputs[]`, we read it here, base64-encode
|
|
13
|
+
* (with optional sharp compression for oversize images), and rewrite the
|
|
14
|
+
* item to `source: 'data'` BEFORE the bridge forwards the request. The
|
|
15
|
+
* server never sees a `local` from this client.
|
|
16
|
+
*
|
|
17
|
+
* `sharp` is an optional dependency. If it is installed and an image
|
|
18
|
+
* exceeds the 4 MB data-URI target, we auto-resize + re-encode as webp
|
|
19
|
+
* so it fits. If not installed, oversize images get a clear error telling
|
|
20
|
+
* the user how to enable auto-compression. Non-image types (video/audio)
|
|
21
|
+
* never touch sharp regardless.
|
|
22
|
+
*/
|
|
23
|
+
import { promises as fs } from 'node:fs';
|
|
24
|
+
import path from 'node:path';
|
|
25
|
+
/**
|
|
26
|
+
* Backend cap is 4.5 MB decoded; we target 4 MB to leave headroom for the
|
|
27
|
+
* base64 overhead + JSON-RPC envelope size. Anything over this after
|
|
28
|
+
* compression is refused rather than silently truncated.
|
|
29
|
+
*/
|
|
30
|
+
const DATA_URI_TARGET_BYTES = 4 * 1024 * 1024;
|
|
31
|
+
/**
|
|
32
|
+
* Fluxpool backend allow-list per type. Kept in sync with the backend
|
|
33
|
+
* ALLOWED_MIME_BY_TYPE (functions/ingestion/index.js). Keeping the client
|
|
34
|
+
* strict too means a mistyped MIME fails locally with a specific message,
|
|
35
|
+
* instead of trekking to the server for a generic 415.
|
|
36
|
+
*/
|
|
37
|
+
const ALLOWED_MIME_BY_TYPE = {
|
|
38
|
+
image: new Set(['image/png', 'image/jpeg', 'image/jpg', 'image/webp', 'image/gif']),
|
|
39
|
+
video: new Set(['video/mp4', 'video/webm', 'video/quicktime']),
|
|
40
|
+
audio: new Set(['audio/mpeg', 'audio/wav', 'audio/ogg', 'audio/mp4']),
|
|
41
|
+
};
|
|
42
|
+
const MIME_BY_EXT = {
|
|
43
|
+
'.png': 'image/png',
|
|
44
|
+
'.jpg': 'image/jpeg',
|
|
45
|
+
'.jpeg': 'image/jpeg',
|
|
46
|
+
'.webp': 'image/webp',
|
|
47
|
+
'.gif': 'image/gif',
|
|
48
|
+
'.mp4': 'video/mp4',
|
|
49
|
+
'.webm': 'video/webm',
|
|
50
|
+
'.mov': 'video/quicktime',
|
|
51
|
+
'.mp3': 'audio/mpeg',
|
|
52
|
+
'.wav': 'audio/wav',
|
|
53
|
+
'.ogg': 'audio/ogg',
|
|
54
|
+
'.m4a': 'audio/mp4',
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* Walk a params object, rewriting every {source:'local'} entry inside
|
|
58
|
+
* `inputs[]` to {source:'data'}. Mutates in place and returns it so
|
|
59
|
+
* callers can chain.
|
|
60
|
+
*
|
|
61
|
+
* Throws with a plain Error whose message the bridge relays back to the
|
|
62
|
+
* MCP client as a JSON-RPC error. The message is written for the human
|
|
63
|
+
* on the other end of the client, not for a machine.
|
|
64
|
+
*/
|
|
65
|
+
export async function resolveLocalInputs(params, options = {}) {
|
|
66
|
+
if (!isObject(params))
|
|
67
|
+
return params;
|
|
68
|
+
const inputs = params.inputs;
|
|
69
|
+
if (!Array.isArray(inputs))
|
|
70
|
+
return params;
|
|
71
|
+
const readFile = options.readFile ?? ((p) => fs.readFile(p));
|
|
72
|
+
const loadSharp = options.loadSharp ?? defaultLoadSharp;
|
|
73
|
+
let sharpModule; // lazy
|
|
74
|
+
for (let i = 0; i < inputs.length; i++) {
|
|
75
|
+
const item = inputs[i];
|
|
76
|
+
if (!isObject(item))
|
|
77
|
+
continue;
|
|
78
|
+
if (item.source !== 'local')
|
|
79
|
+
continue;
|
|
80
|
+
const type = String(item.type || 'image').toLowerCase();
|
|
81
|
+
const pathValue = item.value;
|
|
82
|
+
if (typeof pathValue !== 'string' || pathValue === '') {
|
|
83
|
+
throw new Error(`inputs[${i}].value must be a file path string when source='local'`);
|
|
84
|
+
}
|
|
85
|
+
if (!ALLOWED_MIME_BY_TYPE[type]) {
|
|
86
|
+
throw new Error(`inputs[${i}].type must be one of: image, video, audio (got '${type}')`);
|
|
87
|
+
}
|
|
88
|
+
let buf;
|
|
89
|
+
try {
|
|
90
|
+
buf = await readFile(pathValue);
|
|
91
|
+
}
|
|
92
|
+
catch (cause) {
|
|
93
|
+
throw new Error(`inputs[${i}]: could not read local file '${pathValue}': ${describe(cause)}`);
|
|
94
|
+
}
|
|
95
|
+
let mime = detectMimeFromPath(pathValue);
|
|
96
|
+
if (!mime || !ALLOWED_MIME_BY_TYPE[type].has(mime)) {
|
|
97
|
+
throw new Error(`inputs[${i}]: file '${path.basename(pathValue)}' has unsupported MIME ` +
|
|
98
|
+
`'${mime ?? 'unknown'}' for type='${type}'. ` +
|
|
99
|
+
`Allowed: ${Array.from(ALLOWED_MIME_BY_TYPE[type]).join(', ')}.`);
|
|
100
|
+
}
|
|
101
|
+
// Compress oversize images with sharp when available; refuse otherwise.
|
|
102
|
+
// Video and audio never touch sharp — those callers must use the
|
|
103
|
+
// two-step upload endpoint for oversize files.
|
|
104
|
+
if (buf.length > DATA_URI_TARGET_BYTES) {
|
|
105
|
+
if (type !== 'image') {
|
|
106
|
+
throw new Error(`inputs[${i}]: ${type} file '${path.basename(pathValue)}' is ` +
|
|
107
|
+
`${(buf.length / (1024 * 1024)).toFixed(1)} MB, over the ` +
|
|
108
|
+
`${DATA_URI_TARGET_BYTES / (1024 * 1024)} MB inline cap. ` +
|
|
109
|
+
`Use POST https://api.fluxpool.ai/v1/uploads to upload the file ` +
|
|
110
|
+
`and pass source='url' with the returned URL.`);
|
|
111
|
+
}
|
|
112
|
+
if (sharpModule === undefined)
|
|
113
|
+
sharpModule = await loadSharp();
|
|
114
|
+
if (sharpModule === null) {
|
|
115
|
+
throw new Error(`inputs[${i}]: image '${path.basename(pathValue)}' is ` +
|
|
116
|
+
`${(buf.length / (1024 * 1024)).toFixed(1)} MB, over the ` +
|
|
117
|
+
`${DATA_URI_TARGET_BYTES / (1024 * 1024)} MB inline cap. ` +
|
|
118
|
+
`Install optional dependency 'sharp' (npm i sharp) to enable ` +
|
|
119
|
+
`automatic compression, or resize the image before passing it.`);
|
|
120
|
+
}
|
|
121
|
+
const compressed = await compressWithSharp(sharpModule, buf);
|
|
122
|
+
buf = compressed;
|
|
123
|
+
mime = 'image/webp';
|
|
124
|
+
}
|
|
125
|
+
item.source = 'data';
|
|
126
|
+
item.value = `data:${mime};base64,${buf.toString('base64')}`;
|
|
127
|
+
}
|
|
128
|
+
return params;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Two-pass compression: try quality 82, drop to 65 if still over the cap,
|
|
132
|
+
* fail with a clear message if even 65 isn't enough. Two passes cover
|
|
133
|
+
* everyday phone photos (1-4 MB after resize at q82) and unusually large
|
|
134
|
+
* source images (drops to q65 for extreme cases) without going into
|
|
135
|
+
* an unbounded quality-reduction loop.
|
|
136
|
+
*/
|
|
137
|
+
async function compressWithSharp(mod, buf) {
|
|
138
|
+
const pipeline = (quality) => mod
|
|
139
|
+
.default(buf)
|
|
140
|
+
.rotate() // honour EXIF orientation before resizing
|
|
141
|
+
.resize({ width: 2048, height: 2048, fit: 'inside', withoutEnlargement: true })
|
|
142
|
+
.webp({ quality })
|
|
143
|
+
.toBuffer();
|
|
144
|
+
const first = await pipeline(82);
|
|
145
|
+
if (first.length <= DATA_URI_TARGET_BYTES)
|
|
146
|
+
return first;
|
|
147
|
+
const second = await pipeline(65);
|
|
148
|
+
if (second.length <= DATA_URI_TARGET_BYTES)
|
|
149
|
+
return second;
|
|
150
|
+
throw new Error(`Image is still ${(second.length / (1024 * 1024)).toFixed(1)} MB after ` +
|
|
151
|
+
`resize to 2048px + webp q65. Resize the source further or upload it ` +
|
|
152
|
+
`via POST https://api.fluxpool.ai/v1/uploads and pass source='url'.`);
|
|
153
|
+
}
|
|
154
|
+
async function defaultLoadSharp() {
|
|
155
|
+
try {
|
|
156
|
+
// Dynamic import so sharp stays a truly optional dependency: callers
|
|
157
|
+
// who never pass a local path never pay the ~30 MB install cost.
|
|
158
|
+
// The string is opaque to tsc so a missing @types/sharp does not
|
|
159
|
+
// become a build error — the module is loaded (or not) at runtime.
|
|
160
|
+
const specifier = 'sharp';
|
|
161
|
+
return (await import(specifier));
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
function detectMimeFromPath(p) {
|
|
168
|
+
const ext = path.extname(p).toLowerCase();
|
|
169
|
+
return MIME_BY_EXT[ext] ?? null;
|
|
170
|
+
}
|
|
171
|
+
function isObject(value) {
|
|
172
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
173
|
+
}
|
|
174
|
+
function describe(cause) {
|
|
175
|
+
return cause instanceof Error ? cause.message : String(cause);
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* True when the message is a `tools/call` for `create_generation` that
|
|
179
|
+
* has `inputs[]` with at least one `source: 'local'` entry. Cheap check
|
|
180
|
+
* used by the bridge to decide whether to run the resolver.
|
|
181
|
+
*/
|
|
182
|
+
export function needsLocalResolution(message) {
|
|
183
|
+
if (!isObject(message))
|
|
184
|
+
return false;
|
|
185
|
+
if (message.method !== 'tools/call')
|
|
186
|
+
return false;
|
|
187
|
+
const params = message.params;
|
|
188
|
+
if (!isObject(params))
|
|
189
|
+
return false;
|
|
190
|
+
if (params.name !== 'create_generation')
|
|
191
|
+
return false;
|
|
192
|
+
const args = params.arguments;
|
|
193
|
+
if (!isObject(args))
|
|
194
|
+
return false;
|
|
195
|
+
const inputs = args.inputs;
|
|
196
|
+
if (!Array.isArray(inputs))
|
|
197
|
+
return false;
|
|
198
|
+
return inputs.some((it) => isObject(it) && it.source === 'local');
|
|
199
|
+
}
|
|
200
|
+
//# sourceMappingURL=localInputs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"localInputs.js","sourceRoot":"","sources":["../src/localInputs.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,50 +1,59 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@fluxpool/mcp-server",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "MCP server for Fluxpool.ai — generate images and videos across Flux, Seedream, Seedance, Runway and more from Claude, Cursor, or any MCP client.",
|
|
5
|
-
"keywords": [
|
|
6
|
-
"mcp",
|
|
7
|
-
"model-context-protocol",
|
|
8
|
-
"fluxpool",
|
|
9
|
-
"ai",
|
|
10
|
-
"image-generation",
|
|
11
|
-
"video-generation",
|
|
12
|
-
"claude",
|
|
13
|
-
"cursor"
|
|
14
|
-
],
|
|
15
|
-
"homepage": "https://fluxpool.ai",
|
|
16
|
-
"bugs": {
|
|
17
|
-
"url": "https://github.com/ZKcandy/fluxpool-mcp-server/issues"
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
"
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
"
|
|
49
|
-
}
|
|
50
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "@fluxpool/mcp-server",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "MCP server for Fluxpool.ai — generate images and videos across Flux, Seedream, Seedance, Runway and more from Claude, Cursor, or any MCP client.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"mcp",
|
|
7
|
+
"model-context-protocol",
|
|
8
|
+
"fluxpool",
|
|
9
|
+
"ai",
|
|
10
|
+
"image-generation",
|
|
11
|
+
"video-generation",
|
|
12
|
+
"claude",
|
|
13
|
+
"cursor"
|
|
14
|
+
],
|
|
15
|
+
"homepage": "https://fluxpool.ai",
|
|
16
|
+
"bugs": {
|
|
17
|
+
"url": "https://github.com/ZKcandy/fluxpool-mcp-server/issues",
|
|
18
|
+
"email": "dev@fluxpool.ai"
|
|
19
|
+
},
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "git+https://github.com/ZKcandy/fluxpool-mcp-server.git"
|
|
23
|
+
},
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"author": "Fluxpool <dev@fluxpool.ai>",
|
|
26
|
+
"type": "module",
|
|
27
|
+
"bin": {
|
|
28
|
+
"fluxpool-mcp": "dist/index.js"
|
|
29
|
+
},
|
|
30
|
+
"files": [
|
|
31
|
+
"dist",
|
|
32
|
+
"README.md",
|
|
33
|
+
"LICENSE"
|
|
34
|
+
],
|
|
35
|
+
"engines": {
|
|
36
|
+
"node": ">=20"
|
|
37
|
+
},
|
|
38
|
+
"scripts": {
|
|
39
|
+
"build": "tsc",
|
|
40
|
+
"prepublishOnly": "npm run build && npm test",
|
|
41
|
+
"start": "node dist/index.js",
|
|
42
|
+
"test": "npm run build && node --test test/"
|
|
43
|
+
},
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"@modelcontextprotocol/sdk": "^1.0.4"
|
|
46
|
+
},
|
|
47
|
+
"optionalDependencies": {
|
|
48
|
+
"sharp": "^0.33.5"
|
|
49
|
+
},
|
|
50
|
+
"peerDependenciesMeta": {
|
|
51
|
+
"sharp": {
|
|
52
|
+
"optional": true
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
"devDependencies": {
|
|
56
|
+
"@types/node": "^22.10.2",
|
|
57
|
+
"typescript": "^5.7.2"
|
|
58
|
+
}
|
|
59
|
+
}
|